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"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_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"
4a5e3f2000-11-25Henrik Grubbström (Grubba) #include "block_alloc.h"
6f3ad02001-07-02Martin Stjernholm #include "operators.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*/
f7cfa82001-09-04Martin Stjernholm RCSID("$Id: stralloc.c,v 1.132 2001/09/04 19:26:54 mast Exp $");
e1939c2001-03-30Fredrik Hübinette (Hubbe)  #if PIKE_RUN_UNLOCKED
3ac5e82001-03-30Fredrik Hübinette (Hubbe) /* Make this bigger when we get lightweight threads */ #define BUCKET_LOCKS 2048
e1939c2001-03-30Fredrik Hübinette (Hubbe) static PIKE_MUTEX_T *bucket_locks;
3ac5e82001-03-30Fredrik Hübinette (Hubbe) #define BUCKETLOCK(HVAL) \ (bucket_locks + ((hval__ % htable_size) & (BUCKET_LOCKS-1))) #define LOCK_BUCKET(HVAL) do { \ size_t hval__=(HVAL); \ PIKE_MUTEX_T *bucket_lock; \ while(1) \ { \ bucket_lock=BUCKETLOCK(hval__); \ mt_lock(bucket_lock); \ if(bucket_lock == BUCKETLOCK(hval__)) \ break; \ mt_unlock(bucket_lock); \ } \
e1939c2001-03-30Fredrik Hübinette (Hubbe) }while(0) #define UNLOCK_BUCKET(HVAL) do { \ size_t hval__=(HVAL); \
3ac5e82001-03-30Fredrik Hübinette (Hubbe)  mt_unlock(BUCKETLOCK(hval__)); \
e1939c2001-03-30Fredrik Hübinette (Hubbe) }while(0) #else #define LOCK_BUCKET(HVAL) #define UNLOCK_BUCKET(HVAL) #endif
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; 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)
8bcb3b2001-03-28Fredrik Hübinette (Hubbe) static INLINE size_t low_do_hash(const void *s, ptrdiff_t len__,
b0289e2000-12-01Henrik Grubbström (Grubba)  int size_shift)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  size_t h; DO_HASHMEM(h, s, len__<<size_shift, HASH_PREFIX<<size_shift); return h;
5267b71995-08-09Fredrik Hübinette (Hubbe) }
89fc4c2000-08-10Henrik Grubbström (Grubba) static INLINE size_t do_hash(struct pike_string *s)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
3e625c1998-10-11Fredrik Hübinette (Hubbe)  return low_do_hash(s->str, s->len, s->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe) }
d3b06f2000-08-10Henrik Grubbström (Grubba) static INLINE int find_magnitude1(const unsigned INT16 *s, ptrdiff_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) { while(--len>=0) if(s[len]>=256) return 1; return 0; }
d3b06f2000-08-10Henrik Grubbström (Grubba) static INLINE int find_magnitude2(const unsigned INT32 *s, ptrdiff_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) { 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; }
e526732000-08-04Henrik Grubbström (Grubba) static INLINE unsigned INT32 generic_extract (const void *str, int size, ptrdiff_t pos)
db4a401998-10-09Fredrik Hübinette (Hubbe) { 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) }
a7979d2000-08-11Henrik Grubbström (Grubba) PMOD_EXPORT INLINE unsigned INT32 index_shared_string(struct pike_string *s, ptrdiff_t pos)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
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) {
a7979d2000-08-11Henrik Grubbström (Grubba)  fatal("String index %ld is out of range [0 - %ld]!\n", DO_NOT_WARN((long)pos), DO_NOT_WARN((long)s->len-1));
49ed181998-10-15Henrik Grubbström (Grubba)  } else {
a7979d2000-08-11Henrik Grubbström (Grubba)  fatal("Attempt to index the empty string with %ld!\n", DO_NOT_WARN((long)pos));
49ed181998-10-15Henrik Grubbström (Grubba)  } }
db4a401998-10-09Fredrik Hübinette (Hubbe) #endif return generic_extract(s->str,s->size_shift,pos); }
c3dbe52000-08-09Henrik Grubbström (Grubba) PMOD_EXPORT INLINE void low_set_index(struct pike_string *s, ptrdiff_t 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
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT 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) \
e4b2252000-08-09Henrik Grubbström (Grubba) INLINE void PIKE_CONCAT4(convert_,FROM,_to_,TO)(PIKE_CONCAT(p_wchar,TO) *to, const PIKE_CONCAT(p_wchar,FROM) *from, ptrdiff_t len) \
3e625c1998-10-11Fredrik Hübinette (Hubbe) { while(--len>=0) *(to++)=*(from++); } \
e4b2252000-08-09Henrik Grubbström (Grubba) INLINE INT32 PIKE_CONCAT4(compare_,FROM,_to_,TO)(const PIKE_CONCAT(p_wchar,TO) *to, const PIKE_CONCAT(p_wchar,FROM) *from, ptrdiff_t len) \
3e625c1998-10-11Fredrik Hübinette (Hubbe) { 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)
d3b06f2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT int generic_compare_strings(const void *a, ptrdiff_t alen, int asize, const void *b, ptrdiff_t blen, int bsize)
db4a401998-10-09Fredrik Hübinette (Hubbe) { #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; } }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void generic_memcpy(PCHARP to,
d3b06f2000-08-10Henrik Grubbström (Grubba)  PCHARP from, ptrdiff_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
68d9131999-04-01Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG if(len<0)
a7979d2000-08-11Henrik Grubbström (Grubba)  fatal("Cannot copy %ld bytes!\n", DO_NOT_WARN((long)len));
68d9131999-04-01Fredrik Hübinette (Hubbe) #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; } }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT INLINE void pike_string_cpy(PCHARP to,
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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)  {
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(e);
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)); } }
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e);
9e52381998-03-01Fredrik Hübinette (Hubbe)  }
2043ba1998-02-10Fredrik Hübinette (Hubbe) 
9e52381998-03-01Fredrik Hübinette (Hubbe)  DM(fprintf(stderr,"Plausible problem location(s):\n"));
a4033e2000-04-14Fredrik Hübinette (Hubbe)  DM(dump_memhdr_locations(yes,0,0));
9e52381998-03-01Fredrik Hübinette (Hubbe)  DM(fprintf(stderr,"More Plausible problem location(s):\n"));
a4033e2000-04-14Fredrik Hübinette (Hubbe)  DM(dump_memhdr_locations(yes,no,0));
2043ba1998-02-10Fredrik Hübinette (Hubbe) }
4bdf5f2001-03-30Henrik Grubbström (Grubba) static int bad_pointer(struct pike_string *s) {
cfc9842001-03-30Henrik Grubbström (Grubba)  return (((ptrdiff_t)s)&(sizeof(struct pike_string *)-1));
4bdf5f2001-03-30Henrik Grubbström (Grubba) }
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) {
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  return s->hval != 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!!!! */
b0289e2000-12-01Henrik Grubbström (Grubba) static INLINE struct pike_string *internal_findstring(const char *s, ptrdiff_t len, int size_shift,
4bdf5f2001-03-30Henrik Grubbström (Grubba)  size_t hval)
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
e1939c2001-03-30Fredrik Hübinette (Hubbe)  size_t h; LOCK_BUCKET(hval); h=hval % htable_size;
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) 
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  if (hval == curr->hval &&
5267b71995-08-09Fredrik Hübinette (Hubbe)  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;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(hval);
5267b71995-08-09Fredrik Hübinette (Hubbe)  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 */
89fc4c2000-08-10Henrik Grubbström (Grubba)  if((depth > HASH_PREFIX) && (HASH_PREFIX < (size_t)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
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(hval);
5267b71995-08-09Fredrik Hübinette (Hubbe)  return 0; /* not found */ }
81945f2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string *binary_findstring(const char *foo, ptrdiff_t 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) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *findstring(const char *foo)
ca74dd1996-10-08Fredrik Hübinette (Hubbe) { 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,
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t 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) {
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t h;
af93211996-10-12Fredrik Hübinette (Hubbe)  if(!s) return; rehash_string_backwards(s->next);
89fc4c2000-08-10Henrik Grubbström (Grubba)  h = s->hval % htable_size;
af93211996-10-12Fredrik Hübinette (Hubbe)  s->next=base_table[h]; base_table[h]=s; }
aef30b1996-10-11Fredrik Hübinette (Hubbe) 
e1939c2001-03-30Fredrik Hübinette (Hubbe) static void stralloc_rehash(void)
af93211996-10-12Fredrik Hübinette (Hubbe) { int h,old; struct pike_string **old_base;
aef30b1996-10-11Fredrik Hübinette (Hubbe) 
e1939c2001-03-30Fredrik Hübinette (Hubbe)  old=htable_size; old_base=base_table;
3ac5e82001-03-30Fredrik Hübinette (Hubbe) #ifdef PIKE_RUN_UNLOCKED mt_lock(bucket_locks);
e1939c2001-03-30Fredrik Hübinette (Hubbe)  if(old != htable_size) { /* Someone got here before us */
3ac5e82001-03-30Fredrik Hübinette (Hubbe)  mt_lock(bucket_locks);
e1939c2001-03-30Fredrik Hübinette (Hubbe)  return; } /* Now that we have bucket zero, the hash table * cannot change, go ahead and lock ALL buckets. * NOTE: bucket zero is already locked */
3ac5e82001-03-30Fredrik Hübinette (Hubbe)  for(h=1;h<BUCKET_LOCKS;h++) mt_lock(bucket_locks+h); #endif
af93211996-10-12Fredrik Hübinette (Hubbe) 
75920f1997-12-28Fredrik Hübinette (Hubbe)  htable_size=hashprimes[++hashprimes_entry];
e1939c2001-03-30Fredrik Hübinette (Hubbe) 
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);
e1939c2001-03-30Fredrik Hübinette (Hubbe)  #ifdef PIKE_RUN_UNLOCKED
3ac5e82001-03-30Fredrik Hübinette (Hubbe)  for(h=0;h<BUCKET_LOCKS;h++) mt_unlock(bucket_locks + h);
e1939c2001-03-30Fredrik Hübinette (Hubbe) #endif
5267b71995-08-09Fredrik Hübinette (Hubbe) }
af93211996-10-12Fredrik Hübinette (Hubbe) 
b0289e2000-12-01Henrik Grubbström (Grubba) /* Allocation of strings */
af93211996-10-12Fredrik Hübinette (Hubbe) 
b0289e2000-12-01Henrik Grubbström (Grubba) /* Allocate some fixed string sizes with BLOCK_ALLOC. */
5267b71995-08-09Fredrik Hübinette (Hubbe) 
4a5e3f2000-11-25Henrik Grubbström (Grubba) /* Use the BLOCK_ALLOC() stuff for short strings */ #define SHORT_STRING_BLOCK 256
f599222001-07-03Fredrik Hübinette (Hubbe) #define SHORT_STRING_THRESHOLD 15 /* % 4 === 1 */
4a5e3f2000-11-25Henrik Grubbström (Grubba)  struct short_pike_string0 {
f599222001-07-03Fredrik Hübinette (Hubbe)  PIKE_STRING_CONTENTS;
16b3142001-08-15Fredrik Hübinette (Hubbe)  p_wchar0 str[SHORT_STRING_THRESHOLD+1];
4a5e3f2000-11-25Henrik Grubbström (Grubba) }; struct short_pike_string1 {
f599222001-07-03Fredrik Hübinette (Hubbe)  PIKE_STRING_CONTENTS;
16b3142001-08-15Fredrik Hübinette (Hubbe)  p_wchar1 str[SHORT_STRING_THRESHOLD+1];
4a5e3f2000-11-25Henrik Grubbström (Grubba) }; struct short_pike_string2 {
f599222001-07-03Fredrik Hübinette (Hubbe)  PIKE_STRING_CONTENTS;
16b3142001-08-15Fredrik Hübinette (Hubbe)  p_wchar2 str[SHORT_STRING_THRESHOLD+1];
4a5e3f2000-11-25Henrik Grubbström (Grubba) }; BLOCK_ALLOC(short_pike_string0, SHORT_STRING_BLOCK) BLOCK_ALLOC(short_pike_string1, SHORT_STRING_BLOCK) BLOCK_ALLOC(short_pike_string2, SHORT_STRING_BLOCK) #define really_free_short_pike_string(s) do { \ if (!s->size_shift) { \ really_free_short_pike_string0((struct short_pike_string0 *)s); \ } else if (s->size_shift == 1) { \ really_free_short_pike_string1((struct short_pike_string1 *)s); \ DO_IF_DEBUG( \ } else if (s->size_shift != 2) { \ fatal("Unsupported string shift: %d\n", s->size_shift); \ ) \ } else { \ really_free_short_pike_string2((struct short_pike_string2 *)s); \ } \ } while(0) #define really_free_pike_string(s) do { \ if (s->len <= SHORT_STRING_THRESHOLD) { \ really_free_short_pike_string(s); \ } else { \ debug_free((char *)s, DMALLOC_LOCATION(), 1); \ } \ } while(0)
5267b71995-08-09Fredrik Hübinette (Hubbe) /* note that begin_shared_string expects the _exact_ size of the string, * not the maximum size */
c8318b2000-08-03Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string *debug_begin_shared_string(size_t 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
4a5e3f2000-11-25Henrik Grubbström (Grubba)  if (len <= SHORT_STRING_THRESHOLD) { t=(struct pike_string *)alloc_short_pike_string0(); } else { 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; }
8bcb3b2001-03-28Fredrik Hübinette (Hubbe) static void link_pike_string(struct pike_string *s, size_t hval)
af93211996-10-12Fredrik Hübinette (Hubbe) {
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  size_t h;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(hval);
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  h=hval % htable_size;
af93211996-10-12Fredrik Hübinette (Hubbe)  s->refs = 0; s->next = base_table[h]; base_table[h] = s;
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  s->hval=hval;
af93211996-10-12Fredrik Hübinette (Hubbe)  num_strings++;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(hval);
af93211996-10-12Fredrik Hübinette (Hubbe)  if(num_strings > MAX_AVG_LINK_LENGTH * htable_size)
e1939c2001-03-30Fredrik Hübinette (Hubbe)  stralloc_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 */
8bcb3b2001-03-28Fredrik Hübinette (Hubbe) 
3ac5e82001-03-30Fredrik Hübinette (Hubbe) #ifdef PIKE_RUN_UNLOCKED mt_lock(bucket_locks); if(need_more_hash_prefix <= ( htable_size >> 4)) { /* Someone got here before us */ mt_lock(bucket_locks); return; } for(h=1;h<BUCKET_LOCKS;h++) mt_lock(bucket_locks+h); #endif
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  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) {
d3b06f2000-08-10Henrik Grubbström (Grubba)  size_t h2;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  struct pike_string *tmp2=tmp; /* First unlink */ tmp=tmp2->next;
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  tmp2->hval=do_hash(tmp2); /* compute new hash value */ h2=tmp2->hval % htable_size;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  tmp2->next=base_table[h2]; /* and re-hash */ base_table[h2]=tmp2; } }
3ac5e82001-03-30Fredrik Hübinette (Hubbe) #ifdef PIKE_RUN_UNLOCKED for(h=0;h<BUCKET_LOCKS;h++) mt_unlock(bucket_locks + h); #endif
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  } #endif
af93211996-10-12Fredrik Hübinette (Hubbe) }
c8318b2000-08-03Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string *debug_begin_wide_shared_string(size_t len, int shift)
db4a401998-10-09Fredrik Hübinette (Hubbe) { 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
4a5e3f2000-11-25Henrik Grubbström (Grubba)  if (len <= SHORT_STRING_THRESHOLD) { if (!shift) { t = (struct pike_string *)alloc_short_pike_string0(); } else if (shift == 1) { t = (struct pike_string *)alloc_short_pike_string1(); #ifdef PIKE_DEBUG } else if (shift != 2) { fatal("Unsupported string shift: %d\n", shift); #endif /* PIKE_DEBUG */ } else { t = (struct pike_string *)alloc_short_pike_string2(); } } else { t=(struct pike_string *)xalloc((len<<shift) + sizeof(struct pike_string)); }
db4a401998-10-09Fredrik Hübinette (Hubbe)  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. */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *low_end_shared_string(struct pike_string *s)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
2eed0b2000-10-08Henrik Grubbström (Grubba)  ptrdiff_t len; size_t h;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s2;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
d3b06f2000-08-10Henrik Grubbström (Grubba)  len = s->len; h = do_hash(s);
2eed0b2000-10-08Henrik Grubbström (Grubba)  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) {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  really_free_pike_string(s);
2eed0b2000-10-08Henrik Grubbström (Grubba)  s = s2;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  }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 */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *end_shared_string(struct pike_string *s)
3e625c1998-10-11Fredrik Hübinette (Hubbe) { 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);
4a5e3f2000-11-25Henrik Grubbström (Grubba)  really_free_pike_string(s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  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);
4a5e3f2000-11-25Henrik Grubbström (Grubba)  really_free_pike_string(s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  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);
4a5e3f2000-11-25Henrik Grubbström (Grubba)  really_free_pike_string(s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s=s2; } break; case 0: break; }
3e625c1998-10-11Fredrik Hübinette (Hubbe)  return low_end_shared_string(s);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
d5b1e22000-11-29Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *end_and_resize_shared_string(struct pike_string *str, ptrdiff_t len) { struct pike_string *tmp; #ifdef PIKE_DEBUG if(len > str->len) fatal("Cannot extend string here!\n"); #endif if( str->len <= SHORT_STRING_THRESHOLD ? (len <= SHORT_STRING_THRESHOLD) : (len > SHORT_STRING_THRESHOLD) && str->len > len/2 ) { str->len=len;
3d0d5d2001-01-10Fredrik Hübinette (Hubbe)  str->str[len]=0;
d5b1e22000-11-29Fredrik Hübinette (Hubbe)  return end_shared_string(str); } tmp = make_shared_binary_pcharp(MKPCHARP_STR(str),len); really_free_pike_string(str); return tmp; }
db4a401998-10-09Fredrik Hübinette (Hubbe) 
c8318b2000-08-03Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string * debug_make_shared_binary_string(const char *str,size_t len)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s;
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t h = StrHash(str, len);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
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; }
c8318b2000-08-03Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string * debug_make_shared_binary_pcharp(const PCHARP str,size_t len)
011ad31999-10-22Fredrik Hübinette (Hubbe) { 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"); }
2a515a2000-06-27Henrik Grubbström (Grubba)  /* NOT REACHED */ return NULL; /* Keep the compiler happy */
011ad31999-10-22Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string * debug_make_shared_pcharp(const PCHARP str)
011ad31999-10-22Fredrik Hübinette (Hubbe) { return debug_make_shared_binary_pcharp(str, pcharp_strlen(str)); }
c8318b2000-08-03Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string * debug_make_shared_binary_string0(const p_wchar0 *str,size_t len)
50d6d31999-10-31Henrik Grubbström (Grubba) {
a0d5ae1999-10-31Henrik Grubbström (Grubba)  return debug_make_shared_binary_string((const char *)str, len);
50d6d31999-10-31Henrik Grubbström (Grubba) }
c8318b2000-08-03Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string * debug_make_shared_binary_string1(const p_wchar1 *str,size_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) { struct pike_string *s;
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t h;
db4a401998-10-09Fredrik Hübinette (Hubbe)  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; }
c8318b2000-08-03Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string * debug_make_shared_binary_string2(const p_wchar2 *str,size_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) { struct pike_string *s;
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t h;
db4a401998-10-09Fredrik Hübinette (Hubbe)  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; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *debug_make_shared_string(const char *str)
5267b71995-08-09Fredrik Hübinette (Hubbe) { return make_shared_binary_string(str, strlen(str)); }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *debug_make_shared_string0(const p_wchar0 *str)
50d6d31999-10-31Henrik Grubbström (Grubba) {
a0d5ae1999-10-31Henrik Grubbström (Grubba)  return debug_make_shared_string((const char *)str);
50d6d31999-10-31Henrik Grubbström (Grubba) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT 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); }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT 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) 
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void unlink_pike_string(struct pike_string *s)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
e1939c2001-03-30Fredrik Hübinette (Hubbe)  size_t h; LOCK_BUCKET(s->hval); h= s->hval % htable_size;
5267b71995-08-09Fredrik Hübinette (Hubbe)  propagate_shared_string(s,h);
4bdf5f2001-03-30Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG if (base_table[h] != s) {
f707cd2001-04-13Martin Stjernholm  fatal("propagate_shared_string() failed. Probably got bogus pike_string.\n");
4bdf5f2001-03-30Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */
5267b71995-08-09Fredrik Hübinette (Hubbe)  base_table[h]=s->next;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
89fc4c2000-08-10Henrik Grubbström (Grubba)  s->next=(struct pike_string *)(ptrdiff_t)-1;
2302231998-04-23Fredrik Hübinette (Hubbe) #endif
760b261996-12-03Fredrik Hübinette (Hubbe)  num_strings--;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(s->hval);
0a3d601996-10-09Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void do_free_string(struct pike_string *s)
04965a1998-12-06Fredrik Hübinette (Hubbe) {
65b6732000-07-07Martin Stjernholm  if (s) free_string(s);
04965a1998-12-06Fredrik Hübinette (Hubbe) }
d5b1e22000-11-29Fredrik Hübinette (Hubbe) PMOD_EXPORT void do_really_free_string(struct pike_string *s) { if (s) really_free_string(s); } PMOD_EXPORT void do_really_free_pike_string(struct pike_string *s) { if (s) really_free_pike_string(s); }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void really_free_string(struct pike_string *s)
0a3d601996-10-09Fredrik Hübinette (Hubbe) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
9367351997-01-27Fredrik Hübinette (Hubbe)  extern int d_flag;
2a515a2000-06-27Henrik Grubbström (Grubba)  if (d_flag) { if (s->refs) { fatal("Freeing string with references!\n"); } if(d_flag > 2) {
89fc4c2000-08-10Henrik Grubbström (Grubba)  if(s->next == (struct pike_string *)(ptrdiff_t)-1)
2a515a2000-06-27Henrik Grubbström (Grubba)  fatal("Freeing shared string again!\n");
7abf491998-04-17Fredrik Hübinette (Hubbe) 
89fc4c2000-08-10Henrik Grubbström (Grubba)  if(((ptrdiff_t)s->next) & 1)
2a515a2000-06-27Henrik Grubbström (Grubba)  fatal("Freeing shared string again, memory corrupt or other bug!\n"); }
9367351997-01-27Fredrik Hübinette (Hubbe)  }
c7eadf2001-03-29Henrik Grubbström (Grubba)  if ((s->size_shift < 0) || (s->size_shift > 2)) { fatal("Freeing string with bad shift (0x%08x); could it be a type?\n", s->size_shift); }
9367351997-01-27Fredrik Hübinette (Hubbe) #endif
0a3d601996-10-09Fredrik Hübinette (Hubbe)  unlink_pike_string(s);
4a5e3f2000-11-25Henrik Grubbström (Grubba)  really_free_pike_string(s);
6cb7832000-09-15Martin Stjernholm  GC_FREE_SIMPLE_BLOCK(s);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void debug_free_string(struct pike_string *s)
61e9a01998-01-25Fredrik Hübinette (Hubbe) { 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;
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t 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)  {
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(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)  }
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e);
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,
89fc4c2000-08-10Henrik Grubbström (Grubba)  DO_NOT_WARN((long)overhead_bytes));
5267b71995-08-09Fredrik Hübinette (Hubbe)  my_strcat(b);
89fc4c2000-08-10Henrik Grubbström (Grubba)  sprintf(b, "Space actually required/total string bytes %ld%%\n", DO_NOT_WARN((long)((bytes_distinct_strings + overhead_bytes)*100 / allocd_bytes)));
5267b71995-08-09Fredrik Hübinette (Hubbe)  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) 
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void check_string(struct pike_string *s)
af93211996-10-12Fredrik Hübinette (Hubbe) {
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  if(do_hash(s) != 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) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void verify_shared_strings_tables(void)
af93211996-10-12Fredrik Hübinette (Hubbe) {
beac721998-04-16Fredrik Hübinette (Hubbe)  unsigned INT32 e, h, num=0;
af93211996-10-12Fredrik Hübinette (Hubbe)  struct pike_string *s; for(e=0;e<htable_size;e++) { h=0;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(e);
af93211996-10-12Fredrik Hübinette (Hubbe)  for(s=base_table[e];s;s=s->next) {
beac721998-04-16Fredrik Hübinette (Hubbe)  num++;
af93211996-10-12Fredrik Hübinette (Hubbe)  h++;
4bdf5f2001-03-30Henrik Grubbström (Grubba)  if (bad_pointer(s)) { fatal("Odd string pointer in string table!\n"); }
af93211996-10-12Fredrik Hübinette (Hubbe)  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) 
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  if(do_hash(s) != s->hval) fatal("Shared string hashed to other number.\n"); if((s->hval % htable_size) != 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(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; } }
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e);
af93211996-10-12Fredrik Hübinette (Hubbe)  }
beac721998-04-16Fredrik Hübinette (Hubbe)  if(num != num_strings) fatal("Num strings is wrong %d!=%d\n",num,num_strings);
af93211996-10-12Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int safe_debug_findstring(struct pike_string *foo)
62971d1998-01-19Fredrik Hübinette (Hubbe) { unsigned INT32 e; if(!base_table) return 0; for(e=0;e<htable_size;e++) { struct pike_string *p;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(e);
62971d1998-01-19Fredrik Hübinette (Hubbe)  for(p=base_table[e];p;p=p->next)
e1939c2001-03-30Fredrik Hübinette (Hubbe)  { if(p==foo) { UNLOCK_BUCKET(e); return 1; } } UNLOCK_BUCKET(e);
62971d1998-01-19Fredrik Hübinette (Hubbe)  } return 0; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *debug_findstring(const struct pike_string *foo)
af93211996-10-12Fredrik Hübinette (Hubbe) { 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);
8bcb3b2001-03-28Fredrik Hübinette (Hubbe) 
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(foo->hval);
af93211996-10-12Fredrik Hübinette (Hubbe)  fprintf(stderr,"------ %p %ld\n", base_table[foo->hval %htable_size],
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  foo->hval);
af93211996-10-12Fredrik Hübinette (Hubbe)  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");
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(foo->hval);
af93211996-10-12Fredrik Hübinette (Hubbe)  for(e=0;e<htable_size;e++) {
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(e);
af93211996-10-12Fredrik Hübinette (Hubbe)  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)); }
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e);
af93211996-10-12Fredrik Hübinette (Hubbe)  } } #endif return tmp; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void debug_dump_pike_string(struct pike_string *s, INT32 max)
38d6081998-02-07Fredrik Hübinette (Hubbe) { 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,
89fc4c2000-08-10Henrik Grubbström (Grubba)  DO_NOT_WARN((long)s->len),
a737441998-10-11Henrik Grubbström (Grubba)  s->size_shift,
89fc4c2000-08-10Henrik Grubbström (Grubba)  DO_NOT_WARN((unsigned long)s->hval), DO_NOT_WARN((unsigned long)StrHash(s->str, s->len)));
38d6081998-02-07Fredrik Hübinette (Hubbe)  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++)
e1939c2001-03-30Fredrik Hübinette (Hubbe)  { LOCK_BUCKET(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);
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e); }
5267b71995-08-09Fredrik Hübinette (Hubbe) }
af93211996-10-12Fredrik Hübinette (Hubbe) #endif /*** String compare functions ***/ /* does not take locale into account */
89fc4c2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT int low_quick_binary_strcmp(char *a, ptrdiff_t alen, char *b, ptrdiff_t blen)
af93211996-10-12Fredrik Hübinette (Hubbe) { 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 */
89fc4c2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT ptrdiff_t generic_quick_binary_strcmp(const char *a, ptrdiff_t alen, int asize, const char *b, ptrdiff_t blen, int bsize)
3e625c1998-10-11Fredrik Hübinette (Hubbe) { 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; } }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int c_compare_string(struct pike_string *s, char *foo, int len)
a5787d1999-03-03Fredrik Hübinette (Hubbe) { 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 */
c80ee82000-08-11Henrik Grubbström (Grubba) static int low_binary_strcmp(char *a, ptrdiff_t alen, char *b, ptrdiff_t blen)
af93211996-10-12Fredrik Hübinette (Hubbe) { low_quick_binary_strcmp(a,alen,b,blen); } #else /* takes locale into account */
c80ee82000-08-11Henrik Grubbström (Grubba) static int low_binary_strcmp(char *a, ptrdiff_t alen, char *b, ptrdiff_t blen)
af93211996-10-12Fredrik Hübinette (Hubbe) { while(alen>0 && blen>0) {
986b522001-03-17Henrik Grubbström (Grubba)  int tmp1 = strcoll(a,b); ptrdiff_t tmp2; if(tmp1) return (int)tmp1; tmp2 = strlen(a)+1; a += tmp2; b += tmp2; alen -= tmp2; blen -= tmp2;
af93211996-10-12Fredrik Hübinette (Hubbe)  } 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) 
89fc4c2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT ptrdiff_t my_quick_strcmp(struct pike_string *a, struct pike_string *b)
af93211996-10-12Fredrik Hübinette (Hubbe) { 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 */
89fc4c2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT ptrdiff_t my_strcmp(struct pike_string *a,struct pike_string *b)
af93211996-10-12Fredrik Hübinette (Hubbe) { 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: {
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t e, l = MINIMUM(a->len, b->len);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  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) }
89fc4c2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string *realloc_unlinked_string(struct pike_string *a, ptrdiff_t size)
8d28be1997-02-10Fredrik Hübinette (Hubbe) {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  struct pike_string *r = NULL; if (a->len <= SHORT_STRING_THRESHOLD) { if (size <= SHORT_STRING_THRESHOLD) { /* There's already place enough. */ a->len = size; low_set_index(a, size, 0); return a; } } else if (size > SHORT_STRING_THRESHOLD) { r=(struct pike_string *)realloc((char *)a, sizeof(struct pike_string)+ ((size+1)<<a->size_shift)); /* FIXME !! */ }
8d28be1997-02-10Fredrik Hübinette (Hubbe)  if(!r) {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  r=begin_wide_shared_string(size, a->size_shift); if (a->len <= size) { MEMCPY(r->str, a->str, a->len<<a->size_shift); } else { MEMCPY(r->str, a->str, size<<a->size_shift); } really_free_pike_string(a);
8d28be1997-02-10Fredrik Hübinette (Hubbe)  } 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 */
89fc4c2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string *realloc_shared_string(struct pike_string *a, ptrdiff_t size)
8d28be1997-02-10Fredrik Hübinette (Hubbe) { 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; } }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *new_realloc_shared_string(struct pike_string *a, INT32 size, int shift)
3e625c1998-10-11Fredrik Hübinette (Hubbe) { 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)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *modify_shared_string(struct pike_string *a,
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  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 ***/
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *add_shared_strings(struct pike_string *a,
06983f1996-09-22Fredrik Hübinette (Hubbe)  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);
1743c82001-02-03Fredrik Hübinette (Hubbe)  return low_end_shared_string(ret);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *add_and_free_shared_strings(struct pike_string *a,
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  struct pike_string *b) {
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t alen = a->len;
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(a->size_shift == b->size_shift) {
89fc4c2000-08-10Henrik Grubbström (Grubba)  a = realloc_shared_string(a,alen + b->len);
db4a401998-10-09Fredrik Hübinette (Hubbe)  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; } }
89fc4c2000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT ptrdiff_t string_search(struct pike_string *haystack, struct pike_string *needle, ptrdiff_t start)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
9b1f032000-10-09Fredrik Hübinette (Hubbe)  SearchMojt mojt;
db4a401998-10-09Fredrik Hübinette (Hubbe)  struct generic_mem_searcher s; char *r;
9b1f032000-10-09Fredrik Hübinette (Hubbe)  if(needle->size_shift > haystack->size_shift || start + needle->len > haystack->len)
db4a401998-10-09Fredrik Hübinette (Hubbe)  return -1;
9b1f032000-10-09Fredrik Hübinette (Hubbe)  mojt=compile_memsearcher(MKPCHARP_STR(needle),
db4a401998-10-09Fredrik Hübinette (Hubbe)  needle->len,
5d54232000-10-09Fredrik Hübinette (Hubbe)  haystack->len,
9b1f032000-10-09Fredrik Hübinette (Hubbe)  needle);
db4a401998-10-09Fredrik Hübinette (Hubbe) 
9b1f032000-10-09Fredrik Hübinette (Hubbe)  r=mojt.vtab->funcN(mojt.data, ADD_PCHARP(MKPCHARP_STR(haystack), start),
5d54232000-10-09Fredrik Hübinette (Hubbe)  haystack->len - start).ptr;
9b1f032000-10-09Fredrik Hübinette (Hubbe)  mojt.vtab->freeme(mojt.data);
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(!r) return -1;
5d54232000-10-09Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
bd742e2000-10-19Henrik Grubbström (Grubba)  if((r < haystack->str) || (r - haystack->str)>>haystack->size_shift > haystack->len)
5d54232000-10-09Fredrik Hübinette (Hubbe)  fatal("string_search did a bobo!\n"); #endif
db4a401998-10-09Fredrik Hübinette (Hubbe)  return (r-haystack->str)>>haystack->size_shift;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *string_slice(struct pike_string *s,
ab85722000-08-04Henrik Grubbström (Grubba)  ptrdiff_t start, ptrdiff_t len)
3e625c1998-10-11Fredrik Hübinette (Hubbe) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
3e625c1998-10-11Fredrik Hübinette (Hubbe)  if(start < 0 || len<0 || start+len>s->len ) {
a7979d2000-08-11Henrik Grubbström (Grubba)  fatal("string_slice, start = %ld, len = %ld, s->len = %ld\n", DO_NOT_WARN((long)start), DO_NOT_WARN((long)len), DO_NOT_WARN((long)s->len));
3e625c1998-10-11Fredrik Hübinette (Hubbe)  } #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 ***/
5d54232000-10-09Fredrik Hübinette (Hubbe) typedef char *(* replace_searchfunc)(void *,void *,size_t);
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT 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;
5d54232000-10-09Fredrik Hübinette (Hubbe)  SearchMojt mojt;
41b0b22000-10-20Henrik Grubbström (Grubba)  replace_searchfunc f = (replace_searchfunc)0;
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)  {
5d54232000-10-09Fredrik Hübinette (Hubbe)  mojt=compile_memsearcher(MKPCHARP_STR(del),
3e625c1998-10-11Fredrik Hübinette (Hubbe)  del->len, str->len,
5d54232000-10-09Fredrik Hübinette (Hubbe)  del);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  ret=begin_wide_shared_string(str->len,shift);
5d54232000-10-09Fredrik Hübinette (Hubbe)  switch(str->size_shift) { case 0: f=(replace_searchfunc)mojt.vtab->func0; break; case 1: f=(replace_searchfunc)mojt.vtab->func1; break; case 2: f=(replace_searchfunc)mojt.vtab->func2; break; #ifdef PIKE_DEBUG default: fatal("Illegal shift.\n"); #endif }
1f515a1997-02-15Fredrik Hübinette (Hubbe)  }else{ INT32 delimeters=0;
5d54232000-10-09Fredrik Hübinette (Hubbe)  mojt=compile_memsearcher(MKPCHARP_STR(del),
3e625c1998-10-11Fredrik Hübinette (Hubbe)  del->len, str->len*2,
5d54232000-10-09Fredrik Hübinette (Hubbe)  del);
3e625c1998-10-11Fredrik Hübinette (Hubbe) 
5d54232000-10-09Fredrik Hübinette (Hubbe)  switch(str->size_shift) { case 0: f=(replace_searchfunc)mojt.vtab->func0; break; case 1: f=(replace_searchfunc)mojt.vtab->func1; break; case 2: f=(replace_searchfunc)mojt.vtab->func2; break; #ifdef PIKE_DEBUG default: fatal("Illegal shift.\n"); #endif } while((s = f(mojt.data, s, (end-s)>>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) {
5d54232000-10-09Fredrik Hübinette (Hubbe)  mojt.vtab->freeme(mojt.data);
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) 
5d54232000-10-09Fredrik Hübinette (Hubbe)  while((tmp = f(mojt.data, s, (end-s)>>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) 
5d54232000-10-09Fredrik Hübinette (Hubbe)  mojt.vtab->freeme(mojt.data);
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) {
aad99b2001-03-28Fredrik Hübinette (Hubbe)  init_short_pike_string0_blocks(); init_short_pike_string1_blocks(); init_short_pike_string2_blocks();
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);
e1939c2001-03-30Fredrik Hübinette (Hubbe) #ifdef PIKE_RUN_UNLOCKED { int h;
3ac5e82001-03-30Fredrik Hübinette (Hubbe)  bucket_locks=(PIKE_MUTEX_T *)xalloc(sizeof(PIKE_MUTEX_T)*BUCKET_LOCKS); for(h=0;h<BUCKET_LOCKS;h++) mt_init(bucket_locks + h);
e1939c2001-03-30Fredrik Hübinette (Hubbe)  } #endif
af93211996-10-12Fredrik Hübinette (Hubbe) }
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
46563d2000-12-01Henrik Grubbström (Grubba) 
af93211996-10-12Fredrik Hübinette (Hubbe)  for(e=0;e<htable_size;e++)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(e);
5267b71995-08-09Fredrik Hübinette (Hubbe)  for(s=base_table[e];s;s=next) { next=s->next; #ifdef REALLY_FREE
4a5e3f2000-11-25Henrik Grubbström (Grubba)  really_free_pike_string(s);
5267b71995-08-09Fredrik Hübinette (Hubbe) #else s->next=0; #endif } base_table[e]=0;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
b906cf1996-11-27Fredrik Hübinette (Hubbe)  free((char *)base_table);
61e9a01998-01-25Fredrik Hübinette (Hubbe)  base_table=0; num_strings=0;
46563d2000-12-01Henrik Grubbström (Grubba)  #ifdef DEBUG_MALLOC free_all_short_pike_string0_blocks(); free_all_short_pike_string1_blocks(); free_all_short_pike_string2_blocks();
6519c32000-12-19Henrik Grubbström (Grubba) #endif /* DEBUG_MALLOC */
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;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(e);
c3c7031996-12-04Fredrik Hübinette (Hubbe)  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)  }
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e);
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) 
7a26722000-09-04Martin Stjernholm #ifdef PIKE_DEBUG unsigned gc_touch_all_strings(void) { unsigned INT32 e; unsigned n = 0; 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) debug_gc_touch(p), n++; } return n; } #endif
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) 
f7cfa82001-09-04Martin Stjernholm struct pike_string *next_pike_string (struct pike_string *s) { struct pike_string *next = s->next; if (!next) { size_t h = s->hval; do { h++; LOCK_BUCKET(h); h %= htable_size; next = base_table[h]; UNLOCK_BUCKET(h); } while (!next); } return next; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void init_string_builder(struct string_builder *s, int mag)
db4a401998-10-09Fredrik Hübinette (Hubbe) { s->malloced=256; s->s=begin_wide_shared_string(256,mag); s->s->len=0;
990d652001-06-29Henrik Grubbström (Grubba)  s->s->str[0] = 0;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  s->known_shift=0;
db4a401998-10-09Fredrik Hübinette (Hubbe) }
0cd4262001-02-02Martin Stjernholm PMOD_EXPORT void init_string_builder_alloc(struct string_builder *s, ptrdiff_t length, int mag) { s->malloced=length; s->s=begin_wide_shared_string(length,mag); s->s->len=0;
990d652001-06-29Henrik Grubbström (Grubba)  s->s->str[0] = 0;
0cd4262001-02-02Martin Stjernholm  s->known_shift=0; }
c9f0312000-08-10Henrik Grubbström (Grubba) static void string_build_mkspace(struct string_builder *s, ptrdiff_t chars, int mag)
db4a401998-10-09Fredrik Hübinette (Hubbe) { if(mag > s->s->size_shift) { struct pike_string *n;
c9f0312000-08-10Henrik Grubbström (Grubba)  ptrdiff_t l = s->s->len + chars + s->malloced;
db4a401998-10-09Fredrik Hübinette (Hubbe)  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;
4a5e3f2000-11-25Henrik Grubbström (Grubba)  s->s->len = s->malloced; /* Restore the real length */ really_free_pike_string(s->s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s->malloced=l; s->s=n; }
a7979d2000-08-11Henrik Grubbström (Grubba)  else if(((size_t)s->s->len+chars) > ((size_t)s->malloced))
db4a401998-10-09Fredrik Hübinette (Hubbe)  {
a7979d2000-08-11Henrik Grubbström (Grubba)  size_t newlen = MAXIMUM((size_t)(s->malloced*2), (size_t)(s->s->len + chars));
4a5e3f2000-11-25Henrik Grubbström (Grubba)  ptrdiff_t oldlen = s->s->len;
db4a401998-10-09Fredrik Hübinette (Hubbe) 
4a5e3f2000-11-25Henrik Grubbström (Grubba)  s->s = realloc_unlinked_string(s->s, newlen); s->s->len = oldlen; s->malloced = newlen;
db4a401998-10-09Fredrik Hübinette (Hubbe)  } }
c9f0312000-08-10Henrik Grubbström (Grubba) PMOD_EXPORT void *string_builder_allocate(struct string_builder *s, ptrdiff_t chars, int mag)
3e625c1998-10-11Fredrik Hübinette (Hubbe) { void *ret;
c9f0312000-08-10Henrik Grubbström (Grubba)  string_build_mkspace(s, chars, mag);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  if(chars<0) s->known_shift=0;
c9f0312000-08-10Henrik Grubbström (Grubba)  ret = s->s->str + (s->s->len<<s->s->size_shift); s->s->len += chars;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  return ret; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void string_builder_putchar(struct string_builder *s, int ch)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t i;
b0289e2000-12-01Henrik Grubbström (Grubba)  int mag = min_magnitude(ch); if (mag > s->s->size_shift) { string_build_mkspace(s, 1, mag); s->known_shift = (size_t)mag; } else if (((size_t)s->s->len) >= ((size_t)s->malloced)) { string_build_mkspace(s, 1, mag); s->known_shift = MAXIMUM((size_t)mag, s->known_shift);
4a5e3f2000-11-25Henrik Grubbström (Grubba)  }
89fc4c2000-08-10Henrik Grubbström (Grubba)  i = s->s->len++;
db4a401998-10-09Fredrik Hübinette (Hubbe)  low_set_index(s->s,i,ch);
cb2e382001-08-29Henrik Grubbström (Grubba)  /* Ensure NUL-termination */ s->s->str[s->s->len << s->s->size_shift] = 0;
db4a401998-10-09Fredrik Hübinette (Hubbe) }
c3dbe52000-08-09Henrik Grubbström (Grubba) PMOD_EXPORT void string_builder_binary_strcat(struct string_builder *s, char *str, ptrdiff_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
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;
cb2e382001-08-29Henrik Grubbström (Grubba)  /* Ensure NUL-termination */ s->s->str[s->s->len << s->s->size_shift] = 0;
db4a401998-10-09Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void string_builder_append(struct string_builder *s,
c3dbe52000-08-09Henrik Grubbström (Grubba)  PCHARP from, ptrdiff_t len)
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  int shift; if ((shift = from.shift) > s->s->size_shift) { if (shift == 1) { shift = find_magnitude1((p_wchar1 *)from.ptr, len); } else { shift = find_magnitude2((p_wchar2 *)from.ptr, len); } } string_build_mkspace(s, len, shift);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  generic_memcpy(MKPCHARP_STR_OFF(s->s,s->s->len), from, len); s->s->len+=len;
cb2e382001-08-29Henrik Grubbström (Grubba)  /* Ensure NUL-termination */ s->s->str[s->s->len << s->s->size_shift] = 0;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void string_builder_fill(struct string_builder *s,
c3dbe52000-08-09Henrik Grubbström (Grubba)  ptrdiff_t howmany, PCHARP from, ptrdiff_t len, ptrdiff_t offset)
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) {
c3dbe52000-08-09Henrik Grubbström (Grubba)  ptrdiff_t tmp;
4a5e3f2000-11-25Henrik Grubbström (Grubba)  int shift;
c3dbe52000-08-09Henrik Grubbström (Grubba) 
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);
cb2e382001-08-29Henrik Grubbström (Grubba)  /* Ensure NUL-termination */ s->s->str[s->s->len << s->s->size_shift] = 0;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  return; }
4a5e3f2000-11-25Henrik Grubbström (Grubba)  if ((shift = from.shift) > s->s->size_shift) { /* Check if we really need the extra magnitude. */ /* FIXME: What about offset? */ if (shift == 1) { shift = find_magnitude1((p_wchar1 *)from.ptr, len); } else { shift = find_magnitude2((p_wchar2 *)from.ptr, len); } } string_build_mkspace(s, howmany, shift);
c3dbe52000-08-09Henrik Grubbström (Grubba)  tmp = MINIMUM(howmany, len - offset);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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) {
c3dbe52000-08-09Henrik Grubbström (Grubba)  tmp = MINIMUM(len, howmany);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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; } }
cb2e382001-08-29Henrik Grubbström (Grubba)  /* Ensure NUL-termination */ s->s->str[s->s->len << s->s->size_shift] = 0;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void string_builder_strcat(struct string_builder *s, char *str)
db4a401998-10-09Fredrik Hübinette (Hubbe) { string_builder_binary_strcat(s,str,strlen(str)); }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void string_builder_shared_strcat(struct string_builder *s, struct pike_string *str)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
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);
a7979d2000-08-11Henrik Grubbström (Grubba)  s->known_shift=MAXIMUM(s->known_shift,(size_t)str->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s->s->len+=str->len;
cb2e382001-08-29Henrik Grubbström (Grubba)  /* Ensure NUL-termination */ s->s->str[s->s->len << s->s->size_shift] = 0;
db4a401998-10-09Fredrik Hübinette (Hubbe) }
7238061998-10-11Fredrik Hübinette (Hubbe) 
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void reset_string_builder(struct string_builder *s)
7238061998-10-11Fredrik Hübinette (Hubbe) { s->known_shift=0; s->s->len=0;
cb2e382001-08-29Henrik Grubbström (Grubba)  /* Ensure NUL-termination */ s->s->str[0] = 0;
7238061998-10-11Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void free_string_builder(struct string_builder *s)
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  s->s->len = s->malloced; really_free_pike_string(s->s);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT struct pike_string *finish_string_builder(struct string_builder *s)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
cb2e382001-08-29Henrik Grubbström (Grubba)  /* Ensure NUL-termination */
db4a401998-10-09Fredrik Hübinette (Hubbe)  low_set_index(s->s,s->s->len,0);
4a5e3f2000-11-25Henrik Grubbström (Grubba)  if (s->s->len <= SHORT_STRING_THRESHOLD) { ptrdiff_t len = s->s->len; s->s->len = s->malloced; s->s = realloc_unlinked_string(s->s, len); }
a7979d2000-08-11Henrik Grubbström (Grubba)  if(s->known_shift == (size_t)s->s->size_shift)
3e625c1998-10-11Fredrik Hübinette (Hubbe)  return low_end_shared_string(s->s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return end_shared_string(s->s); }
98f9a92000-08-08Henrik Grubbström (Grubba) PMOD_EXPORT PCHARP MEMCHR_PCHARP(PCHARP ptr, int chr, ptrdiff_t len)
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) { 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)
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT long STRTOL_PCHARP(PCHARP str, PCHARP *ptr, int base)
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) { 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) 
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int string_to_svalue_inumber(struct svalue *r,
011ad31999-10-22Fredrik Hübinette (Hubbe)  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; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int wide_string_to_svalue_inumber(struct svalue *r,
8c37d12000-08-15Henrik Grubbström (Grubba)  void * str, void **ptr, int base, ptrdiff_t maxlength, int shift)
011ad31999-10-22Fredrik Hübinette (Hubbe) { PCHARP tmp; int ret=pcharp_to_svalue_inumber(r, MKPCHARP(str,shift), &tmp, base, maxlength); if(ptr) *ptr=(char *)tmp.ptr; return ret; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int pcharp_to_svalue_inumber(struct svalue *r,
8c37d12000-08-15Henrik Grubbström (Grubba)  PCHARP str, PCHARP *ptr, int base, ptrdiff_t maxlength)
31ea271999-10-22Fredrik Noring {
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. */
29406f2001-06-05Fredrik Hübinette (Hubbe)  if((base==16 || base == 2) && 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); }
29406f2001-06-05Fredrik Hübinette (Hubbe)  str_start=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
29406f2001-06-05Fredrik Hübinette (Hubbe)  * * It could probably also be faster...
011ad31999-10-22Fredrik Hübinette (Hubbe)  */
29406f2001-06-05Fredrik Hübinette (Hubbe)  push_int(base); convert_stack_top_with_base_to_bignum(); if(neg) o_negate();
31ea271999-10-22Fredrik Noring  *r = *--sp; } #endif /* AUTO_BIGNUM */ return 1; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT int convert_stack_top_string_to_inumber(int base)
31ea271999-10-22Fredrik Noring { struct svalue r;
775f3d1999-10-23Fredrik Noring  int i;
31ea271999-10-22Fredrik Noring  if(sp[-1].type != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Cannot convert stack top to integer number.\n");
31ea271999-10-22Fredrik Noring 
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. */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT double STRTOD_PCHARP(PCHARP nptr, PCHARP *endptr)
f3ece81999-02-28Fredrik Hübinette (Hubbe) { 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:
a4a1722000-12-05Per Hedbor  /* Return an overflow error. */
f3ece81999-02-28Fredrik Hübinette (Hubbe)  errno = ERANGE; return HUGE * sign; underflow:
a4a1722000-12-05Per Hedbor  /* Return an underflow error. */
f3ece81999-02-28Fredrik Hübinette (Hubbe)  if (endptr != NULL) *endptr = nptr; errno = ERANGE; return 0.0; noconv: /* There was no number. */ if (endptr != NULL) *endptr = nptr; return 0.0; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT p_wchar0 *require_wstring0(struct pike_string *s,
efae671998-10-21Fredrik Hübinette (Hubbe)  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; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT p_wchar1 *require_wstring1(struct pike_string *s,
efae671998-10-21Fredrik Hübinette (Hubbe)  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; }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT p_wchar2 *require_wstring2(struct pike_string *s,
efae671998-10-21Fredrik Hübinette (Hubbe)  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; }