Ejemplo n.º 1
0
/* Set the done callback */
static void f_set_done_callback(INT32 args)
{
  switch(args) {
  case 2:
    assign_svalue(&(THIS->args), &ARG(2)); 

  case 1:
    if (Pike_sp[-args].type != T_FUNCTION)
      SIMPLE_BAD_ARG_ERROR("_Caudium.nbio()->set_done_callback", 1, "function");
    assign_svalue(&(THIS->cb), &Pike_sp[-args]);
    break;
  case 0:
    free_svalue(&THIS->cb);
    free_svalue(&THIS->args);
    THIS->cb.type=T_INT;
    THIS->args.type=T_INT;
    THIS->args.u.integer = 0;
    return;
    
  default:
    Pike_error("_Caudium.nbio()->set_done_callback: Too many arguments.\n");
    break;
  }
  pop_n_elems(args - 1); 
}
Ejemplo n.º 2
0
int 
m_restore_object(struct object *ob, struct mapping *map)
{
    int p;
    int i;
    struct apair *j;

    if (ob->flags & O_DESTRUCTED)
	return 0;
    
    for (i = 0; i < map->size; i++)
    {
	for (j = map->pairs[i]; j ; j = j->next)
	{
	    if (j->arg.type != T_STRING)
		continue;
	    
	    if ((p = find_status(ob->prog, j->arg.u.string, TYPE_MOD_STATIC))
		== -1)
		continue;

	    assign_svalue(&ob->variables[p], &j->val);
	}
    }
    
    return 1;
}
Ejemplo n.º 3
0
void c_prepare_catch(error_context_t *  econ) {
    if (!save_context(econ))
	error("Can't catch too deep recursion error.\n");
    push_control_stack(FRAME_CATCH);
#if defined(DEBUG) || defined(TRACE_CODE)
    csp->num_local_variables = (csp - 1)->num_local_variables;	/* marion */
#endif
    assign_svalue(&catch_value, &const1);
}
Ejemplo n.º 4
0
int c_next_foreach (void) {
    if ((sp-1)->type == T_LVALUE) {
	/* mapping */
	if ((sp-2)->subtype--) {
	    svalue_t *key = (sp-2)->u.lvalue++;
	    svalue_t *value = find_in_mapping((sp-4)->u.map, key);
		    
	    assign_svalue((sp-1)->u.lvalue, key);
	    if (sp->type == T_REF) {
		if (value == &const0u)
		    sp->u.ref->lvalue = 0;
		else
		    sp->u.ref->lvalue = value;
	    } else
		assign_svalue(sp->u.lvalue, value);
	    return 1;
	}
    } else {
	/* array or string */
	if ((sp-1)->subtype--) {
	    if ((sp-2)->type == T_STRING) {
		if (sp->type == T_REF) {
		    sp->u.ref->lvalue = &global_lvalue_byte;
		    global_lvalue_byte.u.lvalue_byte = (unsigned char *)((sp-1)->u.lvalue_byte++);
		} else {
		    free_svalue(sp->u.lvalue, "string foreach");
		    sp->u.lvalue->type = T_NUMBER;
		    sp->u.lvalue->subtype = 0;
		    sp->u.lvalue->u.number = *((sp-1)->u.lvalue_byte)++;
		}
	    } else {
		if (sp->type == T_REF)
		    sp->u.ref->lvalue = (sp-1)->u.lvalue++;
		else
		    assign_svalue(sp->u.lvalue, (sp-1)->u.lvalue++);
	    }
	    return 1;
	}
    }
    c_exit_foreach();
    return 0;
}
Ejemplo n.º 5
0
/*-------------------------------------------------------------------------*/
void
check_wizlist_for_destr (void)

/* Check the 'extra' info in all wizinfo and remove destructed objects
 * and closures.
 */

