pike.git / src / builtin.cmod

version» Context lines:

pike.git/src/builtin.cmod:19:   #include "pike_types.h"   #include "pike_memory.h"   #include "threads.h"   #include "module_support.h"   #include "cyclic.h"   #include "bignum.h"   #include "main.h"   #include "operators.h"   #include "builtin_functions.h"   #include "fsort.h" - #include "port.h" +    #include "gc.h"   #include "block_allocator.h"   #include "pikecode.h"   #include "opcodes.h"   #include "whitespace.h"      #include <ctype.h>   #include <errno.h>   #include <math.h> -  + #include <arpa/inet.h>      DECLARATIONS         /*! @module System    */    - #if defined(HAVE_MKTIME) && defined(HAVE_GMTIME) && defined(HAVE_LOCALTIME) +    /*! @class TM    *! A wrapper for the system struct tm time keeping structure.    *! This can be used as a (very) lightweight alternative to Calendar.    */   PIKECLASS TM   {    CVAR struct tm t;    CVAR time_t unix_time;    CVAR int modified;    CVAR struct pike_string *set_zone;
pike.git/src/builtin.cmod:182:    */    PIKEFUN int(0..1) strptime( string(1..255) format, string(1..255) data )    {    if( format->size_shift || data->size_shift )    Pike_error("Only 8bit strings are supported\n");    THIS->modified = 1;    if( strptime_zone( data->str, format->str, &THIS->t ) == NULL )    RETURN 0;    RETURN 1;    } - #endif + #endif /* HAVE_STRPTIME */    /*! @decl string(1..255) strftime( string(1..255) format )    *! See also @[Gettext.setlocale]    *!    *! Convert the structure to a string.    *!    *! @dl    *! @item %a    *! The abbreviated weekday name according to the current locale    *!    *! @item %A
pike.git/src/builtin.cmod:349:    *! When read the fields are always normalized.    *!    *! Unlike the system struct tm the 'year' field is not year-1900,    *! instead it is the actual year.    */    PIKEFUN int(0..60) `sec() { FIX_THIS();RETURN THIS->t.tm_sec; }    PIKEFUN int(0..59) `min() { FIX_THIS();RETURN THIS->t.tm_min; }    PIKEFUN int(0..23) `hour() { FIX_THIS();RETURN THIS->t.tm_hour; }    PIKEFUN int(1..31) `mday() { FIX_THIS();RETURN THIS->t.tm_mday; }    PIKEFUN int(0..11) `mon() { FIX_THIS();RETURN THIS->t.tm_mon; } -  PIKEFUN int `year() { FIX_THIS();RETURN THIS->t.tm_year+1900; } +     -  +  PIKEFUN int `year() { FIX_THIS();RETURN THIS->t.tm_year+1900; }    PIKEFUN int `sec=(int a) { MODIFY(tm_sec=a); }    PIKEFUN int `min=(int a) { MODIFY(tm_min=a); }    PIKEFUN int `hour=(int a){ MODIFY(tm_hour=a); }    PIKEFUN int `mday=(int a){ MODIFY(tm_mday=a); }    PIKEFUN int `year=(int a){ MODIFY(tm_year=a-1900); }    PIKEFUN int `mon=(int a){ MODIFY(tm_mon=a); }       /*! @decl int isdst    *!    *! True if daylight savings are in effect. If this field is -1
pike.git/src/builtin.cmod:444:    Pike_error("Can not format as %c", flag );    }    if( post_sum )    {    push_static_text(")");    f_add(3);    }       }    -  PIKEFUN mixed cast( string to ) +  /*! @decl int|string cast(string to) +  *! +  *! Casted to an integer @[unix_time] will be returned. +  *! +  *! Casting to a string will call @[asctime]. +  */ +  PIKEFUN int|string cast( string to )    flags ID_PROTECTED;    {    if( to == literal_int_string )    {    f_TM_unix_time(0);    return;    }    if( to == literal_string_string )    {    f_TM_asctime(0);
pike.git/src/builtin.cmod:601:    free_string( THIS->set_zone );    }   }   /*! @endclass    */   #undef FIX_THIS   #ifdef STRUCT_TM_HAS___TM_GMTOFF   #undef tm_zone   #undef tm_gmtoff   #endif - #endif +    /*! @endmodule    */      /*! @decl array(array(int|string|type)) describe_program(program p)    *! @belongs Debug    *!    *! Debug function for showing the symbol table of a program.    *!    *! @returns    *! Returns an array of arrays with the following information
pike.git/src/builtin.cmod:749:    *!    *! Same as sprintf("%c",x);    *!    *! @seealso    *! @[sprintf()]    */   PMOD_EXPORT   PIKEFUN string int2char(int|object x)    efun;    optflags OPT_TRY_OPTIMIZE; +  rawtype tFunc(tSetvar(0, tOr(tInt,tObj)), tNStr(tVar(0)));   {    int c;    struct program *p;    if(TYPEOF(*x) == T_OBJECT && (p = x->u.object->prog))    {    ptrdiff_t fun = FIND_LFUN(p->inherits[SUBTYPEOF(*x)].prog, LFUN__SPRINTF);    if(fun != -1)    {    push_int('c');    f_aggregate_mapping(0);
pike.git/src/builtin.cmod:898:    /* 'A' - 'F' */    10, 11, 12, 13, 14, 15,       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    /* 'a' - 'f' */    10, 11, 12, 13, 14, 15,   };      PMOD_EXPORT    PIKEFUN string(0..255) string2hex(string s) -  errname String.string2hex; +     optflags OPT_TRY_OPTIMIZE;   {    struct pike_string *hex;    unsigned char *p,*st = (unsigned char *)s->str;    int i, l;       if (s->size_shift)    Pike_error("Bad argument 1 to string2hex(), expected 8-bit string.\n");       hex = begin_shared_string(2 * s->len);
pike.git/src/builtin.cmod:931:   /*! @decl string hex2string(string hex)    *! @appears String.hex2string    *!    *! Convert a string of hexadecimal digits to binary data.    *!    *! @seealso    *! @[string2hex()]    */   PMOD_EXPORT   PIKEFUN string(0..255) hex2string(string hex) -  errname String.hex2string; +     optflags OPT_TRY_OPTIMIZE;   {    struct pike_string *s;    int tmp, i;    unsigned char *p, *q = (unsigned char *)hex->str;    int l = hex->len>>1;    if(hex->size_shift) Pike_error("Only hex digits allowed.\n");    if(hex->len&1) Pike_error("Can't have odd number of digits.\n");       s = begin_shared_string(l);
pike.git/src/builtin.cmod:960:      /*! @decl array(int) range(string s)    *! @appears String.range    *!    *! Returns the character range of a string in an array of two    *! elements. The first element contains the lower bound and the    *! second the upper. The precision is only 8 bits, so for wide    *! strings only character blocks are known.    */   PIKEFUN array(int) string_range(string s) -  errname String.range; +  errname range;    optflags OPT_TRY_OPTIMIZE;   {    int min, max;    check_string_range(s, 0, &min, &max);    pop_n_elems(args);    push_int(min);    push_int(max);    f_aggregate(2);   }   
pike.git/src/builtin.cmod:1179:    *! @member function(int:void) "done_cb"    *! This function is called when the gc is done and about to exit.    *! The argument is the same value as will be returned by gc().    *! @endmapping    *!    *! @seealso    *! @[gc], @[Debug.gc_status]    */   PMOD_EXPORT   PIKEFUN mapping(string:mixed) gc_parameters (void|mapping(string:mixed) params) -  errname Pike.gc_parameters; +     optflags OPT_SIDE_EFFECT;   {    struct pike_string *str;    struct svalue *set;    struct svalue get;       if (!params) {    push_mapping (allocate_mapping (6));    params = Pike_sp[-1].u.mapping;    }
pike.git/src/builtin.cmod:1206:    else { \    GET; \    mapping_string_insert (params, str, &get); \    } \    } while (0)      #define HANDLE_FLOAT_FACTOR(NAME, VAR) \    HANDLE_PARAM (NAME, { \    if (TYPEOF(*set) != T_FLOAT || \    set->u.float_number < 0.0 || set->u.float_number > 1.0) \ -  SIMPLE_BAD_ARG_ERROR ("Pike.gc_parameters", 1, \ +  SIMPLE_BAD_ARG_ERROR ("gc_parameters", 1, \    "float between 0.0 and 1.0 for " NAME); \    VAR = DO_NOT_WARN ((double) set->u.float_number); \    }, { \    SET_SVAL(get, T_FLOAT, 0, float_number, \    DO_NOT_WARN ((FLOAT_TYPE) VAR)); \    });       HANDLE_PARAM ("enabled", {    if (TYPEOF(*set) != T_INT || set->u.integer < -1 || set->u.integer > 1) -  SIMPLE_BAD_ARG_ERROR ("Pike.gc_parameters", 1, +  SIMPLE_BAD_ARG_ERROR ("gc_parameters", 1,    "integer in the range -1..1 for 'enabled'");    if (gc_enabled != set->u.integer) {    if (gc_enabled > 0) {    /* Disabling automatic gc - save the old alloc_threshold and set it to    * the maximum value to avoid getting gc_evaluator_callback added. */    saved_alloc_threshold = alloc_threshold;    alloc_threshold = GC_MAX_ALLOC_THRESHOLD;    }    else if (set->u.integer > 0) {    /* Enabling automatic gc - restore the old alloc_threshold. If the
pike.git/src/builtin.cmod:1376:    *! occurs in the string @[haystack]. The special cases for the needle    *! @expr{""@} is that it occurs one time in the empty string, zero    *! times in a one character string and between every character    *! (length-1) in any other string.    *!    *! @seealso    *! @[search()], @[`/()]    */   PMOD_EXPORT   PIKEFUN int string_count(string haystack, string needle) -  errname String.count; +  errname count;    optflags OPT_TRY_OPTIMIZE;   {    ptrdiff_t c = 0;    ptrdiff_t i, j;       switch (needle->len)    {    case 0:    switch (haystack->len)    {
pike.git/src/builtin.cmod:1415:    RETURN DO_NOT_WARN((INT_TYPE)c);   }      /*! @decl string trim_whites (string s)    *! @belongs String    *!    *! Trim leading and trailing spaces and tabs from the string @[s].    */   PMOD_EXPORT   PIKEFUN string string_trim_whites (string s) -  errname String.trim_whites; +  errname trim_whites;    optflags OPT_TRY_OPTIMIZE;   {    ptrdiff_t start = 0, end = s->len;    int chr;    switch (s->size_shift) {   #define DO_IT(TYPE) \    { \    for (; start < s->len; start++) { \    chr = ((TYPE *) s->str)[start]; \    if (chr != ' ' && chr != '\t') break; \
pike.git/src/builtin.cmod:1465:    *! @note    *! Trailing and leading whitespace around \r and \n characters    *! is stripped as well (only useful if they're not in the @[whitespace] set).    *!    *! @note    *! This function is a lot faster with just one argument (i.e. the builtin    *! whitespace set has an optimised code path).    */   PMOD_EXPORT   PIKEFUN string string_normalize_space (string s, string|void whitespace) -  errname String.normalize_space; +  errname normalize_space;    optflags OPT_TRY_OPTIMIZE;   {    size_t len = s->len, wlen;    const void *src = s->str;    unsigned shift = s->size_shift, replspace;    const void *ws;    void *wstemp = 0;    struct string_builder sb;    unsigned foundspace = 0;   
pike.git/src/builtin.cmod:1596:      /*! @decl string trim_all_whites (string s)    *! @belongs String    *!    *! Trim leading and trailing white spaces characters (space, tab,    *! newline, carriage return, form feed, vertical tab and all the    *! white spaces defined in Unicode) from the string @[s].    */   PMOD_EXPORT   PIKEFUN string string_trim_all_whites (string s) -  errname String.trim_all_whites; +  errname trim_all_whites;    optflags OPT_TRY_OPTIMIZE;   {    ptrdiff_t start = 0, end = s->len;    int chr;    switch (s->size_shift) {      #define DO_IT(TYPE,CASE) \    { \    for (; start < end; start++) { \    chr = ((TYPE *) s->str)[start]; \
pike.git/src/builtin.cmod:1648:    *!    *! @note    *! Currently returns the empty string (@expr{""@})    *! if @[verbose] is zero.    *!    *! @note    *! The formatting and contents of the result    *! may vary between different versions of Pike.    */   PIKEFUN string string_status(int verbose) -  errname String.status; +  errname status;   {    RETURN add_string_status(verbose);   }      /*! @decl int implements(program prog, program api)    *! @belongs Program    *!    *! Returns 1 if @[prog] implements @[api].    */   PMOD_EXPORT   PIKEFUN int program_implements(program prog, program api) -  errname Program.implements; +  errname implements;    optflags OPT_TRY_OPTIMIZE;   {    RETURN implements(prog, api);   }      /*! @decl int inherits(program|object child, program parent)    *! @belongs Program    *!    *! Returns 1 if @[child] has inherited @[parent].    */   PMOD_EXPORT   PIKEFUN int program_inherits(program|object child, program parent) -  errname Program.inherits; +  errname inherits;    optflags OPT_TRY_OPTIMIZE;   {    struct program *p = program_from_svalue(child);       if (!p) -  SIMPLE_ARG_TYPE_ERROR("Program.inherits", 1, "program|object"); +  SIMPLE_ARG_TYPE_ERROR("inherits", 1, "program|object");    RETURN low_get_storage(p, parent) != -1;   }      /*! @decl string defined(program p)    *! @belongs Program    *!    *! Returns a string with filename and linenumber describing where    *! the program @[p] was defined.    *!    *! The returned string is of the format @expr{"filename:linenumber"@}.    *!    *! If it cannot be determined where the program was defined, @expr{0@}    *! (zero) will be returned.    */   PMOD_EXPORT   PIKEFUN string program_defined(program p) -  errname Program.defined; +  errname defined;    optflags OPT_TRY_OPTIMIZE;   {    INT_TYPE line;    struct pike_string *tmp = low_get_program_line(p, &line);       pop_n_elems(args);       if (tmp) {    push_string(tmp);    if(line >= 1)
pike.git/src/builtin.cmod:1740:    *! The string @[s] contains characters >= 65536.    *! @endint    *!    *! @note    *! It is possible that a future version of Pike may return    *! further values. In particular the width @expr{7@} seems    *! like it could be useful.    */   PMOD_EXPORT   PIKEFUN int(8 .. 8)|int(16 .. 16)|int(32 .. 32) string_width(string s) -  errname String.width; +  errname width;    optflags OPT_TRY_OPTIMIZE;   {    RETURN 8 * (1 << s->size_shift);   }      /*! @decl mixed m_delete(object|mapping map, mixed index)    *!    *! If @[map] is an object that implements @[lfun::_m_delete()],    *! that function will be called with @[index] as its single argument.    *!
pike.git/src/builtin.cmod:2201:    pop_stack();    push_int (0);    }       else {    char *entry = getenv (var->str);    pop_stack();    if (!entry)    push_int (0);    else { -  char *eq = STRCHR (entry, '='); +  char *eq = strchr (entry, '=');    /* There should always be a '=' in the entry, but you never know.. */    push_string (make_shared_string (eq ? eq + 1 : entry));    }    }    }       else {   #ifdef DECLARE_ENVIRON    extern char **environ;   #endif
pike.git/src/builtin.cmod:2229:    * one in gnu libc). */    for (n = 0; environ[n]; n++) {}       m = allocate_mapping (n);   #ifndef USE_SETENV    if (env_allocs)    new_env_allocs = allocate_mapping (m_sizeof (env_allocs));   #endif /* !USE_SETENV */       while (--n >= 0) { -  char *entry = environ[n], *eq = STRCHR (entry, '='); +  char *entry = environ[n], *eq = strchr (entry, '=');    if (eq) { /* gnu libc getenv ignores variables without '='. */    struct pike_string *var = make_shared_binary_string (entry, eq - entry);    struct pike_string *val = make_shared_string (eq + 1);    mapping_string_insert_string (m, var, val);      #ifndef USE_SETENV    /* Populate new_env_allocs with the env_allocs entries that    * are still in use. */    if (env_allocs) {    struct svalue *ea_val = low_mapping_string_lookup (env_allocs, var);
pike.git/src/builtin.cmod:2272:    * updates the real environment. Everyone should use the version in    * the master instead so that the cache doesn't get stale. */   PIKEFUN void _putenv (string var, void|string val)   {   #ifndef USE_SETENV    struct pike_string *putenv_str, *env_alloc_var;   #endif       if (var->size_shift)    SIMPLE_ARG_TYPE_ERROR ("putenv", 1, "string(0..255)"); -  if (string_has_null (var) || STRCHR (var->str, '=')) +  if (string_has_null (var) || strchr (var->str, '='))    SIMPLE_ARG_ERROR ("putenv", 1, "Variable name cannot contain '=' or NUL.");       if (val) {   #ifndef USE_SETENV    struct string_builder sb;   #endif       if (val->size_shift)    SIMPLE_ARG_TYPE_ERROR ("putenv", 2, "void|string(0..255)");    if (string_has_null (val))
pike.git/src/builtin.cmod:2613:    push_int(3);    }    }       /*! @decl mixed `[](int index, int|void end_or_none)    *! The BacktraceFrame object can be indexed as an array.    */    PIKEFUN mixed `[](int index, int|void end_or_none)    {    INT_TYPE end = index; -  INT32 numargs = 0; +  INT32 numargs = 3;    INT32 i;    -  if (THIS->args) { -  numargs = THIS->args->size; -  } +  if (THIS->args) +  numargs += THIS->args->size;    -  numargs += 3; -  +     if (!end_or_none) { -  if (index < 0) { +  if (index < 0)    index_error("pike_frame->`[]", Pike_sp-args, args, NULL, Pike_sp-args,    "Indexing with negative index (%"PRINTPIKEINT"d)\n", index); -  } else if (index >= numargs) { +  else if (index >= numargs)    index_error("pike_frame->`[]", Pike_sp-args, args, NULL, Pike_sp-args,    "Indexing with too large index (%"PRINTPIKEINT"d)\n", index); -  } -  } else { -  if (TYPEOF(*end_or_none) != PIKE_T_INT) { -  SIMPLE_BAD_ARG_ERROR("`[]",2,"int|void"); -  } +  } else    end = end_or_none->u.integer; -  } +        pop_n_elems(args);       if (end_or_none) {    if ((end < 0) || (end < index) || (index >= numargs)) {    f_aggregate(0);    return;    }    -  if (end >= numargs) { +  if (end >= numargs)    end = numargs-1;    } -  } +        for (i = index; i <= end; i++) {    switch(i) {    case 0: /* Filename */    if (THIS->lineno == -1) fill_in_file_and_line(); -  if (THIS->filename) { +  if (THIS->filename)    ref_push_string(THIS->filename); -  } else { +  else    push_int(0); -  } +     break;    case 1: /* Linenumber */    if (THIS->lineno == -1) fill_in_file_and_line();    push_int(THIS->lineno);    break;    case 2: /* Function */    push_svalue(&THIS->_fun);    break;    default: /* Arguments */    {    if ((i > 2) && (THIS->args) && (i-3 < THIS->args->size)) {    push_svalue(THIS->args->item + (i - 3));    break;    } -  bad_arg_error("backtrace_frame->`[]", Pike_sp-args, args, 1, +  bad_arg_error("`[]", Pike_sp-args, args, 1,    "int(0..)", Pike_sp-args,    "Bad argument 1 to backtrace_frame->`[](): "    "Expected int(0..%d)\n",    numargs + 2);    }    /* NOT_REACHED */    break;    }    } -  if (end_or_none) { +  if (end_or_none)    f_aggregate(1 + end - index);    } -  } +        /*! @decl mixed `[]=(int index, mixed value)    */    PIKEFUN mixed `[]=(int index, mixed value)    { -  INT32 numargs = 0; +  INT32 numargs = 3;    -  if (THIS->args) { -  numargs = THIS->args->size; -  } +  if (THIS->args) +  numargs += THIS->args->size;    -  numargs += 3; -  -  if ((index < -numargs) || (index >= numargs)) { +  if ((index < -numargs) || (index >= numargs))    index_error("pike_frame->`[]=", Pike_sp-args, args, NULL, Pike_sp-args,    "Index %"PRINTPIKEINT"d is out of array range 0..%d,\n",    index, numargs-1); -  } else if (index < 0) { +  else if (index < 0)    index += numargs; -  } +        if (args > 2) {    pop_n_elems(args - 2);    args = 2;    }       switch(index) {    case 0: /* Filename */    if (THIS->lineno == -1) fill_in_file_and_line();    if (TYPEOF(*value) != PIKE_T_STRING) {    if ((TYPEOF(*value) != PIKE_T_INT) ||    (value->u.integer)) { -  SIMPLE_BAD_ARG_ERROR("backtrace_frame->`[]=", 2, -  "string|int(0..0)"); +  SIMPLE_BAD_ARG_ERROR("`[]=", 2, "string|int(0..0)");    }    if (THIS->filename) {    free_string(THIS->filename);    THIS->filename = NULL;    }    } else {    if (THIS->filename) {    free_string(THIS->filename);    THIS->filename = NULL;    }    copy_shared_string(THIS->filename, value->u.string);    }    break;       case 1: /* Linenumber */    if (THIS->lineno == -1) fill_in_file_and_line(); -  if (TYPEOF(*value) != PIKE_T_INT) { -  SIMPLE_BAD_ARG_ERROR("backtrace_frame->`[]=", 2, "int(1..)"); -  } +  if (TYPEOF(*value) != PIKE_T_INT) +  SIMPLE_BAD_ARG_ERROR("`[]=", 2, "int(1..)");    THIS->lineno = value->u.integer;    break;       case 2: /* Function */    if (THIS->lineno == -1) fill_in_file_and_line();    assign_svalue(&THIS->_fun, value);    break;    default: /* Arguments */    assign_svalue(THIS->args->item + index - 3, value);    break;
pike.git/src/builtin.cmod:2957:    optflags OPT_EXTERNAL_DEPEND;   {    low_backtrace(& Pike_interpreter);   }      /*! @module String    */      /*! @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. +  *! conceptually similar to a string, but speed-optimised for growing +  *! strings.    *! -  *! 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;
pike.git/src/builtin.cmod:2987:    *! 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) +  /*! @decl void create(void|int(1..) 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; +  init_string_builder_alloc(&str->str, +  str->initial = size ? MINIMUM(size->u.integer, 1 ) : 256 , 0);    }       /*! @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. +  *! as @tt{%s@} just as if it were a string.    */    PIKEFUN string _sprintf( int flag, mapping flags )    {    switch( flag )    {    case 'O':    {    struct pike_string *res;    struct Buffer_struct *str = THIS;    push_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 );
pike.git/src/builtin.cmod:3061:    }    return;       case 't':    RETURN make_shared_binary_string("Buffer",6);    }    pop_n_elems( args );    push_undefined();    }    -  /*! @decl mixed cast( string type ) +  /*! @decl string|int 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 ) +  PIKEFUN string|int 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;
pike.git/src/builtin.cmod:3094:    else    f_Buffer_get( 0 );    o_cast_to_int( );    return;    }       pop_stack();    push_undefined();    }    -  /*! @decl String.Buffer `+( string|String.Buffer what ) +  /*! @decl int `[](int index)    */ -  PIKEFUN object `+( string|Buffer what ) +  PIKEFUN int `[](int index) +  { +  struct pike_string *s = THIS->str.s; +  unsigned len = s->len; +  +  if (index<0) +  index += len; +  if (index<0 || index>=len) +  index_error("Buffer->`[]", Pike_sp, args, NULL, Pike_sp, +  "Index %"PRINTPIKEINT"d is out of array range 0..%d,\n", +  index, len-1); +  RETURN generic_extract(s->str, s->size_shift, index); +  } +  +  /*! @decl Buffer `[..](int start, int start_type, int end, int end_type) +  */ +  PIKEFUN Buffer `[..](int start, int start_type, int end, int end_type) +  { +  struct Buffer_struct *str = THIS; +  struct pike_string *s = str->str.s; +  unsigned len = s->len, shift = s->size_shift; +  char *p; +  +  struct object *res; +  struct Buffer_struct *str2; +  +  pop_n_elems(args); +  if (start_type == INDEX_FROM_END) +  start = len-1-start; +  if (end_type != INDEX_FROM_BEG) +  end = len-1-end; +  res = fast_clone_object( Buffer_program ); +  str2 = OBJ2_BUFFER( res ); +  if (start < 0) +  start = 0; +  if (end >= len) +  end = len-1; +  str2->initial = end -= start-1; +  init_string_builder_alloc (&str2->str, end, shift); +  p = s->str; +  memcpy ((s = str2->str.s)->str, p+(start<<shift), end<<shift); +  s->str[end<<shift] = 0; // Ensure NUL-termination +  s->len = end; +  if( (Pike_fp->current_object->flags & OBJECT_CLEAR_ON_EXIT) ) +  res->flags |= OBJECT_CLEAR_ON_EXIT; +  push_object (res); +  } +  +  /*! @decl int `[]=(int index, int ch) +  */ +  PIKEFUN int `[]=(int index, int ch) +  { +  struct Buffer_struct *str = THIS; +  struct pike_string *s = str->str.s; +  unsigned len = s->len; +  +  pop_n_elems(args); +  +  if (index<0) +  index += len; +  if (index<0 || index>=len) +  index_error("Buffer->`[]=", Pike_sp, args, NULL, Pike_sp, +  "Index %"PRINTPIKEINT"d is out of array range 0..%d,\n", +  index, len-1); +  if ((unsigned)ch >= 256) +  switch(s->size_shift) { +  case 0: +  if ((unsigned)ch < 65536) +  len = 1; +  else { +  case 1: +  if((unsigned)ch >= 65536) +  len = 2; +  else +  break; +  } +  string_build_mkspace(&str->str, 0, str->str.known_shift = len); +  } +  low_set_index(str->str.s,index,ch); +  push_int(ch); +  } +  +  /*! @decl Buffer `+( string|Buffer what ) +  */ +  PIKEFUN Buffer `+( 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 ) +  /*! @decl Buffer `+=( string|Buffer what )    */ -  PIKEFUN object `+=( string|Buffer what ) +  PIKEFUN Buffer `+=( 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. -  *! -  *! @seealso -  *! @[addat()] -  */ -  PIKEFUN int add( string|Buffer ... arg1 ) -  rawtype tFuncV(tNone, tOr(tString, tObjIs_BUFFER), tIntPos); +  static struct pike_string*getotherstr(struct svalue*other,unsigned stricttype)    { -  struct Buffer_struct *str = THIS; -  int init_from_arg0 = 0, j; -  -  for (j=0; j < args; j++) { -  if (TYPEOF(Pike_sp[j-args]) == PIKE_T_STRING) { -  } else if ((TYPEOF(Pike_sp[j-args]) != PIKE_T_OBJECT) || -  (Pike_sp[j-args].u.object->prog != Buffer_program)) { -  SIMPLE_BAD_ARG_ERROR("add", j+1, "string|String.Buffer"); +  switch(TYPEOF(*other)) +  { +  case PIKE_T_STRING: +  return other->u.string; +  case PIKE_T_OBJECT: +  if (other->u.object->prog == Buffer_program) +  return OBJ2_BUFFER(other->u.object)->str.s;    } -  +  if(stricttype) +  Pike_error("Unsupported types in comparison.\n"); +  return 0;    }    -  if (!str->str.s && args) { -  ptrdiff_t sum = 0; -  int shift = 0; -  for (j=0; j < args; j++) { +  /*! @decl int(0..1) `==( mixed other ) +  *! +  *! Is able to compare directly with strings and other Buffers. +  */ +  PIKEFUN int(0..1) `==( mixed other ) +  rawtype tFunc(tMixed, tInt01); +  {    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; +  RETURN ((a = getotherstr(other,0)) ? !my_quick_strcmp(THIS->str.s, a) : 0);    } -  sum += a->len; -  shift |= a->size_shift; -  } -  if (sum < str->initial) -  sum = str->initial; -  else if (sum > str->initial) -  sum <<= 1; -  shift = shift & ~(shift >> 1); +     -  if ((TYPEOF(Pike_sp[-args]) == PIKE_T_STRING) && -  (shift == Pike_sp[-args].u.string->size_shift) && -  init_string_builder_with_string (&str->str, Pike_sp[-args].u.string)) { -  mark_free_svalue (Pike_sp - args); -  if (sum > str->str.s->len) -  string_build_mkspace (&str->str, sum - str->str.s->len, shift); -  init_from_arg0 = 1; +  /*! @decl int(0..1) `<( mixed other ) +  *! +  *! Is able to compare directly with strings and other Buffers. +  */ +  PIKEFUN int(0..1) `<( mixed other ) +  rawtype tFunc(tMixed, tInt01); +  { +  RETURN my_quick_strcmp(THIS->str.s, getotherstr(other,1))<0;    } -  else -  init_string_builder_alloc(&str->str, sum, shift); +     -  /* We know it will be a string that really is this wide. */ -  str->str.known_shift = shift; -  } -  -  for( j = init_from_arg0; j<args; j++ ) +  /*! @decl int(0..1) `>( mixed other ) +  *! +  *! Is able to compare directly with strings and other Buffers. +  */ +  PIKEFUN int(0..1) `>( mixed other ) +  rawtype tFunc(tMixed, tInt01);    { -  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; +  RETURN my_quick_strcmp(THIS->str.s, getotherstr(other,1))>0;    } -  string_builder_shared_strcat( &str->str, a ); -  } +     -  if (str->str.s) { -  RETURN str->str.s->len; -  } else { -  RETURN 0; -  } -  } -  -  /*! @decl int addat(int(0..) pos, string|String.Buffer ... data) +  /*! @decl int addat(int(0..) pos, string|Buffer ... data)    *!    *! Adds @[data] to the buffer, starting at position @[pos]. -  +  *! It overwrites existing content at that offset, never truncates the +  *! buffer, possibly extends the buffer if the new content does not fit.    *!    *! @returns    *! Returns the size of the buffer.    *!    *! @note -  *! If the buffer isn't of the required size, it will be padded -  *! with NUL-characters. +  *! If the starting position @[pos] extends beyond the end of the current +  *! buffer content, the gap will be filled with NUL-characters.    *! -  *! @note -  *! Pike 7.8 and earlier did not support adding @[String.Buffer]s -  *! directly. -  *! +     *! @seealso    *! @[add()]    */ -  PIKEFUN int addat(int(0..) pos, string ... arg1 ) -  rawtype tFuncV(tNone, tOr(tString, tObjIs_BUFFER), tIntPos); +  PIKEFUN int addat(int(0..) pos, string|Buffer ... arg1 ) +  rawtype tFuncV(tIntPos, tOr(tString, tObjIs_BUFFER), tIntPos);    {    struct Buffer_struct *str = THIS; -  +  struct pike_string *s; +  ptrdiff_t sum = 0; +  int j,shift = 0;       if (pos < 0)    SIMPLE_BAD_ARG_ERROR("addat", 1, "int(0..)");    -  if (args) { -  int init_from_arg0 = 0, j; -  ptrdiff_t sum = 0; -  int shift = 0; +     for (j=1; j < args; j++) {    struct pike_string *a; -  if (TYPEOF(Pike_sp[j-args]) == PIKE_T_STRING) { +  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)) { +  else if ((TYPEOF(Pike_sp[j-args]) != PIKE_T_OBJECT) || +  (Pike_sp[j-args].u.object->prog != Buffer_program))    SIMPLE_BAD_ARG_ERROR("addat", j+1, "string|String.Buffer"); -  } else { -  a = OBJ2_BUFFER(Pike_sp[j-args].u.object)->str.s; -  if (!a) continue; -  } +  else if(!(a = OBJ2_BUFFER(Pike_sp[j-args].u.object)->str.s)) +  continue;    sum += a->len;    shift |= a->size_shift;    }    -  if (!str->str.s) { -  if ((sum + pos) <= str->initial) { -  sum = str->initial; -  } else { -  sum <<= 1; +  s = str->str.s;    sum += pos; -  } -  shift = shift & ~(shift >> 1); -  -  init_string_builder_alloc(&str->str, sum, shift); -  } else { -  sum += pos; +     shift |= str->str.known_shift;    shift = shift & ~(shift >> 1); -  if (sum > str->str.s->len) { -  string_build_mkspace(&str->str, sum - str->str.s->len, shift); -  } else if (shift != str->str.known_shift) { -  string_build_mkspace(&str->str, 0, shift); +  j = sum - s->len; +  if (j>0) { +  if (str->initial > sum) +  j = str->initial-s->len; +  string_build_mkspace(&str->str, j, shift);    } -  } +  else if (shift != str->str.known_shift) +  string_build_mkspace(&str->str, 0, shift); +  s = str->str.s;    /* We know it will be a string that really is this wide. */    str->str.known_shift = shift;    -  if (str->str.s->len < pos) { -  /* Clear the padding. */ -  MEMSET(str->str.s->str + (str->str.s->len << str->str.s->size_shift), -  0, (pos - str->str.s->len) << str->str.s->size_shift); -  } +  if (s->len < pos) // Clear the padding +  memset(s->str + (s->len << s->size_shift), +  0, (pos - s->len) << s->size_shift);       for(j = 1; j<args; j++) {    struct pike_string *a; -  if (TYPEOF(Pike_sp[j-args]) == PIKE_T_STRING) { +  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, pos), a); +  else if(!(a = OBJ2_BUFFER(Pike_sp[j-args].u.object)->str.s)) +  continue; +  pike_string_cpy(MKPCHARP_STR_OFF(s, pos), a);    pos += a->len;    }    -  if (str->str.s->len < pos) { -  str->str.s->len = pos; -  /* Ensure NUL-termination */ -  str->str.s->str[str->str.s->len << str->str.s->size_shift] = 0; +  if (s->len < pos) { +  s->len = pos; +  s->str[s->len << s->size_shift] = 0; // Ensure NUL-termination    } -  +  +  RETURN s->len;    }    -  if (str->str.s) { -  RETURN str->str.s->len; -  } else { -  RETURN 0; +  /*! @decl int add(string|Buffer ... data) +  *! +  *! Adds @[data] to the buffer. +  *! +  *! @returns +  *! Returns the size of the buffer. +  *! +  *! @seealso +  *! @[addat()] +  */ +  PIKEFUN int add( string|Buffer ... arg1 ) +  rawtype tFuncV(tNone, tOr(tString, tObjIs_BUFFER), tIntPos); +  { +  struct Buffer_struct *str = THIS; +  push_int(str->str.s->len); +  stack_revroll(++args); +  f_Buffer_addat(args);    } -  } +     -  /*! @decl void putchar(int c) -  *! Appends the character @[c] at the end of the string. +  /*! @decl void putchar(int ch) +  *! Appends the character @[ch] at the end of the string.    */ -  PIKEFUN void putchar(int c) { +  PIKEFUN void putchar(int ch) {    struct Buffer_struct *str = THIS; -  if(!str->str.s) -  init_string_builder_alloc(&str->str, str->initial, 0); -  string_builder_putchar(&str->str, c); +  string_builder_putchar(&str->str, ch);    }       /*! @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, 0, &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; -  if( str ) +  ptrdiff_t len; +  if((len = str->len) > 0 )    { -  ptrdiff_t len = str->len; -  if( 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: +  default:    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; -  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; -  RETURN s; +  push_string(s); +  // Pick a smaller size to minimise fragmentation +  // addat() will expand if it notices reuse of +  // the Buffer +  init_string_builder_alloc(&str->str, sizeof(struct svalue), 0);    } -  +  +  /*! @decl Buffer|void cut(int start, int|void end, void|int discard) +  *! +  *! Cut and delete the range of data from the current buffer. +  *! Returns a new buffer with the cut data, unless discard is true. +  *! +  *! @seealso +  *! @[get()], @[get_copy()], @[clear()] +  */ +  PIKEFUN Buffer|void cut(int index, int|void end_or_none,void|int discard) +  { +  struct Buffer_struct *str = THIS, *str2; +  struct object *res; +  struct pike_string *s = str->str.s; +  unsigned len = s->len,shift = s->size_shift; +  char *p = s->str; +  INT_TYPE end,vdiscard; +  +  end = args==1 ? len-1 : end_or_none->u.integer; +  vdiscard = args==3 ? discard->u.integer : 0;    pop_n_elems(args); -  push_empty_string(); -  return; +  +  if (index < 0) +  index = 0; +  if (end >= len) +  end = len-1; +  +  p = (char*)p+(index<<shift); +  index = end-index+1; +  end = len-end; +  len = index<<shift; +  if (!vdiscard) +  { +  struct pike_string *s2; +  +  res = fast_clone_object( Buffer_program ); +  str2 = OBJ2_BUFFER( res ); +  init_string_builder_alloc(&str2->str, str2->initial = index, shift); +  memcpy((s2=str2->str.s)->str, p, len); +  s2->str[len] = 0; // Ensure NUL-termination +  s2->len = index;    } -  +  memmove(p, p+len, end<<shift); // Copy NUL-termination +  if( s->flags & STRING_CLEAR_ON_EXIT) +  guaranteed_memset(p+len+(end<<shift) , 0, len ); +  s->len -= index;    -  +  if(!vdiscard) +  { +  if( (Pike_fp->current_object->flags & OBJECT_CLEAR_ON_EXIT) ) +  res->flags |= OBJECT_CLEAR_ON_EXIT; +  push_object(res); +  } +  else +  push_undefined(); +  } +     /*! @decl void clear()    *! -  *! Empty the buffer, and don't care about the old content. +  *! Empty the buffer, and discard the old content.    *! -  *! @note -  *! This function was not available in Pike 7.8 and earlier. -  *! +     *! @seealso -  *! @[get()] +  *! @[get()], @[cut()]    */    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; +  reset_string_builder(&str->str);    } -  } +        /*! @decl int _sizeof()    *!    *! Returns the size of the buffer.    */    PIKEFUN int _sizeof()    {    struct Buffer_struct *str = THIS; -  RETURN str->str.s ? str->str.s->len : 0; +  RETURN str->str.s->len;    }       INIT    {    struct Buffer_struct *str = THIS; -  MEMSET( str, 0, sizeof( *str ) ); +  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 )    guaranteed_memset( str->str.s->str, 0, str->str.s->len );    free_string_builder( &str->str );    } -  } +        GC_RECURSE    { -  if (mc_count_bytes (Pike_fp->current_object) && THIS->str.s) +  if (mc_count_bytes (Pike_fp->current_object))    mc_counted_bytes += THIS->str.malloced;    }   }      /*! @endclass    */      /*! @class Replace    *!    *! This is a "compiled" version of the @[replace] function applied on
pike.git/src/builtin.cmod:3535:    *    * It probably has to do with the "if (!args)" above: It should    * be possible to create an empty instance. /mast    */    if (!from_arg || !to_arg) {    Pike_error("Bad number of arguments to create().\n");    }    pop_n_elems(args-2);    args = 2;    if (TYPEOF(*from_arg) != T_ARRAY) { -  SIMPLE_BAD_ARG_ERROR("Replace", 1, +  SIMPLE_BAD_ARG_ERROR("replace", 1,    "array(string)|mapping(string:string)");    }    if (TYPEOF(*to_arg) == T_STRING) {    push_int(from_arg->u.array->size);    stack_swap();    f_allocate(2);    }    if (TYPEOF(*to_arg) != T_ARRAY) { -  SIMPLE_BAD_ARG_ERROR("Replace", 2, "array(string)|string"); +  SIMPLE_BAD_ARG_ERROR("replace", 2, "array(string)|string");    }    if (from_arg->u.array->size != to_arg->u.array->size) {    Pike_error("Replace must have equal-sized from and to arrays.\n");    }    add_ref(THIS->from = from_arg->u.array);    add_ref(THIS->to = to_arg->u.array);    }       if (!THIS->from->size) {    /* Enter no-op mode. */    pop_n_elems(args);    push_int(0);    return;    }       if( (THIS->from->type_field & ~BIT_STRING) &&    (array_fix_type_field(THIS->from) & ~BIT_STRING) ) -  SIMPLE_BAD_ARG_ERROR("Replace", 1, +  SIMPLE_BAD_ARG_ERROR("replace", 1,    "array(string)|mapping(string:string)");       if( (THIS->to->type_field & ~BIT_STRING) &&    (array_fix_type_field(THIS->to) & ~BIT_STRING) ) -  SIMPLE_BAD_ARG_ERROR("Replace", 2, "array(string)|string"); +  SIMPLE_BAD_ARG_ERROR("replace", 2, "array(string)|string");       compile_replace_many(&THIS->ctx, THIS->from, THIS->to, 1);       pop_n_elems(args);    push_int(0);    }       /*! @decl string `()(string str)    */    PIKEFUN string `()(string str)
pike.git/src/builtin.cmod:3620:    push_svalue(encoded->item + i);    stack_swap();    }    pop_stack();       f_multi_string_replace_create(i);    }       INIT    { -  MEMSET(&THIS->ctx, 0, sizeof(struct replace_many_context)); +  memset(&THIS->ctx, 0, sizeof(struct replace_many_context));    }       EXIT    gc_trivial;    {    free_replace_many_context(&THIS->ctx);    }   }      /*! @endclass
pike.git/src/builtin.cmod:3676:    THIS->del = NULL;    }    if (THIS->to) {    free_string(THIS->to);    THIS->to = NULL;    }       if (!del) return;       if (!to) { -  SIMPLE_BAD_ARG_ERROR("String.SingleReplace->create", 2, "string"); +  SIMPLE_BAD_ARG_ERROR("replace", 2, "string");    }       if (del == to) {    /* No-op... */    return;    }       copy_shared_string(THIS->del, del);    copy_shared_string(THIS->to, to);   
pike.git/src/builtin.cmod:5475:    if (THIS->num_elems) {    struct pike_list_node *node = THIS->head;    int i;    for (i = 0; i < THIS->num_elems; i++) {    assign_svalue_no_free(ITEM(a) + i, &node->val);    node = node->next;    }    }    }    -  /*! @decl mixed cast(string type) +  /*! @decl array cast(string type)    *! -  *! Cast the lists. @expr{array@} and @expr{object@} are the only -  *! supported types. +  *! Cast the lists. @expr{array@} is the only +  *! supported type.    */ -  PIKEFUN mixed cast(string type) +  PIKEFUN array cast(string type)    flags ID_PROTECTED;    {    pop_stack(); /* type as at least one more reference. */    if (type == literal_array_string)    apply_current(f_List_cq__values_fun_num, 0); -  else if (type == literal_object_string) -  ref_push_object(Pike_fp->current_object); +     else    push_undefined();    }          /*! @decl mixed `[](mixed key) */    PIKEFUN mixed `[](mixed key)    flags ID_PROTECTED;    {    struct pike_list_node *node;