int array_setrange(stk_array **harr, array_iter *start, stk_array *inarr) { stk_array *arr; array_iter idx; if (!harr || !*harr) { return -1; } arr = *harr; if (!inarr || !inarr->items) { return arr->items; } switch (arr->type) { case ARRAY_PACKED:{ if (!start) { return -1; } if (start->type != PROG_INTEGER) { return -1; } if (start->data.number < 0 || start->data.number > arr->items) { return -1; } if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } if (array_first(inarr, &idx)) { do { array_setitem(&arr, start, array_getitem(inarr, &idx)); start->data.number++; } while (array_next(inarr, &idx)); } return arr->items; break; } case ARRAY_DICTIONARY:{ if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } if (array_first(inarr, &idx)) { do { array_setitem(&arr, &idx, array_getitem(inarr, &idx)); } while (array_next(inarr, &idx)); } return arr->items; break; } default: break; } return -1; }
stk_array * array_promote(stk_array *arr) { stk_array *new2; int i; array_iter idx; if (!arr) { return NULL; } if (arr->type != ARRAY_PACKED) { return NULL; } new2 = new_array_dictionary(); idx.type = PROG_INTEGER; for (i = 0; i < arr->items; i++) { idx.data.number = i; array_setitem(&new2, &idx, array_getitem(arr, &idx)); } array_free(arr); return new2; }
/*\ |*| array_mash |*| Takes the lists of values from the first array and |*| uses each value as a key in the second array. For |*| each key, the passed "change_by" value is applied to |*| any existing value. If the value does not exist, it |*| is set. |*| This will be the core of the different/union/intersection |*| code. |*| Of course, this is going to absolutely blow chunks when |*| passed an array with value types that can't be used as |*| key values in an array. Blast. That may be infeasible |*| regardless, though. \*/ void array_mash(stk_array *arr_in, stk_array **mash, int value) { int still_values = 0; array_iter current_key; array_iter *current_keyval; array_iter *current_value; array_data temp_value; if (NULL == arr_in || NULL == mash || NULL == *mash) return; still_values = array_first(arr_in, ¤t_key); while (still_values) { current_keyval = array_getitem(arr_in, ¤t_key); current_value = array_getitem(*mash, current_keyval); if (NULL != current_value) { if (PROG_INTEGER == current_value->type) { copyinst(current_value, &temp_value); temp_value.data.number += value; array_setitem(mash, current_keyval, &temp_value); } } else { temp_value.type = PROG_INTEGER; temp_value.data.number = value; array_insertitem(mash, current_keyval, &temp_value); } still_values = array_next(arr_in, ¤t_key); } }
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; }
int array_appenditem(stk_array **harr, array_data *item) { struct inst key; if (!harr || !*harr) return -1; if ((*harr)->type != ARRAY_PACKED) return -1; key.type = PROG_INTEGER; key.data.number = array_count(*harr); return array_setitem(harr, &key, item); }
int array_set_strkey(stk_array **harr, const char *key, struct inst *val) { struct inst name; int result; name.type = PROG_STRING; name.data.string = alloc_prog_string(key); result = array_setitem(harr, &name, val); CLEAR(&name); return result; }
int array_set_intkey(stk_array **harr, int key, struct inst *val) { struct inst name; int result; name.type = PROG_INTEGER; name.data.number = key; result = array_setitem(harr, &name, val); CLEAR(&name); return result; }
stk_array * array_decouple(stk_array *arr) { stk_array *new2; if (!arr) { return NULL; } new2 = new_array(); new2->pinned = arr->pinned; new2->type = arr->type; switch (arr->type) { case ARRAY_PACKED:{ int i; new2->items = arr->items; new2->data.packed = (array_data *) malloc(sizeof(array_data) * arr->items); for (i = arr->items; i-- > 0;) { copyinst(&arr->data.packed[i], &new2->data.packed[i]); } return new2; break; } case ARRAY_DICTIONARY:{ array_iter idx; array_data *val; if (array_first(arr, &idx)) { do { val = array_getitem(arr, &idx); array_setitem(&new2, &idx, val); } while (array_next(arr, &idx)); } return new2; break; } default: break; } return NULL; }
void prim_array_regmatchval(PRIM_PROTOTYPE) { struct inst *in; stk_array *arr; stk_array *nw; muf_re* re; char* text; int flags; int matchcnt = 0; const char* errstr = NULL; CHECKOP(3); oper3 = POP(); /* int pcreflags */ oper2 = POP(); /* str pattern */ oper1 = POP(); /* arr Array */ if (oper1->type != PROG_ARRAY) abort_interp("Argument not an array. (1)"); if (oper2->type != PROG_STRING) abort_interp("Argument not a string pattern. (2)"); if (oper3->type != PROG_INTEGER) abort_interp("Non-integer argument (3)"); flags = PCRE_NO_AUTO_CAPTURE; if (oper3->data.number & MUF_RE_ICASE) flags |= PCRE_CASELESS; if (oper3->data.number & MUF_RE_EXTENDED) flags |= PCRE_EXTENDED; re = regmatch_re_get(oper2->data.string, flags, &errstr); if (errstr) abort_interp(errstr) nw = new_array_dictionary(); arr = oper1->data.array; 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); } if (array_first(arr, &temp1)) { do { in = array_getitem(arr, &temp1); if (in->type == PROG_STRING) { text = (char *)DoNullInd(in->data.string); if ((matchcnt = regmatch_exec(re, text)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) abort_interp(muf_re_error(matchcnt)); } else { array_setitem(&nw, &temp1, in); } } else if (in->type == PROG_OBJECT) { text = (char *) NAME(in->data.objref); if ((matchcnt = regmatch_exec(re, text)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) abort_interp(muf_re_error(matchcnt)); } else { array_setitem(&nw, &temp1, in); } } } while (array_next(arr, &temp1)); } CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushArrayRaw(nw); }
void prim_array_regsub(PRIM_PROTOTYPE) { struct inst *in; stk_array *arr; stk_array *nw; int matches[MATCH_ARR_SIZE]; int flags = 0; char* write_ptr = buf; int write_left = BUFFER_LEN - 1; muf_re* re; char* text; char* textstart; const char* errstr; int matchcnt, len; CHECKOP(4); oper4 = POP(); /* int:Flags */ oper3 = POP(); /* str:Replace */ oper2 = POP(); /* str:Pattern */ oper1 = POP(); /* str:Text */ if (oper1->type != PROG_ARRAY) abort_interp("Argument not an array of strings. (1)"); if (!array_is_homogenous(oper1->data.array, PROG_STRING)) abort_interp("Argument not an array of strings. (1)"); if (oper2->type != PROG_STRING) abort_interp("Non-string argument (2)"); if (oper3->type != PROG_STRING) abort_interp("Non-string argument (3)"); if (oper4->type != PROG_INTEGER) abort_interp("Non-integer argument (4)"); if (!oper2->data.string) abort_interp("Empty string argument (2)"); if (oper4->data.number & MUF_RE_ICASE) flags |= PCRE_CASELESS; if (oper4->data.number & MUF_RE_EXTENDED) flags |= PCRE_EXTENDED; if ((re = muf_re_get(oper2->data.string, flags, &errstr)) == NULL) abort_interp(errstr); nw = new_array_dictionary(); arr = oper1->data.array; if (!re->extra && ((oper4->data.number & MUF_RE_ALL ) || array_count(arr) > 2)) { /* Study the pattern if the user requested recursive substitution, or * if the input array contains at least three items. */ re->extra = pcre_study(re->re, 0, &errstr); if (errstr) abort_interp(errstr); } if (array_first(arr, &temp1)) { do { write_ptr = buf; write_left = BUFFER_LEN - 1; in = array_getitem(arr, &temp1); textstart = text = (char *)DoNullInd(in->data.string); len = strlen(textstart); while((*text != '\0') && (write_left > 0)) { if ((matchcnt = pcre_exec(re->re, re->extra, textstart, len, text-textstart, 0, matches, MATCH_ARR_SIZE)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) { abort_interp(muf_re_error(matchcnt)); } while((write_left > 0) && (*text != '\0')) { *write_ptr++ = *text++; write_left--; } break; } else { int allstart = matches[0]; int allend = matches[1]; int substart = -1; int subend = -1; char* read_ptr = (char *)DoNullInd(oper3->data.string); int count; for(count = allstart-(text-textstart); (write_left > 0) && (*text != '\0') && (count > 0); count--) { *write_ptr++ = *text++; write_left--; } while((write_left > 0) && (*read_ptr != '\0')) { if (*read_ptr == '\\') { if (!isdigit(*(++read_ptr))) { *write_ptr++ = *read_ptr++; write_left--; } else { int idx = (*read_ptr++) - '0'; if ((idx < 0) || (idx >= matchcnt)) { abort_interp("Invalid \\subexp in substitution string. (3)"); } substart = matches[idx*2]; subend = matches[idx*2+1]; if ((substart >= 0) && (subend >= 0) && (substart < len)) { char* ptr = &textstart[substart]; count = subend - substart; if (count > write_left) { abort_interp("Operation would result in overflow"); } for(; (write_left > 0) && (count > 0) && (*ptr != '\0'); count--) { *write_ptr++ = *ptr++; write_left--; } } } } else { *write_ptr++ = *read_ptr++; write_left--; } } for(count = allend - allstart; (*text != '\0') && (count > 0); count--) text++; if (allstart == allend && *text) { *write_ptr++ = *text++; write_left--; } } if ((oper4->data.number & MUF_RE_ALL) == 0) { while((write_left > 0) && (*text != '\0')) { *write_ptr++ = *text++; write_left--; } break; } } if (*text != '\0') abort_interp("Operation would result in overflow"); *write_ptr = '\0'; temp2.type = PROG_STRING; temp2.data.string = alloc_prog_string(buf); array_setitem(&nw, &temp1, &temp2); CLEAR(&temp2); } while (array_next(arr, &temp1)); } CLEAR(oper4); CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushArrayRaw(nw); }
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); }
int array_insertrange(stk_array **harr, array_iter *start, stk_array *inarr) { stk_array *arr; array_data *itm; array_iter idx; array_iter didx; if (!harr || !*harr) { return -1; } arr = *harr; if (!inarr || !inarr->items) { return arr->items; } switch (arr->type) { case ARRAY_PACKED:{ if (!start) { return -1; } if (start->type != PROG_INTEGER) { return -1; } if (start->data.number < 0 || start->data.number > arr->items) { return -1; } if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } arr->data.packed = (array_data *) realloc(arr->data.packed, sizeof(array_data) * (arr->items + inarr->items)); copyinst(start, &idx); copyinst(start, &didx); idx.data.number = arr->items - 1; didx.data.number = arr->items + inarr->items - 1; while (idx.data.number >= start->data.number) { itm = array_getitem(arr, &idx); copyinst(itm, &arr->data.packed[didx.data.number]); CLEAR(itm); idx.data.number--; didx.data.number--; } if (array_first(inarr, &idx)) { do { itm = array_getitem(inarr, &idx); copyinst(itm, &arr->data.packed[start->data.number]); start->data.number++; } while (array_next(inarr, &idx)); } arr->items += inarr->items; return arr->items; break; } case ARRAY_DICTIONARY:{ if (arr->links > 1 && !arr->pinned) { arr->links--; arr = *harr = array_decouple(arr); } if (array_first(inarr, &idx)) { do { array_setitem(&arr, &idx, array_getitem(inarr, &idx)); } while (array_next(inarr, &idx)); } return arr->items; break; } default: break; } return -1; }
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; }
stk_array * get_pidinfo(int pid) { struct inst temp1, temp2; stk_array *nw; time_t rtime = time(NULL); time_t etime = 0; double pcnt = 0.0; timequeue ptr = tqhead; nw = new_array_dictionary(); while (ptr) { if (ptr->eventnum == pid) { if (ptr->typ != TQ_MUF_TYP || ptr->subtyp != TQ_MUF_TIMER) { break; } } ptr = ptr->next; } if (ptr && (ptr->eventnum == pid) && (ptr->typ != TQ_MUF_TYP || ptr->subtyp != TQ_MUF_TIMER)) { if (ptr->fr) { etime = rtime - ptr->fr->started; if (etime > 0) { pcnt = ptr->fr->totaltime.tv_sec; pcnt += ptr->fr->totaltime.tv_usec / 1000000; pcnt = pcnt * 100 / etime; if (pcnt > 100.0) { pcnt = 100.0; } } else { pcnt = 0.0; } } temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("PID"); temp2.type = PROG_INTEGER; temp2.data.number = ptr->eventnum; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("CALLED_PROG"); temp2.type = PROG_OBJECT; temp2.data.objref = ptr->called_prog; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("TRIG"); temp2.type = PROG_OBJECT; temp2.data.objref = ptr->trig; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("PLAYER"); temp2.type = PROG_OBJECT; temp2.data.objref = ptr->uid; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("CALLED_DATA"); temp2.type = PROG_STRING; temp2.data.string = alloc_prog_string(ptr->called_data); array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("INSTCNT"); temp2.type = PROG_INTEGER; temp2.data.number = ptr->fr ? ptr->fr->instcnt : 0; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("DESCR"); temp2.type = PROG_INTEGER; temp2.data.number = ptr->descr; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("CPU"); temp2.type = PROG_FLOAT; temp2.data.fnumber = pcnt; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("NEXTRUN"); temp2.type = PROG_INTEGER; temp2.data.number = (int) ptr->when; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("STARTED"); temp2.type = PROG_INTEGER; temp2.data.number = (int) (ptr->fr ? ptr->fr->started : 0); array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("TYPE"); temp2.type = PROG_STRING; temp2.data.string = (ptr->typ == TQ_MUF_TYP) ? alloc_prog_string("MUF") : (ptr->typ == TQ_MPI_TYP) ? alloc_prog_string("MPI") : alloc_prog_string("UNK") ; array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); temp1.type = PROG_STRING; temp1.data.string = alloc_prog_string("SUBTYPE"); temp2.type = PROG_STRING; if (ptr->typ == TQ_MUF_TYP) { temp2.data.string = (ptr->subtyp == TQ_MUF_READ) ? alloc_prog_string("READ") : (ptr->subtyp == TQ_MUF_TREAD) ? alloc_prog_string("TREAD") : (ptr->subtyp == TQ_MUF_QUEUE) ? alloc_prog_string("QUEUE") : (ptr->subtyp == TQ_MUF_LISTEN) ? alloc_prog_string("LISTEN") : (ptr->subtyp == TQ_MUF_TIMER) ? alloc_prog_string("TIMER") : (ptr->subtyp == TQ_MUF_DELAY) ? alloc_prog_string("DELAY") : alloc_prog_string(""); } else if (ptr->typ == TQ_MPI_TYP) { int subtyp = (ptr->subtyp & TQ_MPI_SUBMASK); temp2.data.string = (subtyp == TQ_MPI_QUEUE) ? alloc_prog_string("QUEUE") : (subtyp == TQ_MPI_DELAY) ? alloc_prog_string("DELAY") : alloc_prog_string(""); } else { temp2.data.string = alloc_prog_string(""); } array_setitem(&nw, &temp1, &temp2); CLEAR(&temp1); CLEAR(&temp2); } else { nw = get_mufevent_pidinfo(nw, pid); } return nw; }
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); }
void prim_parsepropex(PRIM_PROTOTYPE) { struct inst* oper1 = NULL; /* prevents reentrancy issues! */ struct inst* oper2 = NULL; /* prevents reentrancy issues! */ struct inst* oper3 = NULL; /* prevents reentrancy issues! */ struct inst* oper4 = NULL; /* prevents reentrancy issues! */ stk_array* vars; const char* mpi; char* str = 0; array_iter idx; extern int varc; /* from msgparse.c */ int mvarcnt = 0; char* buffers = NULL; int novars; int hashow = 0; int i; int len; char tname[BUFFER_LEN]; char buf[BUFFER_LEN]; CHECKOP(4); oper4 = POP(); /* int:Private */ oper3 = POP(); /* dict:Vars */ oper2 = POP(); /* str:Prop */ oper1 = POP(); /* ref:Object */ if (mlev < 3) abort_interp("Mucker level 3 or greater required."); if (oper1->type != PROG_OBJECT) abort_interp("Non-object argument. (1)"); if (oper2->type != PROG_STRING) abort_interp("Non-string argument. (2)"); if (oper3->type != PROG_ARRAY) abort_interp("Non-array argument. (3)"); if (oper3->data.array && (oper3->data.array->type != ARRAY_DICTIONARY)) abort_interp("Dictionary array expected. (3)"); if (oper4->type != PROG_INTEGER) abort_interp("Non-integer argument. (4)"); if (!valid_object(oper1)) abort_interp("Invalid object. (1)"); if (!oper2->data.string) abort_interp("Empty string argument. (2)"); if ((oper4->data.number != 0) && (oper4->data.number != 1)) abort_interp("Integer of 0 or 1 expected. (4)"); CHECKREMOTE(oper1->data.objref); if (!prop_read_perms(ProgUID, oper1->data.objref, oper2->data.string->data, mlev)) abort_interp("Permission denied."); len = oper2->data.string->length; strcpyn(tname, sizeof(tname), oper2->data.string->data); while (len-- > 0 && tname[len] == PROPDIR_DELIMITER) { tname[len] = '\0'; } mpi = get_property_class(oper1->data.objref, tname); vars = oper3->data.array; novars = array_count(vars); if (check_mvar_overflow(novars)) abort_interp("Out of MPI variables. (3)"); if (array_first(vars, &idx)) { do { array_data* val = array_getitem(vars, &idx); if (idx.type != PROG_STRING) { CLEAR(&idx); abort_interp("Only string keys supported. (3)"); } if (idx.data.string == NULL) { CLEAR(&idx); abort_interp("Empty string keys not supported. (3)"); } if (strlen(idx.data.string->data) > MAX_MFUN_NAME_LEN) { CLEAR(&idx); abort_interp("Key too long to be an MPI variable. (3)"); } switch(val->type) { case PROG_INTEGER: case PROG_FLOAT: case PROG_OBJECT: case PROG_STRING: case PROG_LOCK: break; default: CLEAR(&idx); abort_interp("Only integer, float, dbref, string and lock values supported. (3)"); break; } if (string_compare(idx.data.string->data, "how") == 0) hashow = 1; } while(array_next(vars, &idx)); } if (mpi && *mpi) { if (novars > 0) { mvarcnt = varc; if ((buffers = (char*)malloc(novars * BUFFER_LEN)) == NULL) abort_interp("Out of memory."); if (array_first(vars, &idx)) { i = 0; do { char* var_buf = buffers + (i++ * BUFFER_LEN); array_data* val; val = array_getitem(vars, &idx); switch(val->type) { case PROG_INTEGER: snprintf(var_buf, BUFFER_LEN, "%i", val->data.number); break; case PROG_FLOAT: snprintf(var_buf, BUFFER_LEN, "%g", val->data.fnumber); break; case PROG_OBJECT: snprintf(var_buf, BUFFER_LEN, "#%i", val->data.objref); break; case PROG_STRING: strncpy(var_buf, DoNullInd(val->data.string), BUFFER_LEN); break; case PROG_LOCK: strncpy(var_buf, unparse_boolexp(ProgUID, val->data.lock, 1), BUFFER_LEN); break; default: var_buf[0] = '\0'; break; } var_buf[BUFFER_LEN - 1] = '\0'; new_mvar(idx.data.string->data, var_buf); } while(array_next(vars, &idx)); } } result = 0; if (oper4->data.number) result |= MPI_ISPRIVATE; if (Prop_Blessed(oper1->data.objref, oper2->data.string->data)) result |= MPI_ISBLESSED; if (hashow) result |= MPI_NOHOW; str = do_parse_mesg(fr->descr, player, oper1->data.objref, mpi, "(parsepropex)", buf, sizeof(buf), result); if (novars > 0) { if (array_first(vars, &idx)) { i = 0; do { char* var_buf = buffers + (i++ * BUFFER_LEN); struct inst temp; temp.type = PROG_STRING; temp.data.string = alloc_prog_string(var_buf); array_setitem(&vars, &idx, &temp); CLEAR(&temp); } while(array_next(vars, &idx)); } free(buffers); varc = mvarcnt; } } oper3->data.array = NULL; CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); CLEAR(oper4); PushArrayRaw(vars); PushString(str); }