{
    wiz_list_t *wl;

    for (wl = &default_wizlist_entry; wl; )
    {
        size_t num;
        svalue_t *item;

        if (wl->extra.type == T_POINTER)
        {
            num = VEC_SIZE(wl->extra.u.vec);
            item = &(wl->extra.u.vec->item[0]);
        }
        else
        {
            num = 1;
            item = &(wl->extra);
        }

        for ( ; num != 0 ; item++, num--)
        {
            switch(item->type)
            {
            case T_POINTER:
                check_for_destr(item->u.vec);
                break;
            case T_MAPPING:
                check_map_for_destr(item->u.map);
                break;
            case T_OBJECT:
            case T_CLOSURE:
                if (destructed_object_ref(item))
                    assign_svalue(item, &const0);
                break;
            default:
                NOOP;
                break;
            }
        }

        if (wl == &default_wizlist_entry)
            wl = all_wiz;
        else
            wl = wl->next;
    }
} /* check_wizlist_for_destr() */
Ejemplo n.º 6
0
INLINE struct vector *
union_array(struct vector *arr1, struct vector *arr2)
{
    int i, size;
    struct mapping *mp;
    struct vector *arr3;
    char *set;

    if (arr1->size == 0)
    {
	INCREF(arr2->ref);
	return arr2;
    }

    if (arr2->size == 0)
    {
	INCREF(arr1->ref);
	return arr1;
    }

    mp = allocate_map(arr1->size);

    for (i = 0; i < arr1->size; i++)
	assign_svalue(get_map_lvalue(mp, &arr1->item[i], 1), &const1);

    set = alloca((size_t)arr2->size);

    for (i = size = 0; i < arr2->size; i++)
    {
	if (get_map_lvalue(mp, &arr2->item[i], 0) == &const0)
	    set[i] = 1, size++;
	else
	    set[i] = 0;
    }

    free_mapping(mp);

    arr3 = allocate_array(arr1->size + size);

    for (i = 0; i < arr1->size; i++)
	assign_svalue_no_free(&arr3->item[i], &arr1->item[i]);

    size = arr1->size;

    for (i = 0; i < arr2->size; i++)
	if (set[i])
	    assign_svalue_no_free(&arr3->item[size++], &arr2->item[i]);

    return arr3;
}
Ejemplo n.º 7
0
void f_store_class_member() {
   int pos = ( sp - 1 )->u.number;
   array_t *arr;

   if( ( sp - 2 )->type != T_CLASS )
      error( "Argument to store_class_member() not a class.\n" );

   arr = ( sp - 2 )->u.arr;

   if( pos < 0 || pos >= arr->size )
      error( "Class index out of bounds.\n" );

   assign_svalue(&arr->item[pos], sp);

   pop_2_elems();
}
Ejemplo n.º 8
0
static void assign_accept_cb (struct port *p, struct svalue *cb)
{
  assign_svalue(& p->accept_callback, cb);
  if (UNSAFE_IS_ZERO (cb)) {
    if (p->box.backend)
      set_fd_callback_events (&p->box, 0, 0);
    set_nonblocking(p->box.fd,0);
  }
  else {
    if (!p->box.backend)
      INIT_FD_CALLBACK_BOX (&p->box, default_backend, p->box.ref_obj,
			    p->box.fd, PIKE_BIT_FD_READ, got_port_event, 0);
    else
      set_fd_callback_events (&p->box, PIKE_BIT_FD_READ, 0);
    set_nonblocking(p->box.fd,1);
  }
}
Ejemplo n.º 9
0
/*-------------------------------------------------------------------------*/
svalue_t *
f_get_extra_wizinfo (svalue_t *sp)

/* EFUN get_extra_wizinfo()
 *
 *   mixed get_extra_wizinfo (object wiz)
 *   mixed get_extra_wizinfo (string wiz)
 *   mixed get_extra_wizinfo (int    wiz)
 *
 * Returns the 'extra' information that was set for the given
 * wizard <wiz> in the wizlist.
 *
 * If <wiz> is an object, the entry of its creator (uid) is used.
 * If <wiz> is a string (a creator aka uid), it names the entry
 * to use.
 * If <wiz> is the number 0, the data is get from the default wizlist
 * entry.
 *
 * The function causes a privilege violation
 * ("get_extra_wizinfo", this_object(), <wiz>).
 */

