Example #1
0
/*\
|*| array_demote_only
|*| array demote discards the values of a dictionary, and
|*| returns a packed list of the keys.
|*| (Useful because keys are ordered and unique, presumably.)
|*| (This allows the keys to be abused as sets.)
\*/
stk_array *
array_demote_only(stk_array *arr, int threshold)
{
    stk_array *demoted_array = NULL;
    int items_left = 0;
    array_iter current_key;
    array_iter *current_value;
    array_iter new_index;

    if (!arr || ARRAY_DICTIONARY != arr->type)
        return NULL;

    new_index.type = PROG_INTEGER;;
    new_index.data.number = 0;
    demoted_array = new_array_packed(0);
    items_left = array_first(arr, &current_key);
    while (items_left) {
        current_value = array_getitem(arr, &current_key);
        if (PROG_INTEGER == current_value->type
            && current_value->data.number >= threshold) {
            array_insertitem(&demoted_array, &new_index, &current_key);
            new_index.data.number++;
        }
        items_left = array_next(arr, &current_key);
    }
    return demoted_array;
}
Example #2
0
stk_array *
get_pids(dbref ref)
{
	struct inst temp1, temp2;
	stk_array  *nw;
	int count = 0;

	timequeue ptr = tqhead;
	nw = new_array_packed(0);
	while (ptr) {
		if (((ptr->typ != TQ_MPI_TYP) ? (ptr->called_prog == ref) : (ptr->trig == ref)) ||
			(ptr->uid == ref) || (ref < 0) ) {
			temp2.type = PROG_INTEGER;
			temp2.data.number = ptr->eventnum;
			temp1.type = PROG_INTEGER;
			temp1.data.number = count++;
			array_setitem(&nw, &temp1, &temp2);
			CLEAR(&temp1);
			CLEAR(&temp2);
		}
		ptr = ptr->next;
	}
	nw = get_mufevent_pids(nw, ref);
	return nw;
}
Example #3
0
void
prim_forcedby_array(PRIM_PROTOTYPE)
{
    stk_array *nu;
    int count = 0;

    CHECKOFLOW(1);
    if (mlev < 4)
	abort_interp("Wizbit only primitive.");

    if (!forcelist) {
	PushArrayRaw(new_array_packed(0, fr->pinning));
	return;
    }

    nu = new_array_packed(force_level, fr->pinning);

    for (objnode *tmp = forcelist; tmp; tmp = tmp->next) {
        array_set_intkey_refval(&nu, count++, tmp->data);
    }

    PushArrayRaw(nu);
}
Example #4
0
void
prim_shallow_copy(PRIM_PROTOTYPE)
{
    EXPECT_READ_STACK(1);
    CHECKOFLOW(1);
    if (arg[*top - 1].type != PROG_ARRAY) {
	copyinst(&arg[*top - 1], &arg[*top]);
	(*top)++;
    } else {
	stk_array *nu;
	stk_array *arr = arg[*top - 1].data.array;
	if (!arr) {
	    nu = new_array_packed(0, fr->pinning);
	} else {
	    nu = array_decouple(arr);
	}
	PushArrayRaw(nu);
    }
}
Example #5
0
void
prim_regfind_array(PRIM_PROTOTYPE)
{
    struct flgchkdat check;
    dbref ref, who;
    const char *name;
    stk_array *nw;
    muf_re* re;
    char* text = NULL;
    int flags;
    int matchcnt = 0;
    const char* errstr = NULL;

    CHECKOP(4);
    oper4 = POP();              /* int:pcreflags */
    oper3 = POP();              /* str:objflags */
    oper2 = POP();              /* str:namepattern */
    oper1 = POP();              /* ref:owner */

    if (mlev < LMAGE)
        abort_interp("MAGE prim.");
    if (oper4->type != PROG_INTEGER)
        abort_interp("Non-integer argument (4)");
    if (oper3->type != PROG_STRING)
        abort_interp("Expected string argument. (3)");
    if (oper2->type != PROG_STRING)
        abort_interp("Expected string argument. (2)");
    if (oper1->type != PROG_OBJECT)
        abort_interp("Expected dbref argument. (1)");
    if (oper1->data.objref < NOTHING || oper1->data.objref >= db_top)
        abort_interp("Bad object. (1)");


    flags = PCRE_NO_AUTO_CAPTURE;

    if (oper4->data.number & MUF_RE_ICASE)
        flags |= PCRE_CASELESS;
    if (oper4->data.number & MUF_RE_EXTENDED)
        flags |= PCRE_EXTENDED;

    re = regmatch_re_get(oper2->data.string, flags, &errstr);
    if (errstr)
        abort_interp(errstr)

    /* We're scanning a chunk of the DB, so studying should pay off.
     * A null return is fine, it just means we can't optimize further. */
    if (re && !re->extra) {
        re->extra = pcre_study(re->re, 0, &errstr);
        if (errstr)
            abort_interp(errstr);
    }

    who = oper1->data.objref;
    name = DoNullInd(oper2->data.string);

    init_checkflags(PSafe, DoNullInd(oper3->data.string), &check);
    nw = new_array_packed(0);

    /* The "result = array_appendref" stuff was copied from find_array. I'm
     * making sure these alterations work as-is before attempting to remove it.
     * -brevantes */
    for (ref = (dbref) 0; ref < db_top; ref++) {
        if (((who == NOTHING) ? 1 : (OWNER(ref) == who)) &&
            checkflags(ref, check) && NAME(ref)) {
            if (!*name)
                result = array_appendref(&nw, ref);
            else
                text = (char *)NAME(ref);
                if ((matchcnt = regmatch_exec(re, text)) < 0)
                {
                    if (matchcnt != PCRE_ERROR_NOMATCH)
                        abort_interp(muf_re_error(matchcnt));
                } else {
                    result = array_appendref(&nw, ref);
                }
        }
    }


    CLEAR(oper1);
    CLEAR(oper2);
    CLEAR(oper3);
    CLEAR(oper4);
    PushArrayRaw(nw);
}
Example #6
0
void
prim_array_regfilter_prop(PRIM_PROTOTYPE)
{
    char buf[BUFFER_LEN];
    struct inst *in;
    stk_array *arr;
    stk_array *nu;
    char* prop;
    const char* ptr;
    muf_re* re;
    int flags;
    int matchcnt = 0;
    const char* errstr = NULL;

    CHECKOP(4);
    oper4 = POP();    /* int     pcreflags */
    oper3 = POP();    /* str     pattern */
    oper2 = POP();    /* str     propname */
    oper1 = POP();    /* refarr  Array */

    if (oper1->type != PROG_ARRAY)
        abort_interp("Argument not an array. (1)");
    if (!array_is_homogenous(oper1->data.array, PROG_OBJECT))
        abort_interp("Argument not an array of dbrefs. (1)");
    if (oper2->type != PROG_STRING || !oper2->data.string)
        abort_interp("Argument not a non-null string. (2)");
    if (oper3->type != PROG_STRING)
        abort_interp("Argument not a string pattern. (3)");
    if (oper4->type != PROG_INTEGER)
        abort_interp("Non-integer argument (4)");


    ptr = oper2->data.string->data;
    while ((ptr = index(ptr, PROPDIR_DELIMITER)))
        if (!(*(++ptr)))
            abort_interp("Cannot access a propdir directly.");
    nu = new_array_packed(0);
    arr = oper1->data.array;

    flags = PCRE_NO_AUTO_CAPTURE;

    if (oper4->data.number & MUF_RE_ICASE)
        flags |= PCRE_CASELESS;
    if (oper4->data.number & MUF_RE_EXTENDED)
        flags |= PCRE_EXTENDED;

    re = regmatch_re_get(oper3->data.string, flags, &errstr);
    if (errstr)
        abort_interp(errstr)

    if (re && !re->extra && array_count(arr) > 2) {
        /* This pattern is getting used 3 or more times, let's study it. A null
         * return is okay, that just means there's nothing to optimize. */
        re->extra = pcre_study(re->re, 0, &errstr);
        if (errstr)
            abort_interp(errstr);
    }

    prop = (char *) DoNullInd(oper2->data.string);
    if (array_first(arr, &temp1)) {
        do {
            in = array_getitem(arr, &temp1);
            if (valid_object(in)) {
                ref = in->data.objref;
                CHECKREMOTE(ref);
                if (prop_read_perms(ProgUID, ref, prop, mlev)) {
                    ptr = get_property_class(ref, prop);
                    if (ptr)
                        strcpy(buf, ptr);
                    else
                        strcpy(buf, "");
                    if ((matchcnt = regmatch_exec(re, buf)) < 0) {
                        if (matchcnt != PCRE_ERROR_NOMATCH)
                            abort_interp(muf_re_error(matchcnt));
                    } else {
                        array_appenditem(&nu, in);
                    }
                }
            }
        } while (array_next(arr, &temp1));
    }


    CLEAR(oper4);
    CLEAR(oper3);
    CLEAR(oper2);
    CLEAR(oper1);
    PushArrayRaw(nu);
}
Example #7
0
void
prim_regexp(PRIM_PROTOTYPE)
{
    stk_array*  nu_val  = 0;
    stk_array*  nu_idx  = 0;
    int         matches[MATCH_ARR_SIZE];
    muf_re*     re;
    char*       text;
    int         flags   = 0;
    int         len, i;
    int         matchcnt = 0;
    const char* errstr;

    CHECKOP(3);

    oper3 = POP(); /* int:Flags */
    oper2 = POP(); /* str:Pattern */
    oper1 = POP(); /* str:Text */

    if (oper1->type != PROG_STRING)
        abort_interp("Non-string argument (1)");
    if (oper2->type != PROG_STRING)
        abort_interp("Non-string argument (2)");
    if (oper3->type != PROG_INTEGER)
        abort_interp("Non-integer argument (3)");
    if (!oper2->data.string)
        abort_interp("Empty string argument (2)");

    if (oper3->data.number & MUF_RE_ICASE)
        flags |= PCRE_CASELESS;
    if (oper3->data.number & MUF_RE_EXTENDED)
        flags |= PCRE_EXTENDED;

    if ((re = muf_re_get(oper2->data.string, flags, &errstr)) == NULL)
        abort_interp(errstr);

    text    = (char *)DoNullInd(oper1->data.string);
    len     = strlen(text);

    if ((matchcnt = pcre_exec(re->re, re->extra, text, len, 0, 0, matches, MATCH_ARR_SIZE)) < 0)
    {
        if (matchcnt != PCRE_ERROR_NOMATCH)
        {
            abort_interp(muf_re_error(matchcnt));
        }

        if (((nu_val = new_array_packed(0)) == NULL) ||
            ((nu_idx = new_array_packed(0)) == NULL))
        {
            if (nu_val != NULL)
                array_free(nu_val);

            if (nu_idx != NULL)
                array_free(nu_idx);

            abort_interp("Out of memory");
        }
    }
    else
    {
        if (((nu_val = new_array_packed(matchcnt)) == NULL) ||
            ((nu_idx = new_array_packed(matchcnt)) == NULL))
        {
            if (nu_val != NULL)
                array_free(nu_val);

            if (nu_idx != NULL)
                array_free(nu_idx);

            abort_interp("Out of memory");
        }

        for(i = 0; i < matchcnt; i++)
        {
            int substart = matches[i*2];
            int subend = matches[i*2+1];
            struct inst idx, val;
            stk_array*  nu;

            if ((substart >= 0) && (subend >= 0) && (substart < len))
                snprintf(buf, BUFFER_LEN, "%.*s", (int)(subend - substart), &text[substart]);
            else
                buf[0] = '\0';

            idx.type        = PROG_INTEGER;
            idx.data.number = i;
            val.type        = PROG_STRING;
            val.data.string = alloc_prog_string(buf);

            array_setitem(&nu_val, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            if ((nu = new_array_packed(2)) == NULL)
            {
                array_free(nu_val);
                array_free(nu_idx);

                abort_interp("Out of memory");
            }

            idx.type        = PROG_INTEGER;
            idx.data.number = 0;
            val.type        = PROG_INTEGER;
            val.data.number = substart + 1;

            array_setitem(&nu, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            idx.type        = PROG_INTEGER;
            idx.data.number = 1;
            val.type        = PROG_INTEGER;
            val.data.number = subend - substart;

            array_setitem(&nu, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            idx.type        = PROG_INTEGER;
            idx.data.number = i;
            val.type        = PROG_ARRAY;
            val.data.array  = nu;

            array_setitem(&nu_idx, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);
        }
    }

    CLEAR(oper3);
    CLEAR(oper2);
    CLEAR(oper1);

    PushArrayRaw(nu_val);
    PushArrayRaw(nu_idx);
}
Example #8
0
stk_array *
array_getrange(stk_array *arr, array_iter *start, array_iter *end)
{
    stk_array *new2;
    array_data *tmp;
    int sidx, eidx;

    if (!arr) {
        return NULL;
    }
    switch (arr->type) {
        case ARRAY_PACKED:{
            array_iter idx;
            array_iter didx;

            if (start->type != PROG_INTEGER) {
                return NULL;
            }
            if (end->type != PROG_INTEGER) {
                return NULL;
            }
            sidx = start->data.number;
            eidx = end->data.number;
            if (sidx < 0) {
                sidx = 0;
            } else if (sidx > arr->items) {
                return NULL;
            }
            if (eidx >= arr->items) {
                eidx = arr->items - 1;
            } else if (eidx < 0) {
                return NULL;
            }
            if (sidx > eidx) {
                return NULL;
            }
            idx.type = PROG_INTEGER;
            idx.data.number = sidx;
            didx.type = PROG_INTEGER;
            didx.data.number = 0;
            new2 = new_array_packed(eidx - sidx + 1);
            while (idx.data.number <= eidx) {
                tmp = array_getitem(arr, &idx);
                if (!tmp)
                    break;
                array_setitem(&new2, &didx, tmp);
                didx.data.number++;
                idx.data.number++;
            }
            return new2;
            break;
        }

        case ARRAY_DICTIONARY:{
            stk_array *new2;
            array_tree *s;
            array_tree *e;

            new2 = new_array_dictionary();
            s = array_tree_find(arr->data.dict, start);
            if (!s) {
                s = array_tree_next_node(arr->data.dict, start);
                if (!s) {
                    return new2;
                }
            }
            e = array_tree_find(arr->data.dict, end);
            if (!e) {
                e = array_tree_prev_node(arr->data.dict, end);
                if (!e) {
                    return new2;
                }
            }
            if (array_tree_compare(&s->key, &e->key, 0, 0, 0) > 0) {
                return new2;
            }
            while (s) {
                array_setitem(&new2, &s->key, &s->data);
                if (s == e)
                    break;
                s = array_tree_next_node(arr->data.dict, &s->key);
            }
            return new2;
            break;
        }

        default:
            break;
    }
    return NULL;
}
Example #9
0
stk_array *
tune_parms_array(const char *pattern, int mlev)
{
    struct tune_str_entry *tstr = tune_str_list;
    struct tune_time_entry *ttim = tune_time_list;
    struct tune_val_entry *tval = tune_val_list;
    struct tune_ref_entry *tref = tune_ref_list;
    struct tune_bool_entry *tbool = tune_bool_list;
    stk_array *nu = new_array_packed(0);
    struct inst temp1;
    char pat[BUFFER_LEN];
    char buf[BUFFER_LEN];
    int i = 0;

    strcpy(pat, pattern);
    while (tbool->name) {
        if (tbool->readmlev <= mlev) {
            strcpy(buf, tbool->name);
            if (!*pattern || equalstr(pat, buf)) {
                stk_array *item = new_array_dictionary();

                array_set_strkey_strval(&item, "type", "boolean");
                array_set_strkey_strval(&item, "group", tbool->group);
                array_set_strkey_strval(&item, "name", tbool->name);
                array_set_strkey_intval(&item, "value", *tbool->boolv ? 1 : 0);
                array_set_strkey_intval(&item, "readmlev", tbool->readmlev);
                array_set_strkey_intval(&item, "writemlev", tbool->writemlev);
                temp1.type = PROG_ARRAY;
                temp1.data.array = item;
                array_set_intkey(&nu, i++, &temp1);
                CLEAR(&temp1);
            }
        }
        tbool++;
    }

    while (ttim->name) {
        if (ttim->readmlev <= mlev) {
            strcpy(buf, ttim->name);
            if (!*pattern || equalstr(pat, buf)) {
                stk_array *item = new_array_dictionary();

                array_set_strkey_strval(&item, "type", "timespan");
                array_set_strkey_strval(&item, "group", ttim->group);
                array_set_strkey_strval(&item, "name", ttim->name);
                array_set_strkey_intval(&item, "value", *ttim->tim);
                array_set_strkey_intval(&item, "readmlev", ttim->readmlev);
                array_set_strkey_intval(&item, "writemlev", ttim->writemlev);
                temp1.type = PROG_ARRAY;
                temp1.data.array = item;
                array_set_intkey(&nu, i++, &temp1);
                CLEAR(&temp1);
            }
        }
        ttim++;
    }

    while (tval->name) {
        if (tval->readmlev <= mlev) {
            strcpy(buf, tval->name);
            if (!*pattern || equalstr(pat, buf)) {
                stk_array *item = new_array_dictionary();

                array_set_strkey_strval(&item, "type", "integer");
                array_set_strkey_strval(&item, "group", tval->group);
                array_set_strkey_strval(&item, "name", tval->name);
                array_set_strkey_intval(&item, "value", *tval->val);
                array_set_strkey_intval(&item, "readmlev", tval->readmlev);
                array_set_strkey_intval(&item, "writemlev", tval->writemlev);
                temp1.type = PROG_ARRAY;
                temp1.data.array = item;
                array_set_intkey(&nu, i++, &temp1);
                CLEAR(&temp1);
            }
        }
        tval++;
    }

    while (tref->name) {
        if (tref->readmlev <= mlev) {
            strcpy(buf, tref->name);
            if (!*pattern || equalstr(pat, buf)) {
                stk_array *item = new_array_dictionary();

                array_set_strkey_strval(&item, "type", "dbref");
                array_set_strkey_strval(&item, "group", tref->group);
                array_set_strkey_strval(&item, "name", tref->name);
                array_set_strkey_refval(&item, "value", *tref->ref);
                array_set_strkey_intval(&item, "readmlev", tref->readmlev);
                array_set_strkey_intval(&item, "writemlev", tref->writemlev);
                switch (tref->typ) {
                case NOTYPE:
                    array_set_strkey_strval(&item, "objtype", "any");
                    break;
                case TYPE_PLAYER:
                    array_set_strkey_strval(&item, "objtype", "player");
                    break;
                case TYPE_THING:
                    array_set_strkey_strval(&item, "objtype", "thing");
                    break;
                case TYPE_ROOM:
                    array_set_strkey_strval(&item, "objtype", "room");
                    break;
                case TYPE_EXIT:
                    array_set_strkey_strval(&item, "objtype", "exit");
                    break;
                case TYPE_PROGRAM:
                    array_set_strkey_strval(&item, "objtype", "program");
                    break;
                case TYPE_GARBAGE:
                    array_set_strkey_strval(&item, "objtype", "garbage");
                    break;
                default:
                    array_set_strkey_strval(&item, "objtype", "unknown");
                    break;
                }
                temp1.type = PROG_ARRAY;
                temp1.data.array = item;
                array_set_intkey(&nu, i++, &temp1);
                CLEAR(&temp1);
            }
        }
        tref++;
    }

    while (tstr->name) {
        if (tstr->readmlev <= mlev) {
            strcpy(buf, tstr->name);
            if (!*pattern || equalstr(pat, buf)) {
                stk_array *item = new_array_dictionary();

                array_set_strkey_strval(&item, "type", "string");
                array_set_strkey_strval(&item, "group", tstr->group);
                array_set_strkey_strval(&item, "name", tstr->name);
                array_set_strkey_strval(&item, "value", *tstr->str);
                array_set_strkey_intval(&item, "readmlev", tstr->readmlev);
                array_set_strkey_intval(&item, "writemlev", tstr->writemlev);
                temp1.type = PROG_ARRAY;
                temp1.data.array = item;
                array_set_intkey(&nu, i++, &temp1);
                CLEAR(&temp1);
            }
        }
        tstr++;
    }
    return nu;
}
Example #10
0
void
prim_regexp(PRIM_PROTOTYPE)
{
    stk_array *nu_val = 0;
    stk_array *nu_idx = 0;
    regmatch_t *matches = 0;
    muf_re *re;
    char *text;
    int flags = 0;
    int nosubs, err, len, i;

    CHECKOP(3);

    oper3 = POP();              /* int:Flags */
    oper2 = POP();              /* str:Pattern */
    oper1 = POP();              /* str:Text */

    if (oper1->type != PROG_STRING)
        abort_interp("Non-string argument (1)");
    if (oper2->type != PROG_STRING)
        abort_interp("Non-string argument (2)");
    if (oper3->type != PROG_INTEGER)
        abort_interp("Non-integer argument (3)");
    if (!oper2->data.string)
        abort_interp("Empty string argument (2)");

    if (oper3->data.number & MUF_RE_ICASE)
        flags |= REG_ICASE;

    if ((re = muf_re_get(oper2->data.string, flags, &err)) == NULL)
        abort_interp(muf_re_error(err));

    text = DoNullInd(oper1->data.string);
    len = strlen(text);
    nosubs = re->re.re_nsub + 1;

    if ((matches = (regmatch_t *) malloc(sizeof(regmatch_t) * nosubs)) == NULL)
        abort_interp("Out of memory");

    if ((err = regexec(&re->re, text, nosubs, matches, 0)) != 0) {
        if (err != REG_NOMATCH) {
            free(matches);
            abort_interp(muf_re_error(err));
        }

        if (((nu_val = new_array_packed(0)) == NULL) ||
            ((nu_idx = new_array_packed(0)) == NULL)) {
            free(matches);

            if (nu_val != NULL)
                array_free(nu_val);

            if (nu_idx != NULL)
                array_free(nu_idx);

            abort_interp("Out of memory");
        }
    } else {
        if (((nu_val = new_array_packed(nosubs)) == NULL) ||
            ((nu_idx = new_array_packed(nosubs)) == NULL)) {
            free(matches);

            if (nu_val != NULL)
                array_free(nu_val);

            if (nu_idx != NULL)
                array_free(nu_idx);

            abort_interp("Out of memory");
        }

        for (i = 0; i < nosubs; i++) {
            regmatch_t *cm = &matches[i];
            struct inst idx, val;
            stk_array *nu;

            if ((cm->rm_so >= 0) && (cm->rm_eo >= 0) && (cm->rm_so < len))
                snprintf(buf, BUFFER_LEN, "%.*s", cm->rm_eo - cm->rm_so,
                         &text[cm->rm_so]);
            else
                buf[0] = '\0';

            idx.type = PROG_INTEGER;
            idx.data.number = i;
            val.type = PROG_STRING;
            val.data.string = alloc_prog_string(buf);

            array_setitem(&nu_val, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            if ((nu = new_array_packed(2)) == NULL) {
                free(matches);

                array_free(nu_val);
                array_free(nu_idx);

                abort_interp("Out of memory");
            }

            idx.type = PROG_INTEGER;
            idx.data.number = 0;
            val.type = PROG_INTEGER;
            val.data.number = cm->rm_so + 1;

            array_setitem(&nu, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            idx.type = PROG_INTEGER;
            idx.data.number = 1;
            val.type = PROG_INTEGER;
            val.data.number = cm->rm_eo - cm->rm_so;

            array_setitem(&nu, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);

            idx.type = PROG_INTEGER;
            idx.data.number = i;
            val.type = PROG_ARRAY;
            val.data.array = nu;

            array_setitem(&nu_idx, &idx, &val);

            CLEAR(&idx);
            CLEAR(&val);
        }
    }

    free(matches);

    CLEAR(oper3);
    CLEAR(oper2);
    CLEAR(oper1);

    PushArrayRaw(nu_val);
    PushArrayRaw(nu_idx);
}
Example #11
0
void
prim_array_filter_prop(PRIM_PROTOTYPE)
{
	char pattern[BUFFER_LEN];
	char tname[BUFFER_LEN];
	struct inst *in;
	struct inst temp1;
	stk_array *arr;
	stk_array *nu;
	char* prop;
	int len;

	CHECKOP(3);
	oper3 = POP();				/* str     pattern */
	oper2 = POP();				/* str     propname */
	oper1 = POP();				/* refarr  Array */
	if (oper1->type != PROG_ARRAY)
		abort_interp("Argument not an array. (1)");
	if (!array_is_homogenous(oper1->data.array, PROG_OBJECT))
		abort_interp("Argument not an array of dbrefs. (1)");
	if (oper2->type != PROG_STRING || !oper2->data.string)
		abort_interp("Argument not a non-null string. (2)");
	if (oper3->type != PROG_STRING)
		abort_interp("Argument not a string pattern. (3)");

	len = oper2->data.string ? oper2->data.string->length : 0;
	strcpyn(tname, sizeof(tname), DoNullInd(oper2->data.string));
	while (len-- > 0 && tname[len] == PROPDIR_DELIMITER) {
		tname[len] = '\0';
	}

	nu = new_array_packed(0);
	arr = oper1->data.array;
	prop = tname;
	strcpyn(pattern, sizeof(pattern), DoNullInd(oper3->data.string));
	if (array_first(arr, &temp1)) {
		do {
			in = array_getitem(arr, &temp1);
			if (valid_object(in)) {
				ref = in->data.objref;
				CHECKREMOTE(ref);
				if (prop_read_perms(ProgUID, ref, prop, mlev)) {
					PropPtr pptr = get_property(ref, prop);

					if (pptr)
					{
						switch(PropType(pptr))
						{
							case PROP_STRTYP:
								strncpy(buf, PropDataStr(pptr), BUFFER_LEN);
							break;

							case PROP_LOKTYP:
								if (PropFlags(pptr) & PROP_ISUNLOADED) {
									strncpy(buf, "*UNLOCKED*", BUFFER_LEN);
								} else {
									strncpy(buf, unparse_boolexp(ProgUID, PropDataLok(pptr), 0), BUFFER_LEN);
								}
							break;

							case PROP_REFTYP:
								snprintf(buf, BUFFER_LEN, "#%i", PropDataRef(pptr));
							break;

							case PROP_INTTYP:
								snprintf(buf, BUFFER_LEN, "%i", PropDataVal(pptr));
							break;

							case PROP_FLTTYP:
								snprintf(buf, BUFFER_LEN, "%g", PropDataFVal(pptr));
							break;

							default:
								strncpy(buf, "", BUFFER_LEN);
							break;
						}
					}
					else
						strncpy(buf, "", BUFFER_LEN);

					if (equalstr(pattern, buf)) {
						array_appenditem(&nu, in);
					}
				}
			}
		} while (array_next(arr, &temp1));
	}

	CLEAR(oper3);
	CLEAR(oper2);
	CLEAR(oper1);

	PushArrayRaw(nu);
}