Branch: Tag:

2003-06-12

2003-06-12 09:31:12 by Martin Stjernholm <mast@lysator.liu.se>

The preprocessor in MSVC doesn't properly separate tokens (the
negation in COUNTER_START became "--" together with the negation in
CONVERT_ENTRY_ID).

Rev: src/encode.c:1.187

2:   || 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.186 2003/06/11 19:59:54 mast Exp $ + || $Id: encode.c,v 1.187 2003/06/12 09:31:12 mast Exp $   */      #include "global.h"
27:   #include "bignum.h"   #include "pikecode.h"    - RCSID("$Id: encode.c,v 1.186 2003/06/11 19:59:54 mast Exp $"); + RCSID("$Id: encode.c,v 1.187 2003/06/12 09:31:12 mast Exp $");    - /* #define ENCODE_DEBUG */ + #define ENCODE_DEBUG      /* Use the old encoding method for programs. */   /* #define OLD_PIKE_ENCODE_PROGRAM */
100:   #define TAG_SMALL 32   #define SIZE_SHIFT 6   #define MAX_SMALL (1<<(8-SIZE_SHIFT)) - #define COUNTER_START -4 + #define COUNTER_START (-MAX_SMALL)      /* Entries used to encode the identifier_references table. */   #define ID_ENTRY_RAW -2
1506:    for(d=0;d<p->num_constants;d++)    {    /* value */ -  encode_value2(&p->constants[d].sval, data, 0); +  /* Must force encoding of constants. They typically are +  * inner classes which must be finished before this +  * program is, since an object might be created for it +  * immediately afterwards which instantiate the inner +  * classes. */ +  encode_value2(&p->constants[d].sval, data, 1);       /* name */    if (p->constants[d].name) {
1737:    struct unfinished_obj_link *unfinished_objects;    struct svalue counter;    struct object *codec; +  struct program *target_prog; +  struct object *placeholder; +  struct array *delayed;    int pickyness;    int pass;    struct pike_string *raw;
1750:    struct Supporter supporter;   };    - static void decode_value2(struct decode_data *data); + static void decode_value2(struct decode_data *data, int force_decode);      static int my_extract_char(struct decode_data *data)   {
2010:    break;       case PIKE_T_NAME: -  decode_value2(data); +  decode_value2(data, 0);       if (Pike_sp[-1].type != PIKE_T_STRING) {    Pike_error("decode_value(): Type name is not a string (%s)\n",
2025:    {    int flag = GETC();    -  decode_value2(data); +  decode_value2(data, 0);    switch(Pike_sp[-1].type)    {    case T_INT:
2064:   }       - static void zap_placeholder(struct object *placeholder) - { -  /* fprintf(stderr, "Destructing placeholder.\n"); */ -  if (placeholder->storage) { -  debug_malloc_touch(placeholder); -  destruct(placeholder); -  } else { -  free_program(placeholder->prog); -  placeholder->prog = NULL; -  debug_malloc_touch(placeholder); -  } -  free_object(placeholder); - } -  +    static int init_placeholder(struct object *placeholder);      
2089:    { \    tmp=*tmpptr; \    VAR=tmp.u.U; \ -  SCOUR; \ +  {SCOUR;} \    }else{ \    tmp.type=TYPE; \ -  tmp.u.U=VAR=ALLOCATE; \ +  {ALLOCATE;} \ +  tmp.u.U=VAR; \    mapping_insert(data->decoded, & entry_id, &tmp); \    /* Since a reference to the object is stored in the mapping, we can \    * safely decrease this reference here. Thus it will be automatically \
2111:      static void cleanup_new_program_decode (int *orig_compilation_depth)   { + #if 0 +  ref_push_program (Pike_compiler->new_program); +  /* FIXME: Shouldn't the compilation handler be used here? */ +  SAFE_APPLY_MASTER("unregister",1); +  pop_stack(); + #endif +     end_first_pass(0);    compilation_depth = *orig_compilation_depth;   }
2160:    pike_throw();   }    - static void decode_value2(struct decode_data *data) + /* force_decode == 0: A placeholder (object or program) suffices. +  * force_decode == 1: Must have the real object. */ + static void decode_value2(struct decode_data *data, int force_decode)      #ifdef PIKE_DEBUG   #undef decode_value2 - #define decode_value2(X) do { struct svalue *_=Pike_sp; decode_value2_(X); if(Pike_sp!=_+1) Pike_fatal("decode_value2 failed!\n"); } while(0) + #define decode_value2(X, Y) do { \ +  struct svalue *_=Pike_sp; \ +  decode_value2_(X, Y); \ +  if(Pike_sp!=_+1) \ +  Pike_fatal("decode_value2 failed!\n"); \ +  } while(0)   #endif    -  +    {    INT32 what, e, num, numh;    struct svalue entry_id, *tmp2;
2315:    EDB(2,fprintf(stderr, "%*sDecoding array of size %d to <%d>\n",    data->depth, "", num, entry_id.u.integer));    -  SETUP_DECODE_MEMOBJ(T_ARRAY, array, a, allocate_array(num), +  SETUP_DECODE_MEMOBJ(T_ARRAY, array, a, a = allocate_array(num),    free_svalues(ITEM(a), a->size, a->type_field));       types = 0;    for(e=0;e<num;e++)    { -  decode_value2(data); +  decode_value2(data, 0);    stack_pop_to_no_free (ITEM(a) + e);    types |= 1 << ITEM(a)[e].type;    }
2343:    EDB(2,fprintf(stderr, "%*sDecoding mapping of size %d to <%d>\n",    data->depth, "", num, entry_id.u.integer));    -  SETUP_DECODE_MEMOBJ(T_MAPPING, mapping, m, allocate_mapping(num), ; ); +  SETUP_DECODE_MEMOBJ(T_MAPPING, mapping, m, m = allocate_mapping(num), ; );       for(e=0;e<num;e++)    { -  decode_value2(data); -  decode_value2(data); +  decode_value2(data, 0); +  decode_value2(data, 0);    mapping_insert(m, Pike_sp-2, Pike_sp-1);    pop_n_elems(2);    }
2374: Inside #if defined(PIKE_NEW_MULTISETS)
   data->depth, "", num, entry_id.u.integer));   #ifdef PIKE_NEW_MULTISETS    SETUP_DECODE_MEMOBJ (T_MULTISET, multiset, m, -  allocate_multiset (0, 0, NULL), ;); +  m = allocate_multiset (0, 0, NULL), ;);    /* FIXME: This array could be avoided by building the multiset directly. */    a = low_allocate_array (num, 0);   #else    SETUP_DECODE_MEMOBJ(T_MULTISET, multiset, m, -  allocate_multiset(low_allocate_array(num, 0)), ;); +  m = allocate_multiset(low_allocate_array(num, 0)), ;);    a=m->ind;   #endif       types = 0;    for(e=0;e<num;e++)    { -  decode_value2(data); +  decode_value2(data, 0);    stack_pop_to_no_free (ITEM(a) + e);    types |= 1 << ITEM(a)[e].type;    }
2408:       case TAG_OBJECT:    { -  decode_value2(data); -  +     switch(num)    {    case 0: -  apply(data->codec,"objectof", 1); +  decode_value2(data, 0); +  push_int (!force_decode); +  apply(data->codec,"objectof", 2);    break;       case 1:    {    int fun; -  +  struct object *o;    /* 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); +  decode_value2(data, 1); +  o = decode_value_clone_object(Pike_sp-1);       if (!o) {    if (data->pickyness)
2432:    data->depth, "", entry_id.u.integer);    print_svalue(stderr, Pike_sp-1);    fputc('\n', stderr);); -  decode_value2(data); +  decode_value2(data, 0);    pop_n_elems(2);    push_undefined();    break;
2464:    fputc('\n', stderr););       ref_push_object(o); -  decode_value2(data); -  if(!data->codec) -  decode_error(Pike_sp - 1, NULL, -  "Cannot decode object without codec.\n"); +  decode_value2(data, 0);       fun = find_identifier("decode_object", data->codec->prog);    if (fun < 0)
2488: Inside #if defined(AUTO_BIGNUM)
   */    case 2:    { +  decode_value2(data, 0);    check_stack(2);    /* 256 would be better, but then negative numbers    * doesn't work... /Hubbe
2499:      #endif    case 3: +  decode_value2(data, 0);    pop_stack(); -  decode_value2(data); +  decode_value2(data, 0);    break;       default:
2515:    }       case TAG_FUNCTION: -  decode_value2(data); -  +     switch(num)    {    case 0: -  apply(data->codec,"functionof", 1); +  decode_value2(data, 0); +  push_int (0); +  apply(data->codec,"functionof", 2);    break;       case 1: {    struct program *p; -  +  decode_value2(data, 1);    if(Pike_sp[-1].type != T_OBJECT && data->pickyness)    decode_error(NULL, Pike_sp - 1,    "Failed to decode function object. Got: ");    -  decode_value2(data); +  decode_value2(data, 0);    if(Pike_sp[-1].type != T_STRING && data->pickyness)    decode_error(NULL, Pike_sp - 1,    "Failed to decode function identifier. Got: ");
2582:    {    struct program *p;    -  decode_value2(data); -  apply(data->codec,"programof", 1); +  decode_value2(data, 0); +  push_int (!force_decode); +  apply(data->codec,"programof", 2);    -  +  if (Pike_sp[-1].type == T_PROGRAM || Pike_sp[-1].type == T_FUNCTION)    p = program_from_svalue(Pike_sp-1); -  +  else +  p = 0;       if (!p) {    if(data->pickyness)
2599:    add_ref(p);    pop_stack();    push_program(p); +  +  if (p->flags == PROGRAM_VIRGIN) { +  EDB (2, +  fprintf (stderr, "%*sdecode: got program embryo to finish later: ", +  data->depth, ""); +  print_svalue (stderr, Pike_sp - 1); +  fputc ('\n', stderr);); +  data->delayed = append_array (data->delayed, Pike_sp - 1); +  } +     break;    }   
2609:    char *dat=0;    struct program *p;    struct object *placeholder=0; -  ONERROR err1, err2, err3, err4; +  ONERROR err1, err2, err3;      #ifdef _REENTRANT    ONERROR err;
2624:    print_svalue(stderr, &entry_id);    fputc('\n', stderr););    -  SETUP_DECODE_MEMOBJ(T_PROGRAM, program, p, low_allocate_program(),;); +  SETUP_DECODE_MEMOBJ(T_PROGRAM, program, p, +  { +  if (data->target_prog) { +  add_ref (p = data->target_prog); +  data->target_prog = NULL; +  } +  else +  p = low_allocate_program(); +  }, +  ;);       SET_ONERROR(err3, zap_unfinished_program, p);    -  + #if 0    if(data->pass == 1)    {    if(! data->supporter.prog)
2654:    pop_stack();    }    } + #endif    -  if(placeholder) -  SET_ONERROR(err4, zap_placeholder, placeholder); +  placeholder = data->placeholder; +  data->placeholder = NULL;    -  decode_value2(data); +  decode_value2(data, 0);    f_version(0);    if(!is_eq(Pike_sp-1,Pike_sp-2))    Pike_error("Cannot decode programs encoded with other pike version.\n");
2689:    }       debug_malloc_touch(p); -  decode_value2(data); +  decode_value2(data, 0);    switch(Pike_sp[-1].type)    {    case T_INT:
2849:    decode_error(Pike_sp - 1, NULL,    "Placeholder is no longer a __null_program clone.\n");    }else{ +  Pike_fatal ("foo\n");    free_program(placeholder->prog);    add_ref(placeholder->prog = p);    debug_malloc_touch(placeholder);
2866:    decode_number(p->inherits[d].parent_identifier,data);    decode_number(p->inherits[d].storage_offset,data);    -  decode_value2(data); +  decode_value2(data, 0);    if(d==0)    {    if(Pike_sp[-1].type != T_PROGRAM ||
2987:    p->flags |= PROGRAM_PASS_1_DONE | PROGRAM_FIXED;    for(d=0;d<p->num_constants;d++)    { -  decode_value2(data); +  decode_value2(data, 0);    if(data->pass > 1)    {    assign_svalue(& p->constants[d].sval , Pike_sp -1 );
3025:       data->pickyness--;    -  if(placeholder) -  { -  free_object(placeholder); -  UNSET_ONERROR(err4); -  } +     UNSET_ONERROR(err3);       ref_push_program(p);
3141:    }       case 2: -  decode_value2(data); -  decode_value2(data); +  decode_value2(data, 1); +  decode_value2(data, 0);    if(Pike_sp[-2].type==T_INT)    {    pop_stack();
3154:    break;       case 3: -  decode_value2(data); +  decode_value2(data, 0);    if ((Pike_sp[-1].type == T_INT) &&    (Pike_sp[-1].u.integer < PROG_DYNAMIC_ID_START) &&    (Pike_sp[-1].u.integer > 0)) {
3171:    }    break;    -  case 5: { /* Forward reference for new-style encoding. */ -  struct program *p = low_allocate_program(); -  -  push_program (p); +  case 5: /* Forward reference for new-style encoding. */ +  push_program (low_allocate_program());    EDB(2,    fprintf (stderr, "%*sInited an embryo for a delay encoded program "    "to <%d>: ",    data->depth, "", entry_id.u.integer);    print_svalue (stderr, Pike_sp - 1);    fputc ('\n', stderr);); -  - #if 0 -  /* Is this necessary? In that case, how do we pass an -  * adequate context to __register_new_program so that it -  * knows which program is being decoded? */ -  if (data->codec) { -  ref_push_program (p); -  apply (data->codec, "__register_new_program", 1); -  -  /* Returns a placeholder. */ -  if (Pike_sp[-1].type == T_OBJECT) { -  if (Pike_sp[-1].u.object->prog != null_program) -  Pike_error ("Placeholder object is not a null_program clone.\n"); -  } -  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"); -  pop_stack(); -  } - #endif -  +     break; -  } +        case 4: /* New-style encoding. */    {    struct program *p; -  +  struct object *placeholder = NULL;    ONERROR err;    int orig_compilation_depth;    int byteorder;
3262:    "for delay encoded program <%d>: ", entry_id.u.integer);    }    /* No new ref here; low_start_new_program will add one for -  * Pike_compiler->new_program and we want ride on that one -  * just like when it's created there. */ +  * Pike_compiler->new_program and we want to ride on that +  * one just like when it's created there. */    p = delayed_enc_val->u.program;    } -  +  else if (data->target_prog) { +  p = data->target_prog; +  debug_malloc_touch (p); +  data->target_prog = NULL; +  }    else    p = NULL;   
3297:       debug_malloc_touch(p);    + #if 0 +  ref_push_program (p); +  apply (data->codec, "__register_new_program", 1); +  +  /* Returns a placeholder. */ +  if (Pike_sp[-1].type == T_OBJECT) { +  if (Pike_sp[-1].u.object->prog != null_program) +  Pike_error ("Placeholder object is not a __null_program clone.\n"); +  placeholder = Pike_sp[-1].u.object; +  dmalloc_touch_svalue (Pike_sp - 1); +  Pike_sp--; +  SET_ONERROR (placeholder_uwp, zap_placeholder, placeholder); +  } +  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"); +  pop_stack(); +  } + #endif +  +  placeholder = data->placeholder; +  data->placeholder = NULL; +     /* Check the version. */ -  decode_value2(data); +  decode_value2(data, 0);    f_version(0);    if(!is_eq(Pike_sp-1,Pike_sp-2))    Pike_error("Cannot decode programs encoded with other pike version.\n");
3309:    data->pickyness++;       /* parent */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type == T_PROGRAM) {    p->parent = Pike_sp[-1].u.program;    } else if ((Pike_sp[-1].type == T_INT) &&
3383:       /* Decode strings */    for (e=0; e<local_num_strings; e++) { -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,
3463:    int no, n;       /* name */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,
3471:    }       /* type */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type != T_TYPE) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,
3514:    int n;       /* name */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,
3522:    }       /* type */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type != T_TYPE) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,
3590:    int n;       /* name */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type != T_STRING) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,
3609:    */       /* type */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type != T_TYPE) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,
3689:    }       /* name */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type == T_STRING) {    name = Pike_sp[-1].u.string;    } else if ((Pike_sp[-1].type != T_INT) ||
3700:    }       /* prog */ -  decode_value2(data); +  decode_value2(data, 1);    if (Pike_sp[-1].type != T_PROGRAM) {    ref_push_program (p);    decode_error(Pike_sp - 1, Pike_sp - 2,
3721:    }       /* parent */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type == T_OBJECT) {    parent = Pike_sp[-1].u.object;    } else if ((Pike_sp[-1].type != T_INT) ||
3773:    data->depth-=2;   #endif    +  push_program(p); /* "Take" the ref from Pike_compiler->new_program. */    UNSET_ONERROR(err);       /* De-kludge to get end_first_pass() to free the program. */
3784:    *    * lfuns and identifier_index    */ -  ref_push_program (p); +     if (!(p = end_first_pass(2))) { -  decode_error(Pike_sp - 1, NULL, "Failed to decode program.\n"); +  decode_error (Pike_sp - 1, NULL, +  "Failed to decode program.\n");    } -  pop_stack(); +     compilation_depth = orig_compilation_depth; -  push_program(p); +        EDB(5, dump_program_tables(p, data->depth));   #ifdef PIKE_DEBUG
3815:    for (e=0; e<local_num_constants; e++) {    struct program_constant *constant = p->constants+e;    /* value */ -  decode_value2(data); +  decode_value2(data, 0);    /* name */ -  decode_value2(data); +  decode_value2(data, 0);    if (Pike_sp[-1].type == T_STRING) {    constant->name = Pike_sp[-1].u.string;    } else if ((Pike_sp[-1].type == T_INT) &&
3839:    /* The program should be consistent now. */    p->flags &= ~PROGRAM_AVOID_CHECK;    +  /* Make a real object of the placeholder. */ +  if (placeholder) { +  if(placeholder->prog != null_program) +  { +  debug_malloc_touch(placeholder); +  ref_push_program (p); +  decode_error(Pike_sp - 1, NULL, +  "Placeholder is no longer a __null_program clone.\n"); +  } +  +  free_program(placeholder->prog); +  add_ref(placeholder->prog = p); +  debug_malloc_touch(placeholder); +  +  if(placeholder->storage) { +  ref_push_object (placeholder); +  decode_error(Pike_sp - 2, Pike_sp - 1, +  "Placeholder already has storage: "); +  } +  +  placeholder->storage=p->storage_needed ? +  (char *)xalloc(p->storage_needed) : +  (char *)0; +  call_c_initializers(placeholder); +  init_placeholder (placeholder); +  } +     EDB(5, fprintf(stderr, "%*sProgram flags: 0x%04x\n",    data->depth, "", p->flags));   
3857:    Pike_error("Failed to restore string. (Illegal type)\n");    }    +  if (data->target_prog || data->placeholder) +  Pike_error ("Failed to decode a program to use for the target or placeholder.\n"); +     mapping_insert(data->decoded, &entry_id, Pike_sp-1);      decode_done:;
3877:    {    dmalloc_touch_svalue(&throw_value);    call_handle_error(); -  zap_placeholder(placeholder); +     UNSETJMP(rec);    return 1;    }else{
3926:    }       free_mapping(data->decoded); +  free_array (data->delayed);      #ifdef PIKE_DEBUG    if(data->unfinished_programs)
3962:    SET_ONERROR(err, free_decode_data, data);    current_decode = data;    -  decode_value2(data); +  decode_value2(data, 0);       while (data->ptr < data->len) { -  decode_value2 (data); +  decode_value2 (data, 0);    pop_stack();    }   
3980:    }   #endif    +  for (e = 0; e < data->delayed->size; e++) { +  struct program *p; + #ifdef PIKE_DEBUG +  if (ITEM (data->delayed)[e].type != T_PROGRAM) +  Pike_fatal ("Invalid value in data->delayed.\n"); + #endif +  p = ITEM (data->delayed)[e].u.program; +  if (p->flags == PROGRAM_VIRGIN) { +  ref_push_program (p); +  apply (data->codec, "finish_program", 1); +  if (p->flags == PROGRAM_VIRGIN) { +  ref_push_program (p); +  decode_error (NULL, Pike_sp - 1, "finish_program() failed to finish "); +  } +  pop_stack(); +  } +  } +     UNSET_ONERROR(err);    free_decode_data(data);   }
3993:   }      static INT32 my_decode(struct pike_string *tmp, -  struct object *codec +  struct object *codec, +  struct program *target_prog, +  struct object *placeholder   #ifdef ENCODE_DEBUG    , int debug   #endif
4032:    data->len=tmp->len;    data->ptr=0;    data->codec=codec; +  data->target_prog = target_prog; +  data->placeholder = placeholder;    data->pickyness=0;    data->pass=1;    data->unfinished_programs=0;
4058:    }       data->decoded=allocate_mapping(128); +  data->delayed = allocate_array (0);       init_supporter(& data->supporter,    (supporter_callback *) re_decode,
4139:    *! @[objectof()], @[functionof()], @[objectof()]    */    - /*! @decl object objectof(string data) + /*! @decl object objectof(string data, int delay) +  *! @decl function functionof(string data, int delay) +  *! @decl program programof(string data, int delay)    *! -  *! Decode object encoded in @[data]. +  *! Get the object, function and program, respectively, represented +  *! by @[data].    *!    *! This function is called by @[decode_value()] when it encounters -  *! encoded objects. +  *! values from @[nameof()] in the encoded data.    *!    *! @param data -  *! Encoding of some object as specified by @[nameof()]. +  *! Encoding of some object, function or program as specified by +  *! @[nameof()].    *! -  *! @param minor -  *! Minor version. +  *! @param delay +  *! This parameter is used to handle circular references between the +  *! values decoded by several different @[decode_value] sessions. In +  *! the simple case when the decoding environment is complete, it's +  *! safe to ignore it.    *! -  *! @returns -  *! Returns the decoded object. +  *! If compilation or decoding is needed to retrieve the object or +  *! program, then try to delay it and return a placeholder object +  *! (@[__null_program] clone) or empty program (@[__empty_program] +  *! return value) instead. If an empty program is returned then the +  *! codec will get a call to @[finish] later on with the returned +  *! value and it should then be filled out to the real program. +  *! (Placeholder objects get no calls since they are converted +  *! automatically when the corresponding program is finished.)    *! -  *! @seealso -  *! @[functionof()], @[programof()] -  */ -  - /*! @decl function functionof(string data) +  *! This delay process isn't applicable for functions since they +  *! always involve an indexing, but the parameter is passed anyway +  *! for consistency.    *! -  *! Decode function encoded in @[data]. -  *! -  *! This function is called by @[decode_value()] when it encounters -  *! encoded functions. -  *! -  *! @param data -  *! Encoding of some function as specified by @[nameof()]. -  *! -  *! @param minor -  *! Minor version. -  *! +     *! @returns -  *! Returns the decoded function. -  *! -  *! @seealso -  *! @[objectof()], @[programof()] +  *! Returns the decoded object.    */    - /*! @decl program programof(string data) + /*! @decl void finish (program target)    *! -  *! Decode program encoded in @[data]. -  *! -  *! This function is called by @[decode_value()] when it encounters -  *! encoded programs. -  *! -  *! @param data -  *! Encoding of some program as specified by @[nameof()]. -  *! -  *! @param minor -  *! Minor version. -  *! -  *! @returns -  *! Returns the decoded program. -  *! -  *! @seealso -  *! @[functionof()], @[objectof()] +  *! FIXME    */    - /*! @decl object __register_new_program(program p) -  *! -  *! 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 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    */   
4281:    if(*l < t) Pike_error("Format error: string to short\n");    push_string(make_shared_binary_string(*v, t));    (*l) -= t; (*v) += t; -  APPLY_MASTER("objectof", 1); +  push_int (0); +  APPLY_MASTER("objectof", 2);    return;       case TAG_FUNCTION:
4289:    if(*l < t) Pike_error("Format error: string to short\n");    push_string(make_shared_binary_string(*v, t));    (*l) -= t; (*v) += t; -  APPLY_MASTER("functionof", 1); +  push_int (0); +  APPLY_MASTER("functionof", 2);    return;       case TAG_PROGRAM:
4297:    if(*l < t) Pike_error("Format error: string to short\n");    push_string(make_shared_binary_string(*v, t));    (*l) -= t; (*v) += t; -  APPLY_MASTER("programof", 1); +  push_int (0); +  APPLY_MASTER("programof", 2);    return;       default:
4306:    }   }    - /*! @decl mixed decode_value(string coded_value, void|Codec codec) + /*! @decl mixed decode_value(string coded_value, void|Codec codec, @ +  *! void|program target, void|object placeholder)    *!    *! Decode a value from the string @[coded_value].    *!
4317:    *! 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.    *! +  *! @[target] and @[placeholder] are used to deal with cyclic +  *! references between programs and modules that are being decoded; +  *! users normally don't need to bother with them. If @[target] is +  *! given, it's extended with the decoded program, so that @[target] +  *! will become it afterwards. @[target] must be a newly created value +  *! from @[__empty_program]. If @[placeholder] is given, it must be a +  *! new created instance of @[__null_program] and it will become an +  *! instance of the program decoded to @[target]. +  *!    *! @seealso    *! @[encode_value()], @[encode_value_canonic()]    */   void f_decode_value(INT32 args)   {    struct pike_string *s; -  struct object *codec; +  struct object *codec, *placeholder = NULL; +  struct program *target_prog = NULL;      #ifdef ENCODE_DEBUG    int debug = 0;
4332:    check_all_args("decode_value", args,    BIT_STRING,    BIT_VOID | BIT_OBJECT | BIT_ZERO, +  BIT_VOID | BIT_PROGRAM | BIT_ZERO, +  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
4347: Inside #if defined(ENCODE_DEBUG)
   default:   #ifdef ENCODE_DEBUG    debug = Pike_sp[4-args].u.integer; +  case 4: + #endif +  if (Pike_sp[3-args].type == T_OBJECT) { +  placeholder = Pike_sp[3-args].u.object; +  if(placeholder->prog != null_program) +  SIMPLE_ARG_ERROR ("decode_value", 4, "Not a __null_program clone.\n"); +  debug_malloc_touch (placeholder); +  }    /* Fall through. */ -  +  case 3: +  if (Pike_sp[2-args].type == T_PROGRAM) { +  target_prog = Pike_sp[2-args].u.program; +  if (target_prog->flags != PROGRAM_VIRGIN) +  SIMPLE_ARG_ERROR ("decode_value", 3, "Not an empty program.\n"); +  } +  /* Fall through. */    case 2: - #endif +     if (Pike_sp[1-args].type == T_OBJECT) {    codec = Pike_sp[1-args].u.object;    break;
4365:    }    }    -  if(!my_decode(s, codec +  if(!my_decode(s, codec, target_prog, placeholder   #ifdef ENCODE_DEBUG    , debug   #endif