{
    wiz_list_t *user;
    short type;

    if ((type = sp->type) == T_OBJECT)
    {
        user = sp->u.ob->user;
    }
    else if (type != T_STRING || !(user = find_wiz(sp->u.str)))
    {
        if (type == T_NUMBER && sp->u.number == 0)
            user = NULL;
        else
            errorf("Bad arg 1 to get_extra_wizinfo(): no valid uid given.\n");
    }

    if (!privilege_violation(STR_GET_EXTRA_WIZINFO, sp, sp))
        errorf("Error in get_extra_wizinfo(): privilege violation.\n");

    assign_svalue(sp, user ? &user->extra : &default_wizlist_entry.extra);

    return sp;
} /* get_extra_wizlist_info() */
Ejemplo n.º 10
0
/*
 * Save an object to a mapping.
 */
struct mapping *
m_save_object(struct object *ob)
{
    int i, j;
    struct mapping *ret;
    struct svalue s = const0;
    
    if (ob->flags & O_DESTRUCTED)
	return allocate_map(0);	/* XXX is this right /LA */

    ret = allocate_map((short)(ob->prog->num_variables +
			       ob->prog->inherit[ob->prog->num_inherited - 1].
			       variable_index_offset));
    
    for (j = 0; j < (int)ob->prog->num_inherited; j++)
    {
	struct program *prog = ob->prog->inherit[j].prog;
	if (ob->prog->inherit[j].type & TYPE_MOD_SECOND ||
	    prog->num_variables == 0)
	    continue;
	for (i = 0; i < (int)prog->num_variables; i++)
	{
	    struct svalue *v =
		&ob->variables[i + ob->prog->inherit[j].
			       variable_index_offset];
	    
	    if (prog->variable_names[i].type & TYPE_MOD_STATIC)
		continue;
	    free_svalue(&s);
	    s.type = T_STRING;
	    s.string_type = STRING_MSTRING;
	    s.u.string = make_mstring(prog->variable_names[i].name);
	    assign_svalue(get_map_lvalue(ret, &s, 1), v);
	}
    }
    
    free_svalue(&s);
    return ret;
}
Ejemplo n.º 11
0
void c_assign() {
#ifdef DEBUG
    if (sp->type != T_LVALUE) fatal("Bad argument to F_ASSIGN\n");
#endif
    switch(sp->u.lvalue->type) {
    case T_LVALUE_BYTE:
	if ((sp - 1)->type != T_NUMBER) {
	    error("Illegal rhs to char lvalue\n");
	} else {
	    *global_lvalue_byte.u.lvalue_byte = ((sp - 1)->u.number & 0xff);
	}
	break;
    default:
	assign_svalue(sp->u.lvalue, sp - 1);
	break;
    case T_LVALUE_RANGE:
	assign_lvalue_range(sp - 1);
	break;
    }
    sp--;              /* ignore lvalue */
    /* rvalue is already in the correct place */
}
Ejemplo n.º 12
0
Archivo: file.c Proyecto: Elohim/FGmud
int copy_file (const char * from, const char * to)
{
    char buf[128];
    int from_fd, to_fd;
    int num_read, num_written;
    char *write_ptr;
    extern svalue_t apply_ret_value;

    from = check_valid_path(from, current_object, "move_file", 0);
    assign_svalue(&from_sv, &apply_ret_value);

    to = check_valid_path(to, current_object, "move_file", 1);
    assign_svalue(&to_sv, &apply_ret_value);

    if (from == 0)
        return -1;
    if (to == 0)
        return -2;

    if (lstat(from, &from_stats) != 0) {
        error("/%s: lstat failed\n", from);
        return 1;
    }
    if (lstat(to, &to_stats) == 0) {
#ifdef WIN32
        if (!strcmp(from, to))
#else
        if (from_stats.st_dev == to_stats.st_dev
            && from_stats.st_ino == to_stats.st_ino)
#endif
        {
            error("`/%s' and `/%s' are the same file", from, to);
            return 1;
        }
    } else if (errno != ENOENT) {
        error("/%s: unknown error\n", to);
        return 1;
    }
    
    from_fd = open(from, OPEN_READ);
    if (from_fd < 0)
        return -1;

    if (file_size(to) == -2) {
        /* Target is a directory; build full target filename. */
        const char *cp;
        char newto[MAX_FNAME_SIZE + MAX_PATH_LEN + 2];

        cp = strrchr(from, '/');
        if (cp)
            cp++;
        else
            cp = from;

        sprintf(newto, "%s/%s", to, cp);
        close(from_fd);
        return copy_file(from, newto);
    }
    to_fd = open(to, OPEN_WRITE | O_CREAT | O_TRUNC, 0666);
    if (to_fd < 0) {
        close(from_fd);
        return -2;
    }
    while ((num_read = read(from_fd, buf, 128)) != 0) {
        if (num_read < 0) {
            debug_perror("copy_file: read", from);
            close(from_fd);
            close(to_fd);
            return -3;
        }
        write_ptr = buf;
        while (write_ptr != (buf + num_read)) {
            num_written = write(to_fd, write_ptr, num_read);
            if (num_written < 0) {
                debug_perror("copy_file: write", to);
                close(from_fd);
                close(to_fd);
                return -3;
            }
            write_ptr += num_written;
        }
    }
    close(from_fd);
    close(to_fd);
    return 1;
}
Ejemplo n.º 13
0
void c_not() {
    if (sp->type == T_NUMBER)
	sp->u.number = !sp->u.number;
    else
	assign_svalue(sp, &const0);
}
Ejemplo n.º 14
0
void c_index() {
    int i;
    
    switch (sp->type) {
    case T_MAPPING:
	{
	    svalue_t *v;
	    mapping_t *m;
	    
	    v = find_in_mapping(m = sp->u.map, sp - 1);
	    assign_svalue(--sp, v);    /* v will always have a
					* value */
	    free_mapping(m);
	    break;
	}
#ifndef NO_BUFFER_TYPE
    case T_BUFFER:
	{
	    if ((sp-1)->type != T_NUMBER)
		error("Indexing a buffer with an illegal type.\n");
	    
	    i = (sp - 1)->u.number;
	    if ((i > sp->u.buf->size) || (i < 0))
		error("Buffer index out of bounds.\n");
	    i = sp->u.buf->item[i];
	    free_buffer(sp->u.buf);
	    (--sp)->u.number = i;
	    break;
	}
#endif
    case T_STRING:
	{
	    if ((sp-1)->type != T_NUMBER) {
		error("Indexing a string with an illegal type.\n");
	    }
	    i = (sp - 1)->u.number;
	    if ((i > SVALUE_STRLEN(sp)) || (i < 0))
		error("String index out of bounds.\n");
	    i = (unsigned char) sp->u.string[i];
	    free_string_svalue(sp);
	    (--sp)->u.number = i;
	    break;
	}
    case T_ARRAY:
	{
	    array_t *arr;
	    
	    if ((sp-1)->type != T_NUMBER)
		error("Indexing an array with an illegal type\n");
	    i = (sp - 1)->u.number;
	    if (i<0) error("Negative index passed to array.\n");
	    arr = sp->u.arr;
	    if (i >= arr->size) error("Array index out of bounds.\n");
	    assign_svalue_no_free(--sp, &arr->item[i]);
	    free_array(arr);
	    break;
	}
    default:
	error("Indexing on illegal type.\n");
    }
    
    /*
     * Fetch value of a variable. It is possible that it is a
     * variable that points to a destructed object. In that case,
     * it has to be replaced by 0.
     */
    if (sp->type == T_OBJECT && (sp->u.ob->flags & O_DESTRUCTED)) {
	free_object(sp->u.ob, "F_INDEX");
	*sp = const0u;
    }
}
Ejemplo n.º 15
0
/*! @decl mixed set_id(mixed id)
 *!
 *! This function sets the id used for accept_callback by this port.
 *! The default id is @[this_object()].
 *!
 *! @seealso
 *!   @[query_id]
 */
