From 0bc4cf6b34beed14dc76afd238a468d0a18b848d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net>
Date: Tue, 13 Oct 1998 22:51:20 -0700
Subject: [PATCH] lots of wide-string stuff

Rev: bin/test_pike.pike:1.14
Rev: src/array.c:1.41
Rev: src/builtin_functions.c:1.129
Rev: src/modules/sprintf/sprintf.c:1.28
Rev: src/operators.c:1.43
Rev: src/pike_memory.c:1.27
Rev: src/stralloc.c:1.43
Rev: src/stralloc.h:1.21
Rev: src/testsuite.in:1.126
---
 bin/test_pike.pike            |   4 +-
 src/array.c                   |  17 +-
 src/builtin_functions.c       |  78 ++++---
 src/modules/sprintf/sprintf.c | 405 ++++++++++++++++++++--------------
 src/operators.c               | 160 +++++++-------
 src/pike_memory.c             |   4 +-
 src/stralloc.c                | 217 ++++++++++++++----
 src/stralloc.h                |  68 +++++-
 src/testsuite.in              |  53 ++++-
 9 files changed, 664 insertions(+), 342 deletions(-)

diff --git a/bin/test_pike.pike b/bin/test_pike.pike
index be45085c1e..31b09c37c1 100755
--- a/bin/test_pike.pike
+++ b/bin/test_pike.pike
@@ -1,6 +1,6 @@
 #!/usr/local/bin/pike
 
-/* $Id: test_pike.pike,v 1.13 1998/04/17 05:04:49 hubbe Exp $ */
+/* $Id: test_pike.pike,v 1.14 1998/10/14 05:47:06 hubbe Exp $ */
 
 #include <simulate.h>
 
@@ -121,7 +121,7 @@ int main(int argc, string *argv)
 	
 	if(verbose)
 	{
-	  werror("Doing test "+(e+1)+"\n");
+	  werror("Doing test %d (%d total)\n",e+1,successes+errors+1);
 	  if(verbose>1)
 	    werror(test+"\n");
 	}
diff --git a/src/array.c b/src/array.c
index f7ff3ceec9..4dab2f2b14 100644
--- a/src/array.c
+++ b/src/array.c
@@ -19,7 +19,7 @@
 #include "gc.h"
 #include "main.h"
 
-RCSID("$Id: array.c,v 1.40 1998/10/11 11:18:50 hubbe Exp $");
+RCSID("$Id: array.c,v 1.41 1998/10/14 05:48:44 hubbe Exp $");
 
 struct array empty_array=
 {
@@ -1424,7 +1424,7 @@ struct array *explode(struct pike_string *str,
 struct pike_string *implode(struct array *a,struct pike_string *del)
 {
   INT32 len,e, inited;
-  char *r;
+  PCHARP r;
   struct pike_string *ret,*tmp;
   int max_shift=0;
 
@@ -1439,10 +1439,11 @@ struct pike_string *implode(struct array *a,struct pike_string *del)
 	max_shift=ITEM(a)[e].u.string->size_shift;
     }
   }
+  if(del->size_shift > max_shift) max_shift=del->size_shift;
   if(len) len-=del->len;
   
   ret=begin_wide_shared_string(len,max_shift);
-  r=ret->str;
+  r=MKPCHARP_STR(ret);
   inited=0;
   for(e=0;e<a->size;e++)
   {
@@ -1450,17 +1451,17 @@ struct pike_string *implode(struct array *a,struct pike_string *del)
     {
       if(inited)
       {
-	pike_string_cpy(r,max_shift,del);
-	r+=del->len << max_shift;
+	pike_string_cpy(r,del);
+	INC_PCHARP(r,del->len);
       }
       inited=1;
       tmp=ITEM(a)[e].u.string;
-      pike_string_cpy(r,max_shift,tmp);
-      r+=tmp->len << max_shift;
+      pike_string_cpy(r,tmp);
+      INC_PCHARP(r,tmp->len);
       len++;
     }
   }
-  return end_shared_string(ret);
+  return low_end_shared_string(ret);
 }
 
 struct array *copy_array_recursively(struct array *a,struct processing *p)
diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index 741423ffaa..3bdc252e87 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: builtin_functions.c,v 1.128 1998/10/11 11:18:50 hubbe Exp $");
+RCSID("$Id: builtin_functions.c,v 1.129 1998/10/14 05:48:45 hubbe Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "pike_macros.h"
@@ -132,6 +132,7 @@ void f_ctime(INT32 args)
   push_string(make_shared_string(ctime(&i)));
 }
 
+/* FIXME: wide char support ! */
 void f_lower_case(INT32 args)
 {
   INT32 i;
@@ -152,6 +153,7 @@ void f_lower_case(INT32 args)
   push_string(end_shared_string(ret));
 }
 
