cb22561995-10-11Fredrik Hübinette (Hubbe) /*\
06983f1996-09-22Fredrik Hübinette (Hubbe) ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License)
cb22561995-10-11Fredrik Hübinette (Hubbe) ||| See the files COPYING and DISCLAIMER for more information. \*/
82b1ff1999-02-27Henrik Grubbström (Grubba) /**/
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "global.h" #include "stralloc.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "dynamic_buffer.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
9aa6fa1997-05-19Fredrik Hübinette (Hubbe) #include "pike_memory.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "error.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "gc.h"
75920f1997-12-28Fredrik Hübinette (Hubbe) #include "stuff.h"
31ea271999-10-22Fredrik Noring #include "bignum.h" #include "interpret.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) 
f3ece81999-02-28Fredrik Hübinette (Hubbe) #include <errno.h>
4c39041999-03-23Marcus Comstedt #include <float.h>
2043ba1998-02-10Fredrik Hübinette (Hubbe) #include <ctype.h>
f3ece81999-02-28Fredrik Hübinette (Hubbe) #include <math.h>
2043ba1998-02-10Fredrik Hübinette (Hubbe) 
4c39041999-03-23Marcus Comstedt #ifndef HUGE #define HUGE HUGE_VAL #endif /*!HUGE*/
699bb02000-04-22Martin Stjernholm RCSID("$Id: stralloc.c,v 1.82 2000/04/22 13:20:40 mast Exp $");
24ddc71998-03-28Henrik Grubbström (Grubba) 
af93211996-10-12Fredrik Hübinette (Hubbe) #define BEGIN_HASH_SIZE 997 #define MAX_AVG_LINK_LENGTH 3
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  /* Experimental dynamic hash length */ #ifndef HASH_PREFIX
8f4f381999-09-16Fredrik Hübinette (Hubbe) static unsigned int HASH_PREFIX=64;
fe3c9f1999-09-06Henrik Grubbström (Grubba) static unsigned int need_more_hash_prefix=0;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #endif
af93211996-10-12Fredrik Hübinette (Hubbe)  unsigned INT32 htable_size=0;
75920f1997-12-28Fredrik Hübinette (Hubbe) static unsigned int hashprimes_entry=0;
af93211996-10-12Fredrik Hübinette (Hubbe) static struct pike_string **base_table=0;
5267b71995-08-09Fredrik Hübinette (Hubbe) static unsigned INT32 full_hash_value;
af93211996-10-12Fredrik Hübinette (Hubbe) unsigned INT32 num_strings=0;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
af93211996-10-12Fredrik Hübinette (Hubbe) /*** Main string hash function ***/
db4a401998-10-09Fredrik Hübinette (Hubbe)  #define StrHash(s,len) low_do_hash(s,len,0) static unsigned int low_do_hash(const void *s, int len, int size_shift)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
db4a401998-10-09Fredrik Hübinette (Hubbe)  full_hash_value=hashmem(s,len<<size_shift,HASH_PREFIX<<size_shift);
af93211996-10-12Fredrik Hübinette (Hubbe)  return full_hash_value % htable_size;
5267b71995-08-09Fredrik Hübinette (Hubbe) }
db4a401998-10-09Fredrik Hübinette (Hubbe) static INLINE unsigned int do_hash(struct pike_string *s) {
3e625c1998-10-11Fredrik Hübinette (Hubbe)  return low_do_hash(s->str, s->len, s->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe) } static INLINE int find_magnitude1(const unsigned INT16 *s, int len) { while(--len>=0) if(s[len]>=256) return 1; return 0; } static INLINE int find_magnitude2(const unsigned INT32 *s, int len) { while(--len>=0) { if(s[len]>=256) { do { if(s[len]>=65536) return 2; }while(--len>=0); return 1; } } return 0; } static INLINE int min_magnitude(const unsigned INT32 c) { if(c<256) return 0; if(c<65536) return 1; return 2; } static INLINE unsigned INT32 generic_extract (const void *str, int size, int pos) { switch(size) { case 0: return ((unsigned char *)str)[pos]; case 1: return ((unsigned INT16 *)str)[pos]; case 2: return ((unsigned INT32 *)str)[pos]; }
efae671998-10-21Fredrik Hübinette (Hubbe)  fatal("Illegal shift size!\n"); return 0;
db4a401998-10-09Fredrik Hübinette (Hubbe) } INLINE unsigned INT32 index_shared_string(struct pike_string *s, int pos) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
a8f9bd1998-10-15Henrik Grubbström (Grubba)  if(pos > s->len || pos<0) {
49ed181998-10-15Henrik Grubbström (Grubba)  if (s->len) { fatal("String index %d is out of range [0 - %d]!\n", pos, s->len-1); } else { fatal("Attempt to index the empty string with %d!\n", pos); } }
db4a401998-10-09Fredrik Hübinette (Hubbe) #endif return generic_extract(s->str,s->size_shift,pos); }
3e625c1998-10-11Fredrik Hübinette (Hubbe) INLINE void low_set_index(struct pike_string *s, int pos, int value)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(pos > s->len || pos<0) fatal("string index out of range!\n"); if(pos == s->len && value) fatal("string zero termination foul!\n"); #endif switch(s->size_shift) { case 0: STR0(s)[pos]=value; break; case 1: STR1(s)[pos]=value; break; case 2: STR2(s)[pos]=value; break; default: fatal("Illegal shift size!\n"); } }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
f9b6af1998-12-20Fredrik Hübinette (Hubbe) INLINE struct pike_string *debug_check_size_shift(struct pike_string *a,int shift)
db4a401998-10-09Fredrik Hübinette (Hubbe) { if(a->size_shift != shift) fatal("Wrong STRX macro used!\n"); return a; } #endif
3e625c1998-10-11Fredrik Hübinette (Hubbe) #define CONVERT(FROM,TO) \ INLINE void PIKE_CONCAT4(convert_,FROM,_to_,TO)(PIKE_CONCAT(p_wchar,TO) *to, const PIKE_CONCAT(p_wchar,FROM) *from, int len) \ { while(--len>=0) *(to++)=*(from++); } \ INLINE INT32 PIKE_CONCAT4(compare_,FROM,_to_,TO)(const PIKE_CONCAT(p_wchar,TO) *to, const PIKE_CONCAT(p_wchar,FROM) *from, int len) \ { int tmp; while(--len>=0) if((tmp=*(to++)-*(from++))) return tmp; return 0; } CONVERT(0,1) CONVERT(0,2) CONVERT(1,0) CONVERT(1,2) CONVERT(2,0) CONVERT(2,1)
db4a401998-10-09Fredrik Hübinette (Hubbe) int generic_compare_strings(const void *a,int alen, int asize, const void *b,int blen, int bsize) { #define TWO_SIZES(X,Y) (((X)<<2)+(Y)) if(alen != blen) return 0; if(asize==bsize) {
19b73a1999-08-14Per Hedbor  return !MEMCMP(a,b,alen<<asize);
db4a401998-10-09Fredrik Hübinette (Hubbe)  }else{ INT32 pos; for(pos=0;pos< alen ;pos++) if(generic_extract(a,asize,pos) != generic_extract(b,bsize,pos)) return 0; return 1; } }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) void generic_memcpy(PCHARP to, PCHARP from,
3e625c1998-10-11Fredrik Hübinette (Hubbe)  int len)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
68d9131999-04-01Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG if(len<0) fatal("Cannot copy %d bytes!\n",len); #endif
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  switch(TWO_SIZES(from.shift,to.shift))
db4a401998-10-09Fredrik Hübinette (Hubbe)  { case TWO_SIZES(0,0):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_0_to_0((p_wchar0 *)to.ptr,(p_wchar0 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; case TWO_SIZES(0,1):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_0_to_1((p_wchar1 *)to.ptr,(p_wchar0 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; case TWO_SIZES(0,2):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_0_to_2((p_wchar2 *)to.ptr,(p_wchar0 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; case TWO_SIZES(1,0):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_1_to_0((p_wchar0 *)to.ptr,(p_wchar1 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; case TWO_SIZES(1,1):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_1_to_1((p_wchar1 *)to.ptr,(p_wchar1 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; case TWO_SIZES(1,2):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_1_to_2((p_wchar2 *)to.ptr,(p_wchar1 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; case TWO_SIZES(2,0):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_2_to_0((p_wchar0 *)to.ptr,(p_wchar2 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; case TWO_SIZES(2,1):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_2_to_1((p_wchar1 *)to.ptr,(p_wchar2 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; case TWO_SIZES(2,2):
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  convert_2_to_2((p_wchar2 *)to.ptr,(p_wchar2 *)from.ptr,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  break; } }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) INLINE void pike_string_cpy(PCHARP to, struct pike_string *from)
3e625c1998-10-11Fredrik Hübinette (Hubbe) {
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  generic_memcpy(to,MKPCHARP_STR(from),from->len);
3e625c1998-10-11Fredrik Hübinette (Hubbe) }
5014211998-10-14Fredrik Hübinette (Hubbe) 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
5014211998-10-14Fredrik Hübinette (Hubbe) #ifdef DEBUG_MALLOC #define DM(X) X #else #define DM(X) #endif
2043ba1998-02-10Fredrik Hübinette (Hubbe) static void locate_problem(int (*isproblem)(struct pike_string *)) { unsigned INT32 e; struct pike_string *s;
9e52381998-03-01Fredrik Hübinette (Hubbe)  DM(struct memhdr *yes=alloc_memhdr()); DM(struct memhdr *no=alloc_memhdr());
2043ba1998-02-10Fredrik Hübinette (Hubbe)  for(e=0;e<htable_size;e++)
9e52381998-03-01Fredrik Hübinette (Hubbe)  {
2043ba1998-02-10Fredrik Hübinette (Hubbe)  for(s=base_table[e];s;s=s->next)
9e52381998-03-01Fredrik Hübinette (Hubbe)  { if(isproblem(s)) { fprintf(stderr,"***Guilty string:\n"); debug_dump_pike_string(s, 70); DM(add_marks_to_memhdr(yes,s)); }else{ DM(add_marks_to_memhdr(no,s)); } } }
2043ba1998-02-10Fredrik Hübinette (Hubbe) 
9e52381998-03-01Fredrik Hübinette (Hubbe)  DM(fprintf(stderr,"Plausible problem location(s):\n")); DM(dump_memhdr_locations(yes,0)); DM(fprintf(stderr,"More Plausible problem location(s):\n")); DM(dump_memhdr_locations(yes,no));
2043ba1998-02-10Fredrik Hübinette (Hubbe) } static int has_zero_refs(struct pike_string *s) { return s->refs<=0; } static int wrong_hash(struct pike_string *s) {
db4a401998-10-09Fredrik Hübinette (Hubbe)  return (s->hval % htable_size) != do_hash(s);
2043ba1998-02-10Fredrik Hübinette (Hubbe) } static int improper_zero_termination(struct pike_string *s) {
db4a401998-10-09Fredrik Hübinette (Hubbe)  return index_shared_string(s,s->len);
2043ba1998-02-10Fredrik Hübinette (Hubbe) } #else #define locate_problem(X) #endif
5267b71995-08-09Fredrik Hübinette (Hubbe) 
fe3c9f1999-09-06Henrik Grubbström (Grubba) /* Find a string in the shared string table. * This assumes that the string is minimized!!!! */
db4a401998-10-09Fredrik Hübinette (Hubbe) static struct pike_string *internal_findstring(const char *s, int len, int size_shift, int h)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *curr,**prev, **base;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #ifndef HASH_PREFIX unsigned int depth=0; #endif
5267b71995-08-09Fredrik Hübinette (Hubbe)  for(base = prev = base_table + h;( curr=*prev ); prev=&curr->next) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(curr->refs<1)
38d6081998-02-07Fredrik Hübinette (Hubbe)  { debug_dump_pike_string(curr, 70);
2043ba1998-02-10Fredrik Hübinette (Hubbe)  locate_problem(has_zero_refs);
5267b71995-08-09Fredrik Hübinette (Hubbe)  fatal("String with no references.\n");
38d6081998-02-07Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) #endif
f43e421999-10-21Fredrik Hübinette (Hubbe)  debug_malloc_touch(curr);
5267b71995-08-09Fredrik Hübinette (Hubbe)  if (full_hash_value == curr->hval && len==curr->len &&
db4a401998-10-09Fredrik Hübinette (Hubbe)  size_shift==curr->size_shift &&
66769e1999-11-04Fredrik Hübinette (Hubbe)  ( curr->str == s || !MEMCMP(curr->str, s,len<<size_shift))) /* found it */
5267b71995-08-09Fredrik Hübinette (Hubbe)  { *prev = curr->next; curr->next = *base; *base = curr; return curr; /* pointer to string */ }
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #ifndef HASH_PREFIX depth++; #endif
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #ifndef HASH_PREFIX /* These heuruistics might require tuning! /Hubbe */
fe3c9f1999-09-06Henrik Grubbström (Grubba)  if((depth > HASH_PREFIX) && (HASH_PREFIX < (unsigned int)len))
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  { need_more_hash_prefix++; /* fprintf(stderr,"depth=%d num_strings=%d need_more_hash_prefix=%d HASH_PREFIX=%d\n",depth,num_strings,need_more_hash_prefix,HASH_PREFIX); */ }else{ if(need_more_hash_prefix) need_more_hash_prefix--; } #endif
5267b71995-08-09Fredrik Hübinette (Hubbe)  return 0; /* not found */ }
ca74dd1996-10-08Fredrik Hübinette (Hubbe) struct pike_string *binary_findstring(const char *foo, INT32 l)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
db4a401998-10-09Fredrik Hübinette (Hubbe)  return internal_findstring(foo, l, 0, StrHash(foo,l));
5267b71995-08-09Fredrik Hübinette (Hubbe) }
ca74dd1996-10-08Fredrik Hübinette (Hubbe) struct pike_string *findstring(const char *foo) { return binary_findstring(foo, strlen(foo)); }
5267b71995-08-09Fredrik Hübinette (Hubbe) /* * find a string that is already shared and move it to the head * of that list in the hastable */
db4a401998-10-09Fredrik Hübinette (Hubbe) static struct pike_string *propagate_shared_string(const struct pike_string *s, int h)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *curr, **prev, **base;
5267b71995-08-09Fredrik Hübinette (Hubbe)  for(base = prev = base_table + h;( curr=*prev ); prev=&curr->next) { if (curr == s) /* found it */ { *prev=curr->next; curr->next=*base; *base=curr; return curr; }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(curr->refs<1)
38d6081998-02-07Fredrik Hübinette (Hubbe)  { debug_dump_pike_string(curr, 70);
2043ba1998-02-10Fredrik Hübinette (Hubbe)  locate_problem(has_zero_refs);
5267b71995-08-09Fredrik Hübinette (Hubbe)  fatal("String with no references.\n");
38d6081998-02-07Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) #endif } return 0; /* not found */ }
af93211996-10-12Fredrik Hübinette (Hubbe) /*** rehash ***/ static void rehash_string_backwards(struct pike_string *s)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
af93211996-10-12Fredrik Hübinette (Hubbe)  int h; if(!s) return; rehash_string_backwards(s->next); h=s->hval % htable_size; s->next=base_table[h]; base_table[h]=s; }
aef30b1996-10-11Fredrik Hübinette (Hubbe) 
be478c1997-08-30Henrik Grubbström (Grubba) static void rehash(void)
af93211996-10-12Fredrik Hübinette (Hubbe) { int h,old; struct pike_string **old_base;
aef30b1996-10-11Fredrik Hübinette (Hubbe) 
af93211996-10-12Fredrik Hübinette (Hubbe)  old=htable_size; old_base=base_table;
75920f1997-12-28Fredrik Hübinette (Hubbe)  htable_size=hashprimes[++hashprimes_entry];
af93211996-10-12Fredrik Hübinette (Hubbe)  base_table=(struct pike_string **)xalloc(sizeof(struct pike_string *)*htable_size); MEMSET((char *)base_table,0,sizeof(struct pike_string *)*htable_size);
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  for(h=0;h<old;h++) rehash_string_backwards(old_base[h]);
af93211996-10-12Fredrik Hübinette (Hubbe)  if(old_base) free((char *)old_base);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
af93211996-10-12Fredrik Hübinette (Hubbe)  /*** Make new strings ***/
5267b71995-08-09Fredrik Hübinette (Hubbe)  /* note that begin_shared_string expects the _exact_ size of the string, * not the maximum size */
61e9a01998-01-25Fredrik Hübinette (Hubbe) struct pike_string *debug_begin_shared_string(int len)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *t;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
6a13711998-04-17Fredrik Hübinette (Hubbe)  extern int d_flag;
7abf491998-04-17Fredrik Hübinette (Hubbe)  if(d_flag>10) verify_shared_strings_tables(); #endif
06983f1996-09-22Fredrik Hübinette (Hubbe)  t=(struct pike_string *)xalloc(len + sizeof(struct pike_string));
ca74dd1996-10-08Fredrik Hübinette (Hubbe)  t->str[len]=0;
5267b71995-08-09Fredrik Hübinette (Hubbe)  t->len=len;
db4a401998-10-09Fredrik Hübinette (Hubbe)  t->size_shift=0;
5267b71995-08-09Fredrik Hübinette (Hubbe)  return t; }
fe3c9f1999-09-06Henrik Grubbström (Grubba) static void link_pike_string(struct pike_string *s, unsigned int h)
af93211996-10-12Fredrik Hübinette (Hubbe) { s->refs = 0; s->next = base_table[h]; base_table[h] = s; s->hval=full_hash_value; num_strings++; if(num_strings > MAX_AVG_LINK_LENGTH * htable_size) rehash();
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  #ifndef HASH_PREFIX /* These heuruistics might require tuning! /Hubbe */ if(need_more_hash_prefix > ( htable_size >> 4)) { /* This could in theory have a pretty ugly complexity */ /* /Hubbe */ unsigned INT32 save_full_hash_value=full_hash_value; need_more_hash_prefix=0; HASH_PREFIX=HASH_PREFIX*2; /* fprintf(stderr,"Doubling HASH_PREFIX to %d and rehashing\n",HASH_PREFIX); */ for(h=0;h<htable_size;h++) { struct pike_string *tmp=base_table[h]; base_table[h]=0; while(tmp) {
fe3c9f1999-09-06Henrik Grubbström (Grubba)  unsigned int h2;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  struct pike_string *tmp2=tmp; /* First unlink */ tmp=tmp2->next; h2=do_hash(tmp2); /* compute new hash value */ tmp2->hval=full_hash_value; tmp2->next=base_table[h2]; /* and re-hash */ base_table[h2]=tmp2; } } full_hash_value=save_full_hash_value; } #endif
af93211996-10-12Fredrik Hübinette (Hubbe) }
db4a401998-10-09Fredrik Hübinette (Hubbe) struct pike_string *debug_begin_wide_shared_string(int len, int shift) { struct pike_string *t;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
db4a401998-10-09Fredrik Hübinette (Hubbe)  extern int d_flag; if(d_flag>10) verify_shared_strings_tables(); #endif t=(struct pike_string *)xalloc((len<<shift) + sizeof(struct pike_string)); t->len=len; t->size_shift=shift; low_set_index(t,len,0); return t; }
3e625c1998-10-11Fredrik Hübinette (Hubbe) /* * This function assumes that the shift size is already the minimum it * can be. */ struct pike_string *low_end_shared_string(struct pike_string *s)
5267b71995-08-09Fredrik Hübinette (Hubbe) { int len,h;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s2;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
3e625c1998-10-11Fredrik Hübinette (Hubbe)  len=s->len; h=do_hash(s); s2=internal_findstring(s->str,len,s->size_shift,h);
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
3e625c1998-10-11Fredrik Hübinette (Hubbe)  if(s2==s) fatal("end_shared_string called twice! (or something like that)\n"); #endif if(s2) { free((char *)s); s=s2; }else{ link_pike_string(s, h); } add_ref(s); return s; } /* * This function checks if the shift size can be decreased before * entering the string in the shared string table */ struct pike_string *end_shared_string(struct pike_string *s) { struct pike_string *s2;
db4a401998-10-09Fredrik Hübinette (Hubbe)  switch(s->size_shift) { default:
1231a41998-10-29Henrik Grubbström (Grubba)  fatal("ARGHEL! size_shift:%d\n", s->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe)  case 2: switch(find_magnitude2(STR2(s),s->len)) { case 0: s2=begin_shared_string(s->len); convert_2_to_0(STR0(s2),STR2(s),s->len); free((char *)s); s=s2; break; case 1:
82b1ff1999-02-27Henrik Grubbström (Grubba)  s2=begin_wide_shared_string(s->len,1);
db4a401998-10-09Fredrik Hübinette (Hubbe)  convert_2_to_1(STR1(s2),STR2(s),s->len); free((char *)s); s=s2; /* Fall though */ } break; case 1: if(!find_magnitude1(STR1(s),s->len)) { s2=begin_shared_string(s->len); convert_1_to_0(STR0(s2),STR1(s),s->len); free((char *)s); s=s2; } break; case 0: break; }
3e625c1998-10-11Fredrik Hübinette (Hubbe)  return low_end_shared_string(s);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
db4a401998-10-09Fredrik Hübinette (Hubbe) 
61e9a01998-01-25Fredrik Hübinette (Hubbe) struct pike_string * debug_make_shared_binary_string(const char *str,int len)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s;
5267b71995-08-09Fredrik Hübinette (Hubbe)  int h=StrHash(str,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s = internal_findstring(str,len,0,h);
5267b71995-08-09Fredrik Hübinette (Hubbe)  if (!s) { s=begin_shared_string(len); MEMCPY(s->str, str, len);
af93211996-10-12Fredrik Hübinette (Hubbe)  link_pike_string(s, h);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(s);
5267b71995-08-09Fredrik Hübinette (Hubbe)  return s; }
011ad31999-10-22Fredrik Hübinette (Hubbe) struct pike_string * debug_make_shared_binary_pcharp(const PCHARP str,int len) { switch(str.shift) { case 0:
01a9572000-02-03Henrik Grubbström (Grubba)  return make_shared_binary_string((char *)(str.ptr), len);
011ad31999-10-22Fredrik Hübinette (Hubbe)  case 1: return make_shared_binary_string1((p_wchar1 *)(str.ptr), len); case 2: return make_shared_binary_string2((p_wchar2 *)(str.ptr), len); default: fatal("Unknown string width!\n"); } } struct pike_string * debug_make_shared_pcharp(const PCHARP str) { return debug_make_shared_binary_pcharp(str, pcharp_strlen(str)); }
50d6d31999-10-31Henrik Grubbström (Grubba) struct pike_string * debug_make_shared_binary_string0(const p_wchar0 *str,int len) {
a0d5ae1999-10-31Henrik Grubbström (Grubba)  return debug_make_shared_binary_string((const char *)str, len);
50d6d31999-10-31Henrik Grubbström (Grubba) }
efae671998-10-21Fredrik Hübinette (Hubbe) struct pike_string * debug_make_shared_binary_string1(const p_wchar1 *str,int len)
db4a401998-10-09Fredrik Hübinette (Hubbe) { struct pike_string *s; int h; if(!find_magnitude1(str,len)) { /* Wrong size, convert */ s=begin_shared_string(len);
efae671998-10-21Fredrik Hübinette (Hubbe)  convert_1_to_0(STR0(s),str,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return end_shared_string(s); }
3e625c1998-10-11Fredrik Hübinette (Hubbe)  h=low_do_hash(str, len, 1);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s = internal_findstring((char *)str,len,1,h); if (!s) { s=begin_wide_shared_string(len,1); MEMCPY(s->str, str, len<<1); link_pike_string(s, h); } add_ref(s); return s; }
efae671998-10-21Fredrik Hübinette (Hubbe) struct pike_string * debug_make_shared_binary_string2(const p_wchar2 *str,int len)
db4a401998-10-09Fredrik Hübinette (Hubbe) { struct pike_string *s; int h; switch(find_magnitude2(str,len)) { case 0: /* Wrong size, convert */ s=begin_shared_string(len);
efae671998-10-21Fredrik Hübinette (Hubbe)  convert_2_to_0(STR0(s),str,len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return end_shared_string(s); case 1: /* Wrong size, convert */ s=begin_wide_shared_string(len,1); convert_2_to_1(STR1(s),str,len); return end_shared_string(s); /* not entirely optimal */ }
3e625c1998-10-11Fredrik Hübinette (Hubbe)  h=low_do_hash(str, len, 2);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s = internal_findstring((char *)str,len,2,h); if (!s) { s=begin_wide_shared_string(len,2); MEMCPY(s->str, str, len<<2); link_pike_string(s, h); } add_ref(s); return s; }
61e9a01998-01-25Fredrik Hübinette (Hubbe) struct pike_string *debug_make_shared_string(const char *str)
5267b71995-08-09Fredrik Hübinette (Hubbe) { return make_shared_binary_string(str, strlen(str)); }
50d6d31999-10-31Henrik Grubbström (Grubba) struct pike_string *debug_make_shared_string0(const p_wchar0 *str) {
a0d5ae1999-10-31Henrik Grubbström (Grubba)  return debug_make_shared_string((const char *)str);
50d6d31999-10-31Henrik Grubbström (Grubba) }
efae671998-10-21Fredrik Hübinette (Hubbe) struct pike_string *debug_make_shared_string1(const p_wchar1 *str)
4d1ed11998-09-18Fredrik Hübinette (Hubbe) {
db4a401998-10-09Fredrik Hübinette (Hubbe)  INT32 len;
4d1ed11998-09-18Fredrik Hübinette (Hubbe)  for(len=0;str[len];len++);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return debug_make_shared_binary_string1(str,len); }
efae671998-10-21Fredrik Hübinette (Hubbe) struct pike_string *debug_make_shared_string2(const p_wchar2 *str)
db4a401998-10-09Fredrik Hübinette (Hubbe) { INT32 len; for(len=0;str[len];len++); return debug_make_shared_binary_string2(str,len);
4d1ed11998-09-18Fredrik Hübinette (Hubbe) }
af93211996-10-12Fredrik Hübinette (Hubbe) /*** Free strings ***/
5267b71995-08-09Fredrik Hübinette (Hubbe) 
0a3d601996-10-09Fredrik Hübinette (Hubbe) void unlink_pike_string(struct pike_string *s)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
c9e5eb1999-10-19Henrik Grubbström (Grubba)  unsigned int h=s->hval % htable_size;
5267b71995-08-09Fredrik Hübinette (Hubbe)  propagate_shared_string(s,h); base_table[h]=s->next;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
2302231998-04-23Fredrik Hübinette (Hubbe)  s->next=(struct pike_string *)-1; #endif
760b261996-12-03Fredrik Hübinette (Hubbe)  num_strings--;
0a3d601996-10-09Fredrik Hübinette (Hubbe) }
04965a1998-12-06Fredrik Hübinette (Hubbe) void do_free_string(struct pike_string *s) { free_string(s); }
0a3d601996-10-09Fredrik Hübinette (Hubbe) void really_free_string(struct pike_string *s) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
9367351997-01-27Fredrik Hübinette (Hubbe)  extern int d_flag; if(d_flag > 2) { if(s->next == (struct pike_string *)-1) fatal("Freeing shared string again!\n");
7abf491998-04-17Fredrik Hübinette (Hubbe)  if(((long)s->next) & 1) fatal("Freeing shared string again, memory corrupt or other bug!\n");
9367351997-01-27Fredrik Hübinette (Hubbe)  } #endif
0a3d601996-10-09Fredrik Hübinette (Hubbe)  unlink_pike_string(s);
20f7a02000-03-20Fredrik Hübinette (Hubbe)  debug_free((char *)s,DMALLOC_LOCATION(),1);
699bb02000-04-22Martin Stjernholm  if (Pike_in_gc) remove_marker(s);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
61e9a01998-01-25Fredrik Hübinette (Hubbe) void debug_free_string(struct pike_string *s) { if(--s->refs<=0) really_free_string(s); }
af93211996-10-12Fredrik Hübinette (Hubbe) 
5267b71995-08-09Fredrik Hübinette (Hubbe) /*
af93211996-10-12Fredrik Hübinette (Hubbe)  * String table status
5267b71995-08-09Fredrik Hübinette (Hubbe)  */
06983f1996-09-22Fredrik Hübinette (Hubbe) struct pike_string *add_string_status(int verbose)
5267b71995-08-09Fredrik Hübinette (Hubbe) { char b[200]; init_buf(); if (verbose) { int allocd_strings=0; int allocd_bytes=0; int num_distinct_strings=0; int bytes_distinct_strings=0; int overhead_bytes=0;
af93211996-10-12Fredrik Hübinette (Hubbe)  unsigned INT32 e;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *p;
af93211996-10-12Fredrik Hübinette (Hubbe)  for(e=0;e<htable_size;e++)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { for(p=base_table[e];p;p=p->next) { num_distinct_strings++;
90e9781999-01-31Fredrik Hübinette (Hubbe)  bytes_distinct_strings+=DO_ALIGN(p->len,sizeof(void *));
5267b71995-08-09Fredrik Hübinette (Hubbe)  allocd_strings+=p->refs;
90e9781999-01-31Fredrik Hübinette (Hubbe)  allocd_bytes+=p->refs*DO_ALIGN(p->len+3,sizeof(void *));
5267b71995-08-09Fredrik Hübinette (Hubbe)  } }
06983f1996-09-22Fredrik Hübinette (Hubbe)  overhead_bytes=(sizeof(struct pike_string)-1)*num_distinct_strings;
5267b71995-08-09Fredrik Hübinette (Hubbe)  my_strcat("\nShared string hash table:\n"); my_strcat("-------------------------\t Strings Bytes\n"); sprintf(b,"Total asked for\t\t\t%8ld %8ld\n", (long)allocd_strings, (long)allocd_bytes); my_strcat(b); sprintf(b,"Strings malloced\t\t%8ld %8ld + %ld overhead\n", (long)num_distinct_strings, (long)bytes_distinct_strings, (long)overhead_bytes); my_strcat(b); sprintf(b,"Space actually required/total string bytes %d%%\n", (bytes_distinct_strings + overhead_bytes)*100 / allocd_bytes); my_strcat(b); } /* sprintf(b,"Searches: %ld Average search length: %6.3f\n", (long)num_str_searches, (double)search_len / num_str_searches); my_strcat(b); */ return free_buf(); }
71f3a21998-11-22Fredrik Hübinette (Hubbe) /*** PIKE_DEBUG ***/ #ifdef PIKE_DEBUG
af93211996-10-12Fredrik Hübinette (Hubbe)  void check_string(struct pike_string *s) {
db4a401998-10-09Fredrik Hübinette (Hubbe)  do_hash(s);
af93211996-10-12Fredrik Hübinette (Hubbe)  if(full_hash_value != s->hval)
2043ba1998-02-10Fredrik Hübinette (Hubbe)  { locate_problem(wrong_hash);
af93211996-10-12Fredrik Hübinette (Hubbe)  fatal("Hash value changed?\n");
2043ba1998-02-10Fredrik Hübinette (Hubbe)  }
af93211996-10-12Fredrik Hübinette (Hubbe)  if(debug_findstring(s) !=s) fatal("Shared string not shared.\n");
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(index_shared_string(s,s->len))
2043ba1998-02-10Fredrik Hübinette (Hubbe)  { locate_problem(improper_zero_termination);
af93211996-10-12Fredrik Hübinette (Hubbe)  fatal("Shared string is not zero terminated properly.\n");
2043ba1998-02-10Fredrik Hübinette (Hubbe)  }
af93211996-10-12Fredrik Hübinette (Hubbe) }
be478c1997-08-30Henrik Grubbström (Grubba) void verify_shared_strings_tables(void)
af93211996-10-12Fredrik Hübinette (Hubbe) {
beac721998-04-16Fredrik Hübinette (Hubbe)  unsigned INT32 e, h, num=0;
95fd021998-05-25Henrik Grubbström (Grubba)  unsigned INT32 orig_full_hash = full_hash_value;
af93211996-10-12Fredrik Hübinette (Hubbe)  struct pike_string *s; for(e=0;e<htable_size;e++) { h=0; for(s=base_table[e];s;s=s->next) {
beac721998-04-16Fredrik Hübinette (Hubbe)  num++;
af93211996-10-12Fredrik Hübinette (Hubbe)  h++; if(s->len < 0) fatal("Shared string shorter than zero bytes.\n"); if(s->refs <= 0)
2043ba1998-02-10Fredrik Hübinette (Hubbe)  { locate_problem(has_zero_refs);
af93211996-10-12Fredrik Hübinette (Hubbe)  fatal("Shared string had too few references.\n");
2043ba1998-02-10Fredrik Hübinette (Hubbe)  }
af93211996-10-12Fredrik Hübinette (Hubbe) 
f4e1ec1998-10-22Fredrik Hübinette (Hubbe)  if(index_shared_string(s,s->len))
2043ba1998-02-10Fredrik Hübinette (Hubbe)  { locate_problem(improper_zero_termination);
af93211996-10-12Fredrik Hübinette (Hubbe)  fatal("Shared string didn't end with a zero.\n");
2043ba1998-02-10Fredrik Hübinette (Hubbe)  }
af93211996-10-12Fredrik Hübinette (Hubbe) 
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(do_hash(s) != e)
2043ba1998-02-10Fredrik Hübinette (Hubbe)  { locate_problem(wrong_hash);
af93211996-10-12Fredrik Hübinette (Hubbe)  fatal("Shared string hashed to wrong place.\n");
2043ba1998-02-10Fredrik Hübinette (Hubbe)  }
af93211996-10-12Fredrik Hübinette (Hubbe)  if(s->hval != full_hash_value) fatal("Shared string hashed to other number.\n"); if(h>10000) { struct pike_string *s2; for(s2=s;s2;s2=s2->next) if(s2 == s) fatal("Shared string table is cyclic.\n"); h=0; } } }
beac721998-04-16Fredrik Hübinette (Hubbe)  if(num != num_strings) fatal("Num strings is wrong %d!=%d\n",num,num_strings);
95fd021998-05-25Henrik Grubbström (Grubba)  full_hash_value = orig_full_hash;
af93211996-10-12Fredrik Hübinette (Hubbe) }
62971d1998-01-19Fredrik Hübinette (Hubbe) int safe_debug_findstring(struct pike_string *foo) { unsigned INT32 e; if(!base_table) return 0; for(e=0;e<htable_size;e++) { struct pike_string *p; for(p=base_table[e];p;p=p->next) if(p==foo) return 1; } return 0; }
af93211996-10-12Fredrik Hübinette (Hubbe) struct pike_string *debug_findstring(const struct pike_string *foo) { struct pike_string *tmp; tmp=propagate_shared_string(foo, foo->hval % htable_size); #if 0 if(!tmp) { unsigned INT32 e; struct pike_string *tmp2; fprintf(stderr,"String %p %ld %ld %s\n", foo, (long)foo->hval, (long)foo->len, foo->str); StrHash(foo->str,foo->len); fprintf(stderr,"------ %p %ld\n", base_table[foo->hval %htable_size], (long)full_hash_value); for(tmp2=base_table[foo->hval % htable_size];tmp2;tmp2=tmp2->next) { if(tmp2 == tmp) fprintf(stderr,"!!%p!!->",tmp2); else fprintf(stderr,"%p->",tmp2); } fprintf(stderr,"0\n"); for(e=0;e<htable_size;e++) { for(tmp2=base_table[e];tmp2;tmp2=tmp2->next) { if(tmp2 == tmp) fprintf(stderr,"String found in hashbin %ld (not %ld)\n", (long)e, (long)(foo->hval % htable_size)); } } } #endif return tmp; }
38d6081998-02-07Fredrik Hübinette (Hubbe) void debug_dump_pike_string(struct pike_string *s, INT32 max) { INT32 e;
a737441998-10-11Henrik Grubbström (Grubba)  fprintf(stderr,"0x%p: %ld refs, len=%ld, size_shift=%d, hval=%lux (%lx)\n",
38d6081998-02-07Fredrik Hübinette (Hubbe)  s, (long)s->refs, (long)s->len,
a737441998-10-11Henrik Grubbström (Grubba)  s->size_shift,
38d6081998-02-07Fredrik Hübinette (Hubbe)  (unsigned long)s->hval, (unsigned long)StrHash(s->str, s->len)); fprintf(stderr," \""); for(e=0;e<s->len && max>0;e++) { int c=EXTRACT_UCHAR(s->str+e); switch(c) { case '\t': fprintf(stderr,"\\t"); max-=2; break; case '\n': fprintf(stderr,"\\n"); max-=2; break; case '\r': fprintf(stderr,"\\r"); max-=2; break; case '\b': fprintf(stderr,"\\b"); max-=2; break; default: if(is8bitalnum(c) || c==' ' || isgraph(c)) { putc(c,stderr); max--; }else{ fprintf(stderr,"\\%03o",c); max-=4; } } } if(!max) fprintf(stderr,"...\n"); else fprintf(stderr,"\"\n"); }
be478c1997-08-30Henrik Grubbström (Grubba) void dump_stralloc_strings(void)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
af93211996-10-12Fredrik Hübinette (Hubbe)  unsigned INT32 e;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *p;
af93211996-10-12Fredrik Hübinette (Hubbe)  for(e=0;e<htable_size;e++)
5267b71995-08-09Fredrik Hübinette (Hubbe)  for(p=base_table[e];p;p=p->next)
38d6081998-02-07Fredrik Hübinette (Hubbe)  debug_dump_pike_string(p, 70);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
af93211996-10-12Fredrik Hübinette (Hubbe) #endif /*** String compare functions ***/ /* does not take locale into account */ int low_quick_binary_strcmp(char *a,INT32 alen, char *b,INT32 blen) { int tmp; if(alen > blen) { tmp=MEMCMP(a, b, blen); if(tmp) return tmp; return 1; }else if(alen < blen){ tmp=MEMCMP(a, b, alen); if(tmp) return tmp; return -1; }else{ return MEMCMP(a, b, alen); } }
a5787d1999-03-03Fredrik Hübinette (Hubbe) 
3e625c1998-10-11Fredrik Hübinette (Hubbe) /* does not take locale into account */ int generic_quick_binary_strcmp(const char *a,INT32 alen, int asize, const char *b,INT32 blen, int bsize) { if(!asize && !bsize) { int tmp; if(alen > blen) { tmp=MEMCMP(a, b, blen); if(tmp) return tmp; return 1; }else if(alen < blen){ tmp=MEMCMP(a, b, alen); if(tmp) return tmp; return -1; }else{ return MEMCMP(a, b, alen); } }else{ INT32 pos; for(pos=0;pos< MINIMUM(alen,blen) ;pos++) { INT32 ac=generic_extract(a,asize,pos); INT32 bc=generic_extract(b,bsize,pos); if(ac-bc) return ac-bc; } return alen-blen; } }
a5787d1999-03-03Fredrik Hübinette (Hubbe) int c_compare_string(struct pike_string *s, char *foo, int len) { return s->len == len && s->size_shift == 0 && !MEMCMP(s->str,foo,len); }
af93211996-10-12Fredrik Hübinette (Hubbe) #ifndef HAVE_STRCOLL /* No locale function available */ static int low_binary_strcmp(char *a,INT32 alen, char *b,INT32 blen) { low_quick_binary_strcmp(a,alen,b,blen); } #else /* takes locale into account */ static int low_binary_strcmp(char *a,INT32 alen, char *b,INT32 blen) { INT32 tmp; while(alen>0 && blen>0) { tmp=strcoll(a,b); if(tmp) return (int)tmp; tmp=strlen(a)+1; a+=tmp; b+=tmp; alen-=tmp; blen-=tmp; } if(alen==blen) return 0; if(alen > blen) return 1; return -1; } #endif /* Does not take locale into account */
3e625c1998-10-11Fredrik Hübinette (Hubbe) 
af93211996-10-12Fredrik Hübinette (Hubbe) int my_quick_strcmp(struct pike_string *a,struct pike_string *b) { if(a==b) return 0;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  return generic_quick_binary_strcmp(a->str, a->len, a->size_shift, b->str, b->len, b->size_shift);
af93211996-10-12Fredrik Hübinette (Hubbe) } /* Does take locale into account */ int my_strcmp(struct pike_string *a,struct pike_string *b) { if(a==b) return 0;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  switch(TWO_SIZES(a->size_shift,b->size_shift)) { case TWO_SIZES(0,0): return low_binary_strcmp(a->str,a->len,b->str,b->len); default: { INT32 e,l=MINIMUM(a->len,b->len); for(e=0;e<l;e++) { INT32 ac=index_shared_string(a,e); INT32 bc=index_shared_string(b,e); #ifdef HAVE_STRCOLL if(ac < 256 && bc < 256) { char atmp[2],btmp[2]; int tmp; atmp[0]=ac; btmp[0]=bc; atmp[1]=0; btmp[1]=0; if((tmp=strcoll(atmp,btmp))) return tmp; }else #endif if(ac-bc) return ac-bc; } return a->len - b->len; } }
af93211996-10-12Fredrik Hübinette (Hubbe) }
8d28be1997-02-10Fredrik Hübinette (Hubbe) struct pike_string *realloc_unlinked_string(struct pike_string *a, INT32 size) { struct pike_string *r; r=(struct pike_string *)realloc((char *)a,
3e625c1998-10-11Fredrik Hübinette (Hubbe)  sizeof(struct pike_string)+ ((size+1)<<a->size_shift)); /* FIXME !! */
8d28be1997-02-10Fredrik Hübinette (Hubbe)  if(!r) { r=begin_shared_string(size);
db4a401998-10-09Fredrik Hübinette (Hubbe)  MEMCPY(r->str, a->str, a->len<<a->size_shift);
8d28be1997-02-10Fredrik Hübinette (Hubbe)  free((char *)a); } r->len=size;
db4a401998-10-09Fredrik Hübinette (Hubbe)  low_set_index(r,size,0);
8d28be1997-02-10Fredrik Hübinette (Hubbe)  return r; } /* Returns an unlinked string ready for end_shared_string */ struct pike_string *realloc_shared_string(struct pike_string *a, INT32 size) { struct pike_string *r; if(a->refs==1) { unlink_pike_string(a); return realloc_unlinked_string(a, size); }else{
db4a401998-10-09Fredrik Hübinette (Hubbe)  r=begin_wide_shared_string(size,a->size_shift); MEMCPY(r->str, a->str, a->len<<a->size_shift);
7094631997-02-24Fredrik Hübinette (Hubbe)  free_string(a);
8d28be1997-02-10Fredrik Hübinette (Hubbe)  return r; } }
3e625c1998-10-11Fredrik Hübinette (Hubbe) struct pike_string *new_realloc_shared_string(struct pike_string *a, INT32 size, int shift) { struct pike_string *r; if(shift == a->size_shift) return realloc_shared_string(a,size); r=begin_wide_shared_string(size,shift);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  pike_string_cpy(MKPCHARP_STR(r),a);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  free_string(a); return r; }
0d3ea51998-01-19Fredrik Hübinette (Hubbe) /* Modify one index in a shared string * Not suitable for building new strings or changing multiple characters * within a string!
db4a401998-10-09Fredrik Hübinette (Hubbe)  * * Phew, this function become complicated when I inserted magic for wide * characters...
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  */ struct pike_string *modify_shared_string(struct pike_string *a, INT32 index,
db4a401998-10-09Fredrik Hübinette (Hubbe)  INT32 c)
0d3ea51998-01-19Fredrik Hübinette (Hubbe) {
db4a401998-10-09Fredrik Hübinette (Hubbe)  INT32 old_value;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  if(index<0 || index>=a->len) fatal("Index out of range in modify_shared_string()\n"); #endif
db4a401998-10-09Fredrik Hübinette (Hubbe)  old_value=index_shared_string(a,index); if(old_value==c) return a; /* First test if the string needs to be grown: * ie; the new value does not fit in the char size of * the old string */ if(min_magnitude(c) > a->size_shift) { /* String must be grown */ struct pike_string *b; switch(TWO_SIZES(min_magnitude(c),a->size_shift)) { case TWO_SIZES(1,0): b=begin_wide_shared_string(a->len,1);
01a9572000-02-03Henrik Grubbström (Grubba)  convert_0_to_1(STR1(b),(p_wchar0 *)a->str,a->len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  STR1(b)[index]=c;
7238061998-10-11Fredrik Hübinette (Hubbe)  free_string(a);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return end_shared_string(b); case TWO_SIZES(2,0): b=begin_wide_shared_string(a->len,2);
01a9572000-02-03Henrik Grubbström (Grubba)  convert_0_to_2(STR2(b),(p_wchar0 *)a->str,a->len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  STR2(b)[index]=c;
7238061998-10-11Fredrik Hübinette (Hubbe)  free_string(a);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return end_shared_string(b); case TWO_SIZES(2,1): b=begin_wide_shared_string(a->len,2); convert_1_to_2(STR2(b),STR1(a),a->len); STR2(b)[index]=c;
7238061998-10-11Fredrik Hübinette (Hubbe)  free_string(a);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return end_shared_string(b); default: fatal("Odd wide string conversion!\n"); } } /* Next we test if the new string can be shrunk * if all characters in the new string can fit in a string * of a lower magnitude, it must be shrunk */ if(min_magnitude(old_value) == a->size_shift && min_magnitude(c) < min_magnitude(old_value)) { /* We *might* need to shrink the string */ struct pike_string *b; int size,tmp; switch(a->size_shift) { case 0: fatal("Unshrinkable!\n"); case 1: /* Test if we *actually* can shrink it.. */ if(find_magnitude1(STR1(a),index)) break; if(find_magnitude1(STR1(a)+index+1,a->len-index-1)) break; b=begin_shared_string(a->len);
01a9572000-02-03Henrik Grubbström (Grubba)  convert_1_to_0((p_wchar0 *)b->str,STR1(a),a->len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  b->str[index]=c; free_string(a); return end_shared_string(b); case 2: /* Test if we *actually* can shrink it.. */ size=find_magnitude2(STR2(a),index); if(size==2) break; /* nope */ tmp=find_magnitude2(STR2(a)+index+1,a->len-index-1); if(tmp==2) break; /* nope */ size=MAXIMUM(MAXIMUM(size,tmp),min_magnitude(c)); switch(size) { case 0: b=begin_shared_string(a->len);
01a9572000-02-03Henrik Grubbström (Grubba)  convert_2_to_0((p_wchar0 *)b->str,STR2(a),a->len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  b->str[index]=c; free_string(a); return end_shared_string(b); case 1: b=begin_wide_shared_string(a->len,1);
01a9572000-02-03Henrik Grubbström (Grubba)  convert_2_to_1((p_wchar1 *)b->str,STR2(a),a->len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  STR1(b)[index]=c; free_string(a); return end_shared_string(b); } } } /* We now know that the string has the right character size */
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  if(a->refs==1) {
db4a401998-10-09Fredrik Hübinette (Hubbe)  /* One ref - destructive mode */
fe3c9f1999-09-06Henrik Grubbström (Grubba)  if((((unsigned int)index) >= HASH_PREFIX) && (index < a->len-8))
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  {
db4a401998-10-09Fredrik Hübinette (Hubbe)  /* Doesn't change hash value - sneak it in there */ low_set_index(a,index,c);
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  return a; }else{ unlink_pike_string(a);
db4a401998-10-09Fredrik Hübinette (Hubbe)  low_set_index(a,index,c);
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  return end_shared_string(a); } }else{ struct pike_string *r;
db4a401998-10-09Fredrik Hübinette (Hubbe)  r=begin_wide_shared_string(a->len,a->size_shift); MEMCPY(r->str, a->str, a->len << a->size_shift); low_set_index(r,index,c);
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  free_string(a); return end_shared_string(r); } }
af93211996-10-12Fredrik Hübinette (Hubbe) /*** Add strings ***/
06983f1996-09-22Fredrik Hübinette (Hubbe) struct pike_string *add_shared_strings(struct pike_string *a, struct pike_string *b)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *ret;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  PCHARP tmp;
db4a401998-10-09Fredrik Hübinette (Hubbe)  int target_size=MAXIMUM(a->size_shift,b->size_shift);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
db4a401998-10-09Fredrik Hübinette (Hubbe)  ret=begin_wide_shared_string(a->len+b->len,target_size);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  tmp=MKPCHARP_STR(ret); pike_string_cpy(tmp,a); INC_PCHARP(tmp,a->len); pike_string_cpy(tmp,b);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return end_shared_string(ret);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) struct pike_string *add_and_free_shared_strings(struct pike_string *a, struct pike_string *b) { INT32 alen=a->len;
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(a->size_shift == b->size_shift) { a=realloc_shared_string(a,alen + b->len); MEMCPY(a->str+(alen<<a->size_shift),b->str,b->len<<b->size_shift); free_string(b); return end_shared_string(a); }else{ struct pike_string *ret=add_shared_strings(a,b); free_string(a); free_string(b); return ret; } } int string_search(struct pike_string *haystack, struct pike_string *needle, int start) { struct generic_mem_searcher s; char *r; if(needle->size_shift > haystack->size_shift) return -1; init_generic_memsearcher(&s, needle->str, needle->len, needle->size_shift,
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  haystack->len-start,
db4a401998-10-09Fredrik Hübinette (Hubbe)  haystack->size_shift); r=(char *)generic_memory_search(&s,
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  haystack->str+(start<<haystack->size_shift), haystack->len-start,
db4a401998-10-09Fredrik Hübinette (Hubbe)  haystack->size_shift); if(!r) return -1; return (r-haystack->str)>>haystack->size_shift;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) }
3e625c1998-10-11Fredrik Hübinette (Hubbe) struct pike_string *string_slice(struct pike_string *s, INT32 start, INT32 len) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
3e625c1998-10-11Fredrik Hübinette (Hubbe)  if(start < 0 || len<0 || start+len>s->len ) { fatal("string_slice, start = %d, len = %d, s->len = %d\n",start,len,s->len); } #endif if(start==0 && len==s->len) { add_ref(s); return s; } switch(s->size_shift) { case 0:
01a9572000-02-03Henrik Grubbström (Grubba)  return make_shared_binary_string((char *)STR0(s)+start,len);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  case 1: return make_shared_binary_string1(STR1(s)+start,len); case 2: return make_shared_binary_string2(STR2(s)+start,len); }
efae671998-10-21Fredrik Hübinette (Hubbe)  fatal("Illegal shift size!\n"); return 0;
3e625c1998-10-11Fredrik Hübinette (Hubbe) }
db4a401998-10-09Fredrik Hübinette (Hubbe) 
af93211996-10-12Fredrik Hübinette (Hubbe) /*** replace function ***/
06983f1996-09-22Fredrik Hübinette (Hubbe) struct pike_string *string_replace(struct pike_string *str,
db4a401998-10-09Fredrik Hübinette (Hubbe)  struct pike_string *del, struct pike_string *to)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *ret;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  char *s,*tmp,*end; PCHARP r;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  int shift; struct generic_mem_searcher searcher;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
a991451997-07-08Fredrik Hübinette (Hubbe)  if(!str->len) {
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(str);
a991451997-07-08Fredrik Hübinette (Hubbe)  return str; }
3e625c1998-10-11Fredrik Hübinette (Hubbe)  shift=MAXIMUM(str->size_shift,to->size_shift);
a991451997-07-08Fredrik Hübinette (Hubbe)  if(!del->len) {
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  int e,pos;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  ret=begin_wide_shared_string(str->len + to->len * (str->len -1),shift); low_set_index(ret,0,index_shared_string(str,0));
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  for(pos=e=1;e<str->len;e++)
a991451997-07-08Fredrik Hübinette (Hubbe)  {
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  pike_string_cpy(MKPCHARP_STR_OFF(ret,pos),to);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  pos+=to->len; low_set_index(ret,pos++,index_shared_string(str,e));
a991451997-07-08Fredrik Hübinette (Hubbe)  } return end_shared_string(ret); }
5267b71995-08-09Fredrik Hübinette (Hubbe)  s=str->str;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  end=s+(str->len<<str->size_shift);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
1f515a1997-02-15Fredrik Hübinette (Hubbe)  if(del->len == to->len)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
3e625c1998-10-11Fredrik Hübinette (Hubbe)  init_generic_memsearcher(&searcher, del->str, del->len, del->size_shift, str->len, str->size_shift); ret=begin_wide_shared_string(str->len,shift);
1f515a1997-02-15Fredrik Hübinette (Hubbe)  }else{ INT32 delimeters=0;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  init_generic_memsearcher(&searcher, del->str, del->len, del->size_shift, str->len*2, str->size_shift); while((s=generic_memory_search(&searcher, s, (end-s)>>str->size_shift, str->size_shift)))
1f515a1997-02-15Fredrik Hübinette (Hubbe)  { delimeters++;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  s+=del->len << str->size_shift;
1f515a1997-02-15Fredrik Hübinette (Hubbe)  } if(!delimeters) {
d6ac731998-04-20Henrik Grubbström (Grubba)  add_ref(str);
1f515a1997-02-15Fredrik Hübinette (Hubbe)  return str; }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
3e625c1998-10-11Fredrik Hübinette (Hubbe)  ret=begin_wide_shared_string(str->len + (to->len-del->len)*delimeters, shift);
5267b71995-08-09Fredrik Hübinette (Hubbe)  } s=str->str;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  r=MKPCHARP_STR(ret);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
3e625c1998-10-11Fredrik Hübinette (Hubbe)  while((tmp=(char *)generic_memory_search(&searcher, s, (end-s)>>str->size_shift, str->size_shift)))
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
68d9131999-04-01Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG if(tmp + (del->len << str->size_shift) > end) fatal("generic_memory_search found a match beyond end of string!!!\n"); #endif
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  s=tmp+(del->len << str->size_shift);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  generic_memcpy(r,MKPCHARP(s,str->size_shift),(end-s)>>str->size_shift);
5267b71995-08-09Fredrik Hübinette (Hubbe)  return end_shared_string(ret); }
af93211996-10-12Fredrik Hübinette (Hubbe) /*** init/exit memory ***/
be478c1997-08-30Henrik Grubbström (Grubba) void init_shared_string_table(void)
af93211996-10-12Fredrik Hübinette (Hubbe) {
85f59e1998-01-08Fredrik Hübinette (Hubbe)  for(hashprimes_entry=0;hashprimes[hashprimes_entry]<BEGIN_HASH_SIZE;hashprimes_entry++);
75920f1997-12-28Fredrik Hübinette (Hubbe)  htable_size=hashprimes[hashprimes_entry];
af93211996-10-12Fredrik Hübinette (Hubbe)  base_table=(struct pike_string **)xalloc(sizeof(struct pike_string *)*htable_size); MEMSET((char *)base_table,0,sizeof(struct pike_string *)*htable_size); }
61e9a01998-01-25Fredrik Hübinette (Hubbe) #ifdef DEBUG_MALLOC struct shared_string_location *all_shared_string_locations; #endif
be478c1997-08-30Henrik Grubbström (Grubba) void cleanup_shared_string_table(void)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
af93211996-10-12Fredrik Hübinette (Hubbe)  unsigned INT32 e;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s,*next;
61e9a01998-01-25Fredrik Hübinette (Hubbe) 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #if defined(PIKE_DEBUG) && defined(DEBUG_MALLOC)
61e9a01998-01-25Fredrik Hübinette (Hubbe)  while(all_shared_string_locations) { struct shared_string_location *x=all_shared_string_locations; all_shared_string_locations=x->next; free_string(x->s); x->s=0; } if(verbose_debug_exit) {
3c0c281998-01-26Fredrik Hübinette (Hubbe)  INT32 num,size; count_memory_in_strings(&num,&size); if(num) { fprintf(stderr,"Strings left: %d (%d bytes) (zapped)\n",num,size); dump_stralloc_strings(); }
61e9a01998-01-25Fredrik Hübinette (Hubbe)  } #endif
af93211996-10-12Fredrik Hübinette (Hubbe)  for(e=0;e<htable_size;e++)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { for(s=base_table[e];s;s=next) { next=s->next; #ifdef REALLY_FREE free((char *)s); #else s->next=0; #endif } base_table[e]=0; }
b906cf1996-11-27Fredrik Hübinette (Hubbe)  free((char *)base_table);
61e9a01998-01-25Fredrik Hübinette (Hubbe)  base_table=0; num_strings=0;
5267b71995-08-09Fredrik Hübinette (Hubbe) }
c3c7031996-12-04Fredrik Hübinette (Hubbe)  void count_memory_in_strings(INT32 *num, INT32 *size) { unsigned INT32 e, num_=0, size_=0;
61e9a01998-01-25Fredrik Hübinette (Hubbe)  if(!base_table) { *num=*size=0; return; }
c3c7031996-12-04Fredrik Hübinette (Hubbe)  size_+=htable_size * sizeof(struct pike_string *); for(e=0;e<htable_size;e++) { struct pike_string *p; for(p=base_table[e];p;p=p->next) { num_++;
db4a401998-10-09Fredrik Hübinette (Hubbe)  size_+=sizeof(struct pike_string)+(p->len<<p->size_shift);
c3c7031996-12-04Fredrik Hübinette (Hubbe)  } }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
c3c7031996-12-04Fredrik Hübinette (Hubbe)  if(num_strings != num_)
beac721998-04-16Fredrik Hübinette (Hubbe)  fatal("Num strings is wrong! %d!=%d.\n",num_strings, num_);
c3c7031996-12-04Fredrik Hübinette (Hubbe) #endif num[0]=num_; size[0]=size_; }
9367351997-01-27Fredrik Hübinette (Hubbe) 
be478c1997-08-30Henrik Grubbström (Grubba) void gc_mark_all_strings(void)
9367351997-01-27Fredrik Hübinette (Hubbe) { unsigned INT32 e; if(!base_table) return; for(e=0;e<htable_size;e++) { struct pike_string *p; for(p=base_table[e];p;p=p->next) gc_is_referenced(p); } }
db4a401998-10-09Fredrik Hübinette (Hubbe)  void init_string_builder(struct string_builder *s, int mag) { s->malloced=256; s->s=begin_wide_shared_string(256,mag); s->s->len=0;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  s->known_shift=0;
db4a401998-10-09Fredrik Hübinette (Hubbe) }
3e625c1998-10-11Fredrik Hübinette (Hubbe) static void string_build_mkspace(struct string_builder *s, int chars, int mag)
db4a401998-10-09Fredrik Hübinette (Hubbe) { if(mag > s->s->size_shift) { struct pike_string *n; int l=s->s->len+chars+s->malloced; n=begin_wide_shared_string(l,mag);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  pike_string_cpy(MKPCHARP_STR(n),s->s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  n->len=s->s->len; s->malloced=l; free((char *)s->s); s->s=n; } else if(s->s->len+chars > s->malloced) { int newlen=MAXIMUM(s->malloced*2,s->s->len+chars); s->s=(struct pike_string *)realloc((char *)s->s, sizeof(struct pike_string)+ ((newlen+1)<<s->s->size_shift)); if(!s->s) fatal("Out of memory.\n"); s->malloced=newlen; } }
1e16942000-03-16Fredrik Hübinette (Hubbe) void *string_builder_allocate(struct string_builder *s, int chars, int mag)
3e625c1998-10-11Fredrik Hübinette (Hubbe) { void *ret; string_build_mkspace(s,chars,mag); if(chars<0) s->known_shift=0; ret=s->s->str + (s->s->len<<s->s->size_shift); s->s->len+=chars; return ret; }
db4a401998-10-09Fredrik Hübinette (Hubbe) void string_builder_putchar(struct string_builder *s, int ch) { INT32 i; string_build_mkspace(s,1,min_magnitude(ch));
3e625c1998-10-11Fredrik Hübinette (Hubbe)  s->known_shift=MAXIMUM(min_magnitude(ch),s->known_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe)  i=s->s->len++; low_set_index(s->s,i,ch); } void string_builder_binary_strcat(struct string_builder *s, char *str, INT32 len) {
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  string_build_mkspace(s,len,0);
db4a401998-10-09Fredrik Hübinette (Hubbe)  switch(s->s->size_shift) {
01a9572000-02-03Henrik Grubbström (Grubba)  case 0: convert_0_to_0(STR0(s->s)+s->s->len,(p_wchar0 *)str,len); break; case 1: convert_0_to_1(STR1(s->s)+s->s->len,(p_wchar0 *)str,len); break; case 2: convert_0_to_2(STR2(s->s)+s->s->len,(p_wchar0 *)str,len); break;
db4a401998-10-09Fredrik Hübinette (Hubbe)  default: fatal("Illegal magnitude!\n"); } s->s->len+=len; }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) 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;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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; } } }
db4a401998-10-09Fredrik Hübinette (Hubbe) void string_builder_strcat(struct string_builder *s, char *str) { string_builder_binary_strcat(s,str,strlen(str)); } void string_builder_shared_strcat(struct string_builder *s, struct pike_string *str) {
9641791999-06-30Fredrik Hübinette (Hubbe)  string_build_mkspace(s,str->len,str->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe) 
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  pike_string_cpy(MKPCHARP_STR_OFF(s->s,s->s->len), str);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  s->known_shift=MAXIMUM(s->known_shift,str->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s->s->len+=str->len; }
7238061998-10-11Fredrik Hübinette (Hubbe)  void reset_string_builder(struct string_builder *s) { s->known_shift=0; s->s->len=0; }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) void free_string_builder(struct string_builder *s) { free((char *)s->s); }
db4a401998-10-09Fredrik Hübinette (Hubbe) struct pike_string *finish_string_builder(struct string_builder *s) { low_set_index(s->s,s->s->len,0);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  if(s->known_shift == s->s->size_shift) return low_end_shared_string(s->s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return end_shared_string(s->s); }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) PCHARP MEMCHR_PCHARP(PCHARP ptr, int chr, int len) { switch(ptr.shift) { case 0: return MKPCHARP(MEMCHR0(ptr.ptr,chr,len),0);
efae671998-10-21Fredrik Hübinette (Hubbe)  case 1: return MKPCHARP(MEMCHR1((p_wchar1 *)ptr.ptr,chr,len),1); case 2: return MKPCHARP(MEMCHR2((p_wchar2 *)ptr.ptr,chr,len),2);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  }
efae671998-10-21Fredrik Hübinette (Hubbe)  fatal("Illegal shift in MEMCHR_PCHARP.\n"); return MKPCHARP(0,0); /* make wcc happy */
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) }
bbee342000-03-31Fredrik Hübinette (Hubbe) #define DIGIT(x) (WIDE_ISDIGIT(x) ? (x) - '0' : \ WIDE_ISLOWER(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) #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;
bbee342000-03-31Fredrik Hübinette (Hubbe)  if (!WIDE_ISALNUM(c = EXTRACT_PCHARP(str)))
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  { 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; }
bbee342000-03-31Fredrik Hübinette (Hubbe)  if (!WIDE_ISALNUM(c) || (xx = DIGIT(c)) >= base)
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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);
bbee342000-03-31Fredrik Hübinette (Hubbe)  if(!(WIDE_ISALNUM(c) && (xx=DIGIT(c)) < base)) break;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  val = base * val - xx; } if (ptr) *ptr = str; return (neg ? val : -val); }
efae671998-10-21Fredrik Hübinette (Hubbe) 
011ad31999-10-22Fredrik Hübinette (Hubbe) int string_to_svalue_inumber(struct svalue *r, char * str, char **ptr, int base, int maxlength) { PCHARP tmp; int ret=pcharp_to_svalue_inumber(r, MKPCHARP(str,0), &tmp, base, maxlength); if(ptr) *ptr=(char *)tmp.ptr; return ret; } int wide_string_to_svalue_inumber(struct svalue *r, void * str, void **ptr, int base, int maxlength, int shift) { PCHARP tmp; int ret=pcharp_to_svalue_inumber(r, MKPCHARP(str,shift), &tmp, base, maxlength); if(ptr) *ptr=(char *)tmp.ptr; return ret; } int pcharp_to_svalue_inumber(struct svalue *r, PCHARP str, PCHARP *ptr, int base,
31ea271999-10-22Fredrik Noring  int maxlength) {
011ad31999-10-22Fredrik Hübinette (Hubbe)  PCHARP str_start;
31ea271999-10-22Fredrik Noring 
6ee24a1999-10-24Fredrik Noring  INT_TYPE xx, neg = 0, is_bignum = 0, implicit_base = 0;
31ea271999-10-22Fredrik Noring  INT_TYPE val; INT_TYPE c; maxlength--; /* max_length <= 0 means no max length. */ str_start = str; /* In case no number is formed. */ r->type = T_INT; r->subtype = NUMBER_NUMBER; r->u.integer = 0; if(ptr != 0) *ptr = str; if(base < 0 || MBASE < base) return 0;
bbee342000-03-31Fredrik Hübinette (Hubbe)  if(!WIDE_ISALNUM(c = EXTRACT_PCHARP(str)))
31ea271999-10-22Fredrik Noring  {
bbee342000-03-31Fredrik Hübinette (Hubbe)  while(WIDE_ISSPACE(c))
011ad31999-10-22Fredrik Hübinette (Hubbe)  { INC_PCHARP(str,1); c = EXTRACT_PCHARP(str); }
31ea271999-10-22Fredrik Noring  switch (c) { case '-': neg++; /* Fall-through. */ case '+':
011ad31999-10-22Fredrik Hübinette (Hubbe)  INC_PCHARP(str,1); c = EXTRACT_PCHARP(str);
31ea271999-10-22Fredrik Noring  } } if(base == 0) {
6ee24a1999-10-24Fredrik Noring  implicit_base = 1;
31ea271999-10-22Fredrik Noring  if(c != '0') base = 10;
011ad31999-10-22Fredrik Hübinette (Hubbe)  else if(INDEX_PCHARP(str,1) == 'x' || INDEX_PCHARP(str,1) == 'X')
31ea271999-10-22Fredrik Noring  base = 16;
5656451999-10-26Fredrik Noring  else if(INDEX_PCHARP(str,1) == 'b' || INDEX_PCHARP(str,1) == 'B') base = 2;
31ea271999-10-22Fredrik Noring  else base = 8; } /* * For any base > 10, the digits incrementally following * 9 are assumed to be "abc...z" or "ABC...Z". */
bbee342000-03-31Fredrik Hübinette (Hubbe)  if(!WIDE_ISALNUM(c) || (xx = DIGIT(c)) >= base)
31ea271999-10-22Fredrik Noring  return 0; /* No number formed. */
5656451999-10-26Fredrik Noring  if(implicit_base && c == '0' &&
011ad31999-10-22Fredrik Hübinette (Hubbe)  INDEX_PCHARP(str,2) < 256 && /* Don't trust isxdigit... */ isxdigit(INDEX_PCHARP(str,2)) &&
5656451999-10-26Fredrik Noring  ((base==16 && (INDEX_PCHARP(str,1)=='x' || INDEX_PCHARP(str,1)=='X')) || (base==2 && (INDEX_PCHARP(str,1)=='b' || INDEX_PCHARP(str,1)=='B'))))
011ad31999-10-22Fredrik Hübinette (Hubbe)  {
11e89c1999-10-30Fredrik Noring  /* Skip over leading "0x", "0X", "0b" or "0B". */
011ad31999-10-22Fredrik Hübinette (Hubbe)  INC_PCHARP(str,2); c=EXTRACT_PCHARP(str); }
31ea271999-10-22Fredrik Noring 
011ad31999-10-22Fredrik Hübinette (Hubbe)  for(val = -DIGIT(c);
bbee342000-03-31Fredrik Hübinette (Hubbe)  (INC_PCHARP(str,1), WIDE_ISALNUM(c = EXTRACT_PCHARP(str) )) &&
011ad31999-10-22Fredrik Hübinette (Hubbe)  (xx = DIGIT(c)) < base && 0 != maxlength--; )
31ea271999-10-22Fredrik Noring  { #ifdef AUTO_BIGNUM if(INT_TYPE_MUL_OVERFLOW(val, base)) is_bignum = 1; #endif /* AUTO_BIGNUM */
11e89c1999-10-30Fredrik Noring  val = base * val;
31ea271999-10-22Fredrik Noring  /* Accumulating a negative value avoids surprises near MIN_TYPE_INT. */
11e89c1999-10-30Fredrik Noring #ifdef AUTO_BIGNUM if(INT_TYPE_SUB_OVERFLOW(val, xx)) is_bignum = 1; #endif /* AUTO_BIGNUM */ val -= xx;
31ea271999-10-22Fredrik Noring  } if(ptr != 0) *ptr = str;
11e89c1999-10-30Fredrik Noring  if(neg) r->u.integer = val; else { #ifdef AUTO_BIGNUM if(INT_TYPE_NEG_OVERFLOW(val)) is_bignum = 1; #endif /* AUTO_BIGNUM */ r->u.integer = -val; }
31ea271999-10-22Fredrik Noring  #ifdef AUTO_BIGNUM
11e89c1999-10-30Fredrik Noring  if(is_bignum)
31ea271999-10-22Fredrik Noring  {
011ad31999-10-22Fredrik Hübinette (Hubbe)  push_string(make_shared_binary_pcharp(str_start, SUBTRACT_PCHARP(str,str_start))); /* Note that this can concievably throw errors() * in some situations that might not be desirable... * take care. * /Hubbe */
6ee24a1999-10-24Fredrik Noring  if(implicit_base) { convert_stack_top_to_bignum(); } else { push_int(base); convert_stack_top_with_base_to_bignum(); }
31ea271999-10-22Fredrik Noring  *r = *--sp; } #endif /* AUTO_BIGNUM */ return 1; } int convert_stack_top_string_to_inumber(int base) { struct svalue r;
775f3d1999-10-23Fredrik Noring  int i;
31ea271999-10-22Fredrik Noring  if(sp[-1].type != T_STRING) error("Cannot convert stack top to integer number.\n");
011ad31999-10-22Fredrik Hübinette (Hubbe)  i=pcharp_to_svalue_inumber(&r, MKPCHARP_STR(sp[-1].u.string), 0, base, 0);
31ea271999-10-22Fredrik Noring  free_string(sp[-1].u.string); sp[-1] = r;
775f3d1999-10-23Fredrik Noring  return i;
31ea271999-10-22Fredrik Noring }
f3ece81999-02-28Fredrik Hübinette (Hubbe) /* Convert PCHARP to a double. If ENDPTR is not NULL, a pointer to the character after the last one used in the number is put in *ENDPTR. */ double STRTOD_PCHARP(PCHARP nptr, PCHARP *endptr) { register PCHARP s; short int sign; /* The number so far. */ double num; int got_dot; /* Found a decimal point. */ int got_digit; /* Seen any digits. */ /* The exponent of the number. */ long int exponent; if (nptr.ptr == NULL) { errno = EINVAL; goto noconv; } s = nptr; /* Eat whitespace. */
bbee342000-03-31Fredrik Hübinette (Hubbe)  while (EXTRACT_PCHARP(s) <256 && WIDE_ISSPACE(EXTRACT_PCHARP(s))) INC_PCHARP(s,1);
f3ece81999-02-28Fredrik Hübinette (Hubbe)  /* Get the sign. */ sign = EXTRACT_PCHARP(s) == '-' ? -1 : 1; if (EXTRACT_PCHARP(s) == '-' || EXTRACT_PCHARP(s) == '+') INC_PCHARP(s,1); num = 0.0; got_dot = 0; got_digit = 0; exponent = 0; for (;; INC_PCHARP(s,1)) {
bbee342000-03-31Fredrik Hübinette (Hubbe)  if (EXTRACT_PCHARP(s)<256 && WIDE_ISDIGIT (EXTRACT_PCHARP(s)))
f3ece81999-02-28Fredrik Hübinette (Hubbe)  { got_digit = 1; /* Make sure that multiplication by 10 will not overflow. */ if (num > DBL_MAX * 0.1) /* The value of the digit doesn't matter, since we have already gotten as many digits as can be represented in a `double'. This doesn't necessarily mean the result will overflow. The exponent may reduce it to within range. We just need to record that there was another digit so that we can multiply by 10 later. */ ++exponent; else num = (num * 10.0) + (EXTRACT_PCHARP(s) - '0'); /* Keep track of the number of digits after the decimal point. If we just divided by 10 here, we would lose precision. */ if (got_dot) --exponent; } else if (!got_dot && (char) EXTRACT_PCHARP(s) == '.') /* Record that we have found the decimal point. */ got_dot = 1; else /* Any other character terminates the number. */ break; } if (!got_digit) goto noconv; if (EXTRACT_PCHARP(s) <256 && tolower(EXTRACT_PCHARP(s)) == 'e') { /* Get the exponent specified after the `e' or `E'. */ int save = errno; PCHARP end; long int exp; errno = 0; INC_PCHARP(s,1); exp = STRTOL_PCHARP(s, &end, 10); if (errno == ERANGE) { /* The exponent overflowed a `long int'. It is probably a safe assumption that an exponent that cannot be represented by a `long int' exceeds the limits of a `double'. */ if (endptr != NULL) *endptr = end; if (exp < 0) goto underflow; else goto overflow; } else if (COMPARE_PCHARP(end,==,s)) /* There was no exponent. Reset END to point to the 'e' or 'E', so *ENDPTR will be set there. */ end = ADD_PCHARP(s,-1); errno = save; s = end; exponent += exp; } if(got_dot && INDEX_PCHARP(s,-1)=='.') INC_PCHARP(s,-1); if (endptr != NULL) *endptr = s; if (num == 0.0) return 0.0; /* Multiply NUM by 10 to the EXPONENT power, checking for overflow and underflow. */ if (exponent < 0) { if (num < DBL_MIN * pow(10.0, (double) -exponent)) goto underflow; } else if (exponent > 0) { if (num > DBL_MAX * pow(10.0, (double) -exponent)) goto overflow; }
bbee342000-03-31Fredrik Hübinette (Hubbe)  if(exponent < 0 && exponent >-100) /* make sure we don't underflow */ num /= pow(10.0, (double) -exponent); else num *= pow(10.0, (double) exponent);
f3ece81999-02-28Fredrik Hübinette (Hubbe)  return num * sign; overflow: /* Return an overflow error. */ errno = ERANGE; return HUGE * sign; underflow: /* Return an underflow error. */ if (endptr != NULL) *endptr = nptr; errno = ERANGE; return 0.0; noconv: /* There was no number. */ if (endptr != NULL) *endptr = nptr; return 0.0; }
efae671998-10-21Fredrik Hübinette (Hubbe) p_wchar0 *require_wstring0(struct pike_string *s, char **to_free) { switch(s->size_shift) { case 0: *to_free=0; return STR0(s); case 1: case 2: return 0; default: fatal("Illegal shift size in string.\n"); } return 0; } p_wchar1 *require_wstring1(struct pike_string *s, char **to_free) { switch(s->size_shift) { case 0: *to_free=xalloc((s->len+1)*2); convert_0_to_1((p_wchar1 *)*to_free, STR0(s),s->len+1); return (p_wchar1 *)*to_free; case 1: *to_free=0; return STR1(s); case 2: return 0; default: fatal("Illegal shift size in string.\n"); } return 0; } p_wchar2 *require_wstring2(struct pike_string *s, char **to_free) { switch(s->size_shift) { case 0: *to_free=xalloc((s->len+1)*4); convert_0_to_2((p_wchar2 *)*to_free, STR0(s),s->len+1); return (p_wchar2 *)*to_free; case 1: *to_free=xalloc((s->len+1)*4); convert_1_to_2((p_wchar2 *)*to_free, STR1(s),s->len+1); return (p_wchar2 *)*to_free; case 2: *to_free=0; return STR2(s); default: fatal("Illegal shift size in string.\n"); } return 0; }