static void port_set_id(INT32 args)
{
  check_all_args(NULL, args, BIT_MIXED, 0);
  assign_svalue(& THIS->id, Pike_sp-args);
  pop_n_elems(args-1);
}
Ejemplo n.º 16
0
Archivo: file.c Proyecto: Elohim/FGmud
int do_rename (const char * fr, const char * t, int flag)
{
    const char *from;
    const char *to;
    char newfrom[MAX_FNAME_SIZE + MAX_PATH_LEN + 2];
    int flen;
    extern svalue_t apply_ret_value;

    /*
     * important that the same write access checks are done for link() as are
     * done for rename().  Otherwise all kinds of security problems would
     * arise (e.g. creating links to files in protected directories and then
     * modifying the protected file by modifying the linked file). The idea
     * is prevent linking to a file unless the person doing the linking has
     * permission to move the file.
     */
    from = check_valid_path(fr, current_object, "rename", 1);
    if (!from)
        return 1;

    assign_svalue(&from_sv, &apply_ret_value);
    
    to = check_valid_path(t, current_object, "rename", 1);
    if (!to)
        return 1;

    assign_svalue(&to_sv, &apply_ret_value);
    if (!strlen(to) && !strcmp(t, "/")) {
        to = "./";
    }

    /* Strip trailing slashes */
    flen = strlen(from);
    if (flen > 1 && from[flen - 1] == '/') {
        const char *p = from + flen - 2;
        int n;
        
        while (*p == '/' && (p > from))
            p--;
        n = p - from + 1;
        memcpy(newfrom, from, n);
        newfrom[n] = 0;
        from = newfrom;
    }

    if (file_size(to) == -2) {
        /* Target is a directory; build full target filename. */
        const char *cp;
        char newto[MAX_FNAME_SIZE + MAX_PATH_LEN + 2];

        cp = strrchr(from, '/');
        if (cp)
            cp++;
        else
            cp = from;

        sprintf(newto, "%s/%s", to, cp);
        return do_move(from, newto, flag);
    } else
        return do_move(from, to, flag);
}
Ejemplo n.º 17
0
/*-------------------------------------------------------------------------*/
svalue_t *
x_map_struct (svalue_t *sp, int num_arg)

