muf_re * muf_re_get(struct shared_string *pattern, int flags, int *err) { int idx = (hash(DoNullInd(pattern), MUF_RE_CACHE_ITEMS) + flags) % MUF_RE_CACHE_ITEMS; muf_re *re = &muf_re_cache[idx]; if (re->pattern) { if ((flags != re->flags) || strcmp(DoNullInd(pattern), DoNullInd(re->pattern))) { regfree(&re->re); if (re->pattern && (--re->pattern->links == 0)) free((void *) re->pattern); } else return re; } if ((*err = regcomp(&re->re, DoNullInd(pattern), flags | REG_EXTENDED)) != 0) { re->pattern = NULL; return NULL; } re->pattern = pattern; re->pattern->links++; re->flags = flags; return re; }
muf_re* muf_re_get(struct shared_string* pattern, int flags, const char** errmsg) { int idx = (hash(DoNullInd(pattern), MUF_RE_CACHE_ITEMS) + flags) % MUF_RE_CACHE_ITEMS; muf_re* re = &muf_re_cache[idx]; int erroff; if (re->pattern) { if ((flags != re->flags) || strcmp(DoNullInd(pattern), DoNullInd(re->pattern))) { pcre_free(re->re); if (re->pattern && (--re->pattern->links == 0)) free((void *)re->pattern); } else return re; } re->re = pcre_compile(DoNullInd(pattern), flags, errmsg, &erroff, NULL); if (re->re == NULL) { re->pattern = NULL; return NULL; } re->pattern = pattern; re->pattern->links++; re->flags = flags; return re; }
void prim_regmatch(PRIM_PROTOTYPE) { muf_re* re; char* text; int flags; int matchcnt = 0; const char* errstr = NULL; int result = 0; 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)"); /* This primitive is for matching, not capturing. Using user-supplied * parenthesis for anything other than grouping purposes is therefore a * waste of resources, but most casual regex users won't know about the * non-capturing parenthesis alternatives available when PCRE_EXTENDED is * set. Since this is the case, we'll enable PCRE_NO_AUTO_CAPTURE as a * default option to optimize the majority of lazy user input. * -brevantes */ 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) text = (char *)DoNullInd(oper1->data.string); if ((matchcnt = regmatch_exec(re, text)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) { abort_interp(muf_re_error(matchcnt)); } } else /* Returning matchcnt isn't useful in match-only mode. */ result = 1; CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushInt(result); }
void prim_abort(PRIM_PROTOTYPE) { CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_STRING) abort_interp("Invalid argument"); strcpy(buf, DoNullInd(oper1->data.string)); abort_interp(buf); }
void prim_force(PRIM_PROTOTYPE) { struct inst *oper1 = NULL; /* prevents re-entrancy issues! */ struct inst *oper2 = NULL; /* prevents re-entrancy issues! */ int i; /* d s -- */ CHECKOP(2); oper1 = POP(); /* string to @force */ oper2 = POP(); /* player dbref */ if (mlev < 4) abort_interp("Wizbit only primitive."); if (fr->level > 8) abort_interp("Interp call loops not allowed."); if (oper1->type != PROG_STRING) abort_interp("Non-string argument (2)."); if (oper2->type != PROG_OBJECT) abort_interp("Non-object argument (1)."); ref = oper2->data.objref; if (ref < 0 || ref >= db_top) abort_interp("Invalid object to force. (1)"); if (Typeof(ref) != TYPE_PLAYER && Typeof(ref) != TYPE_THING) abort_interp("Object to force not a thing or player. (1)"); if (0 == strcmp(DoNullInd(oper1->data.string), "")) abort_interp("Empty command argument (2)."); if (index(oper1->data.string->data, '\r')) abort_interp("Carriage returns not allowed in command string. (2)."); #ifdef GOD_PRIV if (God(oper2->data.objref) && !God(OWNER(program))) abort_interp("Cannot force god (1)."); #endif force_prog = program; force_level++; process_command(dbref_first_descr(oper2->data.objref), oper2->data.objref, oper1->data.string->data); force_level--; force_prog = NOTHING; for (i = 1; i <= fr->caller.top; i++) { if (Typeof(fr->caller.st[i]) != TYPE_PROGRAM) { #ifdef DEBUG char str[BUFFER_LEN]; snprintf(str,BUFFER_LEN,"[debug] prim_force: fr->caller.st[%d] isn't a program.",i); notify_nolisten(player,str,1); #endif /* DEBUG */ do_abort_silent(); } } CLEAR(oper1); CLEAR(oper2); }
void prim_timer_start(PRIM_PROTOTYPE) { CHECKOP(2); oper2 = POP(); /* string: timer id */ oper1 = POP(); /* int: delay length in seconds */ if (fr->timercount > tp_process_timer_limit) abort_interp("Too many timers!"); if (oper1->type != PROG_INTEGER) abort_interp("Expected an integer delay time. (1)"); if (oper2->type != PROG_STRING) abort_interp("Expected a string timer id. (2)"); dequeue_timers(fr->pid, DoNullInd(oper2->data.string)); add_muf_timer_event(fr->descr, player, program, fr, oper1->data.number, DoNullInd(oper2->data.string)); CLEAR(oper1); CLEAR(oper2); }
muf_re* muf_re_get(struct shared_string* pattern, int flags, const char** errmsg) { int idx = (hash(DoNullInd(pattern), MUF_RE_CACHE_ITEMS) + flags) % MUF_RE_CACHE_ITEMS; muf_re* re = &muf_re_cache[idx]; int erroff; const char* errstr; if (re->pattern) { if ((flags != re->flags) || strcmp(DoNullInd(pattern), DoNullInd(re->pattern))) { pcre_free(re->re); free(re->extra); if (re->pattern && (--re->pattern->links == 0)) free((void *)re->pattern); } else { if (++(re->hits) == 3 && !re->extra) { re->extra = pcre_study(re->re, 0, &errstr); // can't abort_interp here... } return re; } } re->re = pcre_compile(DoNullInd(pattern), flags, errmsg, &erroff, NULL); if (re->re == NULL) { re->pattern = NULL; return NULL; } re->pattern = pattern; re->pattern->links++; re->flags = flags; re->hits = 1; re->extra = NULL; return re; }
void prim_event_send(PRIM_PROTOTYPE) { struct frame *destfr; stk_array *arr; struct inst temp1; CHECKOP(3); oper3 = POP(); /* any: data to pass */ oper2 = POP(); /* string: event id */ oper1 = POP(); /* int: process id to send to */ if (mlev < 3) abort_interp("Requires Mucker level 3 or better."); if (oper1->type != PROG_INTEGER) abort_interp("Expected an integer process id. (1)"); if (oper2->type != PROG_STRING) abort_interp("Expected a string event id. (2)"); if (oper1->data.number == fr->pid) destfr = fr; else destfr = timequeue_pid_frame(oper1->data.number); if (destfr) { stk_array_active_list = &destfr->array_active_list; struct inst data_copy; deep_copyinst(oper3, &data_copy, destfr->pinning); arr = new_array_dictionary(destfr->pinning); array_set_strkey(&arr, "data", &data_copy); array_set_strkey_intval(&arr, "caller_pid", fr->pid); array_set_strkey_intval(&arr, "descr", fr->descr); array_set_strkey_refval(&arr, "caller_prog", program); array_set_strkey_refval(&arr, "trigger", fr->trig); array_set_strkey_refval(&arr, "prog_uid", ProgUID); array_set_strkey_refval(&arr, "player", player); temp1.type = PROG_ARRAY; temp1.data.array = arr; snprintf(buf, sizeof(buf), "USER.%.32s", DoNullInd(oper2->data.string)); muf_event_add(destfr, buf, &temp1, 0); stk_array_active_list = &fr->array_active_list; CLEAR(&temp1); CLEAR(&data_copy); } CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); }
void prim_interp(PRIM_PROTOTYPE) { struct inst *oper1 = NULL; /* prevents re-entrancy issues! */ struct inst *oper2 = NULL; /* prevents re-entrancy issues! */ struct inst *oper3 = NULL; /* prevents re-entrancy issues! */ struct inst *rv = NULL; char buf[BUFFER_LEN]; struct frame *tmpfr; CHECKOP(3); oper3 = POP(); /* string -- top stack argument */ oper2 = POP(); /* dbref -- trigger */ oper1 = POP(); /* dbref -- Program to run */ if (!valid_object(oper1) || Typeof(oper1->data.objref) != TYPE_PROGRAM) abort_interp("Bad program reference. (1)"); if (!valid_object(oper2)) abort_interp("Bad object. (2)"); if (oper3->type != PROG_STRING) abort_interp("Expected a string. (3)"); if ((mlev < 3) && !permissions(ProgUID, oper2->data.objref)) abort_interp("Permission denied."); if (fr->level > 8) abort_interp("Interp call loops not allowed."); CHECKREMOTE(oper2->data.objref); strcpyn(buf, sizeof(buf), match_args); strcpyn(match_args, sizeof(match_args), DoNullInd(oper3->data.string)); tmpfr = interp(fr->descr, player, LOCATION(player), oper1->data.objref, oper2->data.objref, PREEMPT, STD_HARDUID, 0); if (tmpfr) { rv = interp_loop(player, oper1->data.objref, tmpfr, 1); } strcpyn(match_args, sizeof(match_args), buf); CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); if (rv) { if (rv->type < PROG_STRING) { push(arg, top, rv->type, MIPSCAST(&rv->data.number)); } else { push(arg, top, rv->type, MIPSCAST(rv->data.string)); } } else { PushNullStr; } }
void prim_nextprop(PRIM_PROTOTYPE) { /* dbref pname -- pname */ char *pname; char exbuf[BUFFER_LEN]; CHECKOP(2); oper2 = POP(); /* pname */ oper1 = POP(); /* dbref */ if (mlev < 3) abort_interp("Permission denied."); if (oper2->type != PROG_STRING) abort_interp("String required. (2)"); if (oper1->type != PROG_OBJECT) abort_interp("Dbref required. (1)"); if (!valid_object(oper1)) abort_interp("Invalid dbref. (1)"); ref = oper1->data.objref; (void) strcpyn(buf, sizeof(buf), DoNullInd(oper2->data.string)); CLEAR(oper1); CLEAR(oper2); { char *tmpname; pname = next_prop_name(ref, exbuf, sizeof(exbuf), buf); #ifdef LOG_PROPS log2file("props.log", "#%d (%d) NEXTPROP: o=%d n=\"%s\" on=\"%s\"", program, pc->line, ref, pname, buf); #endif while (pname && !prop_read_perms(ProgUID, ref, pname, mlev)) { tmpname = next_prop_name(ref, exbuf, sizeof(exbuf), pname); #ifdef LOG_PROPS log2file("props.log", "#%d (%d) NEXTPROP: o=%d n=\"%s\" on=\"%s\"", program, pc->line, ref, tmpname, pname); #endif pname = tmpname; } } if (pname) { PushString(pname); } else { PushNullStr; } }
void prim_timer_stop(PRIM_PROTOTYPE) { CHECKOP(1); oper1 = POP(); /* string: timer id */ if (oper1->type != PROG_STRING) abort_interp("Expected a string timer id. (2)"); dequeue_timers(fr->pid, DoNullInd(oper1->data.string)); CLEAR(oper1); }
void prim_sysparm_array(PRIM_PROTOTYPE) { stk_array *nu; int security = TUNE_MLEV(player); CHECKOP(1); oper1 = POP(); /* string: match pattern */ if (oper1->type != PROG_STRING) abort_interp("Expected a string smatch pattern."); nu = tune_parms_array(DoNullInd(oper1->data.string), security, fr->pinning); CLEAR(oper1); PushArrayRaw(nu); }
void prim_sysparm_array(PRIM_PROTOTYPE) { stk_array *nu; /* string */ CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_STRING) abort_interp("Expected a string smatch pattern. (1)"); nu = tune_parms_array(DoNullInd(oper1->data.string), mlev); CLEAR(oper1); PushArrayRaw(nu); }
void prim_remove_prop(PRIM_PROTOTYPE) { CHECKOP(2); oper1 = POP(); oper2 = POP(); if (oper1->type != PROG_STRING) abort_interp("Non-string argument (2)"); if (!valid_object(oper2)) abort_interp("Non-object argument (1)"); CHECKREMOTE(oper2->data.objref); strncpy(buf, DoNullInd(oper1->data.string), BUFFER_LEN); buf[BUFFER_LEN - 1] = '\0'; { int len = strlen(buf); char* ptr = buf + len; while((--len >= 0) && (*--ptr == PROPDIR_DELIMITER)) *ptr = '\0'; } if (!*buf) abort_interp("Can't remove root propdir (2)"); if (!prop_write_perms(ProgUID, oper2->data.objref, buf, mlev)) abort_interp("Permission denied."); remove_property(oper2->data.objref, buf); #ifdef LOG_PROPS log2file("props.log", "#%d (%d) REMOVEPROP: o=%d n=\"%s\"", program, pc->line, oper2->data.objref, buf); #endif ts_modifyobject(oper2->data.objref); CLEAR(oper1); CLEAR(oper2); }
void prim_queue(PRIM_PROTOTYPE) { dbref temproom; /* int dbref string -- */ CHECKOP(3); oper1 = POP(); oper2 = POP(); oper3 = POP(); if (mlev < LM3) abort_interp("M3 prim"); if (oper3->type != PROG_INTEGER) abort_interp("Non-integer argument (1)"); if (oper2->type != PROG_OBJECT) abort_interp("Argument must be a dbref (2)"); if (!valid_object(oper2)) abort_interp("Invalid dbref (2)"); if (Typeof(oper2->data.objref) != TYPE_PROGRAM) abort_interp("Object must be a program (2)"); if (oper1->type != PROG_STRING) abort_interp("Non-string argument (3)"); if ((oper4 = fr->variables + 1)->type != PROG_OBJECT) temproom = DBFETCH(player)->location; else temproom = oper4->data.objref; result = add_muf_delayq_event(oper3->data.number, fr->descr, player, temproom, NOTHING, oper2->data.objref, DoNullInd(oper1->data.string), "Queued Event.", 0); CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); PushInt(result); }
void prim_event_send(PRIM_PROTOTYPE) { struct frame *destfr; stk_array *arr; struct inst temp1; CHECKOP(3); oper3 = POP(); /* any: data to pass */ oper2 = POP(); /* string: event id */ oper1 = POP(); /* int: process id to send to */ if (mlev < 3) abort_interp("Requires Mucker level 3 or better."); if (oper1->type != PROG_INTEGER) abort_interp("Expected an integer process id. (1)"); if (oper2->type != PROG_STRING) abort_interp("Expected a string event id. (2)"); destfr = (struct frame*) timequeue_pid_frame(oper1->data.number); if (destfr) { arr = new_array_dictionary(); array_set_strkey(&arr, "data", oper3); array_set_strkey_intval(&arr, "caller_pid", fr->pid); array_set_strkey_refval(&arr, "caller_prog", program); temp1.type = PROG_ARRAY; temp1.data.array = arr; sprintf(buf, "USER.%.32s", DoNullInd(oper2->data.string)); muf_event_add(destfr, buf, oper3); } CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); }
void show_re_cache(dbref player) { muf_re* re; size_t tmp; int idx = 0; int patterns = 0; int studies = 0; size_t size_re = 0; size_t size_extra = 0; if (!Boy(OWNER(player))) { anotify_fmt(player, CFAIL "%s", tp_noperm_mesg); return; } anotify(player, SYSYELLOW "idx hits flags studied? pattern"); while (idx <= MUF_RE_CACHE_ITEMS) { re = &muf_re_cache[idx]; if (re->re) { patterns++; notify_fmt(player, "%3i %4i %5i %i \"%s\"", idx, re->hits, re->flags, (re->extra != NULL), DoNullInd(re->pattern)); pcre_fullinfo(re->re, NULL, PCRE_INFO_SIZE, &tmp); size_re = size_re + tmp; if (re->extra) { studies++; pcre_fullinfo(re->re, re->extra, PCRE_INFO_STUDYSIZE, &tmp); size_extra = size_extra + tmp; } } idx++; } anotify_fmt(player, SYSPURPLE "\n%i compiled patterns are using %zd bytes of RAM.", patterns, size_re); anotify_fmt(player, SYSGREEN "%i study instances are using are using %zd bytes of RAM.", studies, size_extra); }
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_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); }
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_regsub(PRIM_PROTOTYPE) { 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_STRING) abort_interp("Non-string argument (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); if (!re->extra && (oper4->data.number & MUF_RE_ALL)) { /* User requested a recursive pattern search. This generally means * pcre_exec will be called at least twice unless the pattern doesn't * exist in the string at all. Presence of this option suggests that * the user anticipates the pattern occurring at least once, so it's * safest to go ahead and study the pattern. -brevantes */ re->extra = pcre_study(re->re, 0, &errstr); if (errstr) abort_interp(errstr); } textstart = text = (char *)DoNullInd(oper1->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'; CLEAR(oper4); CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushString(buf); }
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); }
void prim_regfindnext(PRIM_PROTOTYPE) { struct flgchkdat check; dbref who, item, ref, i; const char *name; muf_re* re; char* text; int flags; int matchcnt = 0; const char* errstr = NULL; CHECKOP(5); oper5 = POP(); /* int:pcreflags */ oper4 = POP(); /* str:objflags */ oper3 = POP(); /* str:namepattern */ oper2 = POP(); /* ref:owner */ oper1 = POP(); /* ref:currobj */ if (oper5->type != PROG_INTEGER) abort_interp("Non-integer argument (5)"); if (oper4->type != PROG_STRING) abort_interp("Expected string argument. (4)"); if (oper3->type != PROG_STRING) abort_interp("Expected string argument. (3)"); if (oper2->type != PROG_OBJECT) abort_interp("Expected dbref argument. (2)"); if (oper2->data.objref < NOTHING || oper2->data.objref >= db_top) abort_interp("Bad object. (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)"); if (oper2->data.objref != NOTHING && Typeof(oper2->data.objref) == TYPE_GARBAGE) abort_interp("Owner dbref is garbage. (2)"); item = oper1->data.objref; who = oper2->data.objref; name = DoNullInd(oper3->data.string); if (mlev < 2) abort_interp("Permission denied. Requires at least Mucker Level 2."); if (mlev < 3) { if (who == NOTHING) { abort_interp ("Permission denied. Owner inspecific searches require Mucker Level 3."); } else if (who != ProgUID) { abort_interp ("Permission denied. Searching for other people's stuff requires Mucker Level 3."); } } flags = PCRE_NO_AUTO_CAPTURE; if (oper5->data.number & MUF_RE_ICASE) flags |= PCRE_CASELESS; if (oper5->data.number & MUF_RE_EXTENDED) flags |= PCRE_EXTENDED; re = regmatch_re_get(oper3->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); } if (item == NOTHING) { item = 0; } else { item++; } ref = NOTHING; init_checkflags(PSafe, DoNullInd(oper4->data.string), &check); for (i = item; i < db_top; i++) { if ((who == NOTHING || OWNER(i) == who) && checkflags(i, check) && NAME(i)) { if (!*name) { ref = i; break; } else { text = (char *) NAME(i); if ((matchcnt = regmatch_exec(re, text)) < 0) { if (matchcnt != PCRE_ERROR_NOMATCH) abort_interp(muf_re_error(matchcnt)); } else { ref = i; break; } } } } CLEAR(oper1); CLEAR(oper2); CLEAR(oper3); CLEAR(oper4); CLEAR(oper5); PushObject(ref); }
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_regsub(PRIM_PROTOTYPE) { regmatch_t *matches = 0; int flags = 0; char *write_ptr = buf; int write_left = BUFFER_LEN - 1; muf_re *re; char *text; int nosubs, err, len, i; CHECKOP(4); oper4 = POP(); /* int:Flags */ oper3 = POP(); /* str:Replace */ 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_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 |= REG_ICASE; if ((re = muf_re_get(oper2->data.string, flags, &err)) == NULL) abort_interp(muf_re_error(err)); text = DoNullInd(oper1->data.string); nosubs = re->re.re_nsub + 1; if ((matches = (regmatch_t *) malloc(sizeof(regmatch_t) * nosubs)) == NULL) abort_interp("Out of memory"); while ((*text != '\0') && (write_left > 0)) { len = strlen(text); if ((err = regexec(&re->re, text, nosubs, matches, 0)) != 0) { if (err != REG_NOMATCH) { free(matches); abort_interp(muf_re_error(err)); } while ((write_left > 0) && (*text != '\0')) { *write_ptr++ = *text++; write_left--; } break; } else { regmatch_t *cm = &matches[0]; char *read_ptr = DoNullInd(oper3->data.string); int soff = cm->rm_so; int count; for (count = cm->rm_so; (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 >= nosubs)) { free(matches); abort_interp("Invalid \\subexp (3)"); } cm = &matches[idx]; if ((cm->rm_so >= 0) && (cm->rm_eo >= 0) && (cm->rm_so < len)) { char *ptr = &text[cm->rm_so - soff]; count = cm->rm_eo - cm->rm_so; if (count > write_left) { free(matches); 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--; } } cm = &matches[0]; for (count = cm->rm_eo - cm->rm_so; (*text != '\0') && (count > 0); count--) text++; } if ((oper4->data.number & MUF_RE_ALL) == 0) { while ((write_left > 0) && (*text != '\0')) { *write_ptr++ = *text++; write_left--; } break; } } free(matches); if (*text != '\0') abort_interp("Operation would result in overflow"); *write_ptr = '\0'; CLEAR(oper4); CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushString(buf); }
void prim_regsub(PRIM_PROTOTYPE) { 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_STRING) abort_interp("Non-string argument (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); textstart = text = DoNullInd(oper1->data.string); len = strlen(textstart); while((*text != '\0') && (write_left > 0)) { if ((matchcnt = pcre_exec(re->re, NULL, 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 = 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'; CLEAR(oper4); CLEAR(oper3); CLEAR(oper2); CLEAR(oper1); PushString(buf); }
void prim_setsysparm(PRIM_PROTOTYPE) { const char *parmname, *newvalue; char *oldvalue; int security = TUNE_MLEV(player); CHECKOP(2); oper1 = POP(); /* string: new parameter value */ oper2 = POP(); /* string: parameter to tune */ if (mlev < 4) abort_interp("Wizbit only primitive."); if (force_level) abort_interp("Cannot be forced."); if (oper2->type != PROG_STRING) abort_interp("Invalid argument. (1)"); if (!oper2->data.string) abort_interp("Null string argument. (1)"); if (oper1->type != PROG_STRING) abort_interp("Invalid argument. (2)"); parmname = oper2->data.string->data; /* Duplicate the string, otherwise the oldvalue pointer will be overridden to the new value when tune_setparm() is called. */ oldvalue = strdup(tune_get_parmstring(oper2->data.string->data, security)); newvalue = DoNullInd(oper1->data.string); result = tune_setparm(player, parmname, newvalue, security); /* Note: free(oldvalue) BEFORE calling abort_interp, or it will leak. */ switch (result) { case TUNESET_SUCCESS: log_status("TUNED (MUF): %s(%d) tuned %s from '%s' to '%s'", NAME(player), player, parmname, oldvalue, newvalue); if (oldvalue) free(oldvalue); break; case TUNESET_SUCCESS_DEFAULT: /* No need to show the flag in output */ TP_CLEAR_FLAG_DEFAULT(parmname); log_status("TUNED (MUF): %s(%d) tuned %s from '%s' to default", NAME(player), player, parmname, oldvalue); if (oldvalue) free(oldvalue); break; case TUNESET_UNKNOWN: if (oldvalue) free(oldvalue); abort_interp("Unknown parameter. (1)"); case TUNESET_SYNTAX: if (oldvalue) free(oldvalue); abort_interp("Bad parameter syntax. (2)"); case TUNESET_BADVAL: if (oldvalue) free(oldvalue); abort_interp("Bad parameter value. (2)"); case TUNESET_DENIED: if (oldvalue) free(oldvalue); abort_interp("Permission denied. (1)"); default: if (oldvalue) free(oldvalue); break; } CLEAR(oper1); CLEAR(oper2); }
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); }
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); }
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); }