pike.git / src / encode.c

version» Context lines:

pike.git/src/encode.c:18:   #include "pike_error.h"   #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"    - RCSID("$Id: encode.c,v 1.130 2001/10/05 01:30:12 hubbe Exp $"); + RCSID("$Id: encode.c,v 1.131 2001/11/08 23:34:28 nilsson Exp $");      /* #define ENCODE_DEBUG */      #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 if (data->debug>=N) {X;} while (0) + #define EDB(N,X) do { debug_malloc_touch(data); if (data->debug>=N) {X;} } while (0)   #else - #define EDB(N,X) do {} while (0) + #define EDB(N,X) do { debug_malloc_touch(data); } while (0)   #endif      /* The sp macro conflicts with Solaris 2.5.1's <sys/conf.h>. */   #ifdef sp   #undef sp   #define STACKPOINTER_WAS_DEFINED   #endif /* sp */      #ifdef _AIX   #include <net/nh.h>
pike.git/src/encode.c:466:   static void encode_type(struct pike_type *t, struct encode_data *data)   {    low_encode_type(t->str, data);   }   #endif /* USE_PIKE_TYPE */      static void zap_unfinished_program(struct program *p)   {    int e;    debug_malloc_touch(p); +  if(p->flags & PROGRAM_FIXED) return; /* allow natural zapping */    if(p->parent)    {    free_program(p->parent);    p->parent=0;    }    for(e=0;e<p->num_constants;e++)    {    free_svalue(& p->constants[e].sval);    p->constants[e].sval.type=T_INT;    DO_IF_DMALLOC(p->constants[e].sval.u.refs=(void *)-1);
pike.git/src/encode.c:1271:   {    unsigned char *data;    ptrdiff_t len;    ptrdiff_t ptr;    struct mapping *decoded;    struct unfinished_prog_link *unfinished_programs;    struct unfinished_obj_link *unfinished_objects;    struct svalue counter;    struct object *codec;    int pickyness; +  int pass;    struct pike_string *raw;    struct decode_data *next;   #ifdef PIKE_THREADS    struct object *thread_id;   #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);
pike.git/src/encode.c:1396:    if(data->ptr + (LEN) > data->len || (LEN) <0) \    Pike_error("Failed to decode string. (string range error)\n"); \    STR=make_shared_binary_string((char *)(data->data + data->ptr), (LEN)); \    data->ptr+=(LEN); \    } \   }while(0)      #define getdata(X) do { \    long length; \    decode_entry(TAG_STRING, length,data); \ +  if(data->pass == 1) \    get_string_data(X, length, data); \ -  +  else \ +  data->ptr+=length; \    }while(0)      #define getdata3(X) do { \    INT32 what, e, num, numh; \    DECODE("getdata3"); \    switch(what & TAG_MASK) \    { \    case TAG_INT: \    X=0; \    break; \
pike.git/src/encode.c:1643:    get_name_of_type(Pike_sp[-1].type));    }    pop_stack();    }    }       UNSET_ONERROR(err2);    UNSET_ONERROR(err1);   }    +  + 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); +  +  + #define SETUP_DECODE_MEMOBJ(TYPE, U, VAR, ALLOCATE,SCOUR) do { \ +  struct svalue *tmpptr; \ +  if(data->pass > 1 && \ +  (tmpptr=low_mapping_lookup(data->decoded, & data->counter))) \ +  { \ +  tmp=*tmpptr; \ +  VAR=tmp.u.U; \ +  SCOUR; \ +  }else{ \ +  tmp.type=TYPE; \ +  tmp.u.U=VAR=ALLOCATE; \ +  mapping_insert(data->decoded, & data->counter, &tmp); \ +  /* Since a reference to the object is stored in the mapping, we can \ +  * safely decrease this reference here. Thus it will be automatically \ +  * freed if something goes wrong. \ +  */ \ +  VAR->refs--; \ +  } \ +  data->counter.u.integer++; \ + }while(0) +    #ifdef USE_PIKE_TYPE   /* This really needs to disable threads.... */   #define decode_type(X,data) do { \    type_stack_mark(); \    low_decode_type(data); \    (X)=pop_unfinished_type(); \   } while(0)   #else /* !USE_PIKE_TYPE */   /* This really needs to disable threads.... */   #define decode_type(X,data) do { \
pike.git/src/encode.c:1808:    case TAG_ARRAY:    {    struct array *a;    if(num < 0)    Pike_error("Failed to decode array. (array size is negative)\n");       /* Heruetical */    if(data->ptr + num > data->len)    Pike_error("Failed to decode array. (not enough data)\n");    -  tmp.type=T_ARRAY; -  tmp.u.array=a=allocate_array(num); +     EDB(2,fprintf(stderr, "%*sDecoding array of size %d to <%d>\n",    data->depth, "", num, data->counter.u.integer)); -  mapping_insert(data->decoded, & data->counter, &tmp); -  data->counter.u.integer++; +     -  /* Since a reference to the array is stored in the mapping, we can -  * safely decrease this reference here. Thus it will be automatically -  * freed if something goes wrong. -  */ -  a->refs--; +  SETUP_DECODE_MEMOBJ(T_ARRAY, array, a, allocate_array(num), +  free_svalues(ITEM(a), a->size, a->type_field));       for(e=0;e<num;e++)    {    decode_value2(data);    ITEM(a)[e]=Pike_sp[-1];    Pike_sp--;    dmalloc_touch_svalue(Pike_sp);    }    ref_push_array(a);   #ifdef ENCODE_DEBUG
pike.git/src/encode.c:1845:    case TAG_MAPPING:    {    struct mapping *m;    if(num<0)    Pike_error("Failed to decode string. (mapping size is negative)\n");       /* Heruetical */    if(data->ptr + num > data->len)    Pike_error("Failed to decode mapping. (not enough data)\n");    -  m=allocate_mapping(num); -  tmp.type=T_MAPPING; -  tmp.u.mapping=m; +     EDB(2,fprintf(stderr, "%*sDecoding mapping of size %d to <%d>\n",    data->depth, "", num, data->counter.u.integer)); -  mapping_insert(data->decoded, & data->counter, &tmp); -  data->counter.u.integer++; -  m->refs--; +     -  +  SETUP_DECODE_MEMOBJ(T_MAPPING, mapping, m, allocate_mapping(num), ; ); +     for(e=0;e<num;e++)    {    decode_value2(data);    decode_value2(data);    mapping_insert(m, Pike_sp-2, Pike_sp-1);    pop_n_elems(2);    }    ref_push_mapping(m);   #ifdef ENCODE_DEBUG    data->depth -= 2;
pike.git/src/encode.c:1880:    struct multiset *m;    struct array *a;    if(num<0)    Pike_error("Failed to decode string. (multiset size is negative)\n");       /* Heruetical */    if(data->ptr + num > data->len)    Pike_error("Failed to decode multiset. (not enough data)\n");       /* NOTE: This code knows stuff about the implementation of multisets...*/ -  a = low_allocate_array(num, 0); -  m = allocate_multiset(a); -  tmp.type = T_MULTISET; -  tmp.u.multiset = m; +     EDB(2,fprintf(stderr, "%*sDecoding multiset of size %d to <%d>\n",    data->depth, "", num, data->counter.u.integer)); -  mapping_insert(data->decoded, & data->counter, &tmp); -  data->counter.u.integer++; -  debug_malloc_touch(m); +  SETUP_DECODE_MEMOBJ(T_MULTISET, multiset, m, +  allocate_multiset(low_allocate_array(num, 0)), ;); +  a=m->ind;       for(e=0;e<num;e++)    {    decode_value2(data); -  a->item[e] = sp[-1]; -  sp--; +  assign_svalue(a->item+e , sp-1); +  pop_stack();    dmalloc_touch_svalue(sp);    }    array_fix_type_field(a);    order_multiset(m); -  push_multiset(m); +  ref_push_multiset(m);   #ifdef ENCODE_DEBUG    data->depth -= 2;   #endif    return;    }       case TAG_OBJECT:    {    tmp=data->counter;    data->counter.u.integer++;
pike.git/src/encode.c:2092:    }    Pike_error("Failed to decode program.\n");    }    /* Remove the extra entry from the stack. */    stack_swap();    pop_stack();    break;    }    case 1:    { -  int d; +  int d, in;    size_t size=0; -  char *dat; +  char *dat=0;    struct program *p; -  ONERROR err1, err2, err3; +  struct object *placeholder=0; +  ONERROR err1, err2, err3, err4;      #ifdef _REENTRANT    ONERROR err;    low_init_threads_disable();    SET_ONERROR(err, do_enable_threads, 0);   #endif    -  p=low_allocate_program(); +  EDB(2,fprintf(stderr, "%*sDecoding a program to <%d>: ", +  data->depth, "", data->counter.u.integer); +  print_svalue(stderr, &tmp); +  fputc('\n', stderr);); +  +  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_sp--; +  }else{    pop_stack();    } -  tmp.type=T_PROGRAM; -  tmp.u.program=p; -  EDB(2,fprintf(stderr, "%*sDecoding a program to <%d>: ", -  data->depth, "", data->counter.u.integer); -  print_svalue(stderr, &tmp); -  fputc('\n', stderr);); -  mapping_insert(data->decoded, & data->counter, &tmp); -  data->counter.u.integer++; -  p->refs--; +  } +  }    -  +  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);       debug_malloc_touch(p);    decode_number(p->flags,data); -  +  +  if(data->pass == 1) +  {    p->flags &= ~(PROGRAM_FINISHED | PROGRAM_OPTIMIZED |    PROGRAM_FIXED | PROGRAM_PASS_1_DONE);    p->flags |= PROGRAM_AVOID_CHECK; -  +  }    decode_number(p->storage_needed,data);    decode_number(p->xstorage,data);    decode_number(p->parent_info_storage,data);    decode_number(p->alignment_needed,data);    decode_number(p->timestamp.tv_sec,data);    decode_number(p->timestamp.tv_usec,data);    -  +  if(data->pass && p->parent) +  { +  free_program(p->parent); +  p->parent=0; +  } +     debug_malloc_touch(p);    decode_value2(data);    switch(Pike_sp[-1].type)    {    case T_INT:    p->parent=0;    break;    case T_PROGRAM:    p->parent=Pike_sp[-1].u.program;    break;
pike.git/src/encode.c:2170:    p->parent_program_id = p->parent->id;    }    pop_stack();       debug_malloc_touch(p);      #define FOO(X,Y,Z) \    decode_number( p->num_##Z, data);   #include "program_areas.h"    +  +  if(data->pass == 1) +  {   #define FOO(NUMTYPE,TYPE,NAME) \    size=DO_ALIGN(size, ALIGNOF(TYPE)); \    size+=p->PIKE_CONCAT(num_,NAME)*sizeof(p->NAME[0]);   #include "program_areas.h"       dat=xalloc(size);    debug_malloc_touch(dat);    MEMSET(dat,0,size);    size=0;   #define FOO(NUMTYPE,TYPE,NAME) \
pike.git/src/encode.c:2194:       for(e=0;e<p->num_constants;e++)    p->constants[e].sval.type=T_INT;       debug_malloc_touch(dat);    debug_malloc_touch(p);       p->total_size=size + sizeof(struct program);       p->flags |= PROGRAM_OPTIMIZED; +  }       {    INT32 bytecode_method = 0;    decode_number(bytecode_method, data);    if (bytecode_method != PIKE_BYTECODE_METHOD) {    Pike_error("Unsupported bytecode method: %d. Expected %d\n",    bytecode_method, PIKE_BYTECODE_METHOD);    }    }   
pike.git/src/encode.c:2286:    debug_malloc_touch(p);    debug_malloc_touch(dat);       data->pickyness++;         /* p->inherits[0].prog=p;    p->inherits[0].parent_offset=1;   */    +  if(placeholder && data->pass==1) +  { +  if(placeholder->prog != null_program) +  { +  debug_malloc_touch(placeholder); +  Pike_error("Placeholder argument is not a null_program clone!"); +  }else{ +  free_program(placeholder->prog); +  add_ref(placeholder->prog = p); +  debug_malloc_touch(placeholder); +  } +  } +     debug_malloc_touch(p); -  for(d=0;d<p->num_inherits;d++) +  +  in=p->num_inherits; +  for(d=0;d<in;d++)    {    decode_number(p->inherits[d].inherit_level,data);    decode_number(p->inherits[d].identifier_level,data);    decode_number(p->inherits[d].parent_offset,data);    decode_number(p->inherits[d].parent_identifier,data);    decode_number(p->inherits[d].storage_offset,data);       decode_value2(data);    if(d==0)    {    if(Pike_sp[-1].type != T_PROGRAM ||    Pike_sp[-1].u.program != p)    Pike_error("Program decode failed!\n");    p->refs--;    }    -  +  if(data->pass > 1) +  { +  if(p->inherits[d].prog) +  { +  free_program(p->inherits[d].prog); +  p->inherits[d].prog=0; +  } +  +  if(p->inherits[d].parent) +  { +  free_object(p->inherits[d].parent); +  p->inherits[d].parent=0; +  } +  } +     switch(Pike_sp[-1].type)    {    case T_FUNCTION:    if(Pike_sp[-1].subtype == FUNCTION_BUILTIN)    Pike_error("Failed to decode parent.\n");       EDB(3, fprintf(stderr,"INHERIT%x = func { %p, %d} \n",p->id,Pike_sp[-1].u.object, Pike_sp[-1].subtype); );       p->inherits[d].parent_identifier=Pike_sp[-1].subtype;    p->inherits[d].prog=program_from_svalue(Pike_sp-1);
pike.git/src/encode.c:2332:    case T_PROGRAM:    EDB(3, fprintf(stderr,"INHERIT%x = prog\n",p->id); );    p->inherits[d].prog=Pike_sp[-1].u.program;    Pike_sp--;    dmalloc_touch_svalue(Pike_sp);    break;    default:    Pike_error("Failed to decode inheritance.\n");    }    +  p->num_inherits=d+1; +     getdata3(p->inherits[d].name);       EDB(3, fprintf(stderr,"INHERIT%x < %d: %d id=%d\n",    p->id,d,    p->inherits[d].prog->num_identifiers,    p->inherits[d].prog->id); );    }       debug_malloc_touch(dat);   
pike.git/src/encode.c:2388:    struct program *new_program_save=Pike_compiler->new_program;    Pike_compiler->new_program=p;    fsort((void *)p->identifier_index,    p->num_identifier_index,    sizeof(unsigned short),(fsortfun)program_function_index_compare);    Pike_compiler->new_program=new_program_save;    }       debug_malloc_touch(dat);    debug_malloc_touch(p); -  p->flags |= PROGRAM_PASS_1_DONE | PROGRAM_FIXED; -  if(data->codec) -  { -  ref_push_program(p); -  apply(data->codec, "__register_new_object", 1); -  pop_stack(); -  } +     -  +  p->flags |= PROGRAM_PASS_1_DONE | PROGRAM_FIXED;    for(d=0;d<p->num_constants;d++)    {    decode_value2(data); -  +  if(data->pass > 1) +  { +  assign_svalue(& p->constants[d].sval , Pike_sp -1 ); +  pop_stack(); +  }else{    p->constants[d].sval=*--Pike_sp; -  +  }    dmalloc_touch_svalue(Pike_sp);    getdata3(p->constants[d].name);    } -  data->pickyness--; +     -  + #ifdef PIKE_DEBUG +  { +  int q; +  for(q=0;q<p->num_inherits;q++) +  if(!p->inherits[q].prog) +  fatal("FOOBAR!@!!!\n"); +  } + #endif    -  +  if(placeholder && data->pass == 1) +  { +  if(!p || (placeholder->storage)) +  { +  Pike_error("Placeholder already has storage!\n"); +  } else { +  placeholder->storage=p->storage_needed ? +  (char *)xalloc(p->storage_needed) : +  (char *)0; +  call_c_initializers(placeholder); +  } +  } +  +  data->pickyness--; +  +  if(placeholder) +  { +  free_object(placeholder); +  UNSET_ONERROR(err4); +  }    UNSET_ONERROR(err3);       ref_push_program(p);    -  +  if(!(p->flags & PROGRAM_FINISHED) && +  !data->supporter.depends_on) +  {    /* Logic for the PROGRAM_FINISHED flag:    * The purpose of this code is to make sure that the PROGRAM_FINISHED    * flat is not set on the program until all inherited programs also    * have that flag. -Hubbe    */    for(d=1;d<p->num_inherits;d++)    if(! (p->inherits[d].prog->flags & PROGRAM_FINISHED))    break;       if(d == p->num_inherits)    {    p->flags &=~ PROGRAM_AVOID_CHECK;    p->flags |= PROGRAM_FINISHED;    -  +  if (placeholder) +  { +  if(!init_placeholder(placeholder)) +  placeholder=0; +  } +     /* Go through the linked list of unfinished programs    * to see what programs are now finished.    */    {    struct unfinished_prog_link *l, **ptr;      #ifdef PIKE_DEBUG    check_program(p);   #endif /* PIKE_DEBUG */   
pike.git/src/encode.c:2486:    * compatibility mode. */    }else{    ptr=&l->next;    continue;    }    }    *ptr = l->next;    free((char *)l);    }    } -  -  +     }else{    struct unfinished_prog_link *l;    l=ALLOC_STRUCT(unfinished_prog_link);    l->prog=p;    l->next=data->unfinished_programs;    data->unfinished_programs=l;    } -  +  }      #ifdef _REENTRANT    UNSET_ONERROR(err);    exit_threads_disable(NULL);   #endif   #ifdef ENCODE_DEBUG    data->depth -= 2;   #endif    return;    }
pike.git/src/encode.c:2558:       EDB(2,fprintf(stderr, "%*sDecoded to <%d>: ", data->depth, "", tmp.u.integer);    print_svalue(stderr, Pike_sp-1);    fputc('\n', stderr););    mapping_insert(data->decoded, & tmp, Pike_sp-1);   #ifdef ENCODE_DEBUG    data->depth -= 2;   #endif   }    + /* Placed after to prevent inlining */ + static int init_placeholder(struct object *placeholder) + { +  JMP_BUF rec; +  /* Initialize the placeholder. */ +  if(SETJMP(rec)) +  { +  dmalloc_touch_svalue(&throw_value); +  call_handle_error(); +  zap_placeholder(placeholder); +  UNSETJMP(rec); +  return 1; +  }else{ +  call_pike_initializers(placeholder,0); +  UNSETJMP(rec); +  return 0; +  } + }    -  +  +    static struct decode_data *current_decode = NULL;      static void free_decode_data(struct decode_data *data)   { -  free_mapping(data->decoded); -  while(data->unfinished_programs) -  { -  struct unfinished_prog_link *tmp=data->unfinished_programs; -  data->unfinished_programs=tmp->next; -  free((char *)tmp); -  } +  int delay;    -  while(data->unfinished_objects) -  { -  struct unfinished_obj_link *tmp=data->unfinished_objects; -  data->unfinished_objects=tmp->next; -  free((char *)tmp); -  } +  debug_malloc_touch(data); +     if (current_decode == data) {    current_decode = data->next;    } else {    struct decode_data *d;    for (d = current_decode; d; d=d->next) {    if (d->next == data) {    d->next = d->next->next;    break;    }    }   #ifdef PIKE_DEBUG    if (!d) {    fatal("Decode data fell off the stack!\n");    }   #endif /* PIKE_DEBUG */    } -  +  +  +  delay=unlink_current_supporter(&data->supporter); +  call_dependants(& data->supporter); +  +  if(delay) +  { +  debug_malloc_touch(data); +  /* We have been delayed */ +  return; +  } +  +  free_mapping(data->decoded); +  + #ifdef PIKE_DEBUG +  if(data->unfinished_programs) +  fatal("We have unfinished programs left in decode()!\n"); +  if(data->unfinished_objects) +  fatal("We have unfinished objects left in decode()!\n"); + #endif +  +  while(data->unfinished_programs) +  { +  struct unfinished_prog_link *tmp=data->unfinished_programs; +  data->unfinished_programs=tmp->next; +  free((char *)tmp); +  } +  +  while(data->unfinished_objects) +  { +  struct unfinished_obj_link *tmp=data->unfinished_objects; +  data->unfinished_objects=tmp->next; +  free((char *)tmp); +  }   #ifdef PIKE_THREADS    free_object(data->thread_id);   #endif -  +  +  free( (char *) data);   }    -  + /* Run pass2 */ + void re_decode(struct decode_data *data) + { +  ONERROR err; +  SET_ONERROR(err, free_decode_data, data); +  data->next = current_decode; +  current_decode = data; +  +  decode_value2(data); +  +  CALL_AND_UNSET_ONERROR(err); +  +  free_decode_data(data); + } +    static INT32 my_decode(struct pike_string *tmp,    struct object *codec   #ifdef ENCODE_DEBUG    , int debug   #endif    )   {    ONERROR err; -  struct decode_data d, *data; +  struct decode_data *data;       /* 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_id == Pike_interpreter.thread_id   #endif    ) {    struct svalue *res;    struct svalue val = {
pike.git/src/encode.c:2632:    val.u.integer = COUNTER_START;    if ((res = low_mapping_lookup(data->decoded, &val))) {    push_svalue(res);    return 1;    }    /* Possible recursion detected. */    /* return 0; */    }    }    -  data=&d; +  data=ALLOC_STRUCT(decode_data);    data->counter.type=T_INT;    data->counter.u.integer=COUNTER_START;    data->data=(unsigned char *)tmp->str;    data->len=tmp->len;    data->ptr=0;    data->codec=codec;    data->pickyness=0; -  +  data->pass=1;    data->unfinished_programs=0;    data->unfinished_objects=0;    data->raw = tmp;    data->next = current_decode;   #ifdef PIKE_THREADS    data->thread_id = Pike_interpreter.thread_id;   #endif   #ifdef ENCODE_DEBUG    data->debug = debug;    data->depth = -2;   #endif    -  if (tmp->size_shift) return 0; -  if(data->len < 5) return 0; -  if(GETC() != 182 || +  if (tmp->size_shift || +  data->len < 5 || +  GETC() != 182 ||    GETC() != 'k' ||    GETC() != 'e' ||    GETC() != '0') -  +  { +  free( (char *) data);    return 0; -  +  }      #ifdef PIKE_THREADS    add_ref(Pike_interpreter.thread_id);   #endif       data->decoded=allocate_mapping(128);       current_decode = data;       SET_ONERROR(err, free_decode_data, data); -  +  +  init_supporter(& data->supporter, +  ( void (*)(void*) )re_decode, +  (void *)data); +     decode_value2(data);    - #ifdef PIKE_DEBUG -  if(data->unfinished_programs) -  fatal("We have unfinished programs left in decode()!\n"); -  if(data->unfinished_objects) -  fatal("We have unfinished objects left in decode()!\n"); - #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)--;