/* EFUN map() on structs
 *
 *   mixed * map(struct arg, string func, string|object ob, mixed extra...)
 *   mixed * map(struct arg, closure cl, mixed extra...)
 *   mixed * map(struct arr, mapping map [, int col])
 *
 * Map the elements of <arr> through a filter defined by the other
 * arguments, and return an array of the elements returned by the filter.
 *
 * The filter can be a function call:
 *
 *    <obj>-><fun>(elem, <extra>...)
 *
 * or a mapping query:
 *
 *    <map>[elem[,idx]]
 *
 * In the mapping case, if <map>[elem[,idx]] does not exist, the original
 * value is returned in the result.
 * [Note: argument type and range checking for idx is done in v_map()]
 *
 * <obj> can both be an object reference or a filename. If <ob> is
 * omitted, or neither an object nor a string, then this_object() is used.
 *
 * As a bonus, all references to destructed objects in <arr> are replaced
 * by proper 0es.
 */

{
    struct_t   *st;
    struct_t   *res;
    svalue_t   *arg;
    svalue_t   *v, *w, *x;
    mp_int      cnt;

    inter_sp = sp;
    arg = sp - num_arg + 1;

    st = arg->u.strct;
    cnt = (mp_int)struct_size(st);

    if (arg[1].type == T_MAPPING)
    {
        /* --- Map through mapping --- */

        mapping_t *m;
        p_int column = 0; /* mapping column to use */

        m = arg[1].u.map;

        if (num_arg > 2)
            column = arg[2].u.number;

        res = struct_new(st->type);
        if (!res)
            errorf("(map_struct) Out of memory: struct[%"PRIdMPINT"] for result\n", cnt);
        push_struct(inter_sp, res); /* In case of errors */

        for (w = st->member, x = res->member; --cnt >= 0; w++, x++)
        {
            if (destructed_object_ref(w))
                assign_svalue(w, &const0);

            v = get_map_value(m, w);
            if (v == &const0)
                assign_svalue_no_free(x, w);
            else
                assign_svalue_no_free(x, v + column);
        }

        if (num_arg > 2)
            free_svalue(arg+2);
        free_svalue(arg+1); /* the mapping */
        sp = arg;
    }
    else
    {
        /* --- Map through function call --- */

        callback_t  cb;
        int         error_index;

        error_index = setup_efun_callback(&cb, arg+1, num_arg-1);
        if (error_index >= 0)
        {
            vefun_bad_arg(error_index+2, arg);
            /* NOTREACHED */
            return arg;
        }
        inter_sp = sp = arg+1;
        put_callback(sp, &cb);
        num_arg = 2;

        res = struct_new(st->type);
        if (!res)
            errorf("(map_struct) Out of memory: struct[%"PRIdMPINT"] for result\n", cnt);
        push_struct(inter_sp, res); /* In case of errors */

        /* Loop through arr and res, mapping the values from arr */
        for (w = st->member, x = res->member; --cnt >= 0; w++, x++)
        {
            if (current_object->flags & O_DESTRUCTED)
                continue;

            if (destructed_object_ref(w))
                assign_svalue(w, &const0);

            if (!callback_object(&cb))
                errorf("object used by map_array destructed");

            push_svalue(w);

            v = apply_callback(&cb, 1);
            if (v)
            {
                transfer_svalue_no_free(x, v);
                v->type = T_INVALID;
            }
        }

        free_callback(&cb);
    }
    
    /* The arguments have been removed already, now just replace
     * the struct on the stack with the result.
     */
    free_struct(st);
    arg->u.strct = res; /* Keep svalue type T_STRUCT */

    return arg;
} /* x_map_struct () */
Ejemplo n.º 18
0
/*-------------------------------------------------------------------------*/
static svalue_t *
insert_alist (svalue_t *key, svalue_t * /* TODO: bool */ key_data, vector_t *list)

