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"
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"
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) 
85df3f2015-07-24Per Hedbor #define HMODULO(X) ((X) & (string_hash.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) 
85df3f2015-07-24Per Hedbor // starting hilfe creates 6128 strings. #define BEGIN_HASH_SIZE 16384
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) 
8282ca2013-11-02Per Hedbor static unsigned int hash_prefix_len=64;
6ed3d22005-01-17Henrik Grubbström (Grubba) static unsigned int need_more_hash_prefix_depth=0;
abce512013-11-06Arne Goedeke static unsigned int need_new_hashkey_depth=0;
85df3f2015-07-24Per Hedbor 
e9d7c52013-11-02Per Hedbor static size_t hashkey = 0;
0169c62011-12-30Henrik Grubbström (Grubba) 
85df3f2015-07-24Per Hedbor static struct {
81189d2015-07-25Per Hedbor  struct pike_string **__restrict__ table;
85df3f2015-07-24Per Hedbor  size_t size; size_t limit; /* size * 0.8, aproximately. */ size_t num_strings; size_t mask; } string_hash;
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) 
8282ca2013-11-02Per Hedbor #define low_do_hash(STR,LEN,SHIFT) low_hashmem( (STR), (LEN)<<(SHIFT), hash_prefix_len<<(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) 
a495ca2014-08-23Arne Goedeke static INLINE int __attribute((unused)) string_is_block_allocated(const struct pike_string * s) { return (s->flags & STRING_ALLOC_MASK) == STRING_ALLOC_BA; } static INLINE int __attribute((unused)) string_is_malloced(const struct pike_string * s) { return (s->flags & STRING_ALLOC_MASK) == STRING_ALLOC_MALLOC; } static INLINE int __attribute((unused)) string_is_static(const struct pike_string * s) { return (s->flags & STRING_ALLOC_MASK) == STRING_ALLOC_STATIC; } static INLINE int __attribute((unused)) string_may_modify(const struct pike_string * s) { return !string_is_static(s) && s->refs == 1; }
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;
37647e2013-11-03Tobias S. Josefowitz  ptrdiff_t i;
9925512013-05-31Per Hedbor  if( loose || ((str->flags & STRING_CONTENT_CHECKED ) && (!str->size_shift || !max)) ) { if( str->flags & STRING_CONTENT_CHECKED ) {
f1298d2014-07-02Arne Goedeke  switch (str->size_shift) { case eightbit: s_min = str->min; s_max = str->max; break; case sixteenbit: s_min = str->min; s_max = str->max; s_min *= 256; s_max *= 256; s_max += 255; break; case thirtytwobit: { unsigned INT32 tmp; tmp = str->min; tmp *= (1 << 24); s_min = tmp; tmp = str->max; tmp *= (1 << 24); tmp += (1 << 24) - 1; s_max = tmp; break; }
9925512013-05-31Per Hedbor  } } 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 ) {
3a059b2013-06-09Chris Angelico  if( !lower )
9925512013-05-31Per Hedbor  str->flags |= STRING_IS_UPPERCASE;
3a059b2013-06-09Chris Angelico  if( !upper )
9925512013-05-31Per Hedbor  str->flags |= STRING_IS_LOWERCASE; } } 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; } }
f1298d2014-07-02Arne Goedeke  str->min = s_min / 256; str->max = s_max / 256;
9925512013-05-31Per Hedbor  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; } }
f1298d2014-07-02Arne Goedeke  str->min = (unsigned INT32)s_min / (1 << 24); str->max = (unsigned INT32)s_max / (1 << 24);
9925512013-05-31Per Hedbor  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; }
a9b8172014-04-05Martin Nilsson static INLINE int min_magnitude(const 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; }
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
119e1e2014-08-22Arne Goedeke 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,
a9b8172014-04-05Martin Nilsson  const PCHARP from,
66d9282011-05-01Per Hedbor  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; } }
a9b8172014-04-05Martin Nilsson PMOD_EXPORT void pike_string_cpy(PCHARP to, const 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
a9b8172014-04-05Martin Nilsson PMOD_EXPORT p_wchar2 index_shared_string(const struct pike_string *s,
e9117b2014-02-25Per Hedbor  ptrdiff_t pos) { 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); } } return generic_extract(s->str,s->size_shift,pos); } PMOD_EXPORT p_wchar2 generic_extract (const void *str, int size, ptrdiff_t pos) { switch(size) { case 0: return ((p_wchar0 *)str)[pos]; case 1: return ((p_wchar1 *)str)[pos]; case 2: return ((p_wchar2 *)str)[pos]; } Pike_fatal("Unsupported string shift: %d\n", size); return 0; }
abe3a82014-05-06Arne Goedeke static void locate_problem(int (*isproblem)(const struct pike_string *))
2043ba1998-02-10Fredrik Hübinette (Hubbe) { 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) 
85df3f2015-07-24Per Hedbor  for(e=0;e<string_hash.size;e++)
9e52381998-03-01Fredrik Hübinette (Hubbe)  {
81189d2015-07-25Per Hedbor  if( (s = string_table.table[e]) )
9e52381998-03-01Fredrik Hübinette (Hubbe)  { if(isproblem(s)) { fprintf(stderr,"***Guilty string:\n"); debug_dump_pike_string(s, 70); DM(add_marks_to_memhdr(yes,s)); }else{ DM(add_marks_to_memhdr(no,s)); } } }
2043ba1998-02-10Fredrik Hübinette (Hubbe) 
9e52381998-03-01Fredrik Hübinette (Hubbe)  DM(fprintf(stderr,"Plausible problem location(s):\n"));
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) }
a9b8172014-04-05Martin Nilsson static int bad_pointer(const struct pike_string *s)
4bdf5f2001-03-30Henrik Grubbström (Grubba) {
cfc9842001-03-30Henrik Grubbström (Grubba)  return (((ptrdiff_t)s)&(sizeof(struct pike_string *)-1));
4bdf5f2001-03-30Henrik Grubbström (Grubba) }
a9b8172014-04-05Martin Nilsson static int has_zero_refs(const struct pike_string *s)
2043ba1998-02-10Fredrik Hübinette (Hubbe) { return s->refs<=0; }
a9b8172014-04-05Martin Nilsson static int improper_zero_termination(const struct pike_string *s)
2043ba1998-02-10Fredrik Hübinette (Hubbe) {
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) 
85df3f2015-07-24Per Hedbor  #define probe_dist(A,B) ((size_t)HMODULO(((size_t)B)+string_hash.size-(size_t)HMODULO(A)))
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,
a9b8172014-04-05Martin Nilsson  ptrdiff_t len, int size_shift, size_t hval)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
85df3f2015-07-24Per Hedbor  size_t h=HMODULO(hval); size_t dist=0;
8282ca2013-11-02Per Hedbor 
85df3f2015-07-24Per Hedbor  for(;;)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
85df3f2015-07-24Per Hedbor  struct pike_string *probe;
81189d2015-07-25Per Hedbor  if(!(probe=string_hash.table[h]))
85df3f2015-07-24Per Hedbor  return NULL;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
81189d2015-07-25Per Hedbor  if(size_shift == probe->size_shift && len == probe->len && !memcmp(s,probe->str,len<<size_shift)) return probe; if(dist > probe_dist(string_hash.table[h]->hval,h)) return NULL;
85df3f2015-07-24Per Hedbor  dist++; h = HMODULO(h+1);
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  }
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) {
85df3f2015-07-24Per Hedbor  return internal_findstring(foo, l, 0, low_do_hash(foo,l,0));
5267b71995-08-09Fredrik Hübinette (Hubbe) }
eb3d132014-05-10Per Hedbor struct pike_string *binary_findstring_pcharp(PCHARP foo, ptrdiff_t l)
dd4aeb2014-05-05Per Hedbor {
eb3d132014-05-10Per Hedbor  int in = foo.shift; void *tmp = NULL; struct pike_string *res;
4cc4052014-05-10Per Hedbor  if( !foo.shift ) return binary_findstring( (void*)foo.ptr, l );
eb3d132014-05-10Per Hedbor 
4cc4052014-05-10Per Hedbor  if( UNLIKELY(foo.shift == 2) )
eb3d132014-05-10Per Hedbor  foo.shift=find_magnitude2( (void*)foo.ptr, l ); else if( foo.shift == 1 ) foo.shift=find_magnitude1( (void*)foo.ptr, l );
4cc4052014-05-10Per Hedbor  if( UNLIKELY(foo.shift != in) )
eb3d132014-05-10Per Hedbor  { tmp = malloc( l * (1<<foo.shift) ); switch(in) { case 1: convert_1_to_0( tmp, (void*)foo.ptr, l ); break; case 2: if( foo.shift == 1 ) convert_2_to_1( tmp, (void*)foo.ptr, l ); else convert_2_to_0( tmp, (void*)foo.ptr, l ); } foo.ptr = tmp; }
4cc4052014-05-10Per Hedbor  res=internal_findstring((void*)foo.ptr, l, foo.shift,
eb3d132014-05-10Per Hedbor  low_do_hash(foo.ptr,l,foo.shift)); if( tmp ) free( tmp ); return res;
dd4aeb2014-05-05Per Hedbor }
5de2692012-05-28Martin Stjernholm struct pike_string *findstring(const char *foo)
ca74dd1996-10-08Fredrik Hübinette (Hubbe) { return binary_findstring(foo, strlen(foo)); }
81189d2015-07-25Per Hedbor static void low_link_pike_string( struct pike_string *entry );
aef30b1996-10-11Fredrik Hübinette (Hubbe) 
81189d2015-07-25Per Hedbor static void stralloc_grow(void)
af93211996-10-12Fredrik Hübinette (Hubbe) {
85df3f2015-07-24Per Hedbor  size_t old,h;
81189d2015-07-25Per Hedbor  struct pike_string **old_table;
e1939c2001-03-30Fredrik Hübinette (Hubbe) 
85df3f2015-07-24Per Hedbor  old=string_hash.size; old_table=string_hash.table; if( !string_hash.size ) string_hash.size = BEGIN_HASH_SIZE; else string_hash.size *= 2;
af93211996-10-12Fredrik Hübinette (Hubbe) 
85df3f2015-07-24Per Hedbor  string_hash.limit = (size_t)((double)string_hash.size*0.8);
81189d2015-07-25Per Hedbor  string_hash.table = xcalloc(sizeof(struct pike_string**), string_hash.size);
85df3f2015-07-24Per Hedbor  string_hash.mask = string_hash.size-1; /* fprintf( stderr, "stralloc rehash: sz=%d, mask=0x%8x, limit=%d, num=%d\n", */ /* string_hash.size, string_hash.mask,string_hash.limit,string_hash.num_strings); */
6ed3d22005-01-17Henrik Grubbström (Grubba) 
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  for(h=0;h<old;h++)
81189d2015-07-25Per Hedbor  if(old_table[h])
85df3f2015-07-24Per Hedbor  low_link_pike_string(old_table[h]);
af93211996-10-12Fredrik Hübinette (Hubbe) 
85df3f2015-07-24Per Hedbor  free(old_table);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
af93211996-10-12Fredrik Hübinette (Hubbe) 
81189d2015-07-25Per Hedbor static void stralloc_rehash() { /* rehash without resize, but new hvals for all strings. */ size_t h; struct pike_string **ht = string_hash.table;
ddca4d2015-07-26Henrik Grubbström (Grubba)  string_hash.table = calloc( string_hash.size, sizeof(struct pike_string*) );
81189d2015-07-25Per Hedbor  for(h=0;h<string_hash.size;h++) { struct pike_string *tmp=ht[h]; if( !tmp ) continue; /* rehash needed, since algorithm changed */ tmp->hval = do_hash(tmp); low_link_pike_string( tmp ); } free(ht); }
b0289e2000-12-01Henrik Grubbström (Grubba) /* Allocation of strings */
af93211996-10-12Fredrik Hübinette (Hubbe) 
85df3f2015-07-24Per Hedbor #define STRING_BLOCK 4096
60e6cf2013-11-09Arne Goedeke static struct block_allocator string_allocator = BA_INIT(sizeof(struct pike_string), STRING_BLOCK);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
60e6cf2013-11-09Arne Goedeke static void free_unlinked_pike_string(struct pike_string * s) {
85df3f2015-07-24Per Hedbor  switch (s->flags & STRING_ALLOC_MASK) {
119e1e2014-08-22Arne Goedeke  case STRING_ALLOC_MALLOC:
60e6cf2013-11-09Arne Goedeke  free(s->str);
119e1e2014-08-22Arne Goedeke  break; case STRING_ALLOC_BA: ba_free(&string_allocator, s->str); break;
60e6cf2013-11-09Arne Goedeke  } ba_free(&string_allocator, s); }
4a5e3f2000-11-25Henrik Grubbström (Grubba) 
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) {
60e6cf2013-11-09Arne Goedeke  return debug_begin_wide_shared_string(len, 0);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
85df3f2015-07-24Per Hedbor /* Insert a new strings. Note: Guaranteed to be new */
81189d2015-07-25Per Hedbor static void low_link_pike_string( struct pike_string *str )
85df3f2015-07-24Per Hedbor {
81189d2015-07-25Per Hedbor  size_t hval = str->hval; size_t h = HMODULO(hval);
85df3f2015-07-24Per Hedbor  size_t dist = 0; size_t max_run = 0, length_issue=0; for(;;) { size_t existing_dist;
81189d2015-07-25Per Hedbor  if( LIKELY(!string_hash.table[h]) )
85df3f2015-07-24Per Hedbor  { /* empty slot. */
81189d2015-07-25Per Hedbor  string_hash.table[h] = str;
85df3f2015-07-24Per Hedbor  return; }
81189d2015-07-25Per Hedbor  existing_dist = probe_dist(string_hash.table[h]->hval, h);
85df3f2015-07-24Per Hedbor 
81189d2015-07-25Per Hedbor  /* ----- This code is for the rehash heuristics. */ if( string_hash.table[h]->hval == hval )
85df3f2015-07-24Per Hedbor  { max_run++;
81189d2015-07-25Per Hedbor  if( str->len > hash_prefix_len+8 )
85df3f2015-07-24Per Hedbor  length_issue++; } else { if( length_issue ) need_more_hash_prefix_depth=MAXIMUM(max_run,need_more_hash_prefix_depth); else need_new_hashkey_depth=MAXIMUM(max_run,need_new_hashkey_depth); max_run=0; length_issue=0; }
81189d2015-07-25Per Hedbor  /* ----- end heuristics. */
85df3f2015-07-24Per Hedbor  if( existing_dist < dist ) {
81189d2015-07-25Per Hedbor  struct pike_string *tmp = string_hash.table[h];
85df3f2015-07-24Per Hedbor  /* steal slot, then insert stolen one. */
81189d2015-07-25Per Hedbor  string_hash.table[h] = str; str = tmp;
85df3f2015-07-24Per Hedbor  dist = existing_dist;
81189d2015-07-25Per Hedbor  /* inentionally not reassigning hval. the max-run length * heuristics are only for the "primary" string. */
85df3f2015-07-24Per Hedbor  } h = HMODULO(h + 1); dist++; } }
81189d2015-07-25Per Hedbor static void link_pike_string(struct pike_string *s)
85df3f2015-07-24Per Hedbor {
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
81189d2015-07-25Per Hedbor 
85df3f2015-07-24Per Hedbor  s->flags &= ~STRING_NOT_SHARED;
81189d2015-07-25Per Hedbor  if(UNLIKELY(++string_hash.num_strings > string_hash.limit)) stralloc_grow(); low_link_pike_string( s );
2cbf7c1999-09-01Fredrik Hübinette (Hubbe) 
6ed3d22005-01-17Henrik Grubbström (Grubba)  /* These heuristics might require tuning! /Hubbe */
81189d2015-07-25Per Hedbor  if(UNLIKELY((need_more_hash_prefix_depth > 8) || (need_new_hashkey_depth > 32)))
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  {
85df3f2015-07-24Per Hedbor  if (need_new_hashkey_depth > 32) {
abce512013-11-06Arne Goedeke  /* A simple mixing function. */ hashkey ^= (hashkey << 5) ^ (current_time.tv_sec ^ current_time.tv_usec); need_new_hashkey_depth = 0; }
85df3f2015-07-24Per Hedbor  if (need_more_hash_prefix_depth > 8) {
8282ca2013-11-02Per Hedbor  hash_prefix_len=hash_prefix_len*2;
85df3f2015-07-24Per Hedbor  need_more_hash_prefix_depth=0; }
81189d2015-07-25Per Hedbor  stralloc_rehash();
2cbf7c1999-09-01Fredrik Hübinette (Hubbe)  }
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;
60e6cf2013-11-09Arne Goedeke  size_t bytes = (len+1) << shift;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
db4a401998-10-09Fredrik Hübinette (Hubbe)  extern int d_flag; if(d_flag>10) verify_shared_strings_tables(); #endif
4a5e3f2000-11-25Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
85df3f2015-07-24Per Hedbor  if (shift > 2) Pike_fatal("Unsupported string shift: %d\n", shift);
4a5e3f2000-11-25Henrik Grubbström (Grubba) #endif /* PIKE_DEBUG */
60e6cf2013-11-09Arne Goedeke  t=(struct pike_string *)ba_alloc(&string_allocator);
119e1e2014-08-22Arne Goedeke  /* we mark the string as static here, to avoid double free if the allocations * fail */ t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_ALLOC_STATIC;
60e6cf2013-11-09Arne Goedeke  if (bytes <= sizeof(struct pike_string)) {
a495ca2014-08-23Arne Goedeke  /* FIXME: This can fail with an exception, which would leak * the string t. We should have ba_alloc and ba_xalloc, really. */
119e1e2014-08-22Arne Goedeke  t->str = ba_alloc(&string_allocator); t->flags |= STRING_ALLOC_BA; } else {
a495ca2014-08-23Arne Goedeke  t->str = malloc(bytes); if (!t->str) { ba_free(&string_allocator, t); Pike_error("Out of memory.\n"); }
119e1e2014-08-22Arne Goedeke  t->flags |= STRING_ALLOC_MALLOC; }
dc245f2011-07-21Henrik Grubbström (Grubba)  t->refs = 0;
a495ca2014-08-23Arne Goedeke  t->size_shift=shift;
dc245f2011-07-21Henrik Grubbström (Grubba)  add_ref(t); /* For DMALLOC */
db4a401998-10-09Fredrik Hübinette (Hubbe)  t->len=len;
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; }
85df3f2015-07-24Per Hedbor static struct pike_string * make_static_string(const char * str, size_t len, enum size_shift shift) {
119e1e2014-08-22Arne Goedeke  struct pike_string * t = ba_alloc(&string_allocator); t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_ALLOC_STATIC;
85df3f2015-07-24Per Hedbor  t->str = (char*)str;
119e1e2014-08-22Arne Goedeke  t->refs = 0; t->len = len; t->size_shift = shift; add_ref(t); /* For DMALLOC */ return t; } PMOD_EXPORT struct pike_string * make_shared_static_string(const char *str, size_t len, enum size_shift shift) { struct pike_string *s;
85df3f2015-07-24Per Hedbor  ptrdiff_t h = low_do_hash(str, len,0);
119e1e2014-08-22Arne Goedeke  s = internal_findstring(str,len,shift,h); if (!s) { s = make_static_string(str, len, shift);
81189d2015-07-25Per Hedbor  s->hval = do_hash(s); link_pike_string(s);
119e1e2014-08-22Arne Goedeke  } else {
7ed4d82014-08-24Arne Goedeke  if (!string_is_static(s)) { if (string_is_block_allocated(s)) { ba_free(&string_allocator, s->str); } else { free(s->str); } s->flags &= ~STRING_ALLOC_MASK; s->flags |= STRING_ALLOC_STATIC;
85df3f2015-07-24Per Hedbor  s->str = (char*)str;
7ed4d82014-08-24Arne Goedeke  }
119e1e2014-08-22Arne Goedeke  add_ref(s); } return s; }
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;
81189d2015-07-25Per Hedbor  s->hval = do_hash(s); s2 = internal_findstring(s->str, len, s->size_shift, s->hval);
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{
81189d2015-07-25Per Hedbor  link_pike_string(s);
3e625c1998-10-11Fredrik Hübinette (Hubbe)  } 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;
85df3f2015-07-24Per Hedbor  switch(UNLIKELY(s->size_shift))
db4a401998-10-09Fredrik Hübinette (Hubbe)  { 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) }
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 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) {
85df3f2015-07-24Per Hedbor  ptrdiff_t h;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s;
81189d2015-07-25Per Hedbor #if 0
85df3f2015-07-24Per Hedbor  if( !len ) { empty_pike_string->refs++; return empty_pike_string; }
81189d2015-07-25Per Hedbor #endif
85df3f2015-07-24Per Hedbor  h = low_do_hash(str, len,0);
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);
59fc9e2014-09-03Martin Nilsson  memcpy(s->str, str, len);
81189d2015-07-25Per Hedbor  s->hval = h; link_pike_string(s);
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) {
85df3f2015-07-24Per Hedbor  if( !len ) { empty_pike_string->refs++; return empty_pike_string; }
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);
59fc9e2014-09-03Martin Nilsson  memcpy(s->str, str, len<<1);
81189d2015-07-25Per Hedbor  s->hval = h; link_pike_string(s);
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);
59fc9e2014-09-03Martin Nilsson  memcpy(s->str, str, len<<2);
81189d2015-07-25Per Hedbor  s->hval = h; link_pike_string(s);
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) 
81189d2015-07-25Per Hedbor static void unlink_pike_string(struct pike_string *s)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
81189d2015-07-25Per Hedbor  size_t h = HMODULO(s->hval); #ifdef PIKE_DEBUG
85df3f2015-07-24Per Hedbor  size_t dist = 0;
81189d2015-07-25Per Hedbor #endif
85df3f2015-07-24Per Hedbor  string_hash.num_strings--;
9cd0372005-11-03Henrik Grubbström (Grubba)  s->flags |= STRING_NOT_SHARED;
85df3f2015-07-24Per Hedbor  for(;;) {
81189d2015-07-25Per Hedbor  if(string_hash.table[h] == s)
85df3f2015-07-24Per Hedbor  { size_t end = HMODULO(h+1); /* Found entry. Now maintain invariant. */ for(;;) {
81189d2015-07-25Per Hedbor  if(!string_hash.table[end] || !probe_dist(string_hash.table[end]->hval,end))
85df3f2015-07-24Per Hedbor  {
81189d2015-07-25Per Hedbor  string_hash.table[h] = NULL;
85df3f2015-07-24Per Hedbor  return; } string_hash.table[h] = string_hash.table[end]; h = end; end = HMODULO(end+1); } }
81189d2015-07-25Per Hedbor #ifdef PIKE_DEBUG if(!string_hash.table[h] || (dist > probe_dist(string_hash.table[h]->hval,h)))
85df3f2015-07-24Per Hedbor  Pike_fatal( "Failed to find string to unlink in table!\n"); dist++;
81189d2015-07-25Per Hedbor #endif
85df3f2015-07-24Per Hedbor  h = HMODULO(h+1); }
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); }
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))
81189d2015-07-25Per Hedbor  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;
85df3f2015-07-24Per Hedbor  for(e=0;e<string_hash.size;e++)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
81189d2015-07-25Per Hedbor  if( (p = string_hash.table[e]) )
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
60e6cf2013-11-09Arne Goedeke  int key = p->size_shift;
af80262013-02-07Henrik Grubbström (Grubba)  num_distinct_strings[key]++;
119e1e2014-08-22Arne Goedeke  alloced_bytes[key] += p->refs*sizeof(struct pike_string);
af80262013-02-07Henrik Grubbström (Grubba)  alloced_strings[key] += p->refs;
119e1e2014-08-22Arne Goedeke  if (string_is_block_allocated(p)) {
ca76852014-08-18Arne Goedeke  alloced_bytes[key] +=
119e1e2014-08-22Arne Goedeke  p->refs*sizeof(struct pike_string);
ca76852014-08-18Arne Goedeke  } else {
119e1e2014-08-22Arne Goedeke  alloced_bytes[key] += p->refs*DO_ALIGN((p->len+3) << p->size_shift,sizeof(void *));
ca76852014-08-18Arne Goedeke  }
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] =
60e6cf2013-11-09Arne Goedeke  DO_NOT_WARN((long)sizeof(struct pike_string) *
af80262013-02-07Henrik Grubbström (Grubba)  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(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;
85df3f2015-07-24Per Hedbor  for(e=0;e<string_hash.size;e++)
af93211996-10-12Fredrik Hübinette (Hubbe)  {
81189d2015-07-25Per Hedbor  struct pike_string *str = string_hash.table[e];
85df3f2015-07-24Per Hedbor  if(!str) continue; num++; if (bad_pointer(s)) { Pike_fatal("Odd string pointer in string table!\n"); }
af93211996-10-12Fredrik Hübinette (Hubbe) 
85df3f2015-07-24Per Hedbor  if(s->len < 0) Pike_fatal("Shared string shorter than zero bytes.\n");
af93211996-10-12Fredrik Hübinette (Hubbe) 
85df3f2015-07-24Per Hedbor  if(s->refs <= 0) { locate_problem(has_zero_refs); Pike_fatal("Shared string had too few references.\n"); }
af93211996-10-12Fredrik Hübinette (Hubbe) 
85df3f2015-07-24Per Hedbor  if(index_shared_string(s,s->len)) { locate_problem(improper_zero_termination); Pike_fatal("Shared string didn't end with a zero.\n"); }
81189d2015-07-25Per Hedbor  if(do_hash(s) != s->hval)
85df3f2015-07-24Per Hedbor  { Pike_fatal("Illegal hash for string.\n");
af93211996-10-12Fredrik Hübinette (Hubbe)  } }
85df3f2015-07-24Per Hedbor  if(num != string_hash.num_strings) Pike_fatal("Num strings is wrong %d!=%d\n",num,string_hash.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;
85df3f2015-07-24Per Hedbor  if( !foo ) return 0; for( e; e<string_hash.size; e++ )
81189d2015-07-25Per Hedbor  if( foo == string_hash.table[e] )
85df3f2015-07-24Per Hedbor  return 1;
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) {
85df3f2015-07-24Per Hedbor  return internal_findstring(foo->str,foo->len,foo->size_shift,do_hash(foo));
af93211996-10-12Fredrik Hübinette (Hubbe) }
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;
85df3f2015-07-24Per Hedbor  fprintf(stderr,"0x%p: %ld refs, len=%ld, size_shift=%d, hval=%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),
85df3f2015-07-24Per Hedbor  DO_NOT_WARN((unsigned long)do_hash(s)));
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;
85df3f2015-07-24Per Hedbor  for(e=0;e<string_hash.size;e++)
e1939c2001-03-30Fredrik Hübinette (Hubbe)  {
81189d2015-07-25Per Hedbor  if(p=string_hash.table[e])
85df3f2015-07-24Per Hedbor  {
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)  }
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 */
a9b8172014-04-05Martin Nilsson int low_quick_binary_strcmp(const char *a, ptrdiff_t alen, const char *b, ptrdiff_t blen)
af93211996-10-12Fredrik Hübinette (Hubbe) { int tmp; if(alen > blen) {
67074e2014-09-03Martin Nilsson  tmp=memcmp(a, b, blen);
af93211996-10-12Fredrik Hübinette (Hubbe)  if(tmp) return tmp; return 1; }else if(alen < blen){
67074e2014-09-03Martin Nilsson  tmp=memcmp(a, b, alen);
af93211996-10-12Fredrik Hübinette (Hubbe)  if(tmp) return tmp; return -1; }else{
67074e2014-09-03Martin Nilsson  return memcmp(a, b, alen);
af93211996-10-12Fredrik Hübinette (Hubbe)  } }
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,
d8e02f2014-09-03Martin Nilsson  ptrdiff_t alen, int asize, const char *b, ptrdiff_t blen, int bsize)
3e625c1998-10-11Fredrik Hübinette (Hubbe) {
0f0bf92014-09-04Martin Nilsson  ptrdiff_t pos;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  if(!asize && !bsize)
d8e02f2014-09-03Martin Nilsson  return low_quick_binary_strcmp(a, alen, b, blen); for(pos=0;pos< MINIMUM(alen,blen) ;pos++)
3e625c1998-10-11Fredrik Hübinette (Hubbe)  {
d8e02f2014-09-03Martin Nilsson  p_wchar2 ac=generic_extract(a,asize,pos); p_wchar2 bc=generic_extract(b,bsize,pos); if(ac != bc) { if (ac < bc) return -1;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  return 1; } }
d8e02f2014-09-03Martin Nilsson  return alen-blen;
3e625c1998-10-11Fredrik Hübinette (Hubbe) }
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) {
67074e2014-09-03Martin Nilsson  return s->len == len && s->size_shift == 0 && !memcmp(s->str,foo,len);
a5787d1999-03-03Fredrik Hübinette (Hubbe) }
af93211996-10-12Fredrik Hübinette (Hubbe) /* 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; } /* Does not take locale into account */
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); 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;
33c3872014-09-04Martin Nilsson  } else if(ac-bc) return ac-bc;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  } 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) {
60e6cf2013-11-09Arne Goedeke  char * s = NULL; size_t nbytes = (size_t)(size+1) << a->size_shift;
119e1e2014-08-22Arne Goedeke  size_t obytes = (size_t)(a->len+1) << a->size_shift;
4a5e3f2000-11-25Henrik Grubbström (Grubba) 
119e1e2014-08-22Arne Goedeke  switch ((a->flags & STRING_ALLOC_MASK) | (nbytes <= sizeof(struct pike_string))) { case STRING_ALLOC_MALLOC:
60e6cf2013-11-09Arne Goedeke  s=realloc(a->str, nbytes); if (!s) Pike_error("Out of memory in realloc_unlinked_string. Could not allocate %"PRINTSIZET" bytes.\n", nbytes); break;
119e1e2014-08-22Arne Goedeke  case STRING_ALLOC_BA: // old string was short
60e6cf2013-11-09Arne Goedeke  s = xalloc(nbytes);
119e1e2014-08-22Arne Goedeke  a->flags &= ~STRING_ALLOC_MASK; a->flags |= STRING_ALLOC_MALLOC;
60e6cf2013-11-09Arne Goedeke  memcpy(s, a->str, obytes); ba_free(&string_allocator, a->str); break;
119e1e2014-08-22Arne Goedeke  case STRING_ALLOC_MALLOC|1:
60e6cf2013-11-09Arne Goedeke  s = ba_alloc(&string_allocator);
119e1e2014-08-22Arne Goedeke  a->flags &= ~STRING_ALLOC_MASK; a->flags |= STRING_ALLOC_BA;
60e6cf2013-11-09Arne Goedeke  memcpy(s, a->str, nbytes); free(a->str); break;
119e1e2014-08-22Arne Goedeke  case STRING_ALLOC_BA|1: // both are short
60e6cf2013-11-09Arne Goedeke  goto done;
119e1e2014-08-22Arne Goedeke  case STRING_ALLOC_STATIC: s = xalloc(nbytes); a->flags &= ~STRING_ALLOC_MASK; a->flags |= STRING_ALLOC_MALLOC; memcpy(s, a->str, obytes); break; case STRING_ALLOC_STATIC|1: s = ba_alloc(&string_allocator); a->flags &= ~STRING_ALLOC_MASK; a->flags |= STRING_ALLOC_BA; memcpy(s, a->str, obytes); break; #ifdef PIKE_DEBUG default: Pike_fatal("encountered string with unknown allocation type %d\n", a->flags & STRING_ALLOC_MASK); #endif
8d28be1997-02-10Fredrik Hübinette (Hubbe)  }
60e6cf2013-11-09Arne Goedeke  a->str = s; done: a->len=size; low_set_index(a,size,0); return a;
8d28be1997-02-10Fredrik Hübinette (Hubbe) } /* 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) {
119e1e2014-08-22Arne Goedeke  if(string_may_modify(a))
8d28be1997-02-10Fredrik Hübinette (Hubbe)  {
81189d2015-07-25Per Hedbor  unlink_pike_string(a);
8d28be1997-02-10Fredrik Hübinette (Hubbe)  return realloc_unlinked_string(a, size); }else{
60e6cf2013-11-09Arne Goedeke  struct pike_string *r=begin_wide_shared_string(size,a->size_shift);
59fc9e2014-09-03Martin Nilsson  memcpy(r->str, a->str, a->len<<a->size_shift);
119e1e2014-08-22Arne Goedeke  r->flags |= a->flags & STRING_CHECKED_MASK;
ed2bed2013-06-14Per Hedbor  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);
119e1e2014-08-22Arne Goedeke  r->flags |= (a->flags & STRING_CHECKED_MASK);
ed2bed2013-06-14Per Hedbor  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 */
119e1e2014-08-22Arne Goedeke  if(string_may_modify(a))
0d3ea51998-01-19Fredrik Hübinette (Hubbe)  {
85df3f2015-07-24Per Hedbor  struct pike_string *old;
db4a401998-10-09Fredrik Hübinette (Hubbe)  /* One ref - destructive mode */
81189d2015-07-25Per Hedbor  unlink_pike_string(a);
e94f072005-01-18Henrik Grubbström (Grubba)  low_set_index(a, index, c);
9925512013-05-31Per Hedbor  CLEAR_STRING_CHECKED(a);
60e6cf2013-11-09Arne Goedeke 
81189d2015-07-25Per Hedbor  old = internal_findstring(a->str, a->len, a->size_shift, a->hval);
85df3f2015-07-24Per Hedbor  if (old) { /* The new string is equal to some old string. */ free_string(a); add_ref(a = old); } else {
81189d2015-07-25Per Hedbor  link_pike_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);
59fc9e2014-09-03Martin Nilsson  memcpy(r->str, a->str, a->len << a->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe)  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 ) {
a2a5812013-08-25Arne Goedeke  ret->flags |= aflags & ~15;
9925512013-05-31Per Hedbor  ret->min = amin; ret->max = amax; return; }
afd5eb2013-06-03Martin Nilsson  if( aflags & b->flags & STRING_CONTENT_CHECKED )
9925512013-05-31Per Hedbor  {
6431dc2013-06-17Henrik Grubbström (Grubba)  ret->min = MINIMUM( amin, b->min ); ret->max = MAXIMUM( amax, b->max );
9925512013-05-31Per Hedbor  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 );
59fc9e2014-09-03Martin Nilsson  memcpy(a->str+(alen<<a->size_shift),b->str,b->len<<b->size_shift);
db4a401998-10-09Fredrik Hübinette (Hubbe)  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
81189d2015-07-25Per Hedbor  if(len == 0)
6a12e42011-05-03Per Hedbor  { 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) {
81189d2015-07-25Per Hedbor  stralloc_grow();
85df3f2015-07-24Per Hedbor  empty_pike_string = make_shared_static_string("",0,0);
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) 
85df3f2015-07-24Per Hedbor  free(string_hash.table); string_hash.table=0; string_hash.size=0; string_hash.num_strings=0;
46563d2000-12-01Henrik Grubbström (Grubba) 
0d70692002-11-28Martin Stjernholm #ifdef DO_PIKE_CLEANUP
22287c2013-06-16Arne Goedeke  ba_destroy(&string_allocator);
0d70692002-11-28Martin Stjernholm #endif /* DO_PIKE_CLEANUP */
5267b71995-08-09Fredrik Hübinette (Hubbe) }
c3c7031996-12-04Fredrik Hübinette (Hubbe) 
a206ac2014-08-24Arne Goedeke void count_string_types() { unsigned INT32 e; size_t num_static = 0, num_short = 0;
85df3f2015-07-24Per Hedbor  for (e = 0; e < string_hash.size; e++) { struct pike_string * s;
81189d2015-07-25Per Hedbor  if( (s = string_hash.table[e]) )
85df3f2015-07-24Per Hedbor  switch (s->flags & STRING_ALLOC_MASK) {
a206ac2014-08-24Arne Goedeke  case STRING_ALLOC_BA: num_short ++; break; case STRING_ALLOC_STATIC: num_static ++; break;
85df3f2015-07-24Per Hedbor  }
a206ac2014-08-24Arne Goedeke  } push_static_text("num_short_pike_strings"); push_ulongest(num_short); push_static_text("num_static_pike_strings"); push_ulongest(num_static); }
a495ca2014-08-23Arne Goedeke size_t count_memory_in_string(const struct pike_string * s) { size_t size = sizeof(struct pike_string);
60e6cf2013-11-09Arne Goedeke 
a495ca2014-08-23Arne Goedeke  switch (s->flags & STRING_ALLOC_MASK) { case STRING_ALLOC_BA: size += sizeof(struct pike_string); break; case STRING_ALLOC_MALLOC: size += PIKE_ALIGNTO(((s->len + 1) << s->size_shift), 4); break; }
60e6cf2013-11-09Arne Goedeke 
a495ca2014-08-23Arne Goedeke  return size;
041a532012-03-08Henrik Grubbström (Grubba) }
a495ca2014-08-23Arne Goedeke void count_memory_in_strings(size_t *num, size_t *_size)
c3c7031996-12-04Fredrik Hübinette (Hubbe) {
a495ca2014-08-23Arne Goedeke  unsigned INT32 e; size_t size = 0;
85df3f2015-07-24Per Hedbor  *num = string_hash.num_strings;
a495ca2014-08-23Arne Goedeke 
81189d2015-07-25Per Hedbor  size += string_hash.size * sizeof(struct pike_string *);
a495ca2014-08-23Arne Goedeke 
85df3f2015-07-24Per Hedbor  for (e = 0; e < string_hash.size; e++) { struct pike_string *s;
81189d2015-07-25Per Hedbor  if( (s = string_hash.table[e]) )
85df3f2015-07-24Per Hedbor  size += count_memory_in_string(s);
a495ca2014-08-23Arne Goedeke  } *_size = size;
c3c7031996-12-04Fredrik Hübinette (Hubbe) }
9367351997-01-27Fredrik Hübinette (Hubbe) 
d056542014-06-17Henrik Grubbström (Grubba) PMOD_EXPORT void visit_string (struct pike_string *s, int action, void *extra)
ad8d052008-05-02Martin Stjernholm {
c42e092014-06-18Henrik Grubbström (Grubba)  visit_enter(s, T_STRING, extra);
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:
a495ca2014-08-23Arne Goedeke  mc_counted_bytes += count_memory_in_string (s);
5e83442008-05-11Martin Stjernholm  break; }
c42e092014-06-18Henrik Grubbström (Grubba)  visit_leave(s, T_STRING, extra);
ad8d052008-05-02Martin Stjernholm }
7a26722000-09-04Martin Stjernholm #ifdef PIKE_DEBUG unsigned gc_touch_all_strings(void) { unsigned INT32 e; unsigned n = 0;
85df3f2015-07-24Per Hedbor  for(e=0;e<string_hash.size;e++)
7a26722000-09-04Martin Stjernholm  { struct pike_string *p;
81189d2015-07-25Per Hedbor  if((p = string_hash.table[e]))
85df3f2015-07-24Per Hedbor  debug_gc_touch(p), n++;
7a26722000-09-04Martin Stjernholm  } return n; }
be478c1997-08-30Henrik Grubbström (Grubba) void gc_mark_all_strings(void)
9367351997-01-27Fredrik Hübinette (Hubbe) { unsigned INT32 e;
85df3f2015-07-24Per Hedbor  for(e=0;e<string_hash.size;e++)
9367351997-01-27Fredrik Hübinette (Hubbe)  { struct pike_string *p;
81189d2015-07-25Per Hedbor  if( (p = string_hash.table[e]) )
85df3f2015-07-24Per Hedbor  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) {
85df3f2015-07-24Per Hedbor  int found = 0; size_t e = 0; for(;;) {
81189d2015-07-25Per Hedbor  if( string_hash.table[e] && found ) return string_hash.table[e]; if( string_hash.table[e] == s )
85df3f2015-07-24Per Hedbor  found=1; e = HMODULO(e+1);
f7cfa82001-09-04Martin Stjernholm  } }
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;
59fc9e2014-09-03Martin Nilsson  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) {
119e1e2014-08-22Arne Goedeke  if (string_may_modify(str)) {
97c5582004-04-15Martin Stjernholm  /* Unlink the string and use it as buffer directly. */
81189d2015-07-25Per Hedbor  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:
21b12a2014-09-03Martin Nilsson  memset (STR0 (s->s) + s->s->len, ch, count);
abeaca2010-05-28Martin Stjernholm  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)))) {
21b12a2014-09-03Martin Nilsson  memset(string_builder_allocate(s,howmany,0),
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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);
59fc9e2014-09-03Martin Nilsson  memcpy(s->s->str + (s->s->len << s->s->size_shift),
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  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);
b848242014-01-15Arne Goedeke  string_builder_append_integer(buf, (unsigned INT32)ch, 16, APPEND_ZERO_PAD, 8, 8);
64b0772006-03-20Henrik Grubbström (Grubba)  } 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. */
5bd3482014-01-11Tobias S. Josefowitz  for (; shift < SIZEOF_LONGEST * 8 && tmp >> shift; 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) {
85df3f2015-07-24Per Hedbor  switch(UNLIKELY(ptr.shift))
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  {
98c0302014-09-03Martin Nilsson  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);
85df3f2015-07-24Per Hedbor #ifdef PIKE_DEBUG case 2: #else default: #endif 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) {
2ae97e2014-09-03Martin Nilsson  /* Note: Code duplication in strtol and pcharp_to_svalue_inumber. */
90784a2003-02-26Martin Stjernholm  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 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 {
2ae97e2014-09-03Martin Nilsson  /* Note: Code duplication in strtol and STRTOL_PCHARP. */
90784a2003-02-26Martin Stjernholm 
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. */
5739832013-08-02Arne Goedeke  if(c == '0' &&
5656451999-10-26Fredrik Noring  ((base==16 && (INDEX_PCHARP(str,1)=='x' || INDEX_PCHARP(str,1)=='X')) ||
5739832013-08-02Arne Goedeke  (base==2 && (INDEX_PCHARP(str,1)=='b' || INDEX_PCHARP(str,1)=='B'))) && INDEX_PCHARP(str,2) < 256 && /* Don't trust isxdigit... */ isxdigit(INDEX_PCHARP(str,2)))
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) {
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);
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) {
21b12a2014-09-03Martin Nilsson  /* Note: Code duplication in strtod. */
71d7d52003-02-26Martin Stjernholm 
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'. */
2ae97e2014-09-03Martin Nilsson  /* NOTE: Don't trust the value returned from strtol.
7ad4122003-10-03Henrik Grubbström (Grubba)  * 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. */
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; }