struct inst * interp_loop(dbref player, dbref program, struct frame *fr, int rettyp) { register struct inst *pc; register int atop; register struct inst *arg; register struct inst *temp1; register struct inst *temp2; register struct stack_addr *sys; register int instr_count; register int stop; int i = 0, tmp, writeonly, mlev; static struct inst retval; char dbuf[BUFFER_LEN]; int instno_debug_line = get_primitive("debug_line"); fr->level = ++interp_depth; /* increment interp level */ /* load everything into local stuff */ pc = fr->pc; atop = fr->argument.top; stop = fr->system.top; arg = fr->argument.st; sys = fr->system.st; writeonly = fr->writeonly; already_created = 0; fr->brkpt.isread = 0; if (!pc) { struct line *tmpline; tmpline = PROGRAM_FIRST(program); PROGRAM_SET_FIRST(program, (struct line *) read_program(program)); do_compile(-1, OWNER(program), program, 0); free_prog_text(PROGRAM_FIRST(program)); PROGRAM_SET_FIRST(program, tmpline); pc = fr->pc = PROGRAM_START(program); if (!pc) { abort_loop_hard("Program not compilable. Cannot run.", NULL, NULL); } PROGRAM_INC_PROF_USES(program); PROGRAM_INC_INSTANCES(program); } ts_useobject(program); err = 0; instr_count = 0; mlev = ProgMLevel(program); gettimeofday(&fr->proftime, NULL); /* This is the 'natural' way to exit a function */ while (stop) { /* Abort program if player/thing running it is recycled */ if ((player < 0) || (player >= db_top) || ((Typeof(player) != TYPE_PLAYER) && (Typeof(player) != TYPE_THING))) { reload(fr, atop, stop); prog_clean(fr); interp_depth--; calc_profile_timing(program,fr); return NULL; } fr->instcnt++; instr_count++; if ((fr->multitask == PREEMPT) || (FLAGS(program) & BUILDER)) { if (mlev == 4) { if (tp_max_ml4_preempt_count) { if (instr_count >= tp_max_ml4_preempt_count) abort_loop_hard("Maximum preempt instruction count exceeded", NULL, NULL); } else instr_count = 0; } else { /* else make sure that the program doesn't run too long */ if (instr_count >= tp_max_instr_count) abort_loop_hard("Maximum preempt instruction count exceeded", NULL, NULL); } } else { /* if in FOREGROUND or BACKGROUND mode, '0 sleep' every so often. */ if ((fr->instcnt > tp_instr_slice * 4) && (instr_count >= tp_instr_slice)) { fr->pc = pc; reload(fr, atop, stop); PLAYER_SET_BLOCK(player, (!fr->been_background)); add_muf_delay_event(0, fr->descr, player, NOTHING, NOTHING, program, fr, (fr->multitask == FOREGROUND) ? "FOREGROUND" : "BACKGROUND"); interp_depth--; calc_profile_timing(program,fr); return NULL; } } if (((FLAGS(program) & ZOMBIE) || fr->brkpt.force_debugging) && !fr->been_background && controls(player, program) ) { fr->brkpt.debugging = 1; } else { fr->brkpt.debugging = 0; } if (FLAGS(program) & DARK || (fr->brkpt.debugging && fr->brkpt.showstack && !fr->brkpt.bypass)) { if ((pc->type != PROG_PRIMITIVE) || (pc->data.number != instno_debug_line)) { char *m = debug_inst(fr, 0, pc, fr->pid, arg, dbuf, sizeof(dbuf), atop, program); notify_nolisten(player, m, 1); } } if (fr->brkpt.debugging) { short breakflag = 0; if (stop == 1 && !fr->brkpt.bypass && pc->type == PROG_PRIMITIVE && pc->data.number == IN_RET ) { /* Program is about to EXIT */ notify_nolisten(player, "Program is about to EXIT.", 1); breakflag = 1; } else if (fr->brkpt.count) { for (i = 0; i < fr->brkpt.count; i++) { if ((!fr->brkpt.pc[i] || pc == fr->brkpt.pc[i]) && /* pc matches */ (fr->brkpt.line[i] == -1 || (fr->brkpt.lastline != pc->line && fr->brkpt.line[i] == pc->line)) && /* line matches */ (fr->brkpt.level[i] == -1 || stop <= fr->brkpt.level[i]) && /* level matches */ (fr->brkpt.prog[i] == NOTHING || fr->brkpt.prog[i] == program) && /* program matches */ (fr->brkpt.linecount[i] == -2 || (fr->brkpt.lastline != pc->line && fr->brkpt.linecount[i]-- <= 0)) && /* line count matches */ (fr->brkpt.pccount[i] == -2 || (fr->brkpt.lastpc != pc && fr->brkpt.pccount[i]-- <= 0)) /* pc count matches */ ) { if (fr->brkpt.bypass) { if (fr->brkpt.pccount[i] == -1) fr->brkpt.pccount[i] = 0; if (fr->brkpt.linecount[i] == -1) fr->brkpt.linecount[i] = 0; } else { breakflag = 1; break; } } } } if (breakflag) { char *m; char buf[BUFFER_LEN]; if (fr->brkpt.dosyspop) { program = sys[--stop].progref; pc = sys[stop].offset; } add_muf_read_event(fr->descr, player, program, fr); reload(fr, atop, stop); fr->pc = pc; fr->brkpt.isread = 0; fr->brkpt.breaknum = i; fr->brkpt.lastlisted = 0; fr->brkpt.bypass = 0; fr->brkpt.dosyspop = 0; PLAYER_SET_CURR_PROG(player, program); PLAYER_SET_BLOCK(player, 0); interp_depth--; if (!fr->brkpt.showstack) { m = debug_inst(fr, 0, pc, fr->pid, arg, dbuf, sizeof(dbuf), atop, program); notify_nolisten(player, m, 1); } if (pc <= PROGRAM_CODE(program) || (pc - 1)->line != pc->line) { list_proglines(player, program, fr, pc->line, 0); } else { m = show_line_prims(fr, program, pc, 15, 1); snprintf(buf, sizeof(buf), " %s", m); notify_nolisten(player, buf, 1); } calc_profile_timing(program,fr); return NULL; } fr->brkpt.lastline = pc->line; fr->brkpt.lastpc = pc; fr->brkpt.bypass = 0; } if (mlev < 3) { if (fr->instcnt > (tp_max_instr_count * ((mlev == 2) ? 4 : 1))) abort_loop_hard("Maximum total instruction count exceeded.", NULL, NULL); } switch (pc->type) { case PROG_INTEGER: case PROG_FLOAT: case PROG_ADD: case PROG_OBJECT: case PROG_VAR: case PROG_LVAR: case PROG_SVAR: case PROG_STRING: case PROG_LOCK: case PROG_MARK: case PROG_ARRAY: if (atop >= STACK_SIZE) abort_loop("Stack overflow.", NULL, NULL); copyinst(pc, arg + atop); pc++; atop++; break; case PROG_LVAR_AT: case PROG_LVAR_AT_CLEAR: { struct inst *tmp; struct localvars *lv; if (atop >= STACK_SIZE) abort_loop("Stack overflow.", NULL, NULL); if (pc->data.number >= MAX_VAR || pc->data.number < 0) abort_loop("Scoped variable number out of range.", NULL, NULL); lv = localvars_get(fr, program); tmp = &(lv->lvars[pc->data.number]); copyinst(tmp, arg + atop); if (pc->type == PROG_LVAR_AT_CLEAR) { CLEAR(tmp); tmp->type = PROG_INTEGER; tmp->data.number = 0; } pc++; atop++; } break; case PROG_LVAR_BANG: { struct inst *the_var; struct localvars *lv; if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); if (pc->data.number >= MAX_VAR || pc->data.number < 0) abort_loop("Scoped variable number out of range.", NULL, NULL); lv = localvars_get(fr, program); the_var = &(lv->lvars[pc->data.number]); CLEAR(the_var); temp1 = arg + --atop; *the_var = *temp1; pc++; } break; case PROG_SVAR_AT: case PROG_SVAR_AT_CLEAR: { struct inst *tmp; if (atop >= STACK_SIZE) abort_loop("Stack overflow.", NULL, NULL); tmp = scopedvar_get(fr, 0, pc->data.number); if (!tmp) abort_loop("Scoped variable number out of range.", NULL, NULL); copyinst(tmp, arg + atop); if (pc->type == PROG_SVAR_AT_CLEAR) { CLEAR(tmp); tmp->type = PROG_INTEGER; tmp->data.number = 0; } pc++; atop++; } break; case PROG_SVAR_BANG: { struct inst *the_var; if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); the_var = scopedvar_get(fr, 0, pc->data.number); if (!the_var) abort_loop("Scoped variable number out of range.", NULL, NULL); CLEAR(the_var); temp1 = arg + --atop; *the_var = *temp1; pc++; } break; case PROG_FUNCTION: { int i = pc->data.mufproc->args; if (atop < i) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < i) abort_loop("Stack protection fault.", NULL, NULL); if (fr->skip_declare) fr->skip_declare = 0; else scopedvar_addlevel(fr, pc, pc->data.mufproc->vars); while (i-->0) { struct inst *tmp; temp1 = arg + --atop; tmp = scopedvar_get(fr, 0, i); if (!tmp) abort_loop_hard("Internal error: Scoped variable number out of range in FUNCTION init.", temp1, NULL); CLEAR(tmp); copyinst(temp1, tmp); CLEAR(temp1); } pc++; } break; case PROG_IF: if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (false_inst(temp1)) pc = pc->data.call; else pc++; CLEAR(temp1); break; case PROG_EXEC: if (stop >= STACK_SIZE) abort_loop("System Stack Overflow", NULL, NULL); sys[stop].progref = program; sys[stop++].offset = pc + 1; pc = pc->data.call; fr->skip_declare = 0; /* Make sure we DON'T skip var decls */ break; case PROG_JMP: /* Don't need to worry about skipping scoped var decls here. */ /* JMP to a function header can only happen in IN_JMP */ pc = pc->data.call; break; case PROG_TRY: if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_INTEGER || temp1->data.number < 0) abort_loop("Argument is not a positive integer.", temp1, NULL); if (fr->trys.top && atop - fr->trys.st->depth < temp1->data.number) abort_loop("Stack protection fault.", NULL, NULL); if (temp1->data.number > atop) abort_loop("Stack Underflow.", temp1, NULL); fr->trys.top++; fr->trys.st = push_try(fr->trys.st); fr->trys.st->depth = atop - temp1->data.number; fr->trys.st->call_level = stop; fr->trys.st->for_count = 0; fr->trys.st->addr = pc->data.call; pc++; CLEAR(temp1); break; case PROG_PRIMITIVE: /* * All pc modifiers and stuff like that should stay here, * everything else call with an independent dispatcher. */ switch (pc->data.number) { case IN_JMP: if (atop < 1) abort_loop("Stack underflow. Missing address.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_ADD) abort_loop("Argument is not an address.", temp1, NULL); if (temp1->data.addr->progref >= db_top || temp1->data.addr->progref < 0 || (Typeof(temp1->data.addr->progref) != TYPE_PROGRAM)) abort_loop_hard("Internal error. Invalid address.", temp1, NULL); if (program != temp1->data.addr->progref) { abort_loop("Destination outside current program.", temp1, NULL); } if (temp1->data.addr->data->type == PROG_FUNCTION) { fr->skip_declare = 1; } pc = temp1->data.addr->data; CLEAR(temp1); break; case IN_EXECUTE: if (atop < 1) abort_loop("Stack Underflow. Missing address.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_ADD) abort_loop("Argument is not an address.", temp1, NULL); if (temp1->data.addr->progref >= db_top || temp1->data.addr->progref < 0 || (Typeof(temp1->data.addr->progref) != TYPE_PROGRAM)) abort_loop_hard("Internal error. Invalid address.", temp1, NULL); if (stop >= STACK_SIZE) abort_loop("System Stack Overflow", temp1, NULL); sys[stop].progref = program; sys[stop++].offset = pc + 1; if (program != temp1->data.addr->progref) { program = temp1->data.addr->progref; fr->caller.st[++fr->caller.top] = program; mlev = ProgMLevel(program); PROGRAM_INC_INSTANCES(program); } pc = temp1->data.addr->data; CLEAR(temp1); break; case IN_CALL: if (atop < 1) abort_loop("Stack Underflow. Missing dbref argument.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; temp2 = 0; if (temp1->type != PROG_OBJECT) { temp2 = temp1; if (atop < 1) abort_loop("Stack Underflow. Missing dbref of func.", temp1, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp2->type != PROG_STRING) abort_loop("Public Func. name string required. (2)", temp1, temp2); if (!temp2->data.string) abort_loop("Null string not allowed. (2)", temp1, temp2); } if (temp1->type != PROG_OBJECT) abort_loop("Dbref required. (1)", temp1, temp2); if (!valid_object(temp1) || Typeof(temp1->data.objref) != TYPE_PROGRAM) abort_loop("Invalid object.", temp1, temp2); if (!(PROGRAM_CODE(temp1->data.objref))) { struct line *tmpline; tmpline = PROGRAM_FIRST(temp1->data.objref); PROGRAM_SET_FIRST(temp1->data.objref, (struct line *) read_program(temp1->data.objref)); do_compile(-1, OWNER(temp1->data.objref), temp1->data.objref, 0); free_prog_text(PROGRAM_FIRST(temp1->data.objref)); PROGRAM_SET_FIRST(temp1->data.objref, tmpline); if (!(PROGRAM_CODE(temp1->data.objref))) abort_loop("Program not compilable.", temp1, temp2); } if (ProgMLevel(temp1->data.objref) == 0) abort_loop("Permission denied", temp1, temp2); if (mlev < 4 && OWNER(temp1->data.objref) != ProgUID && !Linkable(temp1->data.objref)) abort_loop("Permission denied", temp1, temp2); if (stop >= STACK_SIZE) abort_loop("System Stack Overflow", temp1, temp2); sys[stop].progref = program; sys[stop].offset = pc + 1; if (!temp2) { pc = PROGRAM_START(temp1->data.objref); } else { struct publics *pbs; int tmpint; pbs = PROGRAM_PUBS(temp1->data.objref); while (pbs) { tmpint = string_compare(temp2->data.string->data, pbs->subname); if (!tmpint) break; pbs = pbs->next; } if (!pbs) abort_loop("PUBLIC or WIZCALL function not found. (2)", temp2, temp2); if (mlev < pbs->mlev) abort_loop("Insufficient permissions to call WIZCALL function. (2)", temp2, temp2); pc = pbs->addr.ptr; } stop++; if (temp1->data.objref != program) { calc_profile_timing(program,fr); gettimeofday(&fr->proftime, NULL); program = temp1->data.objref; fr->caller.st[++fr->caller.top] = program; PROGRAM_INC_INSTANCES(program); mlev = ProgMLevel(program); } PROGRAM_INC_PROF_USES(program); ts_useobject(program); CLEAR(temp1); if (temp2) CLEAR(temp2); break; case IN_RET: if (stop > 1 && program != sys[stop - 1].progref) { if (sys[stop - 1].progref >= db_top || sys[stop - 1].progref < 0 || (Typeof(sys[stop - 1].progref) != TYPE_PROGRAM)) abort_loop_hard("Internal error. Invalid address.", NULL, NULL); calc_profile_timing(program,fr); gettimeofday(&fr->proftime, NULL); PROGRAM_DEC_INSTANCES(program); program = sys[stop - 1].progref; mlev = ProgMLevel(program); fr->caller.top--; } scopedvar_poplevel(fr); pc = sys[--stop].offset; break; case IN_CATCH: case IN_CATCH_DETAILED: { int depth; if (!(fr->trys.top)) abort_loop_hard("Internal error. TRY stack underflow.", NULL, NULL); depth = fr->trys.st->depth; while (atop > depth) { temp1 = arg + --atop; CLEAR(temp1); } while (fr->trys.st->for_count-->0) { CLEAR(&fr->fors.st->cur); CLEAR(&fr->fors.st->end); fr->fors.top--; fr->fors.st = pop_for(fr->fors.st); } fr->trys.top--; fr->trys.st = pop_try(fr->trys.st); if (pc->data.number == IN_CATCH) { /* IN_CATCH */ if (fr->errorstr) { arg[atop].type = PROG_STRING; arg[atop++].data.string = alloc_prog_string(fr->errorstr); free(fr->errorstr); fr->errorstr = NULL; } else { arg[atop].type = PROG_STRING; arg[atop++].data.string = NULL; } if (fr->errorinst) { free(fr->errorinst); fr->errorinst = NULL; } } else { /* IN_CATCH_DETAILED */ stk_array *nu = new_array_dictionary(); if (fr->errorstr) { array_set_strkey_strval(&nu, "error", fr->errorstr); free(fr->errorstr); fr->errorstr = NULL; } if (fr->errorinst) { array_set_strkey_strval(&nu, "instr", fr->errorinst); free(fr->errorinst); fr->errorinst = NULL; } array_set_strkey_intval(&nu, "line", fr->errorline); array_set_strkey_refval(&nu, "program", fr->errorprog); arg[atop].type = PROG_ARRAY; arg[atop++].data.array = nu; } reload(fr, atop, stop); } pc++; break; case IN_EVENT_WAITFOR: if (atop < 1) abort_loop("Stack Underflow. Missing eventID list array argument.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_ARRAY) abort_loop("EventID string list array expected.", temp1, NULL); if (temp1->data.array && temp1->data.array->type != ARRAY_PACKED) abort_loop("Argument must be a list array of eventid strings.", temp1, NULL); if (!array_is_homogenous(temp1->data.array, PROG_STRING)) abort_loop("Argument must be a list array of eventid strings.", temp1, NULL); fr->pc = pc + 1; reload(fr, atop, stop); { int i, outcount; int count = array_count(temp1->data.array); char** events = (char**)malloc(count * sizeof(char**)); for (outcount = i = 0; i < count; i++) { char *val = array_get_intkey_strval(temp1->data.array, i); if (val != NULL) { int found = 0; int j; for (j = 0; j < outcount; j++) { if (!strcmp(events[j], val)) { found = 1; break; } } if (!found) { events[outcount++] = val; } } } muf_event_register_specific(player, program, fr, outcount, events); free(events); } PLAYER_SET_BLOCK(player, (!fr->been_background)); CLEAR(temp1); interp_depth--; calc_profile_timing(program,fr); return NULL; /* NOTREACHED */ break; case IN_READ: if (writeonly) abort_loop("Program is write-only.", NULL, NULL); if (fr->multitask == BACKGROUND) abort_loop("BACKGROUND programs are write only.", NULL, NULL); reload(fr, atop, stop); fr->brkpt.isread = 1; fr->pc = pc + 1; PLAYER_SET_CURR_PROG(player, program); PLAYER_SET_BLOCK(player, 0); add_muf_read_event(fr->descr, player, program, fr); interp_depth--; calc_profile_timing(program,fr); return NULL; /* NOTREACHED */ break; case IN_SLEEP: if (atop < 1) abort_loop("Stack Underflow.", NULL, NULL); if (fr->trys.top && atop - fr->trys.st->depth < 1) abort_loop("Stack protection fault.", NULL, NULL); temp1 = arg + --atop; if (temp1->type != PROG_INTEGER) abort_loop("Invalid argument type.", temp1, NULL); fr->pc = pc + 1; reload(fr, atop, stop); if (temp1->data.number < 0) abort_loop("Timetravel beyond scope of muf.", temp1, NULL); add_muf_delay_event(temp1->data.number, fr->descr, player, NOTHING, NOTHING, program, fr, "SLEEPING"); PLAYER_SET_BLOCK(player, (!fr->been_background)); interp_depth--; calc_profile_timing(program,fr); return NULL; /* NOTREACHED */ break; default: nargs = 0; reload(fr, atop, stop); tmp = atop; prim_func[pc->data.number - 1] (player, program, mlev, pc, arg, &tmp, fr); atop = tmp; pc++; break; } /* switch */ break; case PROG_CLEARED: log_status("WARNING: attempt to execute instruction cleared by %s:%hd in program %d", (char*)pc->data.addr, pc->line, program); pc = NULL; abort_loop_hard("Program internal error. Program erroneously freed from memory.", NULL, NULL); default: pc = NULL; abort_loop_hard("Program internal error. Unknown instruction type.", NULL, NULL); } /* switch */ if (err) { if (err != ERROR_DIE_NOW && fr->trys.top) { while (fr->trys.st->call_level < stop) { if (stop > 1 && program != sys[stop - 1].progref) { if (sys[stop - 1].progref >= db_top || sys[stop - 1].progref < 0 || (Typeof(sys[stop - 1].progref) != TYPE_PROGRAM)) abort_loop_hard("Internal error. Invalid address.", NULL, NULL); calc_profile_timing(program,fr); gettimeofday(&fr->proftime, NULL); PROGRAM_DEC_INSTANCES(program); program = sys[stop - 1].progref; mlev = ProgMLevel(program); fr->caller.top--; } scopedvar_poplevel(fr); stop--; } pc = fr->trys.st->addr; err = 0; } else { reload(fr, atop, stop); prog_clean(fr); PLAYER_SET_BLOCK(player, 0); interp_depth--; calc_profile_timing(program,fr); return NULL; } } } /* while */ PLAYER_SET_BLOCK(player, 0); if (atop) { struct inst *rv; if (rettyp) { copyinst(arg + atop - 1, &retval); rv = &retval; } else { if (!false_inst(arg + atop - 1)) { rv = (struct inst *) 1; } else { rv = NULL; } } reload(fr, atop, stop); prog_clean(fr); interp_depth--; calc_profile_timing(program,fr); return rv; } reload(fr, atop, stop); prog_clean(fr); interp_depth--; calc_profile_timing(program,fr); return NULL; }
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_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_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); }