/* Implementation of efun insert_alist()
 *
 * The function can be used in two ways:
 *
 * 1. Insert/replace a (new) <key>:<keydata> tuple into the alist <list>.
 *    <key> and <key_data> have to point to an array of svalues. The first
 *    element is the key value, the following values the associated
 *    data values. The function will read as many elements from the
 *    array as necessary to fill the alist <list>.
 *    Result is a fresh copy of the modified alist.
 *
 * 2. Lookup a <key> in the alist <list> and return its index. If the key
 *    is not found, return  the position at which it would be inserted.
 *    <key_data> must be NULL, <key> points to the svalue to be looked
 *    up, and <list> points to an alist with at least the key vector.
 *
 * If <list> is no alist, the result can be wrong (case 2.) or not
 * an alist either (case 1.).
 *
 * If the <key> is a string, it is made shared.
 *
 * TODO: Make the hidden flag 'key_data' a real flag.
 */

{
    static svalue_t stmp; /* Result value */
    mp_int i,j,ix;
    mp_int keynum, list_size;  /* Number of keys, number of alist vectors */
    int new_member;            /* Flag if a new tuple is given */

    /* If key is a string, make it shared */
    if (key->type == T_STRING && !mstr_tabled(key->u.str))
    {
        key->u.str = make_tabled(key->u.str);
    }

    keynum = (mp_int)VEC_SIZE(list->item[0].u.vec);

    /* Locate the key */
    ix = lookup_key(key, list->item[0].u.vec);

    /* If its just a lookup: return the result.
     */
    if (key_data == NULL) {
         put_number(&stmp, ix < 0 ? -ix-1 : ix);
         return &stmp;
    }

    /* Prepare the result alist vector */
    put_array(&stmp, allocate_array(list_size = (mp_int)VEC_SIZE(list)));

    new_member = ix < 0;
    if (new_member)
        ix = -ix-1;

    /* Loop over all key/data vectors in <list>, insert/replace the
     * new value and put the new vector into <stmp>.
     */
    for (i = 0; i < list_size; i++) {
        vector_t *vtmp;

        if (new_member) {

            svalue_t *pstmp = list->item[i].u.vec->item;

            vtmp = allocate_array(keynum+1);
            for (j=0; j < ix; j++) {
               assign_svalue_no_free(&vtmp->item[j], pstmp++);
            }
            assign_svalue_no_free(&vtmp->item[ix], i ? &key_data[i] : key );
            for (j = ix+1; j <= keynum; j++) {
               assign_svalue_no_free(&vtmp->item[j], pstmp++);
            }

        } else {

            vtmp = slice_array(list->item[i].u.vec, 0, keynum-1);
            if (i)
                assign_svalue(&vtmp->item[ix], &key_data[i]);
                /* No need to assign the key value: it's already there. */

        }

        stmp.u.vec->item[i].type=T_POINTER;
        stmp.u.vec->item[i].u.vec=vtmp;
    }

    /* Done */
    return &stmp;
} /* insert_alist() */
Ejemplo n.º 19
0
/*-------------------------------------------------------------------------*/
svalue_t *
v_assoc (svalue_t *sp, int num_arg)

