pike.git / src / encode.c

version» Context lines:

pike.git/src/encode.c:1:   /*   || 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. - || $Id: encode.c,v 1.178 2003/06/05 12:34:43 grubba Exp $ + || $Id: encode.c,v 1.179 2003/06/05 15:03:38 mast Exp $   */      #include "global.h"   #include "stralloc.h"   #include "pike_macros.h"   #include "object.h"   #include "constants.h"   #include "interpret.h"   #include "svalue.h"   #include "mapping.h"
pike.git/src/encode.c:20:   #include "operators.h"   #include "builtin_functions.h"   #include "module_support.h"   #include "fsort.h"   #include "threads.h"   #include "stuff.h"   #include "version.h"   #include "bignum.h"   #include "pikecode.h"    - RCSID("$Id: encode.c,v 1.178 2003/06/05 12:34:43 grubba Exp $"); + RCSID("$Id: encode.c,v 1.179 2003/06/05 15:03:38 mast Exp $");      /* #define ENCODE_DEBUG */      /* Use the old encoding method for programs. */   /* #define OLD_PIKE_ENCODE_PROGRAM */      #ifdef ENCODE_DEBUG   /* Pass a nonzero integer as the third arg to encode_value,    * encode_value_canonic and decode_value to activate this debug. */   #define EDB(N,X) do { debug_malloc_touch(data); if (data->debug>=N) {X;} } while (0)
pike.git/src/encode.c:119:    /* The encoded mapping maps encoded things to their entry IDs. A    * negative value means that it's a forward reference to a thing not    * yet encoded. */    struct array *delayed;    dynamic_buffer buf;   #ifdef ENCODE_DEBUG    int debug, depth;   #endif   };    - static void encode_value2(struct svalue *val, struct encode_data *data, int force_dump); + static void encode_value2(struct svalue *val, struct encode_data *data, int force_encode);      #define addstr(s, l) low_my_binary_strcat((s), (l), &(data->buf))   #define addchar(t) low_my_putchar((char)(t), &(data->buf))      /* Code a pike string */      #if BYTEORDER == 4321   #define ENCODE_DATA(S) \    addstr( (S)->str, (S)->len << (S)->size_shift );   #else
pike.git/src/encode.c:429:    {    if(p->inherits[e].prog)    {    free_program(p->inherits[e].prog);    p->inherits[e].prog=0;    }    }    }   }    - /* force_dump == 0: Maybe dump the thing later, and only a forward + /* force_encode == 0: Maybe dump the thing later, and only a forward    * reference here (applies to programs only).    * -  * force_dump == 1: Dump the thing now. +  * force_encode == 1: Dump the thing now.    * -  * force_dump == 2: A forward reference has been encoded to this +  * force_encode == 2: A forward reference has been encoded to this    * thing. Now it's time to dump it. */    - static void encode_value2(struct svalue *val, struct encode_data *data, int force_dump) + static void encode_value2(struct svalue *val, struct encode_data *data, int force_encode)      #ifdef PIKE_DEBUG   #undef encode_value2   #define encode_value2(X,Y,Z) do { \    struct svalue *_=Pike_sp; \    struct svalue *X_ = (X); \    encode_value2_(X_,Y,Z); \    if(Pike_sp != _) { \    fprintf(stderr, "Stack error when encoding:\n"); \    print_svalue(stderr, X_); \
pike.git/src/encode.c:482:       if((val->type == T_OBJECT ||    (val->type==T_FUNCTION && val->subtype!=FUNCTION_BUILTIN)) &&    !val->u.object->prog)    val = &dested;       if((tmp=low_mapping_lookup(data->encoded, val)))    {    entry_id = *tmp; /* It's always a small integer. */    if (entry_id.u.integer < 0) entry_id.u.integer = -entry_id.u.integer; -  if (force_dump && tmp->u.integer < 0) { +  if (force_encode && tmp->u.integer < 0) {    EDB(1,    fprintf(stderr, "%*sEncoding delayed thing to <%d>: ",    data->depth, "", entry_id.u.integer);    if(data->debug == 1)    {    fprintf(stderr,"TAG%d",val->type);    }else{    print_svalue(stderr, val);       }
pike.git/src/encode.c:505:    tmp->u.integer = entry_id.u.integer;    }    else {    EDB(1,fprintf(stderr, "%*sEncoding TAG_AGAIN from <%d>\n",    data->depth, "", entry_id.u.integer));    code_entry(TAG_AGAIN, entry_id.u.integer, data);    goto encode_done;    }    }else {   #ifdef PIKE_DEBUG -  if (force_dump == 2) +  if (force_encode == 2)    Pike_fatal ("Didn't find old entry for delay encoded thing.\n");   #endif    if (val->type != T_TYPE) {    entry_id = data->counter; /* It's always a small integer. */    EDB(1,fprintf(stderr, "%*sEncoding to <%d>: ",    data->depth, "", entry_id.u.integer);    if(data->debug == 1)    {    fprintf(stderr,"TAG%d",val->type);    }else{
pike.git/src/encode.c:864:       /* We have to remove ourself from the cache */    map_delete(data->encoded, val);       pop_stack();    push_svalue(val);    f_object_program(1);       /* Code the program */    code_entry(TAG_OBJECT, 3,data); -  encode_value2(Pike_sp-1, data, 0); +  encode_value2(Pike_sp-1, data, 1);    pop_stack();       push_svalue(val);       /* If we do not exist in cache, use backwards-    * compatible method, otherwise use newfangled    * style=3. -Hubbe    */    if(!low_mapping_lookup(data->encoded, val))    {
pike.git/src/encode.c:1135:    for(d=0;d<p->num_constants;d++)    {    encode_value2(& p->constants[d].sval, data, 0);    adddata3(p->constants[d].name);    }      #else /* !OLD_PIKE_ENCODE_PROGRAM */       /* Portable encoding (4 and 5). */    -  if (!force_dump) { +  if (!force_encode) {    /* Encode later (5). */    EDB(1, fprintf(stderr, "%*sencode: delayed encoding of program\n",    data->depth, ""));    code_entry (TAG_PROGRAM, 5, data);    data->delayed = append_array (data->delayed, val);    tmp = low_mapping_lookup (data->encoded, val);    tmp->u.integer = -tmp->u.integer;    goto encode_done;    }   
pike.git/src/encode.c:1570:    *! @seealso    *! @[decode_value()], @[sprintf()], @[encode_value_canonic()]    */   void f_encode_value(INT32 args)   {    ONERROR tmp;    struct encode_data d, *data;    int i;    data=&d;    -  check_all_args("encode_value", args, BIT_MIXED, BIT_VOID | BIT_OBJECT, +  check_all_args("encode_value", args, +  BIT_MIXED, +  BIT_VOID | BIT_OBJECT | BIT_ZERO,   #ifdef ENCODE_DEBUG    /* This argument is only an internal debug helper.    * It's intentionally not part of the function    * prototype, to keep the argument position free for    * other uses in the future. */    BIT_VOID | BIT_INT,   #endif    0);       initialize_buf(&data->buf);    data->canonic = 0;    data->encoded=allocate_mapping(128);    data->delayed = allocate_array (0);    data->counter.type=T_INT;    data->counter.u.integer=COUNTER_START; -  if(args > 1) +  if(args > 1 && Pike_sp[1-args].type == T_OBJECT)    {    data->codec=Pike_sp[1-args].u.object;    }else{    data->codec=get_master();    }   #ifdef ENCODE_DEBUG    data->debug = args > 2 ? Pike_sp[2-args].u.integer : 0;    data->depth = -2;   #endif   
pike.git/src/encode.c:1719:    struct thread_state *thread_state;   #endif   #ifdef ENCODE_DEBUG    int debug, depth;   #endif    struct Supporter supporter;   };      static void decode_value2(struct decode_data *data);    - static void fallback_codec(void) - { -  size_t x; -  push_constant_text("."); -  f_divide(2); -  f_reverse(1); -  dmalloc_touch_svalue(Pike_sp-1); -  Pike_sp--; -  x=Pike_sp->u.array->size; -  push_array_items(Pike_sp->u.array); -  ref_push_mapping(get_builtin_constants()); -  while(x--) -  { -  stack_swap(); -  f_arrow(2); -  } - } -  +    static int my_extract_char(struct decode_data *data)   {    if(data->ptr >= data->len)    Pike_error("Format error, not enough data in string.\n");    return data->data [ data->ptr++ ];   }      #define GETC() my_extract_char(data)      #define DECODE(Z) do { \
pike.git/src/encode.c:2398:    goto decode_done;    }       case TAG_OBJECT:    {    decode_value2(data);       switch(num)    {    case 0: -  if(data->codec) -  { +     apply(data->codec,"objectof", 1); -  }else{ -  fallback_codec(); -  } +     break;       case 1:    {    int fun;    /* decode_value_clone_object does not call __INIT, so    * we want to do that ourselves...    */    struct object *o=decode_value_clone_object(Pike_sp-1);   
pike.git/src/encode.c:2510:       break;    }       case TAG_FUNCTION:    decode_value2(data);       switch(num)    {    case 0: -  if(data->codec) -  { +     apply(data->codec,"functionof", 1); -  }else{ -  fallback_codec(); -  } +     break;       case 1: {    struct program *p;    if(Pike_sp[-1].type != T_OBJECT && data->pickyness)    decode_error(NULL, Pike_sp - 1,    "Failed to decode function object. Got: ");       decode_value2(data);    if(Pike_sp[-1].type != T_STRING && data->pickyness)
pike.git/src/encode.c:2578:    EDB(3,    fprintf(stderr, "%*s TAG_PROGRAM(%d)\n",    data->depth, "", num));    switch(num)    {    case 0:    {    struct program *p;       decode_value2(data); -  -  if(data->codec) -  { +     apply(data->codec,"programof", 1); -  }else{ -  fallback_codec(); -  } +        p = program_from_svalue(Pike_sp-1);       if (!p) {    if(data->pickyness)    decode_error(NULL, Pike_sp - 1,    "Failed to decode program. Got: ");    pop_stack();    push_undefined();    break;
pike.git/src/encode.c:2635:    SETUP_DECODE_MEMOBJ(T_PROGRAM, program, p, low_allocate_program(),;);       SET_ONERROR(err3, zap_unfinished_program, p);       if(data->pass == 1)    {    if(! data->supporter.prog)    data->supporter.prog = p;       debug_malloc_touch(p); -  if(data->codec) -  { +     ref_push_program(p);    apply(data->codec, "__register_new_program", 1);       /* return a placeholder */    if(Pike_sp[-1].type == T_OBJECT)    {    placeholder=Pike_sp[-1].u.object;    if(placeholder->prog != null_program) -  Pike_error("Placeholder object is not a null_program clone.\n"); +  Pike_error("Placeholder object is not a __null_program clone.\n");    dmalloc_touch_svalue(Pike_sp-1);    Pike_sp--;    }    else if (Pike_sp[-1].type != T_INT ||    Pike_sp[-1].u.integer)    Pike_error ("Expected placeholder object or zero "    "from __register_new_program.\n");    else {    pop_stack();    }    } -  } +        if(placeholder)    SET_ONERROR(err4, zap_placeholder, placeholder);       decode_value2(data);    f_version(0);    if(!is_eq(Pike_sp-1,Pike_sp-2))    Pike_error("Cannot decode programs encoded with other pike version.\n");    pop_n_elems(2);   
pike.git/src/encode.c:2851:    p->inherits[0].parent_offset=1;   */       if(placeholder && data->pass==1)    {    if(placeholder->prog != null_program)    {    debug_malloc_touch(placeholder);    ref_push_program (p);    decode_error(Pike_sp - 1, NULL, -  "Placeholder argument is not a null_program clone.\n"); +  "Placeholder is no longer a __null_program clone.\n");    }else{    free_program(placeholder->prog);    add_ref(placeholder->prog = p);    debug_malloc_touch(placeholder);    }    }       debug_malloc_touch(p);       in=p->num_inherits;
pike.git/src/encode.c:3461:    add_to_identifier_references(ref);    }    else {    p->identifier_references[no] = ref;    }    }    break;       case ID_ENTRY_VARIABLE:    { -  int no; +  int no, n;       /* name */    decode_value2(data);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,    "Bad variable name (not a string): ");    }       /* type */
pike.git/src/encode.c:3493:    fprintf(stderr,    "%*sdefine_variable(\"%s\", X, 0x%04x)\n",    data->depth, "",    Pike_sp[-2].u.string->str, id_flags));       /* Alters    *    * storage, variable_index, identifiers and    * identifier_references    */ -  if (no != define_variable(Pike_sp[-2].u.string, +  n = define_variable(Pike_sp[-2].u.string,    Pike_sp[-1].u.type, -  id_flags)) { +  id_flags); +  if (no != n) {    ref_push_program (p);    decode_error(Pike_sp - 1, NULL, -  "Bad variable identifier offset: %d\n", no); +  "Bad variable identifier offset: got %d, expected %d\n", +  n, no);    }       pop_n_elems(2);    }    break;    case ID_ENTRY_FUNCTION:    {    union idptr func;    unsigned INT8 func_flags;    unsigned INT16 opt_flags;
pike.git/src/encode.c:3953:    data->unfinished_objects=tmp->next;    free((char *)tmp);    }   #ifdef PIKE_THREADS    data->thread_state = NULL;   #endif       free( (char *) data);   }    - /* Run pass2 */ - int re_decode(struct decode_data *data, int ignored) + static void low_do_decode (struct decode_data *data)   { -  +  int e; +  struct keypair *k;    ONERROR err;    SET_ONERROR(err, free_decode_data, data); -  data->next = current_decode; +     current_decode = data;       decode_value2(data);    -  UNSET_ONERROR(err); +  while (data->ptr < data->len) { +  decode_value2 (data); +  pop_stack(); +  }    -  + #ifdef PIKE_DEBUG +  NEW_MAPPING_LOOP (data->decoded->data) { +  if (k->val.type == T_PROGRAM && +  !(k->val.u.program->flags & PROGRAM_FINISHED)) { +  decode_error (NULL, &k->val, +  "Got unfinished program <%"PRINTPIKEINT"d> after decode: ", +  k->ind.u.integer); +  } +  } + #endif +  +  UNSET_ONERROR(err);    free_decode_data(data); -  + } +  + /* Run pass2 */ + int re_decode(struct decode_data *data, int ignored) + { +  data->next = current_decode; +  low_do_decode (data);    return 1;   }      static INT32 my_decode(struct pike_string *tmp,    struct object *codec   #ifdef ENCODE_DEBUG    , int debug   #endif    )   { -  ONERROR err; +     struct decode_data *data; -  int e; -  struct keypair *k; +        /* Attempt to avoid infinite recursion on circular structures. */    for (data = current_decode; data; data=data->next) {    if (data->raw == tmp && data->codec == codec   #ifdef PIKE_THREADS    && data->thread_state == Pike_interpreter.thread_state   #endif    ) {    struct svalue *res;    struct svalue val = {
pike.git/src/encode.c:4039:    GETC() != 'k' ||    GETC() != 'e' ||    GETC() != '0')    {    free( (char *) data);    return 0;    }       data->decoded=allocate_mapping(128);    -  current_decode = data; -  -  SET_ONERROR(err, free_decode_data, data); -  +     init_supporter(& data->supporter,    (supporter_callback *) re_decode,    (void *)data);    -  decode_value2(data); -  while (data->ptr < data->len) { -  decode_value2 (data); -  pop_stack(); -  } +  low_do_decode (data);    - #ifdef PIKE_DEBUG -  NEW_MAPPING_LOOP (data->decoded->data) { -  if (k->val.type == T_PROGRAM && -  !(k->val.u.program->flags & PROGRAM_FINISHED)) { -  decode_error (NULL, &k->val, -  "Got unfinished program <%"PRINTPIKEINT"d> after decode: ", -  k->ind.u.integer); -  } -  } - #endif -  -  CALL_AND_UNSET_ONERROR(err); +     return 1;   }      /* Compatibilidy decoder */      static unsigned char extract_char(char **v, ptrdiff_t *l)   {    if(!*l) Pike_error("Format error, not enough place for char.\n");    else (*l)--;    (*v)++;
pike.git/src/encode.c:4199:    *! @param minor    *! Minor version.    *!    *! @returns    *! Returns the decoded program.    *!    *! @seealso    *! @[functionof()], @[objectof()]    */    - /*! @decl program __register_new_program(program p) + /*! @decl object __register_new_program(program p)    *! -  *! Called by @[decode_value()] to register a program that is -  *! being decoded. +  *! Called by @[decode_value()] to register the program that is +  *! being decoded. Might get called repeatedly with several other +  *! programs that are being decoded recursively. The only safe +  *! assumption is that when the top level thing being decoded is a +  *! program, then the first call will be with the unfinished embryo +  *! that will later become that program.    *!    *! @returns -  *! Returns a program os a place-holder program. +  *! Returns either zero or a placeholder object. A placeholder +  *! object must be a clone of @[__null_program]. When the program is +  *! finished, the placeholder object will be converted to a clone of +  *! it. This is used for pike module objects.    */      /*! @endclass    */      static void rec_restore_value(char **v, ptrdiff_t *l)   {    ptrdiff_t t, i;       i = extract_int(v,l);
pike.git/src/encode.c:4299:    (*l) -= t; (*v) += t;    APPLY_MASTER("programof", 1);    return;       default:    Pike_error("Format error: Unknown type tag %ld:%ld\n",    PTRDIFF_T_TO_LONG(i), PTRDIFF_T_TO_LONG(t));    }   }    - /*! @decl mixed decode_value(string coded_value, object|void codec) + /*! @decl mixed decode_value(string coded_value, void|Codec codec)    *! -  *! Decode a value from a string. +  *! Decode a value from the string @[coded_value].    *!    *! This function takes a string created with @[encode_value()] or    *! @[encode_value_canonic()] and converts it back to the value that was    *! coded.    *! -  *! If no codec is specified, the current master object will be used as codec. +  *! If @[codec] is specified, it's used as the codec for the decode. +  *! If no codec is specified, the current master object will be used.    *!    *! @seealso    *! @[encode_value()], @[encode_value_canonic()]    */   void f_decode_value(INT32 args)   {    struct pike_string *s;    struct object *codec; -  struct pike_frame *new_frame; +       #ifdef ENCODE_DEBUG -  int debug; +  int debug = 0;   #endif /* ENCODE_DEBUG */       check_all_args("decode_value", args, -  BIT_STRING, BIT_VOID | BIT_OBJECT | BIT_INT, +  BIT_STRING, +  BIT_VOID | BIT_OBJECT | BIT_ZERO,   #ifdef ENCODE_DEBUG    /* This argument is only an internal debug helper.    * It's intentionally not part of the function    * prototype, to keep the argument position free for    * other uses in the future. */    BIT_VOID | BIT_INT,   #endif    0);    - #ifdef ENCODE_DEBUG -  debug = args > 2 ? Pike_sp[2-args].u.integer : 0; - #endif /* ENCODE_DEBUG */ -  +     s = Pike_sp[-args].u.string; -  if(args<2) -  { -  codec=get_master(); +  +  switch (args) { +  default: + #ifdef ENCODE_DEBUG +  debug = Pike_sp[4-args].u.integer; +  /* Fall through. */ +  case 2: + #endif +  if (Pike_sp[1-args].type == T_OBJECT) { +  codec = Pike_sp[1-args].u.object; +  break;    } -  else if(Pike_sp[1-args].type == T_OBJECT) -  { -  codec=Pike_sp[1-args].u.object; +  /* Fall through. */ +  case 1: +  codec = get_master();    } -  else -  { -  codec=0; -  } +        if(!my_decode(s, codec   #ifdef ENCODE_DEBUG    , debug   #endif    ))    {    char *v=s->str;    ptrdiff_t l=s->len;    rec_restore_value(&v, &l);    }    assign_svalue(Pike_sp-args-1, Pike_sp-1);    pop_n_elems(args);   }