e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
aedfb12002-10-09Martin Nilsson 
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"
686ef22004-11-11Henrik Grubbström (Grubba) #include "pike_float.h"
d476592013-06-12Arne Goedeke #include "block_allocator.h"
1d15d42004-11-11Henrik Grubbström (Grubba) #include "port.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) 
e85df82001-09-06Fredrik Hübinette (Hubbe) #define SET_HSIZE(X) htable_mask=(htable_size=(1<<(X)))-1 #define HMODULO(X) ((X) & (htable_mask))
dbce712011-05-15Per Hedbor static unsigned INT32 htable_mask;
e85df82001-09-06Fredrik Hübinette (Hubbe) 
a549642003-03-17Henrik Grubbström (Grubba) #if (SIZEOF_LONG == 4) && defined(_LP64) /* Kludge for gcc and the system header files not using the same model... */ #undef LONG_MIN #undef LONG_MAX #undef ULONG_MAX #define LONG_MIN INT_MIN #define LONG_MAX INT_MAX #define ULONG_MAX UINT_MAX #endif
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) \
e85df82001-09-06Fredrik Hübinette (Hubbe)  (bucket_locks + (HMODULO(hval__) & (BUCKET_LOCKS-1)))
3ac5e82001-03-30Fredrik Hübinette (Hubbe)  #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)
a20d822013-06-08Martin Nilsson #endif /* PIKE_RUN_UNLOCKED */
24ddc71998-03-28Henrik Grubbström (Grubba) 
ed2bed2013-06-14Per Hedbor #define BEGIN_HASH_SIZE 1024
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;
6ed3d22005-01-17Henrik Grubbström (Grubba) static unsigned int need_more_hash_prefix_depth=0;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #endif
af93211996-10-12Fredrik Hübinette (Hubbe) 
0169c62011-12-30Henrik Grubbström (Grubba) /* Force a new hashkey to be generated early during init. */ static unsigned int need_new_hashkey_depth=0xffff; static size_t hashkey = 0xa55aa55a;
bcafc32004-09-19Martin Nilsson static 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;
bcafc32004-09-19Martin Nilsson static unsigned INT32 num_strings=0;
4edb1a2002-09-11David Hedbor PMOD_EXPORT struct pike_string *empty_pike_string = 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)
0169c62011-12-30Henrik Grubbström (Grubba) #define low_do_hash(STR,LEN,SHIFT) low_hashmem( (STR), (LEN)<<(SHIFT), HASH_PREFIX<<(SHIFT), hashkey )
34ffc02011-05-15Per Hedbor #define do_hash(STR) low_do_hash(STR->str,STR->len,STR->size_shift)
db4a401998-10-09Fredrik Hübinette (Hubbe) 
9925512013-05-31Per Hedbor /* Returns true if str could contain n. */ PMOD_EXPORT int string_range_contains( struct pike_string *str, int n ) { INT32 min, max; check_string_range( str, 1, &min, &max ); if( n >= min && n <= max ) return 1; return 0; } /* Returns true if str2 could be in str1. */ PMOD_EXPORT int string_range_contains_string( struct pike_string *str1, struct pike_string *str2 ) { INT32 max1, min1; INT32 max2, min2;
c037bf2013-06-11Martin Nilsson  if( !str2->len ) return 1; /* Empty string is part of every string */
9925512013-05-31Per Hedbor  check_string_range( str1, 1, &min1, &max1 ); check_string_range( str2, 1, &min2, &max2 ); if( (min2 < min1) || (max2 > max1) ) { if( (str1->flags & STRING_CONTENT_CHECKED) == (str2->flags & STRING_CONTENT_CHECKED) ) return 0; /* fallback to simple size-shift check. */ return str1->size_shift >= str2->size_shift; } return 1; } PMOD_EXPORT void check_string_range( struct pike_string *str, int loose, INT32 *min, INT32 *max ) { INT32 s_min = MAX_INT32; INT32 s_max = MIN_INT32; ssize_t i; if( loose || ((str->flags & STRING_CONTENT_CHECKED ) && (!str->size_shift || !max)) ) { if( str->flags & STRING_CONTENT_CHECKED ) { s_min = str->min; s_max = str->max; if( str->size_shift ) { s_min <<= 8 * str->size_shift; s_max <<= 8 * str->size_shift; if( s_min ) s_min -= (1<<(8*str->size_shift))-1; s_max += str->size_shift == 1 ? 255 : 65535; } } else { switch( str->size_shift ) { case 2: s_min = MIN_INT32; s_max=MAX_INT32; break; case 1: s_min = 0; s_max = 65535; break; case 0: s_min = 0; s_max = 255; break; } } } else { str->flags |= STRING_CONTENT_CHECKED; switch( str->size_shift ) { case 0: { p_wchar0 *p = (p_wchar0*)str->str; int upper = 0, lower = 0; for( i=0; i<str->len; i++,p++ ) { /* For 7-bit strings it's easy to check for * lower/uppercase, so do that here as well. */ if( *p >= 'A' && *p <= 'Z') upper++; if( *p >= 'a' && *p <= 'z') lower++; if( *p > s_max ) s_max = *p; if( *p < s_min ) s_min = *p; } if( s_max < 128 ) { if( upper && !lower ) str->flags |= STRING_IS_UPPERCASE; if( lower && !upper ) str->flags |= STRING_IS_LOWERCASE; if( !lower && !upper ) str->flags |= STRING_IS_LOWERCASE|STRING_IS_UPPERCASE; } } str->min = s_min; str->max = s_max; break; case 1: { p_wchar1 *p = (p_wchar1*)str->str; for( i=0; i<str->len; i++,p++ ) { if( *p > s_max ) s_max = *p; if( *p < s_min ) s_min = *p; } } str->min = (s_min+255) >> 8; str->max = (s_max+255) >> 8; break; case 2: { p_wchar2 *p = (p_wchar2*)str->str; for( i=0; i<str->len; i++,p++ ) { if( *p > s_max ) s_max = *p; if( *p < s_min ) s_min = *p; } } str->min = (s_min+65535) >> 16; str->max = (s_max+65535) >> 16; break; } } if( min ) *min = s_min; if( max ) *max = s_max; }
db4a401998-10-09Fredrik Hübinette (Hubbe) 
2eaf022008-06-29Marcus Comstedt static INLINE int find_magnitude1(const p_wchar1 *s, ptrdiff_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
4e808c2011-05-01Per Hedbor  const p_wchar1 *e=s+len; while(s<e) if(*s++>=256)
db4a401998-10-09Fredrik Hübinette (Hubbe)  return 1; return 0; }
2eaf022008-06-29Marcus Comstedt static INLINE int find_magnitude2(const p_wchar2 *s, ptrdiff_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
4e808c2011-05-01Per Hedbor  const p_wchar2 *e=s+len; while(s<e)
34ffc02011-05-15Per Hedbor  {
a8a46f2011-05-10Per Hedbor  if((unsigned INT32)*s>=256)
db4a401998-10-09Fredrik Hübinette (Hubbe)  { do {
4e808c2011-05-01Per Hedbor  if((unsigned INT32)*s++>=65536)
db4a401998-10-09Fredrik Hübinette (Hubbe)  return 2;
4e808c2011-05-01Per Hedbor  }while(s<e);
db4a401998-10-09Fredrik Hübinette (Hubbe)  return 1; }
a8a46f2011-05-10Per Hedbor  s++;
db4a401998-10-09Fredrik Hübinette (Hubbe)  } return 0; }
2eaf022008-06-29Marcus Comstedt static INLINE int min_magnitude(p_wchar2 c)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
2eaf022008-06-29Marcus Comstedt  if(c<0) return 2;
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(c<256) return 0; if(c<65536) return 1; return 2; }
23b9f12008-07-01Marcus Comstedt static INLINE p_wchar2 generic_extract (const void *str, int size, ptrdiff_t pos)
db4a401998-10-09Fredrik Hübinette (Hubbe) { switch(size) {
23b9f12008-07-01Marcus Comstedt  case 0: return ((p_wchar0 *)str)[pos]; case 1: return ((p_wchar1 *)str)[pos]; case 2: return ((p_wchar2 *)str)[pos];
db4a401998-10-09Fredrik Hübinette (Hubbe)  }
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
5aad932002-08-15Marcus Comstedt  Pike_fatal("Illegal shift size!\n");
c6b6042008-05-03Martin Nilsson #endif
efae671998-10-21Fredrik Hübinette (Hubbe)  return 0;
db4a401998-10-09Fredrik Hübinette (Hubbe) }
23b9f12008-07-01Marcus Comstedt PMOD_EXPORT p_wchar2 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) {
b99d882003-05-15Martin Stjernholm  Pike_fatal("String index %"PRINTPTRDIFFT"d is out of " "range 0..%"PRINTPTRDIFFT"d.\n", pos, s->len-1);
49ed181998-10-15Henrik Grubbström (Grubba)  } else {
b99d882003-05-15Martin Stjernholm  Pike_fatal("Attempt to index the empty string with %"PRINTPTRDIFFT"d.\n", pos);
49ed181998-10-15Henrik Grubbström (Grubba)  } }
db4a401998-10-09Fredrik Hübinette (Hubbe) #endif return generic_extract(s->str,s->size_shift,pos); }
5de2692012-05-28Martin Stjernholm 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
b99d882003-05-15Martin Stjernholm  if(pos > s->len || pos<0) { if (s->len) { Pike_fatal("String index %"PRINTPTRDIFFT"d is out of " "range 0..%"PRINTPTRDIFFT"d.\n", pos, s->len-1); } else { Pike_fatal("Attempt to index the empty string with %"PRINTPTRDIFFT"d.\n", pos); } }
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(pos == s->len && value)
5aad932002-08-15Marcus Comstedt  Pike_fatal("string zero termination foul!\n");
db4a401998-10-09Fredrik Hübinette (Hubbe) #endif
9cd0372005-11-03Henrik Grubbström (Grubba)  s->flags |= STRING_NOT_HASHED;
ed2bed2013-06-14Per Hedbor  if(!s->size_shift) STR0(s)[pos]=value; else if(s->size_shift == 1) STR1(s)[pos]=value; else STR2(s)[pos]=value;
db4a401998-10-09Fredrik Hübinette (Hubbe) }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
d7d61d2004-03-19Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string *debug_check_size_shift(struct pike_string *a, int shift)
db4a401998-10-09Fredrik Hübinette (Hubbe) { if(a->size_shift != shift)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Wrong STRX macro used!\n");
db4a401998-10-09Fredrik Hübinette (Hubbe)  return a; } #endif
024adc2004-11-14Martin Stjernholm #define CONVERT(FROM,TO) \ void PIKE_CONCAT4(convert_,FROM,_to_,TO) (PIKE_CONCAT(p_wchar,TO) *to, \ const PIKE_CONCAT(p_wchar,FROM) *from, \ ptrdiff_t len) \ { \
09d0632008-07-16Martin Stjernholm  while(--len>=0) *(to++)= (PIKE_CONCAT (p_wchar, TO)) *(from++); \
024adc2004-11-14Martin Stjernholm  } \ INT32 PIKE_CONCAT4(compare_,FROM,_to_,TO) (const PIKE_CONCAT(p_wchar,TO) *to, \ const PIKE_CONCAT(p_wchar,FROM) *from, \ ptrdiff_t len) \ { \ int tmp; \ while(--len>=0) \ if((tmp=*(to++)-*(from++))) \ return tmp; \ return 0; \ }
3e625c1998-10-11Fredrik Hübinette (Hubbe)  CONVERT(0,1) CONVERT(0,2) CONVERT(1,0) CONVERT(1,2) CONVERT(2,0) CONVERT(2,1)
db4a401998-10-09Fredrik Hübinette (Hubbe) #define TWO_SIZES(X,Y) (((X)<<2)+(Y))
66d9282011-05-01Per Hedbor void generic_memcpy(PCHARP to, PCHARP from, ptrdiff_t len)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
68d9131999-04-01Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG if(len<0)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Cannot copy %ld bytes!\n",
a7979d2000-08-11Henrik Grubbström (Grubba)  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; } }
73bf662004-03-19Henrik Grubbström (Grubba) PMOD_EXPORT void pike_string_cpy(PCHARP to, struct pike_string *from)
3e625c1998-10-11Fredrik Hübinette (Hubbe) {
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  generic_memcpy(to,MKPCHARP_STR(from),from->len);
3e625c1998-10-11Fredrik Hübinette (Hubbe) }
5014211998-10-14Fredrik Hübinette (Hubbe) 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
5014211998-10-14Fredrik Hübinette (Hubbe) #ifdef DEBUG_MALLOC #define DM(X) X #else #define DM(X) #endif
2043ba1998-02-10Fredrik Hübinette (Hubbe) static void locate_problem(int (*isproblem)(struct pike_string *)) { unsigned INT32 e; struct pike_string *s;
9e52381998-03-01Fredrik Hübinette (Hubbe)  DM(struct memhdr *yes=alloc_memhdr()); DM(struct memhdr *no=alloc_memhdr());
2043ba1998-02-10Fredrik Hübinette (Hubbe)  for(e=0;e<htable_size;e++)
9e52381998-03-01Fredrik Hübinette (Hubbe)  {
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)
a20d822013-06-08Martin Nilsson #endif /* PIKE_DEBUG */
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!!!! */
ed2bed2013-06-14Per Hedbor static struct pike_string *internal_findstring(const char *s,
b0289e2000-12-01Henrik Grubbström (Grubba)  ptrdiff_t len, int size_shift,
4bdf5f2001-03-30Henrik Grubbström (Grubba)  size_t hval)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
ed2bed2013-06-14Per Hedbor  struct pike_string *curr; //,**prev, **base;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  unsigned int depth=0;
0169c62011-12-30Henrik Grubbström (Grubba) #ifndef HASH_PREFIX unsigned int prefix_depth=0;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #endif
e1939c2001-03-30Fredrik Hübinette (Hubbe)  size_t h; LOCK_BUCKET(hval);
e85df82001-09-06Fredrik Hübinette (Hubbe)  h=HMODULO(hval);
ed2bed2013-06-14Per Hedbor  for(curr = base_table[h]; curr; curr = curr->next)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
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);
5aad932002-08-15Marcus Comstedt  Pike_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) 
ed2bed2013-06-14Per Hedbor  if ( len == curr->len && size_shift == curr->size_shift && hval == curr->hval && ( curr->str == s || !MEMCMP(curr->str, s,len<<size_shift))) /* found it */
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
ed2bed2013-06-14Per Hedbor  /* *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 */ }
0169c62011-12-30Henrik Grubbström (Grubba)  depth++;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #ifndef HASH_PREFIX
4a79902005-02-26Martin Nilsson  if (curr->len > (ptrdiff_t)HASH_PREFIX)
0169c62011-12-30Henrik Grubbström (Grubba)  prefix_depth++;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #endif
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
0169c62011-12-30Henrik Grubbström (Grubba)  if (depth > need_new_hashkey_depth) { /* Keep track of whether the hashtable is getting unbalanced. */ need_new_hashkey_depth = depth; }
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) #ifndef HASH_PREFIX /* These heuruistics might require tuning! /Hubbe */
0169c62011-12-30Henrik Grubbström (Grubba)  if (prefix_depth > need_more_hash_prefix_depth)
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  {
6ed3d22005-01-17Henrik Grubbström (Grubba) #if 0 fprintf(stderr,
0169c62011-12-30Henrik Grubbström (Grubba)  "prefix_depth=%d num_strings=%d need_more_hash_prefix_depth=%d\n"
6ed3d22005-01-17Henrik Grubbström (Grubba)  " HASH_PREFIX=%d\n",
0169c62011-12-30Henrik Grubbström (Grubba)  prefix_depth, num_strings, need_more_hash_prefix_depth,
6ed3d22005-01-17Henrik Grubbström (Grubba)  HASH_PREFIX); #endif /* 0 */
0169c62011-12-30Henrik Grubbström (Grubba)  need_more_hash_prefix_depth = prefix_depth;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  }
6ed3d22005-01-17Henrik Grubbström (Grubba) #endif /* !HASH_PREFIX */
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(hval);
5267b71995-08-09Fredrik Hübinette (Hubbe)  return 0; /* not found */ }
5de2692012-05-28Martin Stjernholm 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) }
5de2692012-05-28Martin Stjernholm 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);
5aad932002-08-15Marcus Comstedt  Pike_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) {
1bfe772005-01-14Henrik Grubbström (Grubba)  struct pike_string *prev = NULL; struct pike_string *next;
af93211996-10-12Fredrik Hübinette (Hubbe)  if(!s) return;
1bfe772005-01-14Henrik Grubbström (Grubba)  /* Reverse the hash list. */ while ((next = s->next)) { s->next = prev; prev = s; s = next; } s->next = prev; /* Rehash the strings for this list. */ do { ptrdiff_t h = HMODULO(s->hval); next = s->next; s->next = base_table[h]; base_table[h] = s; } while ((s = next));
af93211996-10-12Fredrik Hübinette (Hubbe) }
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) 
e85df82001-09-06Fredrik Hübinette (Hubbe)  SET_HSIZE( ++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);
6ed3d22005-01-17Henrik Grubbström (Grubba)  need_more_hash_prefix_depth = 0;
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) 
3c08602008-05-02Martin Stjernholm /* Without the str at the end, to get the size of the header. */ struct pike_string_hdr { PIKE_STRING_CONTENTS; };
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) #define SHORT_STRING_BLOCK 256
ed2bed2013-06-14Per Hedbor  #define SHORT_STRING_THRESHOLD 15
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) };
ed2bed2013-06-14Per Hedbor static struct block_allocator string_allocator = BA_INIT(sizeof(struct short_pike_string0), SHORT_STRING_BLOCK);
4a5e3f2000-11-25Henrik Grubbström (Grubba) 
fb22942008-06-16Martin Stjernholm #define free_unlinked_pike_string(s) do { \
ed2bed2013-06-14Per Hedbor  if (s->flags & STRING_IS_SHORT) { \ ba_free(&string_allocator, s); \
4a5e3f2000-11-25Henrik Grubbström (Grubba)  } 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
ed2bed2013-06-14Per Hedbor  if (len <= SHORT_STRING_THRESHOLD) { t=(struct pike_string *)ba_alloc(&string_allocator);
d476592013-06-12Arne Goedeke  t->flags = STRING_NOT_HASHED | STRING_NOT_SHARED | STRING_IS_SHORT;
ed2bed2013-06-14Per Hedbor  } else {
3c08602008-05-02Martin Stjernholm  t=(struct pike_string *)xalloc(len + 1 + sizeof(struct pike_string_hdr));
9cd0372005-11-03Henrik Grubbström (Grubba)  t->flags = STRING_NOT_HASHED | STRING_NOT_SHARED;
4a5e3f2000-11-25Henrik Grubbström (Grubba)  }
9386322011-07-21Henrik Grubbström (Grubba) #ifdef ATOMIC_SVALUE t->ref_type = T_STRING; #endif
d229e32008-11-05Henrik Grubbström (Grubba)  t->refs = 0; add_ref(t); /* For DMALLOC */
ca74dd1996-10-08Fredrik Hübinette (Hubbe)  t->str[len]=0;
5267b71995-08-09Fredrik Hübinette (Hubbe)  t->len=len;
9925512013-05-31Per Hedbor /* t->min = t->max = 0; */
db4a401998-10-09Fredrik Hübinette (Hubbe)  t->size_shift=0;
0e602a2006-01-12Henrik Grubbström (Grubba)  DO_IF_DEBUG(t->next = NULL);
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;
9cd0372005-11-03Henrik Grubbström (Grubba)  #ifdef PIKE_DEBUG if (!(s->flags & STRING_NOT_SHARED)) { debug_dump_pike_string(s, 70); Pike_fatal("String already linked.\n"); }
fc6ea02008-07-18Martin Stjernholm  if (PIKE_MEM_NOT_DEF_RANGE (s->str, (s->len + 1) << s->size_shift)) Pike_fatal ("Got undefined contents in pike string %p.\n", s);
9cd0372005-11-03Henrik Grubbström (Grubba) #endif
e1939c2001-03-30Fredrik Hübinette (Hubbe)  LOCK_BUCKET(hval);
e85df82001-09-06Fredrik Hübinette (Hubbe)  h=HMODULO(hval);
af93211996-10-12Fredrik Hübinette (Hubbe)  s->next = base_table[h]; base_table[h] = s;
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  s->hval=hval;
9cd0372005-11-03Henrik Grubbström (Grubba)  s->flags &= ~(STRING_NOT_HASHED|STRING_NOT_SHARED);
af93211996-10-12Fredrik Hübinette (Hubbe)  num_strings++;
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(hval);
ed2bed2013-06-14Per Hedbor  if(num_strings > htable_size) {
e1939c2001-03-30Fredrik Hübinette (Hubbe)  stralloc_rehash();
0169c62011-12-30Henrik Grubbström (Grubba)  }
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  #ifndef HASH_PREFIX
6ed3d22005-01-17Henrik Grubbström (Grubba)  /* These heuristics might require tuning! /Hubbe */
ed2bed2013-06-14Per Hedbor  if((need_more_hash_prefix_depth > 4) || (need_new_hashkey_depth > 128))
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  {
6ed3d22005-01-17Henrik Grubbström (Grubba)  /* Changed heuristic 2005-01-17: * * Increase HASH_PREFIX if there's some bucket containing
ed2bed2013-06-14Per Hedbor  * more than 4 strings that are longer
6ed3d22005-01-17Henrik Grubbström (Grubba)  * than HASH_PREFIX. * /grubba
0169c62011-12-30Henrik Grubbström (Grubba)  * * Changed heuristic 2011-12-30: * * Generate a new hash key if there's some bucket containing
ed2bed2013-06-14Per Hedbor  * more than 16 strings. This ought to
0169c62011-12-30Henrik Grubbström (Grubba)  * suffice to alleviate the #hashdos vulnerability. * * /grubba
6ed3d22005-01-17Henrik Grubbström (Grubba)  */ /* This could in theory have a pretty ugly complexity * /Hubbe
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  */
8bcb3b2001-03-28Fredrik Hübinette (Hubbe) 
3ac5e82001-03-30Fredrik Hübinette (Hubbe) #ifdef PIKE_RUN_UNLOCKED mt_lock(bucket_locks);
ed2bed2013-06-14Per Hedbor  if(need_more_hash_prefix_depth <= 4)
3ac5e82001-03-30Fredrik Hübinette (Hubbe)  { /* Someone got here before us */ mt_lock(bucket_locks); return; } for(h=1;h<BUCKET_LOCKS;h++) mt_lock(bucket_locks+h); #endif
0169c62011-12-30Henrik Grubbström (Grubba)  /* A simple mixing function. */ hashkey ^= (hashkey << 5) | (current_time.tv_sec ^ current_time.tv_usec);
ed2bed2013-06-14Per Hedbor  if (need_more_hash_prefix_depth > 4) {
0169c62011-12-30Henrik Grubbström (Grubba)  HASH_PREFIX=HASH_PREFIX*2; #if 0 fprintf(stderr, "Doubling HASH_PREFIX to %d and rehashing\n", HASH_PREFIX); #endif /* 0 */ } /* NOTE: No need to update to the correct values, since that will
6ed3d22005-01-17Henrik Grubbström (Grubba)  * be done on demand. */
0169c62011-12-30Henrik Grubbström (Grubba)  need_new_hashkey_depth = 0;
6ed3d22005-01-17Henrik Grubbström (Grubba)  need_more_hash_prefix_depth=0;
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  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 */
e85df82001-09-06Fredrik Hübinette (Hubbe)  h2=HMODULO(tmp2->hval);
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)  }
a20d822013-06-08Martin Nilsson #endif /* !HASH_PREFIX */
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) {
4170b92004-11-06Henrik Grubbström (Grubba)  struct pike_string *t = NULL;
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
ed2bed2013-06-14Per Hedbor  if ((len<<shift) <= SHORT_STRING_THRESHOLD) {
4a5e3f2000-11-25Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
d476592013-06-12Arne Goedeke  if (shift > 2)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Unsupported string shift: %d\n", shift);
4a5e3f2000-11-25Henrik Grubbström (Grubba) #endif /* PIKE_DEBUG */
ed2bed2013-06-14Per Hedbor  t=(struct pike_string *)ba_alloc(&string_allocator);
d476592013-06-12Arne Goedeke  t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_IS_SHORT;
4a5e3f2000-11-25Henrik Grubbström (Grubba)  } else {
3c08602008-05-02Martin Stjernholm  t=(struct pike_string *)xalloc(((len + 1)<<shift) + sizeof(struct pike_string_hdr));
9cd0372005-11-03Henrik Grubbström (Grubba)  t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED;
4a5e3f2000-11-25Henrik Grubbström (Grubba)  }
9386322011-07-21Henrik Grubbström (Grubba) #ifdef ATOMIC_SVALUE t->ref_type = T_STRING; #endif
dc245f2011-07-21Henrik Grubbström (Grubba)  t->refs = 0; add_ref(t); /* For DMALLOC */
db4a401998-10-09Fredrik Hübinette (Hubbe)  t->len=len; t->size_shift=shift;
0e602a2006-01-12Henrik Grubbström (Grubba)  DO_IF_DEBUG(t->next = NULL);
db4a401998-10-09Fredrik Hübinette (Hubbe)  low_set_index(t,len,0); return t; }
9cd0372005-11-03Henrik Grubbström (Grubba) PMOD_EXPORT void hash_string(struct pike_string *s) { if (!(s->flags & STRING_NOT_HASHED)) return;
9925512013-05-31Per Hedbor  /* if( s->len < HASH_PREFIX ) */ /* check_string_range( s, 0, 0, 0 ); */
9cd0372005-11-03Henrik Grubbström (Grubba)  s->hval=do_hash(s); s->flags &= ~STRING_NOT_HASHED; }
3e625c1998-10-11Fredrik Hübinette (Hubbe) /* * This function assumes that the shift size is already the minimum it * can be. */
66d9282011-05-01Per Hedbor 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;
ec51ce2006-04-25David Hedbor  size_t h=0;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s2;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
e8371e2008-06-23Martin Stjernholm #ifdef PIKE_DEBUG if (d_flag) { switch (s->size_shift) { case 0: break; case 1: if(!find_magnitude1(STR1(s),s->len)) Pike_fatal ("String %p that should have shift 1 really got 0.\n", s); break; case 2: { int m = find_magnitude2 (STR2 (s), s->len); if (m != 2) Pike_fatal ("String %p that should have shift 2 really got %d.\n", s, m); break; } default: Pike_fatal("ARGHEL! size_shift:%d\n", s->size_shift); } } #endif
d3b06f2000-08-10Henrik Grubbström (Grubba)  len = s->len;
9cd0372005-11-03Henrik Grubbström (Grubba)  if (s->flags & STRING_NOT_HASHED) { h = s->hval = do_hash(s); s->flags &= ~STRING_NOT_HASHED; }
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)
5aad932002-08-15Marcus Comstedt  Pike_fatal("end_shared_string called twice! (or something like that)\n");
3e625c1998-10-11Fredrik Hübinette (Hubbe) #endif if(s2) {
9cd0372005-11-03Henrik Grubbström (Grubba)  free_string(s);
2eed0b2000-10-08Henrik Grubbström (Grubba)  s = s2;
9cd0372005-11-03Henrik Grubbström (Grubba)  add_ref(s);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  }else{ link_pike_string(s, h); } 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:
e8371e2008-06-23Martin Stjernholm #ifdef PIKE_DEBUG
5aad932002-08-15Marcus Comstedt  Pike_fatal("ARGHEL! size_shift:%d\n", s->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe)  case 2:
e8371e2008-06-23Martin Stjernholm #endif
db4a401998-10-09Fredrik Hübinette (Hubbe)  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);
9cd0372005-11-03Henrik Grubbström (Grubba)  free_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);
9cd0372005-11-03Henrik Grubbström (Grubba)  free_string(s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s=s2; /* Fall though */ } break;
9925512013-05-31Per Hedbor 
db4a401998-10-09Fredrik Hübinette (Hubbe)  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);
9cd0372005-11-03Henrik Grubbström (Grubba)  free_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) }
66d9282011-05-01Per Hedbor #if 0
0e602a2006-01-12Henrik Grubbström (Grubba) PMOD_EXPORT struct pike_string *defer_end_string(struct pike_string *s) { #ifdef STRING_DEFER_THRESHOLD if (s->len > STRING_DEFER_THRESHOLD) { return s; } #endif return end_shared_string(s); }
66d9282011-05-01Per Hedbor #endif
0e602a2006-01-12Henrik Grubbström (Grubba) 
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)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Cannot extend string here!\n");
d5b1e22000-11-29Fredrik Hübinette (Hubbe) #endif
d229e32008-11-05Henrik Grubbström (Grubba)  if( (str->len <= SHORT_STRING_THRESHOLD) || ((len > SHORT_STRING_THRESHOLD) && (str->len <= (len<<1))) )
d5b1e22000-11-29Fredrik Hübinette (Hubbe)  {
d229e32008-11-05Henrik Grubbström (Grubba)  /* Short string before and after or * long string and at least half the length of the buffer. * * NOTE: We lose track of the actual buffer length here, so don't * use this function to shorten a string in decrements. */
d5b1e22000-11-29Fredrik Hübinette (Hubbe)  str->len=len;
f2f7632008-11-05Henrik Grubbström (Grubba)  SET_INDEX_PCHARP(MKPCHARP_STR(str), len, 0);
d5b1e22000-11-29Fredrik Hübinette (Hubbe)  return end_shared_string(str); } tmp = make_shared_binary_pcharp(MKPCHARP_STR(str),len);
9cd0372005-11-03Henrik Grubbström (Grubba)  free_string(str);
d5b1e22000-11-29Fredrik Hübinette (Hubbe)  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);
5317302005-11-05Henrik Grubbström (Grubba)  } else { 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);
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
011ad31999-10-22Fredrik Hübinette (Hubbe)  default:
5aad932002-08-15Marcus Comstedt  Pike_fatal("Unknown string width!\n");
c6b6042008-05-03Martin Nilsson #endif
011ad31999-10-22Fredrik Hübinette (Hubbe)  }
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);
5317302005-11-05Henrik Grubbström (Grubba)  } else { add_ref(s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  } 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);
5317302005-11-05Henrik Grubbström (Grubba)  } else { add_ref(s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  } 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) 
66d9282011-05-01Per Hedbor static 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);
e85df82001-09-06Fredrik Hübinette (Hubbe)  h= HMODULO(s->hval);
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) {
5aad932002-08-15Marcus Comstedt  Pike_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);
9cd0372005-11-03Henrik Grubbström (Grubba)  s->flags |= STRING_NOT_SHARED;
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) }
fb22942008-06-16Martin Stjernholm PMOD_EXPORT void do_free_unlinked_pike_string(struct pike_string *s)
d5b1e22000-11-29Fredrik Hübinette (Hubbe) { if (s)
fb22942008-06-16Martin Stjernholm  free_unlinked_pike_string(s);
d5b1e22000-11-29Fredrik Hübinette (Hubbe) }
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;
d631b82002-12-01Martin Stjernholm  if (s->refs) { #ifdef DEBUG_MALLOC describe_something(s, T_STRING, 0,2,0, NULL); #endif Pike_fatal("Freeing string with %d references.\n", s->refs); }
f88e292007-03-29Marcus Comstedt  if(d_flag > 2 && !(s->flags & STRING_NOT_SHARED))
d631b82002-12-01Martin Stjernholm  { if(s->next == (struct pike_string *)(ptrdiff_t)-1) Pike_fatal("Freeing shared string again!\n");
7abf491998-04-17Fredrik Hübinette (Hubbe) 
d631b82002-12-01Martin Stjernholm  if(((ptrdiff_t)s->next) & 1) Pike_fatal("Freeing shared string again, memory corrupt or other bug!\n");
9367351997-01-27Fredrik Hübinette (Hubbe)  }
d476592013-06-12Arne Goedeke  if (s->size_shift > 2) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("Freeing string with bad shift (0x%08x); could it be a type?\n",
c7eadf2001-03-29Henrik Grubbström (Grubba)  s->size_shift); }
9367351997-01-27Fredrik Hübinette (Hubbe) #endif
9cd0372005-11-03Henrik Grubbström (Grubba)  if (!(s->flags & STRING_NOT_SHARED)) unlink_pike_string(s);
8a14542008-06-29Martin Nilsson  if (s->flags & STRING_CLEAR_ON_EXIT)
0a146b2013-03-12Arne Goedeke  guaranteed_memset(s->str, 0, s->len<<s->size_shift);
fb22942008-06-16Martin Stjernholm  free_unlinked_pike_string(s);
6cb7832000-09-15Martin Stjernholm  GC_FREE_SIMPLE_BLOCK(s);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
66d9282011-05-01Per Hedbor void do_really_free_string(struct pike_string *s)
fb22942008-06-16Martin Stjernholm { if (s) really_free_string(s); }
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void debug_free_string(struct pike_string *s)
61e9a01998-01-25Fredrik Hübinette (Hubbe) {
50ea682003-03-14Henrik Grubbström (Grubba)  if(!sub_ref(s))
61e9a01998-01-25Fredrik Hübinette (Hubbe)  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) {
af80262013-02-07Henrik Grubbström (Grubba)  struct string_builder s; init_string_builder(&s, 0);
5267b71995-08-09Fredrik Hübinette (Hubbe)  if (verbose) {
af80262013-02-07Henrik Grubbström (Grubba)  long alloced_strings[8] = {0,0,0,0,0,0,0,0}; long alloced_bytes[8] = {0,0,0,0,0,0,0,0}; long num_distinct_strings[8] = {0,0,0,0,0,0,0,0}; long bytes_distinct_strings[8] = {0,0,0,0,0,0,0,0}; long overhead_bytes[8] = {0,0,0,0,0,0,0,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) {
af80262013-02-07Henrik Grubbström (Grubba)  int is_short = (p->len <= SHORT_STRING_THRESHOLD); int key = (is_short?0:4) | p->size_shift; num_distinct_strings[key]++; if (is_short) { bytes_distinct_strings[key] += DO_ALIGN(SHORT_STRING_THRESHOLD << p->size_shift, sizeof(void *)); } else { bytes_distinct_strings[key] += DO_ALIGN(p->len << p->size_shift, sizeof(void *)); } alloced_strings[key] += p->refs; alloced_bytes[key] += p->refs*DO_ALIGN((p->len+3) << p->size_shift,sizeof(void *));
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
af80262013-02-07Henrik Grubbström (Grubba)  string_builder_sprintf(&s, "\nShared string hash table:\n" "-------------------------\n" "\n" "Type Count Distinct Bytes Actual Overhead %%\n" "------------------------------------------------------------\n"); for(e = 0; e < 8; e++) { int shift = e & 3; ptrdiff_t overhead; if (!num_distinct_strings[e]) continue; if (shift != 3) { if (e < 4) { string_builder_sprintf(&s, "Short/%-2d ", 8<<shift); } else { string_builder_sprintf(&s, "Long/%-2d ", 8<<shift); } overhead_bytes[e] = DO_NOT_WARN((long)sizeof(struct pike_string_hdr) * num_distinct_strings[e]); alloced_strings[e|3] += alloced_strings[e]; alloced_bytes[e|3] += alloced_bytes[e]; num_distinct_strings[e|3] += num_distinct_strings[e]; bytes_distinct_strings[e|3] += bytes_distinct_strings[e]; overhead_bytes[e|3] += overhead_bytes[e]; } else { if (e < 4) { string_builder_sprintf(&s, "Total short"); } else { string_builder_sprintf(&s, "Total long "); } } string_builder_sprintf(&s, "%8ld %8ld %8ld %8ld %8ld ", alloced_strings[e], num_distinct_strings[e], alloced_bytes[e], bytes_distinct_strings[e], overhead_bytes[e]); if (alloced_bytes[e]) { string_builder_sprintf(&s, "%4d\n", (bytes_distinct_strings[e] + overhead_bytes[e]) * 100 / alloced_bytes[e]); } else { string_builder_strcat(&s, " -\n"); } } alloced_strings[7] += alloced_strings[3]; alloced_bytes[7] += alloced_bytes[3]; num_distinct_strings[7] += num_distinct_strings[3]; bytes_distinct_strings[7] += bytes_distinct_strings[3]; overhead_bytes[7] += overhead_bytes[3]; string_builder_sprintf(&s, "------------------------------------------------------------\n" "Total %8ld %8ld %8ld %8ld %8ld ", alloced_strings[7], num_distinct_strings[7], alloced_bytes[7], bytes_distinct_strings[7], overhead_bytes[7]); if (alloced_bytes[7]) { string_builder_sprintf(&s, "%4d\n", (bytes_distinct_strings[7] + overhead_bytes[7]) * 100 / alloced_bytes[7]); } else { string_builder_strcat(&s, " -\n"); }
5267b71995-08-09Fredrik Hübinette (Hubbe)  } /* sprintf(b,"Searches: %ld Average search length: %6.3f\n", (long)num_str_searches, (double)search_len / num_str_searches); my_strcat(b); */
af80262013-02-07Henrik Grubbström (Grubba)  return finish_string_builder(&s);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
71f3a21998-11-22Fredrik Hübinette (Hubbe) /*** PIKE_DEBUG ***/ #ifdef PIKE_DEBUG
af93211996-10-12Fredrik Hübinette (Hubbe) 
6b997c2001-09-04Fredrik Hübinette (Hubbe) static long last_stralloc_verify=0; extern long current_do_debug_cycle;
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void check_string(struct pike_string *s)
af93211996-10-12Fredrik Hübinette (Hubbe) {
6b997c2001-09-04Fredrik Hübinette (Hubbe)  if(current_do_debug_cycle == last_stralloc_verify)
2043ba1998-02-10Fredrik Hübinette (Hubbe)  {
6b997c2001-09-04Fredrik Hübinette (Hubbe)  if(debug_findstring(s) !=s)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Shared string not shared.\n");
6b997c2001-09-04Fredrik Hübinette (Hubbe)  }else{
abdf6b2005-04-02Martin Stjernholm  switch (s->size_shift) { case 0: break; case 1: { ptrdiff_t i; p_wchar1 *str = STR1 (s); for (i = 0; i < s->len; i++) if (str[i] > 0xff) goto size_shift_check_done; Pike_fatal ("Shared string is too wide.\n"); } case 2: { ptrdiff_t i; p_wchar2 *str = STR2 (s); for (i = 0; i < s->len; i++)
3e99182008-06-29Henrik Grubbström (Grubba)  if ((str[i] > 0xffff) || (str[i] < 0))
abdf6b2005-04-02Martin Stjernholm  goto size_shift_check_done; Pike_fatal ("Shared string is too wide.\n"); } default: Pike_fatal ("Invalid size shift %d.\n", s->size_shift); } size_shift_check_done:;
6b997c2001-09-04Fredrik Hübinette (Hubbe)  if(do_hash(s) != s->hval) { locate_problem(wrong_hash);
5aad932002-08-15Marcus Comstedt  Pike_fatal("Hash value changed?\n");
6b997c2001-09-04Fredrik Hübinette (Hubbe)  }
9925512013-05-31Per Hedbor 
6b997c2001-09-04Fredrik Hübinette (Hubbe)  if(debug_findstring(s) !=s)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Shared string not shared.\n");
af93211996-10-12Fredrik Hübinette (Hubbe) 
6b997c2001-09-04Fredrik Hübinette (Hubbe)  if(index_shared_string(s,s->len)) { locate_problem(improper_zero_termination);
5aad932002-08-15Marcus Comstedt  Pike_fatal("Shared string is not zero terminated properly.\n");
6b997c2001-09-04Fredrik Hübinette (Hubbe)  }
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;
6b997c2001-09-04Fredrik Hübinette (Hubbe)  last_stralloc_verify=current_do_debug_cycle;
af93211996-10-12Fredrik Hübinette (Hubbe)  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)) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("Odd string pointer in string table!\n");
4bdf5f2001-03-30Henrik Grubbström (Grubba)  }
af93211996-10-12Fredrik Hübinette (Hubbe)  if(s->len < 0)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Shared string shorter than zero bytes.\n");
af93211996-10-12Fredrik Hübinette (Hubbe)  if(s->refs <= 0)
2043ba1998-02-10Fredrik Hübinette (Hubbe)  { locate_problem(has_zero_refs);
5aad932002-08-15Marcus Comstedt  Pike_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);
5aad932002-08-15Marcus Comstedt  Pike_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)
8be4822004-11-06Henrik Grubbström (Grubba)  { locate_problem(wrong_hash);
5aad932002-08-15Marcus Comstedt  Pike_fatal("Shared string hashed to other number.\n");
8be4822004-11-06Henrik Grubbström (Grubba)  }
8bcb3b2001-03-28Fredrik Hübinette (Hubbe) 
e85df82001-09-06Fredrik Hübinette (Hubbe)  if(HMODULO(s->hval) != e)
2043ba1998-02-10Fredrik Hübinette (Hubbe)  { locate_problem(wrong_hash);
5aad932002-08-15Marcus Comstedt  Pike_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)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Shared string table is cyclic.\n");
af93211996-10-12Fredrik Hübinette (Hubbe)  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)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Num strings is wrong %d!=%d\n",num,num_strings);
af93211996-10-12Fredrik Hübinette (Hubbe) }
66d9282011-05-01Per Hedbor 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; }
66d9282011-05-01Per Hedbor struct pike_string *debug_findstring(const struct pike_string *foo)
af93211996-10-12Fredrik Hübinette (Hubbe) { struct pike_string *tmp;
e85df82001-09-06Fredrik Hübinette (Hubbe)  tmp=propagate_shared_string(foo, HMODULO(foo->hval));
af93211996-10-12Fredrik Hübinette (Hubbe)  #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",
e85df82001-09-06Fredrik Hübinette (Hubbe)  base_table[HMODULO(foo->hval)],
8bcb3b2001-03-28Fredrik Hübinette (Hubbe)  foo->hval);
e85df82001-09-06Fredrik Hübinette (Hubbe)  for(tmp2=base_table[HMODULO(foo->hval)];tmp2;tmp2=tmp2->next)
af93211996-10-12Fredrik Hübinette (Hubbe)  { 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,
e85df82001-09-06Fredrik Hübinette (Hubbe)  (long)HMODULO(foo->hval));
af93211996-10-12Fredrik Hübinette (Hubbe)  }
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e);
af93211996-10-12Fredrik Hübinette (Hubbe)  } }
a20d822013-06-08Martin Nilsson #endif /* 0 */
af93211996-10-12Fredrik Hübinette (Hubbe)  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);
024adc2004-11-14Martin Stjernholm  for(p=base_table[e];p;p=p->next) {
38d6081998-02-07Fredrik Hübinette (Hubbe)  debug_dump_pike_string(p, 70);
024adc2004-11-14Martin Stjernholm #ifdef DEBUG_MALLOC debug_malloc_dump_references (p, 2, 1, 0); #endif }
e1939c2001-03-30Fredrik Hübinette (Hubbe)  UNLOCK_BUCKET(e); }
5267b71995-08-09Fredrik Hübinette (Hubbe) }
a20d822013-06-08Martin Nilsson #endif /* PIKE_DEBUG */
af93211996-10-12Fredrik Hübinette (Hubbe)  /*** String compare functions ***/ /* does not take locale into account */
5de2692012-05-28Martin Stjernholm 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 */
66d9282011-05-01Per Hedbor ptrdiff_t generic_quick_binary_strcmp(const char *a,
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t alen, int asize, const char *b, ptrdiff_t blen, int bsize)
3e625c1998-10-11Fredrik Hübinette (Hubbe) { if(!asize && !bsize) { int tmp;
8dc56f2006-03-11Henrik Grubbström (Grubba)  /* FIXME: Does MEMCMP() guarantee that the characters * are compared as unsigned? * /grubba 2006-03-11 */
3e625c1998-10-11Fredrik Hübinette (Hubbe)  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{
8dc56f2006-03-11Henrik Grubbström (Grubba)  ptrdiff_t pos;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  for(pos=0;pos< MINIMUM(alen,blen) ;pos++) {
8dc56f2006-03-11Henrik Grubbström (Grubba)  p_wchar2 ac=generic_extract(a,asize,pos); p_wchar2 bc=generic_extract(b,bsize,pos);
d7cc372006-03-10Henrik Grubbström (Grubba)  if(ac != bc) { if (ac < bc) return -1; return 1; }
3e625c1998-10-11Fredrik Hübinette (Hubbe)  } return alen-blen; } }
d7cc372006-03-10Henrik Grubbström (Grubba) /* Does not take locale into account * * Similar to (and could be used in place of) generic_quick_binary_strcmp(), * but returns +/- (offset + 1) to the first difference beween the strings. * * This can be used by eg replace_many() to speed up the comparisons. */
66d9282011-05-01Per Hedbor ptrdiff_t generic_find_binary_prefix(const char *a,
d7cc372006-03-10Henrik Grubbström (Grubba)  ptrdiff_t alen, int asize, const char *b, ptrdiff_t blen, int bsize) { ptrdiff_t pos; ptrdiff_t len = MINIMUM(alen, blen); switch(TWO_SIZES(asize, bsize)) { #define CASE(AZ, BZ) \ case TWO_SIZES(AZ, BZ): { \ PIKE_CONCAT(p_wchar, AZ) *a_arr = \ (PIKE_CONCAT(p_wchar, AZ) *)a; \
8dc56f2006-03-11Henrik Grubbström (Grubba)  PIKE_CONCAT(p_wchar, BZ) *b_arr = \ (PIKE_CONCAT(p_wchar, BZ) *)b; \
d7cc372006-03-10Henrik Grubbström (Grubba)  for (pos=0; pos<len; pos++) { \ if (a_arr[pos] == b_arr[pos]) \ continue; \ if (a_arr[pos] < b_arr[pos]) \ return ~pos; \ return pos+1; \ } \ } break CASE(0,0); CASE(0,1); CASE(0,2); CASE(1,0); CASE(1,1); CASE(1,2); CASE(2,0); CASE(2,1); CASE(2,2); #undef CASE } if (alen == blen) return 0; if (alen < blen) return ~alen; return blen+1; }
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) }
5de2692012-05-28Martin Stjernholm 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;
ed2bed2013-06-14Per Hedbor  if (a->flags & STRING_IS_SHORT ) { if (size <= SHORT_STRING_THRESHOLD/(1<<a->size_shift)) {
e464e02008-06-23Martin Stjernholm  /* There's already space enough. */
4a5e3f2000-11-25Henrik Grubbström (Grubba)  a->len = size; low_set_index(a, size, 0); return a; }
ed2bed2013-06-14Per Hedbor  } else {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  r=(struct pike_string *)realloc((char *)a,
3c08602008-05-02Martin Stjernholm  sizeof(struct pike_string_hdr)+
d224752003-10-13Martin Stjernholm  ((size+1)<<a->size_shift));
4a5e3f2000-11-25Henrik Grubbström (Grubba)  }
ed2bed2013-06-14Per Hedbor 
8d28be1997-02-10Fredrik Hübinette (Hubbe)  if(!r) {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  r=begin_wide_shared_string(size, a->size_shift);
ed2bed2013-06-14Per Hedbor  r->flags |= a->flags & ~15; r->min = a->min; r->max = a->max;
4a5e3f2000-11-25Henrik Grubbström (Grubba)  if (a->len <= size) { MEMCPY(r->str, a->str, a->len<<a->size_shift); } else { MEMCPY(r->str, a->str, size<<a->size_shift); }
9cd0372005-11-03Henrik Grubbström (Grubba)  free_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 */
66d9282011-05-01Per Hedbor static 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);
ed2bed2013-06-14Per Hedbor  r->flags |= a->flags & ~15; r->min = a->min; r->max = a->max;
7094631997-02-24Fredrik Hübinette (Hubbe)  free_string(a);
8d28be1997-02-10Fredrik Hübinette (Hubbe)  return r; } }
66d9282011-05-01Per Hedbor 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);
ed2bed2013-06-14Per Hedbor  r->flags |= (a->flags & ~15); r->min = a->min; r->max = a->max;
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)  */
66d9282011-05-01Per Hedbor 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)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Index out of range in modify_shared_string()\n");
0d3ea51998-01-19Fredrik Hübinette (Hubbe) #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);
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
db4a401998-10-09Fredrik Hübinette (Hubbe)  default:
5aad932002-08-15Marcus Comstedt  Pike_fatal("Odd wide string conversion!\n");
c6b6042008-05-03Martin Nilsson #endif
db4a401998-10-09Fredrik Hübinette (Hubbe)  } } /* 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:
5aad932002-08-15Marcus Comstedt  Pike_fatal("Unshrinkable!\n");
db4a401998-10-09Fredrik Hübinette (Hubbe)  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 */
e94f072005-01-18Henrik Grubbström (Grubba)  unlink_pike_string(a); low_set_index(a, index, c);
9925512013-05-31Per Hedbor  CLEAR_STRING_CHECKED(a);
fe3c9f1999-09-06Henrik Grubbström (Grubba)  if((((unsigned int)index) >= HASH_PREFIX) && (index < a->len-8))
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  {
6ed3d22005-01-17Henrik Grubbström (Grubba)  struct pike_string *old;
5cc19b2005-05-18Martin Nilsson #ifdef PIKE_DEBUG
950ade2005-05-17Henrik Grubbström (Grubba)  if (wrong_hash(a)) { Pike_fatal("Broken hash optimization.\n"); }
5cc19b2005-05-18Martin Nilsson #endif
db4a401998-10-09Fredrik Hübinette (Hubbe)  /* Doesn't change hash value - sneak it in there */
6ed3d22005-01-17Henrik Grubbström (Grubba)  old = internal_findstring(a->str, a->len, a->size_shift, a->hval); if (old) { /* The new string is equal to some old string. */
9cd0372005-11-03Henrik Grubbström (Grubba)  free_string(a);
6ed3d22005-01-17Henrik Grubbström (Grubba)  add_ref(a = old); } else { link_pike_string(a, a->hval); }
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  }else{
e94f072005-01-18Henrik Grubbström (Grubba)  a = end_shared_string(a);
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  }
e94f072005-01-18Henrik Grubbström (Grubba)  return a;
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  }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); } }
9925512013-05-31Per Hedbor PMOD_EXPORT void set_flags_for_add( struct pike_string *ret, unsigned char aflags, unsigned char amin, unsigned char amax, struct pike_string *b) { if( !b->len ) { ret->flags |= aflags & ~15; ret->min = amin; ret->max = amax; return; }
afd5eb2013-06-03Martin Nilsson  if( aflags & b->flags & STRING_CONTENT_CHECKED )
9925512013-05-31Per Hedbor  { ret->min = MIN( amin, b->min ); ret->max = MAX( amax, b->max ); ret->flags |= STRING_CONTENT_CHECKED; } else ret->flags &= ~STRING_CONTENT_CHECKED;
a21b582013-06-09Martin Nilsson  ret->flags &= ~(STRING_IS_LOWERCASE | STRING_IS_UPPERCASE); ret->flags |= (aflags & b->flags & (STRING_IS_LOWERCASE | STRING_IS_UPPERCASE));
9925512013-05-31Per Hedbor } PMOD_EXPORT void update_flags_for_add( struct pike_string *a, struct pike_string *b) { if( !b->len ) return; if( a->flags & STRING_CONTENT_CHECKED ) { if(b->flags & STRING_CONTENT_CHECKED) { if( b->min < a->min ) a->min = b->min; if( b->max > a->max ) a->max = b->max; } else a->flags &= ~STRING_CONTENT_CHECKED; }
f3b33d2013-06-03Martin Nilsson  a->flags &= ~(STRING_IS_LOWERCASE | STRING_IS_UPPERCASE) | b->flags;
9925512013-05-31Per Hedbor }
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,
9925512013-05-31Per Hedbor  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);
9925512013-05-31Per Hedbor  set_flags_for_add( ret, a->flags, a->min, a->max, 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,
9925512013-05-31Per Hedbor  struct pike_string *b)
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) {
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t alen = a->len;
db4a401998-10-09Fredrik Hübinette (Hubbe)  if(a->size_shift == b->size_shift) {
9925512013-05-31Per Hedbor  a = realloc_shared_string(a, alen + b->len);
ed2bed2013-06-14Per Hedbor  update_flags_for_add( a, b );
db4a401998-10-09Fredrik Hübinette (Hubbe)  MEMCPY(a->str+(alen<<a->size_shift),b->str,b->len<<b->size_shift); free_string(b);
9cd0372005-11-03Henrik Grubbström (Grubba)  a->flags |= STRING_NOT_HASHED;
db4a401998-10-09Fredrik Hübinette (Hubbe)  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)  char *r;
9925512013-05-31Per Hedbor  if( !string_range_contains_string( haystack, needle ) ) return -1; if(start + needle->len > haystack->len)
db4a401998-10-09Fredrik Hübinette (Hubbe)  return -1;
bfcfb02001-11-08Fredrik Hübinette (Hubbe)  if(!needle->len) return start;
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) 
6e54c72004-03-24Henrik Grubbström (Grubba)  r = (char *)mojt.vtab->funcN(mojt.data, ADD_PCHARP(MKPCHARP_STR(haystack), start), haystack->len - start).ptr;
9b1f032000-10-09Fredrik Hübinette (Hubbe) 
8c11832008-06-23Martin Stjernholm  if (mojt.container) free_object (mojt.container);
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)
5aad932002-08-15Marcus Comstedt  Pike_fatal("string_search did a bobo!\n");
5d54232000-10-09Fredrik Hübinette (Hubbe) #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 ) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("string_slice, start = %ld, len = %ld, s->len = %ld\n",
a7979d2000-08-11Henrik Grubbström (Grubba)  DO_NOT_WARN((long)start), DO_NOT_WARN((long)len), DO_NOT_WARN((long)s->len));
3e625c1998-10-11Fredrik Hübinette (Hubbe)  } #endif
6a12e42011-05-03Per Hedbor  if( len == 0) { add_ref(empty_pike_string); return empty_pike_string; }
3e625c1998-10-11Fredrik Hübinette (Hubbe)  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); }
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
5aad932002-08-15Marcus Comstedt  Pike_fatal("Illegal shift size!\n");
c6b6042008-05-03Martin Nilsson #endif
efae671998-10-21Fredrik Hübinette (Hubbe)  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;
8c11832008-06-23Martin Stjernholm  ONERROR mojt_uwp;
41b0b22000-10-20Henrik Grubbström (Grubba)  replace_searchfunc f = (replace_searchfunc)0;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
4dd43e2013-06-10Arne Goedeke  if(!str->len || !string_range_contains_string(str, del))
a991451997-07-08Fredrik Hübinette (Hubbe)  {
4dd43e2013-06-10Arne Goedeke  add_ref(str); return str;
a991451997-07-08Fredrik Hübinette (Hubbe)  }
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);
8c11832008-06-23Martin Stjernholm  SET_ONERROR (mojt_uwp, do_free_object, mojt.container);
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
5aad932002-08-15Marcus Comstedt  default: Pike_fatal("Illegal shift.\n");
5d54232000-10-09Fredrik Hübinette (Hubbe) #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);
8c11832008-06-23Martin Stjernholm  SET_ONERROR (mojt_uwp, do_free_object, mojt.container);
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
5aad932002-08-15Marcus Comstedt  default: Pike_fatal("Illegal shift.\n");
5d54232000-10-09Fredrik Hübinette (Hubbe) #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) {
8c11832008-06-23Martin Stjernholm  CALL_AND_UNSET_ONERROR (mojt_uwp);
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)
362d302004-03-08Martin Nilsson  Pike_fatal("SearchMojt found a match beyond end of string!!!\n");
68d9131999-04-01Fredrik Hübinette (Hubbe) #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) 
8c11832008-06-23Martin Stjernholm  CALL_AND_UNSET_ONERROR (mojt_uwp);
5267b71995-08-09Fredrik Hübinette (Hubbe)  return end_shared_string(ret); }
af93211996-10-12Fredrik Hübinette (Hubbe) /*** init/exit memory ***/
be478c1997-08-30Henrik Grubbström (Grubba) void init_shared_string_table(void)
af93211996-10-12Fredrik Hübinette (Hubbe) {
85f59e1998-01-08Fredrik Hübinette (Hubbe)  for(hashprimes_entry=0;hashprimes[hashprimes_entry]<BEGIN_HASH_SIZE;hashprimes_entry++);
e85df82001-09-06Fredrik Hübinette (Hubbe)  SET_HSIZE(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
4edb1a2002-09-11David Hedbor  empty_pike_string = make_shared_string("");
9925512013-05-31Per Hedbor  empty_pike_string->flags |= STRING_CONTENT_CHECKED | STRING_IS_LOWERCASE | STRING_IS_UPPERCASE; empty_pike_string->min = empty_pike_string->max = 0;
af93211996-10-12Fredrik Hübinette (Hubbe) }
31a8682004-09-27Martin Stjernholm #ifdef DO_PIKE_CLEANUP
00e6682006-07-05Martin Stjernholm PMOD_EXPORT struct shared_string_location *all_shared_string_locations;
61e9a01998-01-25Fredrik Hübinette (Hubbe) #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) 
4edb1a2002-09-11David Hedbor  if (empty_pike_string) { free_string(empty_pike_string); empty_pike_string = 0;
7ff5712001-12-20Martin Stjernholm  }
31a8682004-09-27Martin Stjernholm #ifdef DO_PIKE_CLEANUP
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; }
31a8682004-09-27Martin Stjernholm  if (exit_with_cleanup)
61e9a01998-01-25Fredrik Hübinette (Hubbe)  {
f757d02008-05-01Martin Stjernholm  size_t num,size;
3c0c281998-01-26Fredrik Hübinette (Hubbe)  count_memory_in_strings(&num,&size); if(num) {
f757d02008-05-01Martin Stjernholm  fprintf(stderr,"Strings left: %"PRINTSIZET"d " "(%"PRINTSIZET"d bytes) (zapped)\n",num,size);
31a8682004-09-27Martin Stjernholm #ifdef PIKE_DEBUG
3c0c281998-01-26Fredrik Hübinette (Hubbe)  dump_stralloc_strings();
31a8682004-09-27Martin Stjernholm #endif
3c0c281998-01-26Fredrik Hübinette (Hubbe)  }
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
fb22942008-06-16Martin Stjernholm  free_unlinked_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) 
0d70692002-11-28Martin Stjernholm #ifdef DO_PIKE_CLEANUP
d476592013-06-12Arne Goedeke  ba_destroy(string_allocator+0); ba_destroy(string_allocator+1); ba_destroy(string_allocator+2);
0d70692002-11-28Martin Stjernholm #endif /* DO_PIKE_CLEANUP */
5267b71995-08-09Fredrik Hübinette (Hubbe) }
c3c7031996-12-04Fredrik Hübinette (Hubbe) 
3c08602008-05-02Martin Stjernholm static INLINE size_t memory_in_string (struct pike_string *s) {
ed2bed2013-06-14Per Hedbor  if (s->flags & STRING_IS_SHORT ) return sizeof (struct short_pike_string0);
3c08602008-05-02Martin Stjernholm  else return sizeof (struct pike_string_hdr) + ((s->len + 1) << s->size_shift); }
041a532012-03-08Henrik Grubbström (Grubba) void count_memory_in_short_pike_strings(size_t *num, size_t *size) {
ed2bed2013-06-14Per Hedbor  ba_count_all(&string_allocator, num, size);
041a532012-03-08Henrik Grubbström (Grubba) }
f757d02008-05-01Martin Stjernholm void count_memory_in_strings(size_t *num, size_t *size)
c3c7031996-12-04Fredrik Hübinette (Hubbe) {
f757d02008-05-01Martin Stjernholm  unsigned INT32 e; size_t 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_++;
3c08602008-05-02Martin Stjernholm  size_ += memory_in_string (p);
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_)
5aad932002-08-15Marcus Comstedt  Pike_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) 
1eb9852008-05-11Martin Stjernholm PMOD_EXPORT void visit_string (struct pike_string *s, int action)
ad8d052008-05-02Martin Stjernholm {
5e83442008-05-11Martin Stjernholm  switch (action) { #ifdef PIKE_DEBUG default: Pike_fatal ("Unknown visit action %d.\n", action); case VISIT_NORMAL: case VISIT_COMPLEX_ONLY: break; #endif case VISIT_COUNT_BYTES: mc_counted_bytes += memory_in_string (s); break; }
ad8d052008-05-02Martin Stjernholm }
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; }
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;
5e83442008-05-11Martin Stjernholm  for(p=base_table[e];p;p=p->next) gc_is_referenced(p);
9367351997-01-27Fredrik Hübinette (Hubbe)  } }
30431f2001-09-27Martin Stjernholm #endif
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);
e85df82001-09-06Fredrik Hübinette (Hubbe)  h = HMODULO(h);
f7cfa82001-09-04Martin Stjernholm  next = base_table[h]; UNLOCK_BUCKET(h); } while (!next); } return next; }
058cc42009-01-06Stephen R. van den Berg PMOD_EXPORT void init_string_builder_alloc(struct string_builder *s, ptrdiff_t length, int mag)
db4a401998-10-09Fredrik Hübinette (Hubbe) {
058cc42009-01-06Stephen R. van den Berg  s->s=begin_wide_shared_string(length,mag); s->malloced=length; s->known_shift=0;
db4a401998-10-09Fredrik Hübinette (Hubbe)  s->s->len=0;
e8371e2008-06-23Martin Stjernholm  low_set_index (s->s, 0, 0);
db4a401998-10-09Fredrik Hübinette (Hubbe) }
058cc42009-01-06Stephen R. van den Berg PMOD_EXPORT void init_string_builder(struct string_builder *s, int mag)
0cd4262001-02-02Martin Stjernholm {
058cc42009-01-06Stephen R. van den Berg  init_string_builder_alloc(s, 256, mag);
0cd4262001-02-02Martin Stjernholm }
8d3b382003-04-07Martin Stjernholm PMOD_EXPORT void init_string_builder_copy(struct string_builder *to, struct string_builder *from) { to->malloced = from->malloced;
e8371e2008-06-23Martin Stjernholm  to->s = begin_wide_shared_string (from->malloced, from->s->size_shift); to->s->len = from->s->len; MEMCPY (to->s->str, from->s->str, (from->s->len + 1) << from->s->size_shift);
8d3b382003-04-07Martin Stjernholm  to->known_shift = from->known_shift; }
97c5582004-04-15Martin Stjernholm /* str becomes invalid if successful (i.e. nonzero returned), * otherwise nothing happens. */ PMOD_EXPORT int init_string_builder_with_string (struct string_builder *s, struct pike_string *str) { if (str->refs == 1 && str->len > SHORT_STRING_THRESHOLD) { /* Unlink the string and use it as buffer directly. */ unlink_pike_string (str);
0d379b2013-06-12Arne Goedeke  str->flags = STRING_NOT_SHARED;
97c5582004-04-15Martin Stjernholm  s->s = str; s->malloced = str->len; s->known_shift = str->size_shift; return 1; } return 0; } PMOD_EXPORT void string_build_mkspace(struct string_builder *s, ptrdiff_t chars, int mag)
024adc2004-11-14Martin Stjernholm /* Doesn't touch or sanity check s->known_shift. */
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 */
9cd0372005-11-03Henrik Grubbström (Grubba)  free_string(s->s);
db4a401998-10-09Fredrik Hübinette (Hubbe)  s->malloced=l; s->s=n; }
97c5582004-04-15Martin Stjernholm  else if(s->s->len+chars > s->malloced)
db4a401998-10-09Fredrik Hübinette (Hubbe)  {
97c5582004-04-15Martin Stjernholm  ptrdiff_t newlen = MAXIMUM(s->malloced*2, s->s->len + chars);
4a5e3f2000-11-25Henrik Grubbström (Grubba)  ptrdiff_t oldlen = s->s->len;
db4a401998-10-09Fredrik Hübinette (Hubbe) 
ef17c02001-09-21Henrik Grubbström (Grubba)  s->s->len = s->malloced; /* Restore the real length */
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);
5bc68f2010-06-15Henrik Grubbström (Grubba)  string_build_mkspace(s, 1, mag); if (mag > s->known_shift) {
6f18712004-11-14Martin Stjernholm  s->known_shift = mag;
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) }
abeaca2010-05-28Martin Stjernholm PMOD_EXPORT void string_builder_putchars(struct string_builder *s, int ch, ptrdiff_t count) { ptrdiff_t len = s->s->len; int mag = min_magnitude(ch);
1b20202011-01-11Henrik Grubbström (Grubba)  /* This is not really expected to happen. But since we are doing * memset here, a negative argument should be avoided. */ if (count < 0) Pike_fatal("Non-positive count in call to string_builder_putchars().\n");
b963e52011-01-11Arne Goedeke  if (!count) return;
5bc68f2010-06-15Henrik Grubbström (Grubba)  string_build_mkspace(s, count, mag); if (mag > s->known_shift) {
abeaca2010-05-28Martin Stjernholm  s->known_shift = mag; } switch (s->s->size_shift) { case 0: MEMSET (STR0 (s->s) + s->s->len, ch, count); break; case 1: { int i; for (i = 0; i < count; i++) (STR1 (s->s) + s->s->len)[i] = ch; break; } case 2: { int i; for (i = 0; i < count; i++) (STR2 (s->s) + s->s->len)[i] = ch; break; } } s->s->len += count; /* Ensure NUL-termination */ s->s->str[s->s->len << s->s->size_shift] = 0; }
db4a401998-10-09Fredrik Hübinette (Hubbe) 
024adc2004-11-14Martin Stjernholm PMOD_EXPORT void string_builder_binary_strcat0(struct string_builder *s, const p_wchar0 *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) {
024adc2004-11-14Martin Stjernholm  case 0: convert_0_to_0(STR0(s->s)+s->s->len,str,len); break; case 1: convert_0_to_1(STR1(s->s)+s->s->len,str,len); break; case 2: convert_0_to_2(STR2(s->s)+s->s->len,str,len); break; #ifdef PIKE_DEBUG
db4a401998-10-09Fredrik Hübinette (Hubbe)  default:
024adc2004-11-14Martin Stjernholm  Pike_fatal ("Illegal magnitude! (%d)\n", s->s->size_shift); #endif
db4a401998-10-09Fredrik Hübinette (Hubbe)  } 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) }
024adc2004-11-14Martin Stjernholm PMOD_EXPORT void string_builder_binary_strcat1(struct string_builder *s, const p_wchar1 *str, ptrdiff_t len) { if (s->s->size_shift == 0) { if (find_magnitude1 (str, len) == 0) { string_build_mkspace (s, len, 0); convert_1_to_0 (STR0(s->s) + s->s->len, str, len); s->s->len += len; /* Ensure NUL-termination */ s->s->str[s->s->len] = 0; return; } s->known_shift = 1; } string_build_mkspace (s, len, 1); if (s->s->size_shift == 1) convert_1_to_1 (STR1(s->s)+s->s->len, str, len); else { #ifdef PIKE_DEBUG if (s->s->size_shift != 2) Pike_fatal ("I aint got no clue 'bout nothing, dude. (%d)\n", s->s->size_shift); #endif convert_1_to_2 (STR2(s->s)+s->s->len, str, len); } s->s->len += len; /* Ensure NUL-termination */ s->s->str[s->s->len << s->s->size_shift] = 0; } PMOD_EXPORT void string_builder_binary_strcat2(struct string_builder *s, const p_wchar2 *str, ptrdiff_t len) { if (s->s->size_shift < 2) { int shift = find_magnitude2 (str, len); if (shift > s->s->size_shift) { string_build_mkspace (s, len, shift); if (shift == 1) convert_2_to_1 (STR1(s->s) + s->s->len, str, len); else { #ifdef PIKE_DEBUG if (shift != 2) Pike_fatal ("Uhh.. Like, what? (%d)\n", shift); #endif convert_2_to_2 (STR2(s->s) + s->s->len, str, len); } s->known_shift = shift; } else { string_build_mkspace (s, len, 0); if (s->s->size_shift == 0) convert_2_to_0 (STR0(s->s) + s->s->len, str, len); else { #ifdef PIKE_DEBUG if (s->s->size_shift != 1) Pike_fatal ("This is soo way bogus, man. (%d)\n", s->s->size_shift); #endif convert_2_to_1 (STR1(s->s) + s->s->len, str, len); } } } else { string_build_mkspace (s, len, 2); convert_2_to_2 (STR2(s->s) + s->s->len, str, len); } s->s->len += len; /* 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) {
024adc2004-11-14Martin Stjernholm  int shift = from.shift; if (shift > s->s->size_shift) {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  if (shift == 1) { shift = find_magnitude1((p_wchar1 *)from.ptr, len); } else { shift = find_magnitude2((p_wchar2 *)from.ptr, len); }
024adc2004-11-14Martin Stjernholm  if (shift > s->known_shift) s->known_shift = shift;
4a5e3f2000-11-25Henrik Grubbström (Grubba)  } 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)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Cannot fill with zero length strings!\n");
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) #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) { 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) }
357a522011-04-22Henrik Grubbström (Grubba) /* Append a NUL-terminated UTF16 string possibly containing surrogates. */ PMOD_EXPORT void string_builder_utf16_strcat(struct string_builder *s, const p_wchar1 *utf16str) { p_wchar1 uc; while ((uc = *(utf16str++))) { if ((uc & 0xf800) == 0xd800) { /* Surrogate. */ p_wchar2 wchar = uc & 0x03ff; if (!(uc & 0x0400)) { /* High order 10 bits. */ wchar <<= 10; } uc = *(utf16str++); if (uc & 0x0400) { /* Low order 10 bits. */ wchar |= (uc & 0x3ff); } else { /* High order 10 bits. */ wchar |= (uc & 0x3ff) << 10; } string_builder_putchar(s, wchar + 0x00010000); } else { string_builder_putchar(s, uc); } } }
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);
6f18712004-11-14Martin Stjernholm  s->known_shift=MAXIMUM(s->known_shift,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) }
711f442006-03-20Henrik Grubbström (Grubba) PMOD_EXPORT ptrdiff_t string_builder_quote_string(struct string_builder *buf, struct pike_string *str, ptrdiff_t i, ptrdiff_t max_len, int flags)
64b0772006-03-20Henrik Grubbström (Grubba) { ptrdiff_t old_len = buf->s->len;
711f442006-03-20Henrik Grubbström (Grubba)  for (; i < str->len; i++) {
64b0772006-03-20Henrik Grubbström (Grubba)  p_wchar2 ch = index_shared_string(str, i);
2eaf022008-06-29Marcus Comstedt  if (ch < 0 || ch > 0xffff) {
64b0772006-03-20Henrik Grubbström (Grubba)  /* Huge character. */ string_builder_binary_strcat(buf, "\\U", 2); string_builder_append_integer(buf, ch, 16, APPEND_ZERO_PAD, 8, 8); } else if (ch > 0xff) { /* Unicode character. */ string_builder_binary_strcat(buf, "\\u", 2); string_builder_append_integer(buf, ch, 16, APPEND_ZERO_PAD, 4, 4); } else if (ch & 0x60) { /* Printable character or DEL. */ if (ch == '\177') { /* DEL */
a66b812009-04-10Henrik Grubbström (Grubba)  goto ctrl_char;
64b0772006-03-20Henrik Grubbström (Grubba)  } else if ((ch == '"') || (ch == '\\')) { string_builder_putchar(buf, '\\'); } string_builder_putchar(buf, ch); } else { p_wchar2 next_ch;
34f38e2009-04-10Henrik Grubbström (Grubba)  ctrl_char:
64b0772006-03-20Henrik Grubbström (Grubba)  /* Control character. */ string_builder_putchar(buf, '\\'); if ((ch > 6) && (ch < 14)) { string_builder_putchar(buf, "0123456abtnvfr"[ch]);
711f442006-03-20Henrik Grubbström (Grubba)  if ((ch == 10) && (flags & QUOTE_BREAK_AT_LF)) { if (buf->s->len > max_len) { /* Too bad; no place for the lf. */ buf->s->len = old_len; return i; } return i+1; }
89347a2006-03-20Henrik Grubbström (Grubba)  goto next;
64b0772006-03-20Henrik Grubbström (Grubba)  } if (ch == 27) { string_builder_putchar(buf, 'e');
89347a2006-03-20Henrik Grubbström (Grubba)  goto next;
64b0772006-03-20Henrik Grubbström (Grubba)  } /* Check if we can use an octal escape. */ if ((i+1 < str->len) && ((next_ch = index_shared_string(str, i+1)) >= '0') && (next_ch <= '7')) { /* No. */ if (flags & QUOTE_NO_STRING_CONCAT) { string_builder_putchar(buf, 'u');
ee01802006-03-20Henrik Grubbström (Grubba)  string_builder_append_integer(buf, ch, 16, APPEND_ZERO_PAD, 4, 4);
64b0772006-03-20Henrik Grubbström (Grubba)  } else { string_builder_append_integer(buf, ch, 8, 0, 1, 1); string_builder_binary_strcat(buf, "\"\"", 2); }
89347a2006-03-20Henrik Grubbström (Grubba)  goto next;
64b0772006-03-20Henrik Grubbström (Grubba)  } string_builder_append_integer(buf, ch, 8, 0, 1, 1); }
89347a2006-03-20Henrik Grubbström (Grubba)  next:
64b0772006-03-20Henrik Grubbström (Grubba)  if (buf->s->len > max_len) { buf->s->len = old_len;
711f442006-03-20Henrik Grubbström (Grubba)  return i;
64b0772006-03-20Henrik Grubbström (Grubba)  } old_len = buf->s->len; }
711f442006-03-20Henrik Grubbström (Grubba)  return i;
64b0772006-03-20Henrik Grubbström (Grubba) }
8be4822004-11-06Henrik Grubbström (Grubba) PMOD_EXPORT void string_builder_append_integer(struct string_builder *s, LONGEST val, unsigned int base,
bcc5892004-11-06Henrik Grubbström (Grubba)  int flags, size_t min_width, size_t precision)
8be4822004-11-06Henrik Grubbström (Grubba) { unsigned LONGEST tmp;
bcc5892004-11-06Henrik Grubbström (Grubba)  size_t len = 1;
8be4822004-11-06Henrik Grubbström (Grubba)  const char *numbers = "0123456789abcdef"; if ((base < 2) || (base > 16)) { Pike_fatal("string_builder_append_int(): Unsupported base %u.\n", base); } if (flags & APPEND_UPPER_CASE) { numbers = "0123456789ABCDEF"; } if ((flags & APPEND_SIGNED) && (val < 0)) { string_builder_putchar(s, '-'); val = -val; } else if (flags & APPEND_POSITIVE) { string_builder_putchar(s, '+'); }
bcc5892004-11-06Henrik Grubbström (Grubba)  if ((flags & APPEND_ZERO_PAD) && (precision < min_width)) { precision = min_width; }
8be4822004-11-06Henrik Grubbström (Grubba)  tmp = val; if (base & (base - 1)) {
4569462013-02-07Henrik Grubbström (Grubba)  size_t cnt;
8be4822004-11-06Henrik Grubbström (Grubba)  /* Calculate the output length. * Use do-while to ensure that zero isn't output as an empty string. */
bcc5892004-11-06Henrik Grubbström (Grubba)  len = 0;
8be4822004-11-06Henrik Grubbström (Grubba)  do { len++; tmp /= base; } while (tmp);
bcc5892004-11-06Henrik Grubbström (Grubba)  /* Precision is minimum number of digits. */ if (len < precision) len = precision; /* Perform padding. */
6f74712013-02-07Henrik Grubbström (Grubba)  if (!(flags & APPEND_LEFT)) { if (len < min_width) { string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); }
bcc5892004-11-06Henrik Grubbström (Grubba)  min_width = 0; }
4569462013-02-07Henrik Grubbström (Grubba)  cnt = len;
8be4822004-11-06Henrik Grubbström (Grubba)  tmp = val; switch(s->s->size_shift) { case 0: { p_wchar0 *p = string_builder_allocate(s, len, 0); do {
4569462013-02-07Henrik Grubbström (Grubba)  p[--cnt] = numbers[tmp%base];
8be4822004-11-06Henrik Grubbström (Grubba)  tmp /= base;
4569462013-02-07Henrik Grubbström (Grubba)  } while (cnt);
8be4822004-11-06Henrik Grubbström (Grubba)  } break; case 1: { p_wchar1 *p = string_builder_allocate(s, len, 0); do {
4569462013-02-07Henrik Grubbström (Grubba)  p[--cnt] = numbers[tmp%base];
8be4822004-11-06Henrik Grubbström (Grubba)  tmp /= base;
4569462013-02-07Henrik Grubbström (Grubba)  } while (cnt);
8be4822004-11-06Henrik Grubbström (Grubba)  } break; case 2: { p_wchar2 *p = string_builder_allocate(s, len, 0); do {
4569462013-02-07Henrik Grubbström (Grubba)  p[--cnt] = numbers[tmp%base];
8be4822004-11-06Henrik Grubbström (Grubba)  tmp /= base;
4569462013-02-07Henrik Grubbström (Grubba)  } while (cnt);
8be4822004-11-06Henrik Grubbström (Grubba)  } break; } } else { /* base is a power of two, so we can do without * the division and modulo operations. */ int delta;
bcc5892004-11-06Henrik Grubbström (Grubba)  size_t shift;
8be4822004-11-06Henrik Grubbström (Grubba)  unsigned int mask; for(delta = 1; (base>>delta) > 1; delta++) ; mask = (1<<delta)-1; /* Usually base-1. */
bcc5892004-11-06Henrik Grubbström (Grubba)  /* Precision is minimum number of digits. */ if (precision) shift = (len = precision) * delta; else shift = delta; /* Calculate actual number of digits and initial shift. */
fc6ea02008-07-18Martin Stjernholm  for (; tmp >> shift && shift < SIZEOF_LONGEST * 8; shift += delta, len++)
8be4822004-11-06Henrik Grubbström (Grubba)  ;
bcc5892004-11-06Henrik Grubbström (Grubba)  if ((len < min_width) && !(flags & APPEND_LEFT)) { /* Perform padding. * Note that APPEND_ZERO_PAD can not be active here, since * len is at least min_width in that case. */ string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); min_width = 0; } while(shift) {
8be4822004-11-06Henrik Grubbström (Grubba)  shift -= delta;
bcc5892004-11-06Henrik Grubbström (Grubba)  string_builder_putchar(s, numbers[(tmp>>shift) & mask]);
8be4822004-11-06Henrik Grubbström (Grubba)  } }
bcc5892004-11-06Henrik Grubbström (Grubba)  if (len < min_width) { /* Perform padding. * Note that APPEND_ZERO_PAD can not be active here, since * len is at least min_width in that case. * Note that APPEND_LEFT is always active here, since * min_width isn't zero. */ string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); }
4170b92004-11-06Henrik Grubbström (Grubba) }
bcc5892004-11-06Henrik Grubbström (Grubba) 
46a4ce2004-11-09Henrik Grubbström (Grubba) /* Kludge around brokeness of gcc/x86_64 */ #ifdef VA_LIST_IS_STATE_PTR #define VA_LIST_PTR va_list #define VA_LIST_ADDR(X) (X) #define VA_LIST_DEREF(X) (X) #else #define VA_LIST_PTR va_list * #define VA_LIST_ADDR(X) (&(X)) #define VA_LIST_DEREF(X) (*(X)) #endif static LONGEST pike_va_int(VA_LIST_PTR args, int flags)
4170b92004-11-06Henrik Grubbström (Grubba) { switch (flags & (APPEND_WIDTH_MASK|APPEND_SIGNED)) { case APPEND_WIDTH_HALF:
46a4ce2004-11-09Henrik Grubbström (Grubba)  return va_arg(VA_LIST_DEREF(args), unsigned int) & 0xffff;
4170b92004-11-06Henrik Grubbström (Grubba)  case APPEND_WIDTH_HALF|APPEND_SIGNED:
46a4ce2004-11-09Henrik Grubbström (Grubba)  return (short)va_arg(VA_LIST_DEREF(args), int);
4170b92004-11-06Henrik Grubbström (Grubba)  case 0:
46a4ce2004-11-09Henrik Grubbström (Grubba)  return va_arg(VA_LIST_DEREF(args), unsigned int);
4170b92004-11-06Henrik Grubbström (Grubba)  case APPEND_SIGNED:
46a4ce2004-11-09Henrik Grubbström (Grubba)  return va_arg(VA_LIST_DEREF(args), int);
4170b92004-11-06Henrik Grubbström (Grubba)  case APPEND_WIDTH_LONG:
46a4ce2004-11-09Henrik Grubbström (Grubba)  return va_arg(VA_LIST_DEREF(args), unsigned long);
4170b92004-11-06Henrik Grubbström (Grubba)  case APPEND_WIDTH_LONG|APPEND_SIGNED:
46a4ce2004-11-09Henrik Grubbström (Grubba)  return va_arg(VA_LIST_DEREF(args), long);
4170b92004-11-06Henrik Grubbström (Grubba) #ifdef INT64 case APPEND_WIDTH_LONG_LONG:
46a4ce2004-11-09Henrik Grubbström (Grubba)  return va_arg(VA_LIST_DEREF(args), unsigned INT64);
4170b92004-11-06Henrik Grubbström (Grubba)  case APPEND_WIDTH_LONG_LONG|APPEND_SIGNED:
46a4ce2004-11-09Henrik Grubbström (Grubba)  return va_arg(VA_LIST_DEREF(args), INT64);
4170b92004-11-06Henrik Grubbström (Grubba) #endif /* INT64 */ }
6cde652004-11-08Henrik Grubbström (Grubba)  Pike_fatal("string_builder_append_integerv(): Unsupported flags: 0x%04x\n", flags); return 0;
8be4822004-11-06Henrik Grubbström (Grubba) }
686ef22004-11-11Henrik Grubbström (Grubba) /* Values used internally in string_builder_vsprintf() */ #define STATE_MIN_WIDTH 1 #define STATE_PRECISION 2
f619da2004-11-05Henrik Grubbström (Grubba) PMOD_EXPORT void string_builder_vsprintf(struct string_builder *s, const char *fmt, va_list args) { while (*fmt) { if (*fmt == '%') {
bcc5892004-11-06Henrik Grubbström (Grubba)  int flags = 0; size_t min_width = 0; size_t precision = 0; int state = 0;
f619da2004-11-05Henrik Grubbström (Grubba)  fmt++;
e9864c2004-11-06Henrik Grubbström (Grubba)  while (1) { switch (*(fmt++)) { case '%': string_builder_putchar(s, '%'); break;
7a1f0e2004-11-06Henrik Grubbström (Grubba) 
bcc5892004-11-06Henrik Grubbström (Grubba)  case '+': flags |= APPEND_POSITIVE;
7a1f0e2004-11-06Henrik Grubbström (Grubba)  continue;
bcc5892004-11-06Henrik Grubbström (Grubba)  case '-': flags |= APPEND_LEFT;
7a1f0e2004-11-06Henrik Grubbström (Grubba)  continue;
bcc5892004-11-06Henrik Grubbström (Grubba)  case '0': if (!state) { flags |= APPEND_ZERO_PAD; } /* FALL_THROUGH */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
f4193c2004-11-06Henrik Grubbström (Grubba)  if (state == STATE_PRECISION) {
24d0c12004-11-06Henrik Grubbström (Grubba)  precision = precision * 10 + fmt[-1] - '0';
bcc5892004-11-06Henrik Grubbström (Grubba)  } else { state = STATE_MIN_WIDTH;
24d0c12004-11-06Henrik Grubbström (Grubba)  min_width = min_width * 10 + fmt[-1] - '0';
bcc5892004-11-06Henrik Grubbström (Grubba)  }
7a1f0e2004-11-06Henrik Grubbström (Grubba)  continue;
f4193c2004-11-06Henrik Grubbström (Grubba) 
bcc5892004-11-06Henrik Grubbström (Grubba)  case '.': state = STATE_PRECISION;
7a1f0e2004-11-06Henrik Grubbström (Grubba)  continue;
4170b92004-11-06Henrik Grubbström (Grubba)  case 'h': flags |= APPEND_WIDTH_HALF; continue;
7b9fd12004-11-06Henrik Grubbström (Grubba) 
5382542004-11-06Henrik Grubbström (Grubba)  case 'w': /* Same as l, but old-style, and only for %s. */
4170b92004-11-06Henrik Grubbström (Grubba)  case 'l': if (flags & APPEND_WIDTH_LONG) { flags |= APPEND_WIDTH_LONG_LONG; } else { flags |= APPEND_WIDTH_LONG; } continue;
1d15d42004-11-11Henrik Grubbström (Grubba)  case 't': /* ptrdiff_t */ case 'z': /* size_t */ flags = (flags & ~APPEND_WIDTH_MASK) | APPEND_WIDTH_PTR; continue;
bcc5892004-11-06Henrik Grubbström (Grubba) 
e9864c2004-11-06Henrik Grubbström (Grubba)  case 'O': {
8a2cd62004-11-06Henrik Grubbström (Grubba)  /* FIXME: Doesn't care about field or integer widths yet. */
e9864c2004-11-06Henrik Grubbström (Grubba)  dynamic_buffer old_buf; init_buf(&old_buf); describe_svalue(va_arg(args, struct svalue *), 0, NULL); string_builder_binary_strcat(s, pike_global_buffer.s.str, pike_global_buffer.s.len); toss_buffer(&pike_global_buffer); restore_buffer(&old_buf); } break; case 'S':
7b9fd12004-11-06Henrik Grubbström (Grubba)  /* Note: On some platforms this is an alias for %ls, so if you * want to output wchar_t strings, use %ls instead! */
bcc5892004-11-06Henrik Grubbström (Grubba)  { struct pike_string *str = va_arg(args, struct pike_string *); size_t len = str->len; if (precision && (precision < len)) len = precision; if (min_width > len) { if (flags & APPEND_LEFT) { string_builder_append(s, MKPCHARP_STR(str), len); string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); } else { string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); string_builder_append(s, MKPCHARP_STR(str), len); } } else { string_builder_append(s, MKPCHARP_STR(str), len); } }
e9864c2004-11-06Henrik Grubbström (Grubba)  break; case 's':
7b9fd12004-11-06Henrik Grubbström (Grubba)  if (flags & APPEND_WIDTH_LONG) { /* Wide string: %ws, %ls or %lls */ PCHARP str; size_t len; if ((flags & APPEND_WIDTH_LONG)== APPEND_WIDTH_LONG) { str = MKPCHARP(va_arg(args, p_wchar1 *), 1); } else { str = MKPCHARP(va_arg(args, p_wchar2 *), 2); } len = pcharp_strlen(str); if (precision && precision < len) len = precision; if (min_width > len) { if (flags & APPEND_LEFT) { string_builder_append(s, str, len); string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); } else { string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); string_builder_append(s, str, len); } } else { string_builder_append(s, str, len); } } else {
e9864c2004-11-06Henrik Grubbström (Grubba)  const char *str = va_arg(args, char *);
bcc5892004-11-06Henrik Grubbström (Grubba)  size_t len = strlen(str); if (precision && precision < len) len = precision; if (min_width > len) { if (flags & APPEND_LEFT) { string_builder_binary_strcat(s, str, len); string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); } else { string_builder_fill(s, min_width - len, MKPCHARP(" ", 0), 4, 0); string_builder_binary_strcat(s, str, len); } } else { string_builder_binary_strcat(s, str, len); }
e9864c2004-11-06Henrik Grubbström (Grubba)  } break; case 'c':
8a2cd62004-11-06Henrik Grubbström (Grubba)  /* FIXME: Doesn't care about field or integer widths yet. */
4170b92004-11-06Henrik Grubbström (Grubba)  string_builder_putchar(s, va_arg(args, int));
e9864c2004-11-06Henrik Grubbström (Grubba)  break; case 'b':
46a4ce2004-11-09Henrik Grubbström (Grubba)  string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 2,
6cde652004-11-08Henrik Grubbström (Grubba)  flags, min_width, precision);
e9864c2004-11-06Henrik Grubbström (Grubba)  break; case 'o':
46a4ce2004-11-09Henrik Grubbström (Grubba)  string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 8,
6cde652004-11-08Henrik Grubbström (Grubba)  flags, min_width, precision);
e9864c2004-11-06Henrik Grubbström (Grubba)  break; case 'x':
46a4ce2004-11-09Henrik Grubbström (Grubba)  string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 16,
6cde652004-11-08Henrik Grubbström (Grubba)  flags, min_width, precision);
e9864c2004-11-06Henrik Grubbström (Grubba)  break; case 'X':
46a4ce2004-11-09Henrik Grubbström (Grubba)  string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 16,
6cde652004-11-08Henrik Grubbström (Grubba)  flags | APPEND_UPPER_CASE, min_width, precision);
e9864c2004-11-06Henrik Grubbström (Grubba)  break; case 'u':
46a4ce2004-11-09Henrik Grubbström (Grubba)  string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 10,
6cde652004-11-08Henrik Grubbström (Grubba)  flags, min_width, precision);
e9864c2004-11-06Henrik Grubbström (Grubba)  break; case 'd':
cc9fcb2005-03-09Martin Stjernholm  flags |= APPEND_SIGNED;
46a4ce2004-11-09Henrik Grubbström (Grubba)  string_builder_append_integer(s, pike_va_int(VA_LIST_ADDR(args), flags), 10,
cc9fcb2005-03-09Martin Stjernholm  flags, min_width, precision);
e9864c2004-11-06Henrik Grubbström (Grubba)  break;
7b9fd12004-11-06Henrik Grubbström (Grubba) 
686ef22004-11-11Henrik Grubbström (Grubba)  /* %f used in modules/Image/colors.c. */
f74ecc2009-11-30Arne Goedeke  case 'a': case 'e': case 'E':
686ef22004-11-11Henrik Grubbström (Grubba)  case 'f':
f74ecc2009-11-30Arne Goedeke  case 'g': case 'G':
686ef22004-11-11Henrik Grubbström (Grubba)  { double val = va_arg(args, double); size_t bytes;
f74ecc2009-11-30Arne Goedeke  char nfmt[] = { '%', fmt[-1], 0 };
686ef22004-11-11Henrik Grubbström (Grubba)  if (PIKE_ISNAN(val)) { /* NaN */ string_builder_strcat(s, "nan"); break; } if (val < 0.0) { string_builder_putchar(s, '-'); val = -val; } else if (flags & APPEND_SIGNED) { string_builder_putchar(s, '+'); }
f74ecc2009-11-30Arne Goedeke  if ((val+val == val) && (val > 0.0)) { /* Infinity */ string_builder_strcat(s, "inf");
686ef22004-11-11Henrik Grubbström (Grubba)  break; } /* FIXME: Field lengths and precision. */
f74ecc2009-11-30Arne Goedeke  if ((bytes = SNPRINTF(NULL, 0, nfmt, val))) {
686ef22004-11-11Henrik Grubbström (Grubba)  p_wchar0 *p = string_builder_allocate(s, bytes, 0);
f74ecc2009-11-30Arne Goedeke  size_t check = SNPRINTF((char*)p, bytes+1, nfmt, val);
686ef22004-11-11Henrik Grubbström (Grubba)  if (check != bytes) {
f74ecc2009-11-30Arne Goedeke  Pike_fatal("string_builder_vsprintf(): snprintf(\"%s\", %f) " "is not trustworthy: " "%"PRINTSIZET"u != %"PRINTSIZET"u\n", nfmt, val, bytes, check);
686ef22004-11-11Henrik Grubbström (Grubba)  } if (s->s->size_shift) { /* We need to widen the string we just wrote. */ if (s->s->size_shift == 1) { p_wchar1 *p1 = (p_wchar1 *)p; while (bytes--) { p1[bytes] = p[bytes]; } } else { p_wchar2 *p2 = (p_wchar2 *)p; while (bytes--) { p2[bytes] = p[bytes]; } } } } } break;
7b9fd12004-11-06Henrik Grubbström (Grubba) 
e9864c2004-11-06Henrik Grubbström (Grubba)  default: Pike_fatal("string_builder_vsprintf(): Invalid formatting method: "
f74ecc2009-11-30Arne Goedeke  "\"%%%c\" 0x%x.\n", (fmt[-1] & 0xff), fmt[-1]);
f619da2004-11-05Henrik Grubbström (Grubba)  } break; } } else { const char *start = fmt; while (*fmt && (*fmt != '%')) fmt++; string_builder_binary_strcat(s, start, fmt-start); } } }
46a4ce2004-11-09Henrik Grubbström (Grubba) 
f619da2004-11-05Henrik Grubbström (Grubba) PMOD_EXPORT void string_builder_sprintf(struct string_builder *s, const char *fmt, ...) { va_list args; va_start(args, fmt); string_builder_vsprintf(s, fmt, args); va_end(args); }
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 */
e8371e2008-06-23Martin Stjernholm  low_set_index (s->s, 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;
9cd0372005-11-03Henrik Grubbström (Grubba)  free_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) {
e464e02008-06-23Martin Stjernholm  ptrdiff_t len = s->s->len; if (len != s->malloced) {
4a5e3f2000-11-25Henrik Grubbström (Grubba)  s->s->len = s->malloced; s->s = realloc_unlinked_string(s->s, len); }
e464e02008-06-23Martin Stjernholm  else /* Ensure NUL-termination */ low_set_index(s->s,s->s->len,0);
6f18712004-11-14Martin Stjernholm  if(s->known_shift == 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) {
66d9282011-05-01Per Hedbor  case 0: return MKPCHARP(MEMCHR(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)  }
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
5aad932002-08-15Marcus Comstedt  Pike_fatal("Illegal shift in MEMCHR_PCHARP.\n");
c6b6042008-05-03Martin Nilsson #endif
efae671998-10-21Fredrik Hübinette (Hubbe)  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) {
90784a2003-02-26Martin Stjernholm  /* Note: Code duplication in STRTOL and pcharp_to_svalue_inumber. */ unsigned long val, mul_limit; int c; int xx, neg = 0, add_limit, overflow = 0;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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)  {
90784a2003-02-26Martin Stjernholm  while (WIDE_ISSPACE(c))
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  { INC_PCHARP(str,1); c=EXTRACT_PCHARP(str); } switch (c) { case '-': neg++;
f74ecc2009-11-30Arne Goedeke  /* FALL_THROUGH */ case '+':
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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" */ }
90784a2003-02-26Martin Stjernholm 
a549642003-03-17Henrik Grubbström (Grubba)  mul_limit = ((unsigned long)LONG_MAX)/base; add_limit = (int) (LONG_MAX % base);
90784a2003-02-26Martin Stjernholm  if (neg) {
a549642003-03-17Henrik Grubbström (Grubba)  if (++add_limit == base) { add_limit = 0; mul_limit++; }
90784a2003-02-26Martin Stjernholm  } val=DIGIT(c);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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;
a549642003-03-17Henrik Grubbström (Grubba)  if (val > mul_limit || (val == mul_limit && xx > add_limit)) {
90784a2003-02-26Martin Stjernholm  overflow = 1;
a549642003-03-17Henrik Grubbström (Grubba)  } else
90784a2003-02-26Martin Stjernholm  val = base * val + xx;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  }
90784a2003-02-26Martin Stjernholm 
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  if (ptr) *ptr = str;
90784a2003-02-26Martin Stjernholm  if (overflow) { errno = ERANGE; return neg ? LONG_MIN : LONG_MAX; } else { if (neg)
a549642003-03-17Henrik Grubbström (Grubba)  return (long)(~val + 1);
90784a2003-02-26Martin Stjernholm  else return (long) val; }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) }
efae671998-10-21Fredrik Hübinette (Hubbe) 
66d9282011-05-01Per Hedbor /* static 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; }
66d9282011-05-01Per Hedbor */
011ad31999-10-22Fredrik Hübinette (Hubbe) 
66d9282011-05-01Per Hedbor int wide_string_to_svalue_inumber(struct svalue *r,
8c37d12000-08-15Henrik Grubbström (Grubba)  void * str,
f4778d2003-07-30Martin Stjernholm  void *ptr,
8c37d12000-08-15Henrik Grubbström (Grubba)  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);
f4778d2003-07-30Martin Stjernholm  if(ptr) *(p_wchar0 **)ptr=tmp.ptr;
011ad31999-10-22Fredrik Hübinette (Hubbe)  return ret; }
15f63a2008-07-23Martin Stjernholm int safe_wide_string_to_svalue_inumber(struct svalue *r, void * str, void *ptr, int base, ptrdiff_t maxlength, int shift) /* For use from the lexer where we can't let errors be thrown. */ { PCHARP tmp; JMP_BUF recovery; int ret = 0; free_svalue (&throw_value); mark_free_svalue (&throw_value); if (SETJMP (recovery)) { /* We know that pcharp_to_svalue_inumber has initialized the * svalue before any error might be thrown. */ call_handle_error(); ret = 0; } else ret = pcharp_to_svalue_inumber(r, MKPCHARP(str,shift), &tmp, base, maxlength); UNSETJMP (recovery); if(ptr) *(p_wchar0 **)ptr=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 {
90784a2003-02-26Martin Stjernholm  /* Note: Code duplication in STRTOL and STRTOL_PCHARP. */
011ad31999-10-22Fredrik Hübinette (Hubbe)  PCHARP str_start;
31ea271999-10-22Fredrik Noring 
90784a2003-02-26Martin Stjernholm  unsigned INT_TYPE val, mul_limit; int c; int xx, neg = 0, add_limit, overflow = 0;
31ea271999-10-22Fredrik Noring  maxlength--; /* max_length <= 0 means no max length. */ str_start = str; /* In case no number is formed. */
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(*r, T_INT, NUMBER_NUMBER, integer, 0);
31ea271999-10-22Fredrik Noring  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) { 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;
90784a2003-02-26Martin Stjernholm  if (neg) { mul_limit = (unsigned INT_TYPE) MIN_INT_TYPE / base; add_limit = (int) ((unsigned INT_TYPE) MIN_INT_TYPE % base); } else { mul_limit = MAX_INT_TYPE / base; add_limit = (int) (MAX_INT_TYPE % base); }
31ea271999-10-22Fredrik Noring 
90784a2003-02-26Martin Stjernholm  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  {
90784a2003-02-26Martin Stjernholm  if (val > mul_limit || (val == mul_limit && xx > add_limit)) overflow = 1; else val = base * val + xx;
31ea271999-10-22Fredrik Noring  } if(ptr != 0) *ptr = str;
90784a2003-02-26Martin Stjernholm  if (overflow) {
31ea271999-10-22Fredrik Noring #ifdef AUTO_BIGNUM
011ad31999-10-22Fredrik Hübinette (Hubbe)  push_string(make_shared_binary_pcharp(str_start, SUBTRACT_PCHARP(str,str_start)));
90784a2003-02-26Martin Stjernholm  /* Note that this can conceivably throw errors()
011ad31999-10-22Fredrik Hübinette (Hubbe)  * 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 
9b150a2002-05-11Martin Nilsson  *r = *--Pike_sp;
90784a2003-02-26Martin Stjernholm  dmalloc_touch_svalue (r); #else /* !AUTO_BIGNUM */ r->u.integer = neg ? MIN_INT_TYPE : MAX_INT_TYPE; #endif
31ea271999-10-22Fredrik Noring  }
90784a2003-02-26Martin Stjernholm  else { if (neg) r->u.integer = val > (unsigned INT_TYPE) MAX_INT_TYPE ? -(INT_TYPE) (val - (unsigned INT_TYPE) MAX_INT_TYPE) - MAX_INT_TYPE : -(INT_TYPE) val; else r->u.integer = (INT_TYPE) val; }
31ea271999-10-22Fredrik Noring  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 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-1]) != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Cannot convert stack top to integer number.\n");
31ea271999-10-22Fredrik Noring 
9b150a2002-05-11Martin Nilsson  i=pcharp_to_svalue_inumber(&r, MKPCHARP_STR(Pike_sp[-1].u.string), 0, base, 0);
31ea271999-10-22Fredrik Noring 
9b150a2002-05-11Martin Nilsson  free_string(Pike_sp[-1].u.string); Pike_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) {
71d7d52003-02-26Martin Stjernholm  /* Note: Code duplication in STRTOD. */
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'. */
7ad4122003-10-03Henrik Grubbström (Grubba)  /* NOTE: Don't trust the value returned from STRTOL. * We need to find the sign of the exponent by hand. */ p_wchar2 c; while(WIDE_ISSPACE(c = EXTRACT_PCHARP(s))) { INC_PCHARP(s, 1); }
f3ece81999-02-28Fredrik Hübinette (Hubbe)  if (endptr != NULL) *endptr = end;
7ad4122003-10-03Henrik Grubbström (Grubba)  if (c == '-')
f3ece81999-02-28Fredrik Hübinette (Hubbe)  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;
90784a2003-02-26Martin Stjernholm  return HUGE_VAL * sign;
f3ece81999-02-28Fredrik Hübinette (Hubbe)  underflow:
a4a1722000-12-05Per Hedbor  /* Return an underflow error. */
71d7d52003-02-26Martin Stjernholm #if 0
f3ece81999-02-28Fredrik Hübinette (Hubbe)  if (endptr != NULL) *endptr = nptr;
71d7d52003-02-26Martin Stjernholm #endif
f3ece81999-02-28Fredrik Hübinette (Hubbe)  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;
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
efae671998-10-21Fredrik Hübinette (Hubbe)  default:
5aad932002-08-15Marcus Comstedt  Pike_fatal("Illegal shift size in string.\n");
c6b6042008-05-03Martin Nilsson #endif
efae671998-10-21Fredrik Hübinette (Hubbe)  } 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;
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
efae671998-10-21Fredrik Hübinette (Hubbe)  default:
5aad932002-08-15Marcus Comstedt  Pike_fatal("Illegal shift size in string.\n");
c6b6042008-05-03Martin Nilsson #endif
efae671998-10-21Fredrik Hübinette (Hubbe)  } 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);
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
efae671998-10-21Fredrik Hübinette (Hubbe)  default:
5aad932002-08-15Marcus Comstedt  Pike_fatal("Illegal shift size in string.\n");
c6b6042008-05-03Martin Nilsson #endif
efae671998-10-21Fredrik Hübinette (Hubbe)  } return 0; }