/* EFUN assoc()
 *
 *     int   assoc (mixed key, mixed *keys)
 *     mixed assoc (mixed key, mixed *alist [, mixed fail] )
 *     mixed assoc (mixed key, mixed *keys, mixed *data [, mixed fail])
 *
 * Search for <key> in the <alist> resp. in the <keys>.
 *
 * When the key list of an alist contains destructed objects
 * it is better not to free them till the next reordering by
 * order_alist to retain the alist property.
 */

{
    svalue_t *args;
    vector_t *keys,*data;
    svalue_t *fail_val;
    int ix;

    args = sp -num_arg +1;

    /* Analyse the arguments */
    if ( !VEC_SIZE(args[1].u.vec)
     ||  args[1].u.vec->item[0].type != T_POINTER )
    {
        keys = args[1].u.vec;
        if (num_arg == 2)
        {
            data = NULL;
        }
        else
        {
            if (args[2].type != T_POINTER
             || VEC_SIZE(args[2].u.vec) != VEC_SIZE(keys))
            {
                errorf("Number of values in key and data arrays differ.\n");
                /* NOTREACHED */
                return sp;
            }
            data = args[2].u.vec;
        }
        if (num_arg == 4)
        {
            fail_val = &args[3];
        }
        else
        {
            fail_val = &const0;
        }
    }
    else
    {
        keys = args[1].u.vec->item[0].u.vec;
        if (VEC_SIZE(args[1].u.vec) > 1)
        {
            if (args[1].u.vec->item[1].type != T_POINTER
             || VEC_SIZE(args[1].u.vec->item[1].u.vec) != VEC_SIZE(keys))
            {
                errorf("Number of values in key and data arrays differ.\n");
                /* NOTREACHED */
                return sp;
            }
            data = args[1].u.vec->item[1].u.vec;
        }
        else
        {
            data = NULL;
        }

        if (num_arg == 3) fail_val = &args[2];
        else if (num_arg == 2) fail_val = &const0;
        else
        {
            errorf("too many args to efun assoc\n");
            /* NOTREACHED */
            return sp;
        }
    }

    /* Call lookup_key() and push the result */
    ix = lookup_key(&args[0],keys);
    if (data == NULL)
    {
        sp = pop_n_elems(num_arg, sp);
        push_number(sp, ix < 0 ? -1 : ix);
    }
    else
    {
        assign_svalue(args
                     , ix < 0
                       ? fail_val
                       : (destructed_object_ref(&data->item[ix])
                         ? &const0
                         : &data->item[ix])
                     );
        sp = pop_n_elems(num_arg-1, sp);
    }

    return sp;
} /* v_assoc() */