+/* FIXME: wide char support ! */
 void f_upper_case(INT32 args)
 {
   INT32 i;
@@ -217,7 +219,6 @@ void f_search(INT32 args)
   case T_STRING:
   {
     char *ptr;
-    INT32 len;
     if(sp[1-args].type != T_STRING)
       PIKE_ERROR("search", "Bad argument 2.\n", sp, args);
     
@@ -231,20 +232,13 @@ void f_search(INT32 args)
       if(start<0)
 	PIKE_ERROR("search", "Start must be greater or equal to zero.\n", sp, args);
     }
-    len=sp[-args].u.string->len - start;
 
     if(len<0)
       PIKE_ERROR("search", "Start must not be greater than the length of the string.\n", sp, args);
 
-    if(len>0 && (ptr=my_memmem(sp[1-args].u.string->str,
-			       sp[1-args].u.string->len,
-			       sp[-args].u.string->str+start,
-			       len)))
-    {
-      start=ptr-sp[-args].u.string->str;
-    }else{
-      start=-1;
-    }
+    start=string_search(sp[-args].u.string,
+			sp[1-args].u.string,
+			start);
     pop_n_elems(args);
     push_int(start);
     break;
@@ -1135,10 +1129,26 @@ void f_reverse(INT32 args)
   {
     INT32 e;
     struct pike_string *s;
-    s=begin_shared_string(sp[-args].u.string->len);
-    for(e=0;e<sp[-args].u.string->len;e++)
-      s->str[e]=sp[-args].u.string->str[sp[-args].u.string->len-1-e];
-    s=end_shared_string(s);
+    s=begin_wide_shared_string(sp[-args].u.string->len,
+			  sp[-args].u.string->size_shift);
+    switch(sp[-args].u.string->size_shift)
+    {
+      case 0:
+	for(e=0;e<sp[-args].u.string->len;e++)
+	  STR0(s)[e]=STR0(sp[-args].u.string)[sp[-args].u.string->len-1-e];
+	break;
+
+      case 1:
+	for(e=0;e<sp[-args].u.string->len;e++)
+	  STR1(s)[e]=STR1(sp[-args].u.string)[sp[-args].u.string->len-1-e];
+	break;
+
+      case 2:
+	for(e=0;e<sp[-args].u.string->len;e++)
+	  STR2(s)[e]=STR2(sp[-args].u.string)[sp[-args].u.string->len-1-e];
+	break;
+    }
+    s=low_end_shared_string(s);
     pop_n_elems(args);
     push_string(s);
     break;
@@ -1360,12 +1370,17 @@ void f_replace(INT32 args)
 void f_compile(INT32 args)
 {
   struct program *p;
+
   if(args < 1)
     PIKE_ERROR("compile", "Too few arguments.\n", sp, args);
 
   if(sp[-args].type != T_STRING)
     PIKE_ERROR("compile", "Bad argument 1.\n", sp, args);
 
+  if(sp[-args].u.string->size_shift)
+    PIKE_ERROR("compile", "Wide strings not supported yet.\n", sp, args);
+
+
   p=compile(sp[-args].u.string);
   pop_n_elems(args);
   push_program(p);
@@ -1808,33 +1823,34 @@ static void f_mktime (INT32 args)
 
 
 /* Check if the string s[0..len[ matches the glob m[0..mlen[ */
-static int does_match(char *s, int len, char *m, int mlen)
+static int does_match(struct pike_string *s,int j,
+		      struct pike_string *m,int i)
 {
-  int i,j;
-  for (i=j=0; i<mlen; i++)
+  for (; i<m->len; i++)
   {
-    switch (m[i])
+    switch (index_shared_string(m,i))
     {
      case '?':
-       if(j++>=len) return 0;
+       if(j++>=s->len) return 0;
        break;
 
      case '*': 
       i++;
-      if (i==mlen) return 1;	/* slut */
+      if (i==m->len) return 1;	/* slut */
 
-      for (;j<len;j++)
-	if (does_match(s+j,len-j,m+i,mlen-i))
+      for (;j<s->len;j++)
+	if (does_match(s,j,m,i))
 	  return 1;
 
       return 0;
 
      default: 
-       if(j>=len || m[i]!=s[j]) return 0;
+       if(j>=s->len ||
+	  index_shared_string(m,i)!=index_shared_string(s,j)) return 0;
        j++;
     }
   }
-  return j==len;
+  return j==s->len;
 }
 
 void f_glob(INT32 args)
@@ -1858,10 +1874,7 @@ void f_glob(INT32 args)
   switch(sp[1-args].type)
   {
   case T_STRING:
-    i=does_match(sp[1-args].u.string->str,
-		 sp[1-args].u.string->len,
-		 glob->str,
-		 glob->len);
+    i=does_match(sp[1-args].u.string,0,glob,0);
     pop_n_elems(2);
     push_int(i);
     break;
@@ -1874,10 +1887,7 @@ void f_glob(INT32 args)
       if(ITEM(a)[i].type != T_STRING)
 	PIKE_ERROR("glob", "Bad argument 2.\n", sp, args);
 
-      if(does_match(ITEM(a)[i].u.string->str,
-		    ITEM(a)[i].u.string->len,
-		    glob->str,
-		    glob->len))
+      if(does_match(ITEM(a)[i].u.string,0,glob,0))
       {
 	add_ref(ITEM(a)[i].u.string);
 	push_string(ITEM(a)[i].u.string);
diff --git a/src/modules/sprintf/sprintf.c b/src/modules/sprintf/sprintf.c
index fa9e8f0d3b..4d530ae716 100644
--- a/src/modules/sprintf/sprintf.c
+++ b/src/modules/sprintf/sprintf.c
@@ -3,6 +3,9 @@
 ||| Pike is distributed as GPL (General Public License)
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
+
+/* TODO: use ONERROR to cleanup fsp */
+
 /*
   Pike Sprintf v2.0 By Fredrik Hubinette (Profezzorn@nannymud)
   Should be reasonably compatible and somewhat faster than v1.05+ of Lynscar's
@@ -96,7 +99,7 @@
 */
 
 #include "global.h"
-RCSID("$Id: sprintf.c,v 1.27 1998/08/07 16:29:07 grubba Exp $");
+RCSID("$Id: sprintf.c,v 1.28 1998/10/14 05:51:20 hubbe Exp $");
 #include "error.h"
 #include "array.h"
 #include "svalue.h"
@@ -107,6 +110,7 @@ RCSID("$Id: sprintf.c,v 1.27 1998/08/07 16:29:07 grubba Exp $");
 #include "interpret.h"
 #include "pike_memory.h"
 #include "pike_macros.h"
+#include <ctype.h>
 
 #ifdef PC
 #undef PC
@@ -126,17 +130,17 @@ RCSID("$Id: sprintf.c,v 1.27 1998/08/07 16:29:07 grubba Exp $");
 struct format_info
 {
   char *fi_free_string;
-  char *b;
+  PCHARP b;
   int len;
   int width;
   int precision;
-  char *pad_string;
+  PCHARP pad_string;
   int pad_length;
   int column_entries;
   short flags;
-  short pos_pad;
-  short column_width;
-  short column_modulo;
+  char pos_pad;
+  int column_width;
+  int column_modulo;
 };
 
 static struct format_info format_info_stack[FORMAT_INFO_STACK_SIZE];
@@ -340,57 +344,62 @@ INLINE static void low_write_IEEE_float(char *b, double d, int sz)
 
 /* Position a string inside a field with fill */
 
-INLINE static void fix_field(char *b,
+INLINE static void fix_field(struct string_builder *r,
+			     PCHARP b,
 			     int len,
 			     int flags,
 			     int width,
-			     char *pad_string,
+			     PCHARP pad_string,
 			     int pad_length,
 			     char pos_pad)
 {
   int e,d;
   if(!width)
   {
-    if(pos_pad && b[0]!='-') my_putchar(pos_pad);
-    my_binary_strcat(b,len);
+    if(pos_pad && EXTRACT_PCHARP(b)!='-') string_builder_putchar(r,pos_pad);
+    string_builder_append(r,b,len);
     return;
   }
 
   d=0;
-  if(!(flags & DO_TRUNC) && len+(pos_pad && b[0]!='-')>=width)
+  if(!(flags & DO_TRUNC) && len+(pos_pad && EXTRACT_PCHARP(b)!='-')>=width)
   {
-    if(pos_pad && b[0]!='-') my_putchar(pos_pad);
-    my_binary_strcat(b,len);
+    if(pos_pad && EXTRACT_PCHARP(b)!='-') string_builder_putchar(r,pos_pad);
+    string_builder_append(r,b,len);
     return;
   }
   if(flags & ZERO_PAD)		/* zero pad is kind of special... */
   {
-    if(b[0]=='-')
+    if(EXTRACT_PCHARP(b)=='-')
     {
-      my_putchar('-');
-      b++;
+      string_builder_putchar(r,'-');
+      INC_PCHARP(b,1);
       len--;
       width--;
     }else{
       if(pos_pad)
       {
-        my_putchar(pos_pad);
+        string_builder_putchar(r,pos_pad);
         width--;
       }
     }
-    for(;width>len;width--) my_putchar('0');
-    my_binary_strcat(b,len);
+#if 1
+    string_builder_fill(r,width-len,MKPCHARP("0",0),1,0);
+#else
+    for(;width>len;width--) string_builder_putchar(r,'0');
+#endif
+    string_builder_append(r,b,len);
     return;
   }
 
   if(flags & FIELD_CENTER)
   {
     e=len;
-    if(pos_pad && b[0]!='-') e++;
+    if(pos_pad && EXTRACT_PCHARP(b)!='-') e++;
     e=(width-e)/2;
     if(e>0)
     {
-      memfill(make_buf_space(e), e, pad_string, pad_length, 0);
+      string_builder_fill(r,e,pad_string, pad_length, 0);
       width-=e;
     }
     flags|=FIELD_LEFT;
@@ -398,11 +407,18 @@ INLINE static void fix_field(char *b,
 
   if(flags & FIELD_LEFT)
   {
-    if(pos_pad && b[0]!='-') { my_putchar(pos_pad); width--; d++; }
+    if(pos_pad && EXTRACT_PCHARP(b)!='-')
+    {
+      string_builder_putchar(r,pos_pad);
+      width--;
+      d++;
+    }
+
     d+=MINIMUM(width,len);
     while(len && width)
     {
-      my_putchar(*(b++));
+      string_builder_putchar(r,EXTRACT_PCHARP(b));
+      INC_PCHARP(b,1);
       len--;
       width--;
     }
@@ -410,7 +426,7 @@ INLINE static void fix_field(char *b,
     if(width>0)
     {
       d%=pad_length;
-      memfill(make_buf_space(width), width, pad_string, pad_length, d);
+      string_builder_fill(r,width,pad_string,pad_length,d);
     }
     
     return;
@@ -418,22 +434,22 @@ INLINE static void fix_field(char *b,
 
   /* Right-justification */
 
-  if(pos_pad && b[0]!='-') len++;
+  if(pos_pad && EXTRACT_PCHARP(b)!='-') len++;
   e=width-len;
   if(e>0)
   {
-    memfill(make_buf_space(e), e, pad_string, pad_length, 0);
+    string_builder_fill(r,e,pad_string, pad_length, 0);
     width-=e;
   }
 
-  if(pos_pad && b[0]!='-' && len==width)
+  if(pos_pad && EXTRACT_PCHARP(b)!='-' && len==width)
   {
-    my_putchar(pos_pad);
+    string_builder_putchar(r,pos_pad);
     len--;
     width--;
   }
-  b+=len-width;
-  my_binary_strcat(b,width);
+  INC_PCHARP(b,len-width);
+  string_builder_append(r,b,width);
 }
 
 static struct svalue temp_svalue = { T_INT };
@@ -468,12 +484,13 @@ static void sprintf_error(char *s,...)
  * if there is more for next line.
  */
 
-INLINE static int do_one(struct format_info *f)
+INLINE static int do_one(struct string_builder *r,
+			 struct format_info *f)
 {
-  char *rest;
+  PCHARP rest;
   int e,d,lastspace;
 
-  rest=NULL;
+  rest.ptr=0;
   if(f->flags & (LINEBREAK|ROUGH_LINEBREAK))
   {
     if(!f->width)
@@ -481,28 +498,40 @@ INLINE static int do_one(struct format_info *f)
     lastspace=-1;
     for(e=0;e<f->len && e<=f->width;e++)
     {
-      if(f->b[e]=='\n')
+      switch(INDEX_PCHARP(f->b,e))
       {
-        lastspace=e;
-        rest=f->b+e+1;
-        break;
-      }
-      if(f->b[e]==' ' && (f->flags & LINEBREAK))
-      {
-        lastspace=e;
-        rest=f->b+e+1;
+	case '\n':
+	  lastspace=e;
+	  rest=ADD_PCHARP(f->b,e+1);
+	  break;
+
+	case ' ':
+	  if(f->flags & LINEBREAK)
+	  {
+	    lastspace=e;
+	    rest=ADD_PCHARP(f->b,e+1);
+	  }
+	default:
+	  continue;
       }
+      break;
     }
     if(e==f->len && f->len<=f->width)
     {
       lastspace=e;
-      rest=f->b+lastspace;
+      rest=ADD_PCHARP(f->b,lastspace);
     }else if(lastspace==-1){
       lastspace=MINIMUM(f->width,f->len);
-      rest=f->b+lastspace;
+      rest=ADD_PCHARP(f->b,lastspace);
     }
-    fix_field(f->b,lastspace,f->flags,f->width,f->pad_string,
-	      f->pad_length,f->pos_pad);
+    fix_field(r,
+	      f->b,
+	      lastspace,
+	      f->flags,
+	      f->width,
+	      f->pad_string,
+	      f->pad_length,
+	      f->pos_pad);
   }
   else if(f->flags & INVERSE_COLUMN_MODE)
   {
@@ -512,33 +541,45 @@ INLINE static int do_one(struct format_info *f)
     if(!f->column_width || e<1) e=1;
 
     rest=f->b;
-    for(d=0;rest[d] && e;d++)
+    for(d=0;INDEX_PCHARP(rest,d) && e;d++)
     {
 #if 0
       if(rest != f->b)
 	fix_field(" ",1,0,1," ",1,0);
 #endif
 
-      while(rest[d] && rest[d]!='\n') d++;
-      fix_field(rest,d,f->flags,f->column_width,f->pad_string,
-		f->pad_length,f->pos_pad);
+      while(INDEX_PCHARP(rest,d) && INDEX_PCHARP(rest,d)!='\n')
+	d++;
+
+      fix_field(r,
+		rest,
+		d,
+		f->flags,
+		f->column_width,
+		f->pad_string,
+		f->pad_length,
+		f->pos_pad);
 
       e--;
-      rest+=d;
+      INC_PCHARP(rest,d);
       d=-1;
-      if(*rest) rest++;
+      if(EXTRACT_PCHARP(rest)) INC_PCHARP(rest,1);
     }
   }
   else if(f->flags & COLUMN_MODE)
   {
     int mod,col;
+    PCHARP end;
+
     if(!f->width)
       sprintf_error("Must have field width for column mode.\n");
     mod=f->column_modulo;
     col=f->width/(f->column_width+1);
     if(!f->column_width || col<1) col=1;
     rest=f->b;
-    for(d=0;rest && d<col;d++)
+    end=ADD_PCHARP(rest,f->len);
+
+    for(d=0;rest.ptr && d<col;d++)
     {
 #if 0
       if(rest != f->b)
@@ -546,51 +587,52 @@ INLINE static int do_one(struct format_info *f)
 #endif
 
       /* Find end of entry */
-      for(e=0;rest[e] && rest[e]!='\n';e++);
+      for(e=0;COMPARE_PCHARP(rest,<,end) && INDEX_PCHARP(rest,e)!='\n';e++);
 
-      fix_field(rest,e,f->flags,f->column_width,
+      fix_field(r,rest,e,f->flags,f->column_width,
 		f->pad_string,f->pad_length,f->pos_pad);
 
       f->column_entries--;
 
       /* Advance to after entry */
-      rest+=e;
-      if(!*rest) break;
-      rest++;
+      INC_PCHARP(rest,e);
+      if(!COMPARE_PCHARP(rest,<,end)) break;
+      INC_PCHARP(rest,1);
 
       for(e=1;e<mod;e++)
       {
-	char *s=STRCHR(rest,'\n');
-	if(s)
+	PCHARP s=MEMCHR_PCHARP(rest,'\n',SUBTRACT_PCHARP(end,rest));
+	if(s.ptr)
 	{
-	  rest=s+1;
+	  rest=ADD_PCHARP(s,1);
 	}else{
-	  rest=0;
+	  rest.ptr=0;
 	  break;
 	}
       }
     }
     if(f->column_entries>0)
     {
-      for(rest=f->b;*rest && *rest!='\n';rest++);
-      if(*rest) rest++;
+      for(rest=f->b;COMPARE_PCHARP(rest,>=,end) &&
+	    EXTRACT_PCHARP(rest)!='\n';INC_PCHARP(rest,1));
+      if(COMPARE_PCHARP(rest,<,end)) INC_PCHARP(rest,1);
     }else{
-      rest=NULL;
+      rest.ptr=0;
     }
   }
   else
   {
-    fix_field(f->b,f->len,f->flags,f->width,f->pad_string,f->pad_length,f->pos_pad);
+    fix_field(r,f->b,f->len,f->flags,f->width,f->pad_string,f->pad_length,f->pos_pad);
   }
 
   if(f->flags & REPEAT) return 0;
-  if(rest)
+  if(rest.ptr)
   {
-    f->len-=rest-f->b;
+    f->len-=SUBTRACT_PCHARP(rest,f->b);
     f->b=rest;
   }else{
     f->len=0;
-    f->b="";
+    f->b=MKPCHARP("",0);
   }
   return f->len>0;
 }
@@ -632,26 +674,28 @@ INLINE static int do_one(struct format_info *f)
 #define DO_OP() \
    if(fsp->flags & SNURKEL) \
    { \
+     ONERROR _e; \
      struct array *_v; \
-     string _b; \
-     _b.str=0; \
-     _b.len=0; \
+     struct string_builder _b; \
+     init_string_builder(&_b,0); \
+     SET_ONERROR(_e, free_string_builder, &_b); \
      GET_ARRAY(_v); \
      for(tmp=0;tmp<_v->size;tmp++) \
      { \
        struct svalue *save_sp=sp; \
        array_index_no_free(sp,_v,tmp); \
        sp++; \
-       _b=low_pike_sprintf(begin,a-begin+1,sp-1,1,_b,nosnurkel+1); \
+       low_pike_sprintf(&_b,begin,SUBTRACT_PCHARP(a,begin)+1,sp-1,1,nosnurkel+1); \
        if(save_sp < sp) pop_stack(); \
      } \
-     fsp->b=_b.str; \
-     fsp->len=_b.len; \
-     fsp->fi_free_string=fsp->b; \
-     fsp->pad_string=" "; \
+     fsp->b=MKPCHARP_STR(_b.s); \
+     fsp->len=_b.s->len; \
+     fsp->fi_free_string=(char *)_b.s; \
+     fsp->pad_string=MKPCHARP(" ",0); \
      fsp->pad_length=1; \
      fsp->column_width=0; \
      fsp->pos_pad=fsp->flags=fsp->width=fsp->precision=0; \
+     UNSET_ONERROR(_e); \
      break; \
    }
 
@@ -661,24 +705,26 @@ INLINE static int do_one(struct format_info *f)
  * the buffer in save_objectII.c
  */
 
-static string low_pike_sprintf(char *format,
-			       int format_len,
-			       struct svalue *argp,
-			       int num_arg,
-			       string prefix,
-			       int nosnurkel)
+static void low_pike_sprintf(struct string_builder *r,
+			     PCHARP format,
+			     int format_len,
+			     struct svalue *argp,
+			     int num_arg,
+			     int nosnurkel)
 {
   int argument=0;
   int tmp,setwhat,pos,d,e;
-  char *a,*begin;
-  char buffer[40];
+  char buffer[140];
   struct format_info *f,*start;
   float tf;
   struct svalue *arg=0;	/* pushback argument */
   struct svalue *lastarg=0;
 
+  PCHARP a,begin;
+  PCHARP format_end=ADD_PCHARP(format,format_len);
+
   start=fsp;
-  for(a=format;a<format+format_len;a++)
+  for(a=format;COMPARE_PCHARP(a,<,format_end);INC_PCHARP(a,1))
   {
     int num_snurkel;
 
@@ -689,19 +735,20 @@ static string low_pike_sprintf(char *format,
 #endif
     if(fsp-format_info_stack==FORMAT_INFO_STACK_SIZE)
       sprintf_error("Sprintf stack overflow.\n");
-    fsp->pad_string=" ";
+    fsp->pad_string=MKPCHARP(" ",0);
     fsp->pad_length=1;
-    fsp->fi_free_string=NULL;
+    fsp->fi_free_string=0;
     fsp->column_width=0;
     fsp->pos_pad=fsp->flags=fsp->width=fsp->precision=0;
 
-    if(*a!='%')
+    if(EXTRACT_PCHARP(a)!='%')
     {
-      for(e=0;a[e]!='%' && a+e<format+format_len;e++);
+      for(e=0;INDEX_PCHARP(a,e)!='%' &&
+	    COMPARE_PCHARP(ADD_PCHARP(a,e),<,format_end);e++);
       fsp->b=a;
       fsp->len=e;
       fsp->width=e;
-      a+=e-1;
+      INC_PCHARP(a,e-1);
       continue;
     }
     num_snurkel=0;
@@ -709,12 +756,19 @@ static string low_pike_sprintf(char *format,
     setwhat=pos=0;
     begin=a;
 
-    for(a++;;a++)
+    for(INC_PCHARP(a,1);;INC_PCHARP(a,1))
     {
-      switch(*a)
+/*      fprintf(stderr,"sprintf-flop: %d (%c)\n",EXTRACT_PCHARP(a),EXTRACT_PCHARP(a)); */
+      switch(EXTRACT_PCHARP(a))
       {
       default:
-	sprintf_error("Error in format string.\n");
+	if(EXTRACT_PCHARP(a) < 256 && 
+	   isprint(EXTRACT_PCHARP(a)))
+	{
+	  sprintf_error("Error in format string, %c is not a format.\n",EXTRACT_PCHARP(a));
+	}else{
+	  sprintf_error("Error in format string, \\%o is not a format.\n",EXTRACT_PCHARP(a));
+	}
 	fatal("Foo, you shouldn't be here!\n");
 
         /* First the modifiers */
@@ -723,8 +777,8 @@ static string low_pike_sprintf(char *format,
       case '1': case '2': case '3':
       case '4': case '5': case '6':
       case '7': case '8': case '9':
-	tmp=STRTOL(a,&a,10);
-	a--;
+	tmp=STRTOL_PCHARP(a,&a,10);
+	INC_PCHARP(a,-1);
 	goto got_arg;
 
       case '*':
@@ -766,22 +820,25 @@ static string low_pike_sprintf(char *format,
 
       case '\'':
 	tmp=0;
-	for(a++;a[tmp]!='\'';tmp++)
-	  if(a >= format + format_len )
+	for(INC_PCHARP(a,1);INDEX_PCHARP(a,tmp)!='\'';tmp++)
+	{
+/*	  fprintf(stderr,"Sprinf-glop: %d (%c)\n",INDEX_PCHARP(a,tmp),INDEX_PCHARP(a,tmp)); */
+	  if(COMPARE_PCHARP(a,>=,format_end))
 	    sprintf_error("Unfinished pad string in format string.\n");
+	}
 	if(tmp)
 	{
 	  fsp->pad_string=a;
 	  fsp->pad_length=tmp;
 	}
-	a+=tmp;
+	INC_PCHARP(a,tmp);
 	continue;
 
       case '~':
       {
 	struct pike_string *s;
 	GET_STRING(s);
-	fsp->pad_string=s->str;
+	fsp->pad_string=MKPCHARP_STR(s);
 	fsp->pad_length=s->len;
 	continue;
       }
@@ -797,21 +854,21 @@ static string low_pike_sprintf(char *format,
       case '{':
       {
 	struct array *w;
-	string b;
+	struct string_builder b;
 #ifdef DEBUG
 	struct format_info *fsp_save=fsp;
 #endif
 	DO_OP();
 	for(e=1,tmp=1;tmp;e++)
 	{
-	  if(!a[e])
+	  if(!INDEX_PCHARP(a,e))
 	  {
 	    sprintf_error("Missing %%} in format string.\n");
 	    break;		/* UNREACHED */
 	  }
-	  if(a[e]=='%')
+	  if(INDEX_PCHARP(a,e)=='%')
 	  {
-	    switch(a[e+1])
+	    switch(INDEX_PCHARP(a,e+1))
 	    {
 	    case '%': e++; break;
 	    case '}': tmp--; break;
@@ -823,11 +880,12 @@ static string low_pike_sprintf(char *format,
 	GET_ARRAY(w);
 	if(!w->size)
 	{
-	  fsp->b="";
+	  fsp->b=MKPCHARP("",0);
 	  fsp->len=0;
 	}else{
-	  b.str=NULL;
-	  b.len=0;
+	  ONERROR err;
+	  init_string_builder(&b,0);
+	  SET_ONERROR(err,free_string_builder,&b);
 	  for(tmp=0;tmp<w->size;tmp++)
 	  {
 	    struct svalue *s;
@@ -844,7 +902,7 @@ static string low_pike_sprintf(char *format,
 	      array_index_no_free(sp,w,tmp);
 	      sp++;
 	    }
-	    b=low_pike_sprintf(a+1,e-2,s,sp-s,b,0);
+	    low_pike_sprintf(&b,ADD_PCHARP(a,1),e-2,s,sp-s,0);
 	    pop_n_elems(sp-s);
 	  }
 #ifdef DEBUG
@@ -853,22 +911,24 @@ static string low_pike_sprintf(char *format,
 	  if(fsp!=fsp_save)
 	    fatal("sprintf: fsp incorrect after recursive sprintf.\n");
 #endif
-	  fsp->b=b.str;
-	  fsp->len=b.len;
-	  fsp->fi_free_string=fsp->b;
+	  fsp->b=MKPCHARP_STR(b.s);
+	  fsp->len=b.s->len;
+	  fsp->fi_free_string=(char *)b.s;
+	  UNSET_ONERROR(err);
 	}
-	a+=e;
+	
+	INC_PCHARP(a,e);
 	break;
       }
 
       case '%':
-	fsp->b="%";
+	fsp->b=MKPCHARP("%",0);
 	fsp->len=fsp->width=1;
 	break;
 
       case 'n':
 	DO_OP();
-	fsp->b="";
+	fsp->b=MKPCHARP("",0);
 	fsp->len=0;
 	break;
 
@@ -877,23 +937,25 @@ static string low_pike_sprintf(char *format,
 	struct svalue *t;
 	DO_OP();
 	GET_SVALUE(t);
-	fsp->b=get_name_of_type(t->type);
-	fsp->len=strlen(fsp->b);
+	fsp->b=MKPCHARP(get_name_of_type(t->type),0);
+	fsp->len=strlen((char *)fsp->b.ptr);
 	break;
       }
 
       case 'c':
       {
         INT32 l,tmp;
+	char *x;
         DO_OP();
         l=1;
         if(fsp->width > 0) l=fsp->width;
-	fsp->b=(char *)alloca(l);
+	x=(char *)alloca(l);
+	fsp->b=MKPCHARP(x,0);
 	fsp->len=l;
 	GET_INT(tmp);
         while(--l>=0)
         {
-          fsp->b[l]=tmp & 0xff;
+          x[l]=tmp & 0xff;
           tmp>>=8;
         }
 	break;
@@ -904,36 +966,45 @@ static string low_pike_sprintf(char *format,
       case 'u':
       case 'x':
       case 'X':
+      {
+	char *x;
 	DO_OP();
 	GET_INT(tmp);
 	buffer[0]='%';
-	buffer[1]=*a;
+	buffer[1]=EXTRACT_PCHARP(a);
 	buffer[2]=0;
-	fsp->b=(char *)alloca(100);
-	sprintf(fsp->b,buffer,tmp);
-	fsp->len=strlen(fsp->b);
+	x=(char *)alloca(100);
+	fsp->b=MKPCHARP(x,0);
+	sprintf(x,buffer,tmp);
+	fsp->len=strlen(x);
 	break;
+      }
 
       case 'e':
       case 'f':
       case 'g':
       case 'E':
       case 'G':
+      {
+	char *x;
 	DO_OP();
-	fsp->b=(char *)xalloc(100+MAXIMUM(fsp->width,8)+
+	x=(char *)xalloc(100+MAXIMUM(fsp->width,8)+
 			      MAXIMUM(fsp->precision,3));
-	sprintf(buffer,"%%*.*%c",*a);
+	fsp->b=MKPCHARP(x,0);
+	sprintf(buffer,"%%*.*%c",EXTRACT_PCHARP(a));
 	GET_FLOAT(tf);
-	sprintf(fsp->b,buffer,
+	sprintf(x,buffer,
 		fsp->width?fsp->width:8,
 		fsp->precision?fsp->precision:3,tf);
-	fsp->len=strlen(fsp->b);
-	fsp->fi_free_string=fsp->b;
+	fsp->len=strlen(x);
+	fsp->fi_free_string=x;
 	break;
+      }
 
       case 'F':
       {
         INT32 l;
+	char *x;
 #if defined(DOUBLE_IS_IEEE_LITTLE) || defined(DOUBLE_IS_IEEE_BIG)
 	double td;
 #endif
@@ -942,42 +1013,43 @@ static string low_pike_sprintf(char *format,
         if(fsp->width > 0) l=fsp->width;
 	if(l != 4 && l != 8)
 	  sprintf_error("Invalid IEEE width %d.\n", l);
-	fsp->b=(char *)alloca(l);
+	x=(char *)alloca(l);
+	fsp->b=MKPCHARP(x,0);
 	fsp->len=l;
 	GET_FLOAT(tf);
 	switch(l) {
 	case 4:
 #ifdef FLOAT_IS_IEEE_BIG
-	  MEMCPY(fsp->b, &tf, 4);
+	  MEMCPY(x, &tf, 4);
 #else
 #ifdef FLOAT_IS_IEEE_LITTLE
-	  fsp->b[0] = ((char *)&tf)[3];
-	  fsp->b[1] = ((char *)&tf)[2];
-	  fsp->b[2] = ((char *)&tf)[1];
-	  fsp->b[3] = ((char *)&tf)[0];
+	  x[0] = ((char *)&tf)[3];
+	  x[1] = ((char *)&tf)[2];
+	  x[2] = ((char *)&tf)[1];
+	  x[3] = ((char *)&tf)[0];
 #else
-	  low_write_IEEE_float(fsp->b, (double)tf, 4);
+	  low_write_IEEE_float(x, (double)tf, 4);
 #endif
 #endif
 	  break;
 	case 8:
 #ifdef DOUBLE_IS_IEEE_BIG
 	  td = (double)tf;
-	  MEMCPY(fsp->b, &td, 8);
+	  MEMCPY(x, &td, 8);
 #else
 #ifdef DOUBLE_IS_IEEE_LITTLE
 	  td = (double)tf;
 
-	  fsp->b[0] = ((char *)&td)[7];
-	  fsp->b[1] = ((char *)&td)[6];
-	  fsp->b[2] = ((char *)&td)[5];
-	  fsp->b[3] = ((char *)&td)[4];
-	  fsp->b[4] = ((char *)&td)[3];
-	  fsp->b[5] = ((char *)&td)[2];
-	  fsp->b[6] = ((char *)&td)[1];
-	  fsp->b[7] = ((char *)&td)[0];
+	  x[0] = ((char *)&td)[7];
+	  x[1] = ((char *)&td)[6];
+	  x[2] = ((char *)&td)[5];
+	  x[3] = ((char *)&td)[4];
+	  x[4] = ((char *)&td)[3];
+	  x[5] = ((char *)&td)[2];
+	  x[6] = ((char *)&td)[1];
+	  x[7] = ((char *)&td)[0];
 #else
-	  low_write_IEEE_float(fsp->b, (double)tf, 8);
+	  low_write_IEEE_float(x, (double)tf, 8);
 #endif
 #endif
 	}
@@ -993,9 +1065,9 @@ static string low_pike_sprintf(char *format,
 	init_buf();
 	describe_svalue(t,0,0);
 	s=complex_free_buf();
-	fsp->b=s.str;
+	fsp->b=MKPCHARP(s.str,0);
 	fsp->len=s.len;
-	fsp->fi_free_string=fsp->b;
+	fsp->fi_free_string=s.str;
 	break;
       }
 
@@ -1004,7 +1076,7 @@ static string low_pike_sprintf(char *format,
 	struct pike_string *s;
 	DO_OP();
 	GET_STRING(s);
-	fsp->b=s->str;
+	fsp->b=MKPCHARP_STR(s);
 	fsp->len=s->len;
 	break;
       }
@@ -1024,7 +1096,7 @@ static string low_pike_sprintf(char *format,
       tmp=1;
       for(max_len=nr=e=0;e<f->len;e++)
       {
-	if(f->b[e]=='\n')
+	if(INDEX_PCHARP(f->b,e)=='\n')
 	{
 	  nr++;
 	  if(max_len<tmp) max_len=tmp;
@@ -1048,18 +1120,17 @@ static string low_pike_sprintf(char *format,
     if((f[1].flags & MULTILINE) &&
        !(f[0].flags & (MULTILINE|MULTI_LINE_BREAK)))
     {
-      if(! MEMCHR(f->b, '\n', f->len)) f->flags|=MULTI_LINE;
+      if(! MEMCHR_PCHARP(f->b, '\n', f->len).ptr ) f->flags|=MULTI_LINE;
     }
   }
-  init_buf_with_string(prefix);
   for(f=start+1;f<=fsp;)
   {
-    for(;f<=fsp && !(f->flags&MULTILINE);f++) do_one(f);
+    for(;f<=fsp && !(f->flags&MULTILINE);f++) do_one(r,f);
     do
     {
       d=0;
-      for(e=0;f+e<=fsp && (f[e].flags & MULTILINE);e++) d|=do_one(f+e);
-      if(d) my_putchar('\n');
+      for(e=0;f+e<=fsp && (f[e].flags & MULTILINE);e++) d|=do_one(r,f+e);
+      if(d) string_builder_putchar(r,'\n');
     }while(d);
 
     for(;f<=fsp && (f->flags&MULTILINE); f++);
@@ -1075,10 +1146,10 @@ static string low_pike_sprintf(char *format,
     fsp->fi_free_string=0;
     fsp--;
   }
-  return complex_free_buf();
 }
 
-/* An C-callable pike_sprintf */
+
+/* An C-callable pike_sprintf
 string pike_sprintf(char *format,struct svalue *argp,int num_arg)
 {
   string prefix;
@@ -1089,15 +1160,15 @@ string pike_sprintf(char *format,struct svalue *argp,int num_arg)
   fsp=format_info_stack-1;
   return low_pike_sprintf(format,strlen(format),argp,num_arg,prefix,0);
 }
+ */
 
 /* The efun */
 void f_sprintf(INT32 num_arg)
 {
+  ONERROR tmp;
   struct pike_string *ret;
   struct svalue *argp;
-  string s;
-  s.str=0;
-  s.len=0;
+  struct string_builder r;
 
   argp=sp-num_arg;
   free_sprintf_strings();
@@ -1106,14 +1177,16 @@ void f_sprintf(INT32 num_arg)
   if(argp[0].type != T_STRING)
     error("Bad argument 1 to sprintf.\n");
 
-  s=low_pike_sprintf(argp->u.string->str,
-		     argp->u.string->len,
-		     argp+1,
-		     num_arg-1,
-		     s,
-		     0);
-  ret=make_shared_binary_string(s.str, s.len);
-  free(s.str);
+  init_string_builder(&r,0);
+  SET_ONERROR(tmp, free_string_builder, &r);
+  low_pike_sprintf(&r,
+		   MKPCHARP_STR(argp->u.string),
+		   argp->u.string->len,
+		   argp+1,
+		   num_arg-1,
+		   0);
+  UNSET_ONERROR(tmp);
+  ret=finish_string_builder(&r);
 
   free_svalue(&temp_svalue);
   temp_svalue.type=T_INT;
diff --git a/src/operators.c b/src/operators.c
index ce21f31d9f..d8fc9aae74 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -5,7 +5,7 @@
 \*/
 #include "global.h"
 #include <math.h>
-RCSID("$Id: operators.c,v 1.42 1998/10/12 22:55:10 hubbe Exp $");
+RCSID("$Id: operators.c,v 1.43 1998/10/14 05:48:45 hubbe Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "multiset.h"
@@ -25,6 +25,7 @@ RCSID("$Id: operators.c,v 1.42 1998/10/12 22:55:10 hubbe Exp $");
 #include "object.h"
 #include "pike_types.h"
 #include "module_support.h"
+#include "pike_macros.h"
 
 #define COMPARISON(ID,NAME,FUN)			\
 void ID(INT32 args)				\
@@ -139,7 +140,7 @@ void f_add(INT32 args)
   case BIT_STRING:
   {
     struct pike_string *r;
-    char *buf;
+    PCHARP buf;
     INT32 tmp;
     int max_shift=0;
 
@@ -156,11 +157,11 @@ void f_add(INT32 args)
     tmp=sp[-args].u.string->len;
     r=new_realloc_shared_string(sp[-args].u.string,size,max_shift);
     sp[-args].type=T_INT;
-    buf=r->str+(tmp<<max_shift);
+    buf=MKPCHARP_STR_OFF(r,tmp);
     for(e=-args+1;e<0;e++)
     {
-      pike_string_cpy(buf,max_shift,sp[e].u.string);
-      buf+=sp[e].u.string->len << max_shift;
+      pike_string_cpy(buf,sp[e].u.string);
+      INC_PCHARP(buf,sp[e].u.string->len);
     }
     sp[-args].u.string=end_shared_string(r);
     sp[-args].type=T_STRING;
@@ -175,7 +176,7 @@ void f_add(INT32 args)
   case BIT_STRING | BIT_FLOAT | BIT_INT:
   {
     struct pike_string *r;
-    char *buf;
+    PCHARP buf;
     char buffer[50];
     int max_shift=0;
     size=0;
@@ -200,7 +201,7 @@ void f_add(INT32 args)
     }
 
     r=begin_wide_shared_string(size,max_shift);
-    buf=r->str;
+    buf=MKPCHARP_STR(r);
     size=0;
     
     for(e=-args;e<0;e++)
@@ -208,8 +209,8 @@ void f_add(INT32 args)
       switch(sp[e].type)
       {
       case T_STRING:
-	pike_string_cpy(buf,max_shift,sp[e].u.string);
-	buf+=sp[e].u.string->len<<max_shift;
+	pike_string_cpy(buf,sp[e].u.string);
+	INC_PCHARP(buf,sp[e].u.string->len);
 	break;
 
       case T_INT:
@@ -221,14 +222,23 @@ void f_add(INT32 args)
       append_buffer:
 	switch(max_shift)
 	{
-	  case 0: convert_0_to_0((p_wchar0 *)buf,buffer,strlen(buffer)); break;
-	  case 1: convert_0_to_1((p_wchar1 *)buf,buffer,strlen(buffer)); break;
-	  case 2: convert_0_to_2((p_wchar2 *)buf,buffer,strlen(buffer)); break;
+	  case 0:
+	    convert_0_to_0((p_wchar0 *)buf.ptr,buffer,strlen(buffer));
+	    break;
+
+	  case 1:
+	    convert_0_to_1((p_wchar1 *)buf.ptr,buffer,strlen(buffer));
+	    break;
+
+	  case 2:
+	    convert_0_to_2((p_wchar2 *)buf.ptr,buffer,strlen(buffer));
+	    break;
+
 	}
-	buf+=strlen(buffer)<<max_shift;
+	INC_PCHARP(buf,strlen(buffer));
       }
     }
-    r->len=(buf-r->str)>>max_shift;
+    r->len=SUBTRACT_PCHARP(buf,MKPCHARP_STR(r));
     low_set_index(r,r->len,0);
     r=end_shared_string(r);
     pop_n_elems(args);
@@ -671,21 +681,37 @@ void o_and(void)
     push_array(a);
     return;
   }
-  case T_STRING:
-  {
-    struct pike_string *s;
-    INT32 len, i;
 
-    len = sp[-2].u.string->len;
-    if (len != sp[-1].u.string->len)
-      PIKE_ERROR("`&", "Bitwise AND on strings of different lengths.\n", sp, 2);
-    s = begin_shared_string(len);
-    for (i=0; i<len; i++)
-      s->str[i] = sp[-2].u.string->str[i] & sp[-1].u.string->str[i];
-    pop_n_elems(2);
-    push_string(end_shared_string(s));
-    return;
-  }
+#define STRING_BITOP(OP,STROP)						  \
+  case T_STRING:							  \
+  {									  \
+    struct pike_string *s;						  \
+    INT32 len, i;							  \
+									  \
+    len = sp[-2].u.string->len;						  \
+    if (len != sp[-1].u.string->len)					  \
+      PIKE_ERROR("`" #OP, "Bitwise "STROP				  \
+		 " on strings of different lengths.\n", sp, 2);		  \
+    if(!sp[-2].u.string->size_shift && !sp[-1].u.string->size_shift)	  \
+    {									  \
+      s = begin_shared_string(len);					  \
+      for (i=0; i<len; i++)						  \
+	s->str[i] = sp[-2].u.string->str[i] OP sp[-1].u.string->str[i];	  \
+    }else{								  \
+      s = begin_wide_shared_string(len,					  \
+				   MAXIMUM(sp[-2].u.string->size_shift,	  \
+					   sp[-1].u.string->size_shift)); \
+      for (i=0; i<len; i++)						  \
+	low_set_index(s,i,index_shared_string(sp[-2].u.string,i) OP 	  \
+		      index_shared_string(sp[-1].u.string,i));		  \
+    }									  \
+    pop_n_elems(2);							  \
+    push_string(end_shared_string(s));					  \
+    return;								  \
+  }
+
+  STRING_BITOP(&,"AND")
+
   default:
     PIKE_ERROR("`&", "Bitwise and on illegal type.\n", sp, 2);
   }
@@ -837,21 +863,7 @@ void o_or(void)
     return;
   }
 
-  case T_STRING:
-  {
-    struct pike_string *s;
-    INT32 len, i;
-
-    len = sp[-2].u.string->len;
-    if (len != sp[-1].u.string->len)
-      PIKE_ERROR("`|", "Bitwise OR on strings of different lengths.\n", sp, 2);
-    s = begin_shared_string(len);
-    for (i=0; i<len; i++)
-      s->str[i] = sp[-2].u.string->str[i] | sp[-1].u.string->str[i];
-    pop_n_elems(2);
-    push_string(end_shared_string(s));
-    return;
-  }
+  STRING_BITOP(|,"OR")
 
   default:
     PIKE_ERROR("`|", "Bitwise or on illegal type.\n", sp, 2);
@@ -941,21 +953,7 @@ void o_xor(void)
     return;
   }
 
-  case T_STRING:
-  {
-    struct pike_string *s;
-    INT32 len, i;
-
-    len = sp[-2].u.string->len;
-    if (len != sp[-1].u.string->len)
-      PIKE_ERROR("`^", "Bitwise XOR on strings of different lengths.\n", sp, 2);
-    s = begin_shared_string(len);
-    for (i=0; i<len; i++)
-      s->str[i] = sp[-2].u.string->str[i] ^ sp[-1].u.string->str[i];
-    pop_n_elems(2);
-    push_string(end_shared_string(s));
-    return;
-  }
+  STRING_BITOP(^,"XOR")
 
   default:
     PIKE_ERROR("`^", "Bitwise XOR on illegal type.\n", sp, 2);
@@ -1091,15 +1089,17 @@ void o_multiply(void)
       {
 	struct pike_string *ret;
 	char *pos;
-	INT32 e;
+	INT32 e,len;
 	if(sp[-1].u.integer < 0)
 	  PIKE_ERROR("`*", "Cannot multiply string by negative number.\n", sp, 2);
-	ret=begin_shared_string(sp[-2].u.string->len * sp[-1].u.integer);
+	ret=begin_wide_shared_string(sp[-2].u.string->len * sp[-1].u.integer,
+				     sp[-2].u.string->size_shift);
 	pos=ret->str;
-	for(e=0;e<sp[-1].u.integer;e++,pos+=sp[-2].u.string->len)
-	  MEMCPY(pos,sp[-2].u.string->str,sp[-2].u.string->len);
+	len=sp[-2].u.string->len << sp[-2].u.string->size_shift;
+	for(e=0;e<sp[-1].u.integer;e++,pos+=len)
+	  MEMCPY(pos,sp[-2].u.string->str,len);
 	pop_n_elems(2);
-	push_string(end_shared_string(ret));
+	push_string(low_end_shared_string(ret));
 	return;
       }
 
@@ -1201,8 +1201,7 @@ void o_divide(void)
       case TWO_TYPES(T_STRING,T_INT):
       {
 	struct array *a;
-	char *pos=sp[-2].u.string->str;
-	INT32 size,e,len;
+	INT32 size,e,len,pos=0;
 
 	len=sp[-1].u.integer;
 	if(!len)
@@ -1219,7 +1218,7 @@ void o_divide(void)
 	a=allocate_array(size);
 	for(e=0;e<size;e++)
 	{
-	  a->item[e].u.string=make_shared_binary_string(pos,len);
+	  a->item[e].u.string=string_slice(sp[-2].u.string, pos,len);
 	  a->item[e].type=T_STRING;
 	  pos+=len;
 	}
@@ -1248,16 +1247,16 @@ void o_divide(void)
 	  for(last=sp[-2].u.string->len,e=0;e<size-1;e++)
 	  {
 	    pos=sp[-2].u.string->len - (INT32)((e+1)*len);
-	    a->item[size-1-e].u.string=make_shared_binary_string(
-	      sp[-2].u.string->str + pos,
-	      last-pos);
+	    a->item[size-1-e].u.string=string_slice(sp[-2].u.string,
+						    pos,
+						    last-pos);
 	    a->item[size-1-e].type=T_STRING;
 	    last=pos;
 	  }
 	  pos=0;
-	  a->item[0].u.string=make_shared_binary_string(
-	    sp[-2].u.string->str + pos,
-	    last-pos);
+	  a->item[0].u.string=string_slice(sp[-2].u.string,
+					   pos,
+					   last-pos);
 	  a->item[0].type=T_STRING;
 	}else{
 	  size=(INT32)ceil( ((double)sp[-2].u.string->len) / len);
@@ -1266,16 +1265,16 @@ void o_divide(void)
 	  for(last=0,e=0;e<size-1;e++)
 	  {
 	    pos=(INT32)((e+1)*len);
-	    a->item[e].u.string=make_shared_binary_string(
-	      sp[-2].u.string->str + last,
-	      pos-last);
+	    a->item[e].u.string=string_slice(sp[-2].u.string,
+					     last,
+					     pos-last);
 	    a->item[e].type=T_STRING;
 	    last=pos;
 	  }
 	  pos=sp[-2].u.string->len;
-	  a->item[e].u.string=make_shared_binary_string(
-	    sp[-2].u.string->str + last,
-	    pos-last);
+	  a->item[e].u.string=string_slice(sp[-2].u.string,
+					   last,
+					   pos-last);
 	  a->item[e].type=T_STRING;
 	}
 	a->type_field=BIT_STRING;
@@ -1489,7 +1488,7 @@ void o_mod(void)
 	  tmp=s->len % tmp;
 	  base=s->len - tmp;
 	}
-	s=make_shared_binary_string(s->str + base, tmp);
+	s=string_slice(s, base, tmp);
 	pop_n_elems(2);
 	push_string(s);
 	return;
@@ -1649,6 +1648,9 @@ void o_compl(void)
     struct pike_string *s;
     INT32 len, i;
 
+    if(sp[-1].u.string->size_shift)
+      error("`~ cannot handle wide strings.\n");
+
     len = sp[-1].u.string->len;
     s = begin_shared_string(len);
     for (i=0; i<len; i++)
diff --git a/src/pike_memory.c b/src/pike_memory.c
index fd28c52ec8..896a5535f6 100644
--- a/src/pike_memory.c
+++ b/src/pike_memory.c
@@ -9,7 +9,7 @@
 #include "pike_macros.h"
 #include "gc.h"
 
-RCSID("$Id: pike_memory.c,v 1.26 1998/10/11 11:18:52 hubbe Exp $");
+RCSID("$Id: pike_memory.c,v 1.27 1998/10/14 05:48:46 hubbe Exp $");
 
 /* strdup() is used by several modules, so let's provide it */
 #ifndef HAVE_STRDUP
@@ -561,7 +561,7 @@ void memfill(char *to,
       while(tolen>0)
       {
 	tmp=MINIMUM(tolen, fromlen);
-	MEMCPY(to, from, MINIMUM(tolen, fromlen));
+	MEMCPY(to, from, tmp);
 	fromlen+=tmp;
 	tolen-=tmp;
 	to+=tmp;
diff --git a/src/stralloc.c b/src/stralloc.c
index a38128b8c0..e08d4ed995 100644
--- a/src/stralloc.c
+++ b/src/stralloc.c
@@ -15,7 +15,7 @@
 
 #include <ctype.h>
 
-RCSID("$Id: stralloc.c,v 1.42 1998/10/11 22:34:02 hubbe Exp $");
+RCSID("$Id: stralloc.c,v 1.43 1998/10/14 05:48:46 hubbe Exp $");
 
 #define BEGIN_HASH_SIZE 997
 #define MAX_AVG_LINK_LENGTH 3
@@ -164,49 +164,48 @@ int generic_compare_strings(const void *a,int alen, int asize,
 }
 
 
-void generic_memcpy(void *to, int to_shift,
-		    void *from, int from_shift,
+void generic_memcpy(PCHARP to,
+		    PCHARP from,
 		    int len)
 {
-  switch(TWO_SIZES(from_shift,to_shift))
+  switch(TWO_SIZES(from.shift,to.shift))
   {
     case TWO_SIZES(0,0):
-      convert_0_to_0((p_wchar0 *)to,(p_wchar0 *)from,len);
+      convert_0_to_0((p_wchar0 *)to.ptr,(p_wchar0 *)from.ptr,len);
       break;
     case TWO_SIZES(0,1):
-      convert_0_to_1((p_wchar1 *)to,(p_wchar0 *)from,len);
+      convert_0_to_1((p_wchar1 *)to.ptr,(p_wchar0 *)from.ptr,len);
       break;
     case TWO_SIZES(0,2):
-      convert_0_to_2((p_wchar2 *)to,(p_wchar0 *)from,len);
+      convert_0_to_2((p_wchar2 *)to.ptr,(p_wchar0 *)from.ptr,len);
       break;
 
     case TWO_SIZES(1,0):
-      convert_1_to_0((p_wchar0 *)to,(p_wchar1 *)from,len);
+      convert_1_to_0((p_wchar0 *)to.ptr,(p_wchar1 *)from.ptr,len);
       break;
     case TWO_SIZES(1,1):
-      convert_1_to_1((p_wchar1 *)to,(p_wchar1 *)from,len);
+      convert_1_to_1((p_wchar1 *)to.ptr,(p_wchar1 *)from.ptr,len);
       break;
     case TWO_SIZES(1,2):
-      convert_1_to_2((p_wchar2 *)to,(p_wchar1 *)from,len);
+      convert_1_to_2((p_wchar2 *)to.ptr,(p_wchar1 *)from.ptr,len);
       break;
 
     case TWO_SIZES(2,0):
-      convert_2_to_0((p_wchar0 *)to,(p_wchar2 *)from,len);
+      convert_2_to_0((p_wchar0 *)to.ptr,(p_wchar2 *)from.ptr,len);
       break;
     case TWO_SIZES(2,1):
-      convert_2_to_1((p_wchar1 *)to,(p_wchar2 *)from,len);
+      convert_2_to_1((p_wchar1 *)to.ptr,(p_wchar2 *)from.ptr,len);
       break;
     case TWO_SIZES(2,2):
-      convert_2_to_2((p_wchar2 *)to,(p_wchar2 *)from,len);
+      convert_2_to_2((p_wchar2 *)to.ptr,(p_wchar2 *)from.ptr,len);
       break;
   }
 }
 
-INLINE void pike_string_cpy(void *to,
-		     int to_shift,
-		     struct pike_string *from)
+INLINE void pike_string_cpy(PCHARP to,
+			    struct pike_string *from)
 {
-  generic_memcpy(to,to_shift,from->str,from->size_shift,from->len);
+  generic_memcpy(to,MKPCHARP_STR(from),from->len);
 }
 
 static void locate_problem(int (*isproblem)(struct pike_string *))
@@ -1028,7 +1027,7 @@ struct pike_string *new_realloc_shared_string(struct pike_string *a, INT32 size,
   if(shift == a->size_shift) return realloc_shared_string(a,size);
 
   r=begin_wide_shared_string(size,shift);
-  pike_string_cpy(r->str,shift,a);
+  pike_string_cpy(MKPCHARP_STR(r),a);
   free_string(a);
   return r;
 }
@@ -1181,11 +1180,14 @@ struct pike_string *add_shared_strings(struct pike_string *a,
 					 struct pike_string *b)
 {
   struct pike_string *ret;
+  PCHARP tmp;
   int target_size=MAXIMUM(a->size_shift,b->size_shift);
 
   ret=begin_wide_shared_string(a->len+b->len,target_size);
-  pike_string_cpy(ret->str,ret->size_shift,a);
-  pike_string_cpy(ret->str+(a->len<<target_size),ret->size_shift,b);
+  tmp=MKPCHARP_STR(ret);
+  pike_string_cpy(tmp,a);
+  INC_PCHARP(tmp,a->len);
+  pike_string_cpy(tmp,b);
   return end_shared_string(ret);
 }
 
@@ -1222,13 +1224,13 @@ int string_search(struct pike_string *haystack,
 			   needle->str,
 			   needle->len,
 			   needle->size_shift,
-			   haystack->len,
+			   haystack->len-start,
 			   haystack->size_shift);
 
   
   r=(char *)generic_memory_search(&s,
-				  haystack->str,
-				  haystack->len,
+				  haystack->str+(start<<haystack->size_shift),
+				  haystack->len-start,
 				  haystack->size_shift);
 
   if(!r) return -1;
@@ -1274,7 +1276,8 @@ struct pike_string *string_replace(struct pike_string *str,
 				   struct pike_string *to)
 {
   struct pike_string *ret;
-  char *s,*tmp,*r,*end;
+  char *s,*tmp,*end;
+  PCHARP r;
   int shift;
   struct generic_mem_searcher searcher;
 
@@ -1288,14 +1291,12 @@ struct pike_string *string_replace(struct pike_string *str,
 
   if(!del->len)
   {
-    int e;
-    int pos;
+    int e,pos;
     ret=begin_wide_shared_string(str->len + to->len * (str->len -1),shift);
     low_set_index(ret,0,index_shared_string(str,0));
-    pos=1;
-    for(e=1;e<str->len;e++)
+    for(pos=e=1;e<str->len;e++)
     {
-      pike_string_cpy(ret->str+(pos<<shift),shift,to);
+      pike_string_cpy(MKPCHARP_STR_OFF(ret,pos),to);
       pos+=to->len;
       low_set_index(ret,pos++,index_shared_string(str,e));
     }
@@ -1341,20 +1342,20 @@ struct pike_string *string_replace(struct pike_string *str,
     ret=begin_wide_shared_string(str->len + (to->len-del->len)*delimeters, shift);
   }
   s=str->str;
-  r=ret->str;
+  r=MKPCHARP_STR(ret);
 
   while((tmp=(char *)generic_memory_search(&searcher,
 					   s,
 					   (end-s)>>str->size_shift,
 					   str->size_shift)))
   {
-    generic_memcpy(r,shift,s,str->size_shift,(tmp-s)>>str->size_shift);
-    r+=tmp-s;
-    pike_string_cpy(r,shift,to);
-    r+=to->len << shift;
+    generic_memcpy(r,MKPCHARP(s,str->size_shift),(tmp-s)>>str->size_shift);
+    INC_PCHARP(r,(tmp-s)>>str->size_shift);
+    pike_string_cpy(r,to);
+    INC_PCHARP(r,to->len);
     s=tmp+(del->len << str->size_shift);
   }
-  generic_memcpy(r,shift,s,str->size_shift,(end-s)>>str->size_shift);
+  generic_memcpy(r,MKPCHARP(s,str->size_shift),(end-s)>>str->size_shift);
 
   return end_shared_string(ret);
 }
@@ -1468,7 +1469,7 @@ static void string_build_mkspace(struct string_builder *s, int chars, int mag)
     struct pike_string *n;
     int l=s->s->len+chars+s->malloced;
     n=begin_wide_shared_string(l,mag);
-    pike_string_cpy(n->str,mag,s->s);
+    pike_string_cpy(MKPCHARP_STR(n),s->s);
     n->len=s->s->len;
     s->malloced=l;
     free((char *)s->s);
@@ -1509,7 +1510,7 @@ void string_builder_putchar(struct string_builder *s, int ch)
 
 void string_builder_binary_strcat(struct string_builder *s, char *str, INT32 len)
 {
-  string_build_mkspace(s,len,1);
+  string_build_mkspace(s,len,0);
   switch(s->s->size_shift)
   {
     case 0: convert_0_to_0(STR0(s->s)+s->s->len,str,len); break;
@@ -1522,6 +1523,69 @@ void string_builder_binary_strcat(struct string_builder *s, char *str, INT32 len
 }
 
 
+void string_builder_append(struct string_builder *s,
+			   PCHARP from,
+			   INT32 len)
+{
+  string_build_mkspace(s,len,from.shift);
+  generic_memcpy(MKPCHARP_STR_OFF(s->s,s->s->len), from, len);
+  s->s->len+=len;
+}
+
+void string_builder_fill(struct string_builder *s,
+			 int howmany,
+			 PCHARP from,
+			 INT32 len,
+			 INT32 offset)
+{
+  INT32 tmp;
+#ifdef DEBUG
+  if(len<=0)
+    fatal("Cannot fill with zero length strings!\n");
+#endif
+  if(howmany<=0) return;
+
+  if(!s->s->size_shift &&
+     len == 1 &&
+     (!from.shift || !min_magnitude(EXTRACT_PCHARP(from))))
+  {
+    MEMSET(string_builder_allocate(s,howmany,0),
+	   EXTRACT_PCHARP(from),
+	   howmany);
+    return;
+  }
+
+  string_build_mkspace(s,howmany,from.shift);
+  tmp=MINIMUM(howmany, len - offset);
+
+  generic_memcpy(MKPCHARP_STR_OFF(s->s,s->s->len),
+		 ADD_PCHARP(from,offset),
+		 tmp);
+  s->s->len+=tmp;
+  howmany-=tmp;
+  if(howmany > 0)
+  {
+    void *new_from;
+    PCHARP to;
+    tmp=MINIMUM(howmany, len);
+    to=MKPCHARP_STR_OFF(s->s,s->s->len);
+    generic_memcpy(to,from, tmp);
+    s->s->len+=tmp;
+    howmany-=tmp;
+
+    while(howmany > 0)
+    {
+      tmp=MINIMUM(len, howmany);
+      MEMCPY(s->s->str + (s->s->len << s->s->size_shift),
+	     to.ptr,
+	     tmp << s->s->size_shift);
+      len+=tmp;
+      howmany-=tmp;
+      s->s->len+=tmp;
+    }
+  }
+}
+
 void string_builder_strcat(struct string_builder *s, char *str)
 {
   string_builder_binary_strcat(s,str,strlen(str));
@@ -1531,9 +1595,7 @@ void string_builder_shared_strcat(struct string_builder *s, struct pike_string *
 {
   string_build_mkspace(s,str->len,s->s->size_shift);
 
-  pike_string_cpy(s->s->str + (s->s->len << s->s->size_shift),
-		  s->s->size_shift,
-		  str);
+  pike_string_cpy(MKPCHARP_STR_OFF(s->s,s->s->len), str);
   s->known_shift=MAXIMUM(s->known_shift,str->size_shift);
   s->s->len+=str->len;
 }
@@ -1545,6 +1607,11 @@ void reset_string_builder(struct string_builder *s)
   s->s->len=0;
 }
 
+void free_string_builder(struct string_builder *s)
+{
+  free((char *)s->s);
+}
+
 struct pike_string *finish_string_builder(struct string_builder *s)
 {
   low_set_index(s->s,s->s->len,0);
@@ -1553,3 +1620,73 @@ struct pike_string *finish_string_builder(struct string_builder *s)
   return end_shared_string(s->s);
 }
 
+PCHARP MEMCHR_PCHARP(PCHARP ptr, int chr, int len)
+{
+  switch(ptr.shift)
+  {
+    case 0: return MKPCHARP(MEMCHR0(ptr.ptr,chr,len),0);
+    case 1: return MKPCHARP(MEMCHR1(ptr.ptr,chr,len),1);
+    case 2: return MKPCHARP(MEMCHR2(ptr.ptr,chr,len),2);
+    default:
+      fatal("Illegal shift in MEMCHR_PCHARP.\n");
+  }
+}
+
+#define DIGIT(x)	(isdigit(x) ? (x) - '0' : \
+			islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
+#define MBASE	('z' - 'a' + 1 + 10)
+
+long STRTOL_PCHARP(PCHARP str, PCHARP *ptr, int base)
+{
+  register long val;
+  register int c;
+  int xx, neg = 0;
+
+  if (ptr)  *ptr = str;
+  if (base < 0 || base > MBASE)  return 0;
+  if (!isalnum(c = EXTRACT_PCHARP(str)))
+  {
+    while (ISSPACE(c))
+    {
+      INC_PCHARP(str,1);
+      c=EXTRACT_PCHARP(str);
+    }
+    switch (c)
+    {
+    case '-':
+      neg++;
+    case '+':			/* fall-through */
+      INC_PCHARP(str,1);
+      c=EXTRACT_PCHARP(str);
+    }
+  }
+
+  if (!base)
+  {
+    if (c != '0')
+      base = 10;
+    else if (INDEX_PCHARP(str,1) == 'x' || INDEX_PCHARP(str,1) == 'X')
+      base = 16;
+    else
+      base = 8;
+  }
+
+  if (!isalnum(c) || (xx = DIGIT(c)) >= base)
+    return 0;			/* no number formed */
+  if (base == 16 && c == '0' && isxdigit(INDEX_PCHARP(str,2)) &&
+      (INDEX_PCHARP(str,1) == 'x' || INDEX_PCHARP(str,1) == 'X'))
+  {
+    INC_PCHARP(str,2);
+    c = EXTRACT_PCHARP(str);		/* skip over leading "0x" or "0X" */
+  }
+  val=-DIGIT(c);
+  while(1)
+  {
+    INC_PCHARP(str,1);
+    c=EXTRACT_PCHARP(str);
+    if(!(isalnum(c)  && (xx=DIGIT(c)) < base)) break;
+    val = base * val - xx;
+  }
+  if (ptr) *ptr = str;
+  return (neg ? val : -val);
+}
diff --git a/src/stralloc.h b/src/stralloc.h
index a410faabcb..d2de73691d 100644
--- a/src/stralloc.h
+++ b/src/stralloc.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: stralloc.h,v 1.20 1998/10/11 22:34:02 hubbe Exp $
+ * $Id: stralloc.h,v 1.21 1998/10/14 05:48:46 hubbe Exp $
  */
 #ifndef STRALLOC_H
 #define STRALLOC_H
@@ -53,6 +53,52 @@ struct pike_string *debug_findstring(const struct pike_string *foo);
 #define STR2(X) ((p_wchar2 *)(X)->str)
 #endif
 
+#define INDEX_CHARP(PTR,IND,SHIFT) \
+  ((SHIFT)==0?((p_wchar0 *)(PTR))[(IND)]:(SHIFT)==1?((p_wchar1 *)(PTR))[(IND)]:((p_wchar2 *)(PTR))[(IND)])
+
+#define SET_INDEX_CHARP(PTR,IND,SHIFT,VAL) \
+  ((SHIFT)==0?((p_wchar0 *)(PTR))[(IND)]=(VAL):(SHIFT)==1?((p_wchar1 *)(PTR))[(IND)]=(VAL):((p_wchar2 *)(PTR))[(IND)]=(VAL))
+
+
+#define EXTRACT_CHARP(PTR,SHIFT) INDEX_CHARP((PTR),0,(SHIFT))
+#define CHARP_ADD(PTR,X,SHIFT) (PTR)+=(X)<<(SHIFT)
+
+typedef struct p_wchar_p
+{
+  void *ptr;
+  int shift;
+} PCHARP;
+
+#define INDEX_PCHARP(X,Y) INDEX_CHARP((X).ptr,(Y),(X).shift)
+#define SET_INDEX_PCHARP(X,Y,Z) INDEX_CHARP((X).ptr,(Y),(X).shift,(Z))
+#define EXTRACT_PCHARP(X) INDEX_CHARP((X).ptr,(0),(X).shift)
+#define INC_PCHARP(X,Y) (((char *)(X).ptr)+=(Y) << (X).shift)
+
+#define LOW_COMPARE_PCHARP(X,CMP,Y) (((char *)((X).ptr)) CMP ((char *)((Y).ptr)))
+#define LOW_SUBTRACT_PCHARP(X,Y) LOW_COMPARE_PCHARP((X),-,(Y))
+
+#ifdef DEBUG
+#define SUBTRACT_PCHARP(X,Y)    ((X).shift!=(Y).shift?(fatal("Subtracting different size charp!\n")),0:LOW_SUBTRACT_PCHARP((X),(Y)))
+#define COMPARE_PCHARP(X,CMP,Y) ((X).shift!=(Y).shift?(fatal("Subtracting different size charp!\n")),0:LOW_COMPARE_PCHARP((X),CMP,(Y)))
+#else
+#define SUBTRACT_PCHARP(X,Y) LOW_SUBTRACT_PCHARP((X),(Y))
+#define COMPARE_PCHARP(X,CMP,Y) LOW_COMPARE_PCHARP((X),CMP,(Y))
+#endif
+
+static INLINE PCHARP MKPCHARP(void *ptr, int shift)
+{
+  PCHARP tmp;
+  tmp.ptr=ptr;
+  tmp.shift=shift;
+  return tmp;
+}
+
+#define MKPCHARP_OFF(PTR,SHIFT,OFF) MKPCHARP( ((char *)(PTR)) + ((OFF)<<(SHIFT)), (SHIFT))
+#define MKPCHARP_STR(STR) MKPCHARP((STR)->str, (STR)->size_shift)
+#define MKPCHARP_STR_OFF(STR,OFF) \
+ MKPCHARP((STR)->str + ((OFF)<<(STR)->size_shift), (STR)->size_shift)
+#define ADD_PCHARP(PTR,I) MKPCHARP_OFF((PTR).ptr,(PTR).shift,(I))
+
 #ifdef DEBUG_MALLOC
 #define reference_shared_string(s) do { struct pike_string *S_=(s); debug_malloc_touch(S_); S_->refs++; }while(0)
 #define copy_shared_string(to,s) do { struct pike_string *S_=(to)=(s); debug_malloc_touch(S_); S_->refs++; }while(0)
@@ -120,12 +166,11 @@ CONVERT(2,1)
 
 int generic_compare_strings(const void *a,int alen, int asize,
 			    const void *b,int blen, int bsize);
-void generic_memcpy(void *to, int to_shift,
-		    void *from, int from_shift,
+void generic_memcpy(PCHARP to,
+		    PCHARP from,
 		    int len);
-INLINE void pike_string_cpy(void *to,
-		     int to_shift,
-		     struct pike_string *from);
+INLINE void pike_string_cpy(PCHARP to,
+			    struct pike_string *from);
 struct pike_string *binary_findstring(const char *foo, INT32 l);
 struct pike_string *findstring(const char *foo);
 struct pike_string *debug_begin_shared_string(int len);
@@ -180,10 +225,21 @@ void gc_mark_all_strings(void);
 void init_string_builder(struct string_builder *s, int mag);
 void string_builder_putchar(struct string_builder *s, int ch);
 void string_builder_binary_strcat(struct string_builder *s, char *str, INT32 len);
+void string_builder_append(struct string_builder *s,
+			   PCHARP from,
+			   INT32 len);
+void string_builder_fill(struct string_builder *s,
+			 int howmany,
+			 PCHARP from,
+			 INT32 len,
+			 INT32 offset);
 void string_builder_strcat(struct string_builder *s, char *str);
 void string_builder_shared_strcat(struct string_builder *s, struct pike_string *str);
 void reset_string_builder(struct string_builder *s);
+void free_string_builder(struct string_builder *s);
 struct pike_string *finish_string_builder(struct string_builder *s);
+PCHARP MEMCHR_PCHARP(PCHARP ptr, int chr, int len);
+long STRTOL_PCHARP(PCHARP str, PCHARP *ptr, int base);
 /* Prototypes end here */
 
 #ifdef DEBUG_MALLOC
diff --git a/src/testsuite.in b/src/testsuite.in
index a9a1eff9a5..27e6e04a22 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -1,4 +1,4 @@
-stest_true([["$Id: testsuite.in,v 1.125 1998/10/12 22:57:13 hubbe Exp $"]])
+stest_true([["$Id: testsuite.in,v 1.126 1998/10/14 05:48:47 hubbe Exp $"]])
 cond([[all_constants()->_verify_internals]],
 [[
   test_do(_verify_internals())
@@ -1059,6 +1059,7 @@ test_eq(10-3.0,7.0)
 test_eq(3-10.0,-7.0)
 test_eq(10.0-3,7.0)
 test_eq(3.0-10,-7.0)
+test_eq(034567 - 10000,4711)
 test_eq("foobargazonk"-"o","fbargaznk")
 test_equal(({"foo","bar","gazonk"})-({"foo","gazonk"}),({"bar"}))
 test_equal(({"c","foo","bar","gazonk","a","b",})-({"foo","gazonk"}),({"c","bar","a","b"}))
@@ -1084,9 +1085,20 @@ test_eq(2*2.0*2.0*2.0*2.0,32.0)
 test_eq(3.0*4,12.0)
 test_eq(4.0*3,12.0)
 test_eq(2.0*2*2.0*2*2.0,32.0)
+
 test_eq(({"foo","bar","gazonk"})*"-","foo-bar-gazonk")
 test_eq(({"f\777\777","bar","gaz\777nk"})*"-","f\777\777-bar-gaz\777nk")
 test_eq(({"f\7777777\7777777","bar","gaz\7777777nk"})*"-","f\7777777\7777777-bar-gaz\7777777nk")
+
+test_eq(({"foo","bar","gazonk"})*"\777","foo\777bar\777gazonk")
+test_eq(({"f\777\777","bar","gaz\777nk"})*"\777","f\777\777\777bar\777gaz\777nk")
+test_eq(({"f\7777777\7777777","bar","gaz\7777777nk"})*"\777","f\7777777\7777777\777bar\777gaz\7777777nk")
+
+test_eq(({"foo","bar","gazonk"})*"\7777777","foo\7777777bar\7777777gazonk")
+test_eq(({"f\777\777","bar","gaz\777nk"})*"\7777777","f\777\777\7777777bar\7777777gaz\777nk")
+test_eq(({"f\7777777\7777777","bar","gaz\7777777nk"})*"\7777777","f\7777777\7777777\7777777bar\7777777gaz\7777777nk")
+
+
 test_equal( ({ ({1}), ({2}), ({3}) })*({8}), ({1,8,2,8,3}))
 test_equal( ({ 1 })*3, ({1,1,1}) )
 test_equal( "foo"*3, "foofoofoo" )
@@ -1132,6 +1144,30 @@ test_equal("foobargazonk"/5.0,({"fooba","rgazo","nk"}))
 test_equal("foobargazonk"/-5.0,({"fo","obarg","azonk"}))
 test_equal("foobargazonk"/2.5,({"fo","oba","rg","azo","nk"}))
 
+test_equal("f\777\777bargaz\777nk"/1,"f\777\777bargaz\777nk"/"")
+test_equal("f\777\777bargaz\777nk"/2,({"f\777","\777b","ar","ga","z\777","nk"}))
+test_equal("f\777\777bargaz\777nk"/3,({"f\777\777","bar","gaz","\777nk"}))
+test_equal("f\777\777bargaz\777nk"/4,({"f\777\777b","arga","z\777nk"}))
+test_equal("f\777\777bargaz\777nk"/5,({"f\777\777ba","rgaz\777"}))
+test_equal("f\777\777bargaz\777nk"/-6,({"f\777\777bar","gaz\777nk"}))
+test_equal("f\777\777bargaz\777nk"/-7,({"rgaz\777nk"}))
+
+test_equal("f\777\777bargaz\777nk"/5.0,({"f\777\777ba","rgaz\777","nk"}))
+test_equal("f\777\777bargaz\777nk"/-5.0,({"f\777","\777barg","az\777nk"}))
+test_equal("f\777\777bargaz\777nk"/2.5,({"f\777","\777ba","rg","az\777","nk"}))
+
+test_equal("f\7777777\7777777bargaz\7777777nk"/1,"f\7777777\7777777bargaz\7777777nk"/"")
+test_equal("f\7777777\7777777bargaz\7777777nk"/2,({"f\7777777","\7777777b","ar","ga","z\7777777","nk"}))
+test_equal("f\7777777\7777777bargaz\7777777nk"/3,({"f\7777777\7777777","bar","gaz","\7777777nk"}))
+test_equal("f\7777777\7777777bargaz\7777777nk"/4,({"f\7777777\7777777b","arga","z\7777777nk"}))
+test_equal("f\7777777\7777777bargaz\7777777nk"/5,({"f\7777777\7777777ba","rgaz\7777777"}))
+test_equal("f\7777777\7777777bargaz\7777777nk"/-6,({"f\7777777\7777777bar","gaz\7777777nk"}))
+test_equal("f\7777777\7777777bargaz\7777777nk"/-7,({"rgaz\7777777nk"}))
+
+test_equal("f\7777777\7777777bargaz\7777777nk"/5.0,({"f\7777777\7777777ba","rgaz\7777777","nk"}))
+test_equal("f\7777777\7777777bargaz\7777777nk"/-5.0,({"f\7777777","\7777777barg","az\7777777nk"}))
+test_equal("f\7777777\7777777bargaz\7777777nk"/2.5,({"f\7777777","\7777777ba","rg","az\7777777","nk"}))
+
 test_equal(({1,2,3})/1,({ ({1}), ({2}), ({3}) }))
 test_equal(({1,2,3})/2,({ ({1,2}) }))
 test_equal(({1,2,3})/-2,({ ({2,3}) }))
@@ -1168,6 +1204,10 @@ test_eval_error(return 15.0 % 0.0)
 
 test_eq("foobargazonk"%5,"nk")
 test_eq("foobargazonk"%-5,"fo")
+test_eq("f\777\777bargaz\777nk"%5,"nk")
+test_eq("f\777\777bargaz\777nk"%-5,"f\777")
+test_eq("f\7777777\7777777bargaz\7777777nk"%5,"nk")
+test_eq("f\7777777\7777777bargaz\7777777nk"%-5,"f\7777777")
 test_equal(({1,2,3})%2,({3}))
 test_equal(({1,2,3})%-2,({1}))
 
@@ -2266,6 +2306,8 @@ test_equal(replace(([1:2,3:4,5:1,2:3]),3,-1),([1:2,3:4,5:1,2:-1]))
 
 // - reverse
 test_eq(reverse("reverse"),"esrever")
+test_eq(reverse("r\777v\777rs\777"),"\777sr\777v\777r")
+test_eq(reverse("r\7777777v\7777777rs\7777777"),"\7777777sr\7777777v\7777777r")
 test_eq(reverse(""),"")
 test_eq(reverse("a"),"a")
 test_equal(reverse(({1,5,9})),({9,5,1}))
@@ -2301,6 +2343,7 @@ test_eq(search(([1:2,3:4,5:6,7:8]),8),7)
 
 // test large searches (find string, size, pattern)
 define(test_search,[[
+test_eq(sprintf($1+"%'"+$3+"'*n",$2)[..strlen($1)-1],$1)
 test_eq(search(sprintf($1+"%'"+$3+"'*n",$2),$1),0)
 test_eq(search(sprintf("%'"+$3+"'*n" ,$2),$1),-1)
 test_eq(search(sprintf("%'"+$3+"'*n"+$1,$2),$1),$2)
@@ -2337,10 +2380,10 @@ test_search4("\345-------------------")
 test_search4(sprintf("%'argel-bargel glop-glyf?'2000n"))
 
 dnl these can be uncommented when sprintf handles wide strings
-dnl test_search4("\34567-------------------")
-dnl test_search4("\345677777-------------------")
-dnl test_search4("kapit\3333l>")
-dnl test_search4("kapit\3333333l>")
+test_search4("\34567-------------------")
+test_search4("\345677777-------------------")
+test_search4("kapit\3333l>")
+test_search4("kapit\3333333l>")
 
 
 // - sizeof
-- 
GitLab