pike.git / src / builtin.cmod

version» Context lines:

pike.git/src/builtin.cmod:2900:    *! @[catch()], @[throw()]    */   PMOD_EXPORT   PIKEFUN array(mixed) backtrace()    efun;    optflags OPT_EXTERNAL_DEPEND;   {    low_backtrace(& Pike_interpreter);   }    - /*! @module String -  */ -  - #define PROG_BUFFER_ID PROG_STRING_BUFFER_ID -  - /*! @class Buffer -  *! A buffer, used for building strings. It's -  *! conceptually similar to a string, but you can only @[add] -  *! strings to it, and you can only @[get] the value from it once. -  *! -  *! There is a reason for those seemingly rather odd limitations, -  *! it makes it possible to do some optimizations that really speed -  *! things up. -  *! -  *! You do not need to use this class unless you add very many -  *! strings together, or very large strings. -  *! -  *! @example -  *! For the fastest possible operation, write your code like this: -  *! -  *! @code -  *! String.Buffer b = String.Buffer( ); -  *! -  *! function add = b->add; -  *! -  *! .. call add several times in code ... -  *! -  *! string result = b->get(); // also clears the buffer -  *! @endcode -  */ - PIKECLASS Buffer - { -  CVAR struct string_builder str; -  CVAR int initial; -  -  PIKEFUN int _size_object() -  { -  if( THIS->str.s ) -  RETURN THIS->str.malloced; -  RETURN 0; -  } -  -  void f_Buffer_get_copy( INT32 args ); -  void f_Buffer_get( INT32 args ); -  void f_Buffer_add( INT32 args ); -  -  /*! @decl void create(int initial_size) -  *! -  *! Initializes a new buffer. -  *! -  *! If no @[initial_size] is specified, 256 is used. If you -  *! know approximately how big the buffer will be, you can optimize -  *! the operation of @[add()] (slightly) by passing the size to this -  *! function. -  */ -  PIKEFUN void create( int|void size ) -  { -  struct Buffer_struct *str = THIS; -  if( size ) -  str->initial = MAXIMUM( size->u.integer, 512 ); -  else -  str->initial = 256; -  pop_n_elems(args); -  } -  -  /*! @decl string _sprintf( int flag, mapping flags ) -  *! It is possible to @[sprintf] a String.Buffer object -  *! as @tt{%s@} just as if it was a string. -  */ -  PIKEFUN string _sprintf( int flag, mapping flags ) -  { -  switch( flag ) -  { -  case 'O': -  { -  struct pike_string *res; -  struct Buffer_struct *str = THIS; -  push_static_text( "Buffer(%d /* %d */)" ); -  if( str->str.s ) -  { -  push_int(str->str.s->len); -  push_int(str->str.malloced); -  } -  else -  { -  push_int( 0 ); -  push_int( 0 ); -  } -  f_sprintf( 3 ); -  dmalloc_touch_svalue(Pike_sp-1); -  res = Pike_sp[-1].u.string; -  Pike_sp--; -  RETURN res; -  } -  -  case 's': -  { -  pop_n_elems( args ); -  if( Pike_fp->current_object->refs != 1 ) -  f_Buffer_get_copy( 0 ); -  else -  f_Buffer_get( 0 ); -  } -  return; -  -  case 't': -  RETURN make_shared_binary_string("Buffer",6); -  } -  pop_n_elems( args ); -  push_undefined(); -  } -  -  /*! @decl mixed cast( string type ) -  *! It is possible to cast a String.Buffer object to -  *! a @expr{string@} and an @expr{int@}. -  */ -  PIKEFUN mixed cast( string type ) -  flags ID_PROTECTED; -  { -  if( type == literal_string_string ) -  { -  pop_stack(); -  if( Pike_fp->current_object->refs != 1 ) -  f_Buffer_get_copy( 0 ); -  else -  f_Buffer_get( 0 ); -  return; -  } -  -  if( type == literal_int_string ) -  { -  struct Buffer_struct *str = THIS; -  pop_stack(); -  if( Pike_fp->current_object->refs != 1 ) -  f_Buffer_get_copy( 0 ); -  else -  f_Buffer_get( 0 ); -  o_cast_to_int( ); -  return; -  } -  -  pop_stack(); -  push_undefined(); -  } -  -  /*! @decl String.Buffer `+( string|String.Buffer what ) -  */ -  PIKEFUN object `+( string|Buffer what ) -  rawtype tFunc(tOr(tString, tObjIs_BUFFER), tObjIs_BUFFER); -  { -  struct Buffer_struct *str = THIS, *str2; -  struct object *res = fast_clone_object( Buffer_program ); -  str2 = OBJ2_BUFFER( res ); -  str2->initial = str->initial; -  if( str->str.s ) -  init_string_builder_copy (&str2->str, &str->str); -  if( (Pike_fp->current_object->flags & OBJECT_CLEAR_ON_EXIT) ) -  res->flags |= OBJECT_CLEAR_ON_EXIT; -  apply( res, "add", 1 ); -  RETURN res; -  } -  -  /*! @decl String.Buffer `+=( string|String.Buffer what ) -  */ -  PIKEFUN object `+=( string|Buffer what ) -  rawtype tFunc(tOr(tString, tObjIs_BUFFER), tObjIs_BUFFER); -  { -  f_Buffer_add( 1 ); -  REF_RETURN Pike_fp->current_object; -  } -  -  /*! @decl int add(string|String.Buffer ... data) -  *! -  *! Adds @[data] to the buffer. -  *! -  *! @returns -  *! Returns the size of the buffer. -  *! -  *! @note -  *! Pike 7.8 and earlier did not support adding @[String.Buffer]s -  *! directly. -  */ -  PIKEFUN int add( string|Buffer ... arg1 ) -  rawtype tFuncV(tNone, tOr(tString, tObjIs_BUFFER), tIntPos); -  { -  struct Buffer_struct *str = THIS; -  -  if (args) { -  int init_from_arg0 = 0, j; -  ptrdiff_t sum = 0; -  int shift = 0; -  for (j=0; j < args; j++) { -  struct pike_string *a; -  if (TYPEOF(Pike_sp[j-args]) == PIKE_T_STRING) -  a = Pike_sp[j-args].u.string; -  else if ((TYPEOF(Pike_sp[j-args]) != PIKE_T_OBJECT) || -  (Pike_sp[j-args].u.object->prog != Buffer_program)) -  SIMPLE_ARG_TYPE_ERROR("add", j+1, "string|String.Buffer"); -  else { -  a = OBJ2_BUFFER(Pike_sp[j-args].u.object)->str.s; -  if (!a) continue; -  } -  sum += a->len; -  shift |= a->size_shift; -  } -  shift |= str->str.known_shift; -  shift = shift & ~(shift >> 1); -  /* We know it will be a string that really is this wide. */ -  str->str.known_shift = shift; -  -  if (!str->str.s) { -  if (sum <= str->initial) -  sum = str->initial; -  else -  sum <<= 1; -  -  init_string_builder_alloc(&str->str, sum, shift); -  } else -  string_build_mkspace(&str->str, sum, shift); -  -  for(sum = str->str.s->len, j = 0; j<args; j++) { -  struct pike_string *a; -  if (TYPEOF(Pike_sp[j-args]) == PIKE_T_STRING) -  a = Pike_sp[j-args].u.string; -  else { -  a = OBJ2_BUFFER(Pike_sp[j-args].u.object)->str.s; -  if (!a) continue; -  } -  pike_string_cpy(MKPCHARP_STR_OFF(str->str.s, sum), a); -  sum += a->len; -  } -  -  str->str.s->len = sum; -  } -  -  RETURN str->str.s ? str->str.s->len : 0; -  } -  -  /*! @decl void putchar(int c) -  *! Appends the character @[c] at the end of the string. -  */ -  PIKEFUN void putchar(int c) { -  struct Buffer_struct *str = THIS; -  if(!str->str.s) -  init_string_builder_alloc(&str->str, str->initial, 0); -  string_builder_putchar(&str->str, c); -  } -  -  /*! @decl int sprintf(strict_sprintf_format format, sprintf_args ... args) -  *! Appends the output from @[sprintf] at the end of the string. -  *! Returns the resulting size of the String.Buffer. -  */ -  PIKEFUN int sprintf(mixed ... arguments) -  rawtype tFuncV(tAttr("strict_sprintf_format", tOr(tStr, tObj)), -  tAttr("sprintf_args", tMix), tStr); -  -  { -  // FIXME: Reset length on exception? -  struct Buffer_struct *str = THIS; -  if(!str->str.s) -  init_string_builder_alloc(&str->str, str->initial, 0); -  low_f_sprintf(args, &str->str); -  RETURN str->str.s->len; -  } -  -  /*! @decl string get_copy() -  *! -  *! Get the data from the buffer. Significantly slower than @[get], -  *! but does not clear the buffer. -  *! -  *! @seealso -  *! @[get()] -  */ -  PIKEFUN string get_copy() -  { -  struct pike_string *str = THIS->str.s; -  ptrdiff_t len; -  if( str && (len = str->len) > 0 ) -  { -  char *d = (char *)str->str; -  switch( str->size_shift ) -  { -  case 0: -  str=make_shared_binary_string0((p_wchar0 *)d,len); -  break; -  case 1: -  str=make_shared_binary_string1((p_wchar1 *)d,len); -  break; -  case 2: -  str=make_shared_binary_string2((p_wchar2 *)d,len); -  break; -  } -  if( Pike_fp->current_object->flags & OBJECT_CLEAR_ON_EXIT ) -  str->flags |= STRING_CLEAR_ON_EXIT; -  RETURN str; -  } -  push_empty_string(); -  return; -  } -  -  /*! @decl string get() -  *! -  *! Get the data from the buffer. -  *! -  *! @note -  *! This will clear the data in the buffer -  *! -  *! @seealso -  *! @[get_copy()], @[clear()] -  */ -  PIKEFUN string get( ) -  { -  struct Buffer_struct *str = THIS; -  pop_n_elems(args); -  if( str->str.s ) -  { -  struct pike_string *s = finish_string_builder( &str->str ); -  str->str.malloced = 0; -  str->str.s = NULL; -  if( Pike_fp->current_object->flags & OBJECT_CLEAR_ON_EXIT ) -  s->flags |= STRING_CLEAR_ON_EXIT; -  push_string(s); -  } -  else -  push_empty_string(); -  } -  -  /*! @decl void clear() -  *! -  *! Empty the buffer, and don't care about the old content. -  *! -  *! @note -  *! This function was not available in Pike 7.8 and earlier. -  *! -  *! @seealso -  *! @[get()] -  */ -  PIKEFUN void clear() -  { -  /* FIXME: Support resetting the initial size? */ -  struct Buffer_struct *str = THIS; -  if (str->str.s) { -  /* FIXME: There's also the alternative of using -  * reset_string_builder() here. -  */ -  free_string_builder(&str->str); -  str->str.s = NULL; -  } -  } -  -  /*! @decl int _sizeof() -  *! -  *! Returns the size of the buffer. -  */ -  PIKEFUN int _sizeof() -  flags ID_PROTECTED; -  { -  struct Buffer_struct *str = THIS; -  RETURN str->str.s ? str->str.s->len : 0; -  } -  -  /*! @decl int(0..) _search(int character, int|void start, int|void end) -  *! -  *! Search for a @[character] in the buffer, starting the scan -  *! from @[start] and ending at @[end] (inclusive). -  *! -  *! @returns -  *! Returns to position in the buffer where the character was found -  *! on success, and @[UNDEFINED] on failure. -  *! -  *! @seealso -  *! @[Stdio.Buffer()->_search()], @[search()], @[lfun::_search()] -  */ -  PIKEFUN int(0..) _search(int character, int|void start, int|void end) -  { -  PCHARP buf = MKPCHARP_STR(THIS->str.s); -  ptrdiff_t len = THIS->str.s->len; -  ptrdiff_t i; -  -  if (end && (end->u.integer + 1 < len)) { -  len = end->u.integer + 1; -  } -  if (len > 0 && start && (start->u.integer > 0)) { -  INC_PCHARP(buf, start->u.integer); -  len -= start->u.integer; -  } -  if (len <= 0) { -  push_int(-1); -  return; -  } -  if (UNLIKELY(THIS->str.s->size_shift == thirtytwobit)) { - #if SIZEOF_INT_TYPE > 4 -  if (UNLIKELY((0x7fffffff < character) || (character < -0x80000000))) { -  push_int(-1); -  return; -  } - #endif -  } else if (UNLIKELY((1L<<(8<<THIS->str.s->size_shift)) <= character) || -  UNLIKELY(character < 0)) { -  push_int(-1); -  return; -  } -  for (i = 0; i < len; i++) { -  p_wchar2 c = INDEX_PCHARP(buf, i); -  if (c == character) { -  if(start) -  i += start->u.integer; -  push_int64(i); -  return; -  } -  } -  push_int(-1); -  } -  -  /*! @decl int(0..) _search(string substring, int|void start, int|void end) -  *! -  *! Search for a @[substring] in the buffer, starting the scan -  *! from @[start] and ending at @[end] (inclusive). -  *! -  *! @returns -  *! Returns to position in the buffer where the substring was found -  *! on success, and @[UNDEFINED] on failure. -  *! -  *! @seealso -  *! @[Stdio.Buffer()->_search()], @[search()], @[lfun::_search()] -  */ -  PIKEFUN int(0..) _search(string substring, int|void start, int|void end) -  { -  PCHARP buf = MKPCHARP_STR(THIS->str.s); -  ptrdiff_t len = THIS->str.s->len; -  ptrdiff_t i; -  SearchMojt mojt; -  PCHARP res; -  -  if (end && (end->u.integer + 1 < len)) { -  len = end->u.integer + 1; -  } -  if (len > 0 && start && (start->u.integer > 0)) { -  INC_PCHARP(buf, start->u.integer); -  len -= start->u.integer; -  } -  if (len < substring->len) { -  push_undefined(); -  return; -  } -  if (!substring->len) { -  push_int(0); -  return; -  } -  if (substring->size_shift > THIS->str.s->size_shift) { -  push_undefined(); -  return; -  } -  -  mojt = compile_memsearcher(MKPCHARP_STR(substring), substring->len, -  len, substring); -  -  res = mojt.vtab->funcN(mojt.data, buf, len); -  -  if (!res.ptr) { -  push_undefined(); -  } else { -  push_int64((((char *)res.ptr) - ((char *)buf.ptr)) >> -  THIS->str.s->size_shift); -  } -  } -  -  INIT -  { -  struct Buffer_struct *str = THIS; -  memset( str, 0, sizeof( *str ) ); -  } -  -  EXIT -  gc_trivial; -  { -  struct Buffer_struct *str = THIS; -  if( str->str.s ) -  { -  if( Pike_fp->flags & OBJECT_CLEAR_ON_EXIT ) -  secure_zero( str->str.s->str, str->str.s->len ); -  free_string_builder( &str->str ); -  } -  } -  -  GC_RECURSE -  { -  if (mc_count_bytes (Pike_fp->current_object) && THIS->str.s) -  mc_counted_bytes += THIS->str.malloced; -  } - } -  - /*! @endclass -  */ -  +    /*! @class Replace    *!    *! This is a "compiled" version of the @[replace] function applied on    *! a string, with more than one replace string. The replace strings    *! are given to the create method as a @i{from@} and @i{to@} array    *! and are then analyzed. The @expr{`()@} is then called with a    *! string and the replace rules in the Replace object will be    *! applied. The Replace object is used internally by the Pike    *! optimizer and need not be used manually.    */