* can provide a starting point.
*/
- dbref thing;
- ATTR *attrib;
- char const *ap;
- char *abuf, *result, *rp, *rsave;
+ ufun_attrib ufun;
char *cp;
- char *tptr[2];
+ char *wenv[2];
char sep;
int funccount, per;
- int pe_flags = PE_DEFAULT;
+ char base[BUFFER_LEN];
+ char result[BUFFER_LEN];
if (!delim_check(buff, bp, nargs, args, 4, &sep))
return;
- /* find our object and attribute */
- parse_anon_attrib(executor, args[0], &thing, &attrib);
-
- if (!GoodObject(thing) || !attrib || !Can_Read_Attr(executor, thing, attrib)) {
- free_anon_attrib(attrib);
+ if (!fetch_ufun_attrib(args[0], executor, &ufun, 1))
return;
- }
- if (!CanEvalAttr(executor, thing, attrib)) {
- free_anon_attrib(attrib);
- return;
- }
-
- /* Now we can go to work */
- if (AF_Debug(attrib))
- pe_flags |= PE_DEBUG;
- result = (char *) mush_malloc(BUFFER_LEN, "string");
- rsave = (char *) mush_malloc(BUFFER_LEN, "string");
- if (!result || !rsave)
- mush_panic("Unable to allocate memory in fun_fold");
-
- abuf = safe_atr_value(attrib);
-
- /* save our stack */
- tptr[0] = global_eval_context.wenv[0];
- tptr[1] = global_eval_context.wenv[1];
cp = args[1];
/* If we have three or more arguments, the third one is the base case */
if (nargs >= 3) {
- global_eval_context.wenv[0] = args[2];
- global_eval_context.wenv[1] = split_token(&cp, sep);
+ strncpy(base, args[2], BUFFER_LEN);
} else {
- global_eval_context.wenv[0] = split_token(&cp, sep);
- global_eval_context.wenv[1] = split_token(&cp, sep);
+ strncpy(base, split_token(&cp, sep), BUFFER_LEN);
}
- rp = result;
- ap = abuf;
- process_expression(result, &rp, &ap, thing, executor, enactor,
- pe_flags, PT_DEFAULT, pe_info);
- *rp = '\0';
- strcpy(rsave, result);
+ wenv[0] = base;
+ wenv[1] = split_token(&cp, sep);
+
+ call_ufun(&ufun, wenv, 2, result, executor, enactor, pe_info);
+
+ strncpy(base, result, BUFFER_LEN);
+
funccount = pe_info->fun_invocations;
/* handle the rest of the cases */
while (cp && *cp) {
- global_eval_context.wenv[0] = rsave;
- global_eval_context.wenv[1] = split_token(&cp, sep);
- rp = result;
- ap = abuf;
- per = process_expression(result, &rp, &ap, thing, executor, enactor,
- pe_flags, PT_DEFAULT, pe_info);
- *rp = '\0';
+ wenv[1] = split_token(&cp, sep);
+ per = call_ufun(&ufun, wenv, 2, result, executor, enactor, pe_info);
if (per || (pe_info->fun_invocations >= FUNCTION_LIMIT &&
- pe_info->fun_invocations == funccount &&
- !strcmp(rsave, result)))
+ pe_info->fun_invocations == funccount && !strcmp(base, result)))
break;
funccount = pe_info->fun_invocations;
- strcpy(rsave, result);
+ strcpy(base, result);
}
- safe_str(rsave, buff, bp);
-
- /* restore the stack */
- global_eval_context.wenv[0] = tptr[0];
- global_eval_context.wenv[1] = tptr[1];
-
- free((Malloc_t) abuf);
- mush_free((Malloc_t) result, "string");
- mush_free((Malloc_t) rsave, "string");
- free_anon_attrib(attrib);
+ safe_str(base, buff, bp);
}
/* ARGSUSED */
* of the list for which the function evaluates to 1.
*/
- dbref thing;
- ATTR *attrib;
- char const *ap;
- char *abuf, result[BUFFER_LEN], *rp;
+ ufun_attrib ufun;
+ char result[BUFFER_LEN];
char *cp;
- char *tptr;
+ char *wenv[1];
char sep;
int first;
int check_bool = 0;
int funccount;
char *osep, osepd[2] = { '\0', '\0' };
- int pe_flags = PE_DEFAULT;
if (!delim_check(buff, bp, nargs, args, 3, &sep))
return;
- if (nargs == 4)
- osep = args[3];
- else {
- osepd[0] = sep;
- osep = osepd;
- }
+ osepd[0] = sep;
+ osep = (nargs >= 4) ? args[3] : osepd;
if (strcmp(called_as, "FILTERBOOL") == 0)
check_bool = 1;
/* find our object and attribute */
- parse_anon_attrib(executor, args[0], &thing, &attrib);
-
- if (!GoodObject(thing) || !attrib || !Can_Read_Attr(executor, thing, attrib)) {
- free_anon_attrib(attrib);
+ if (!fetch_ufun_attrib(args[0], executor, &ufun, 1))
return;
- }
- if (!CanEvalAttr(executor, thing, attrib)) {
- free_anon_attrib(attrib);
- return;
- }
-
- if (AF_Debug(attrib))
- pe_flags |= PE_DEBUG;
-
- abuf = safe_atr_value(attrib);
-
- tptr = global_eval_context.wenv[0];
+ /* Go through each argument */
cp = trim_space_sep(args[1], sep);
first = 1;
funccount = pe_info->fun_invocations;
while (cp && *cp) {
- global_eval_context.wenv[0] = split_token(&cp, sep);
- ap = abuf;
- rp = result;
- if (process_expression(result, &rp, &ap, thing, executor, enactor,
- pe_flags, PT_DEFAULT, pe_info))
+ wenv[0] = split_token(&cp, sep);
+ if (call_ufun(&ufun, wenv, 1, result, executor, enactor, pe_info))
break;
- *rp = '\0';
if ((check_bool == 0)
? (*result == '1' && *(result + 1) == '\0')
: parse_boolean(result)) {
first = 0;
else
safe_str(osep, buff, bp);
- safe_str(global_eval_context.wenv[0], buff, bp);
+ safe_str(wenv[0], buff, bp);
}
/* Can't do *bp == oldbp like in all the others, because bp might not
* move even when not full, if one of the list elements is null and
break;
funccount = pe_info->fun_invocations;
}
-
- global_eval_context.wenv[0] = tptr;
-
- free((Malloc_t) abuf);
- free_anon_attrib(attrib);
}
/* ARGSUSED */
* This function takes delimiters.
*/
- dbref thing;
- ATTR *attrib;
- char const *ap;
- char *asave, *lp;
- char *tptr[2];
+ ufun_attrib ufun;
+ char *lp;
+ char *wenv[2];
char place[16];
int placenr = 1;
char sep;
int funccount;
- char *oldbp;
char *osep, osepd[2] = { '\0', '\0' };
- int pe_flags = PE_DEFAULT;
+ char rbuff[BUFFER_LEN];
if (!delim_check(buff, bp, nargs, args, 3, &sep))
return;
- if (nargs == 4)
- osep = args[3];
- else {
- osepd[0] = sep;
- osep = osepd;
- }
+ osepd[0] = sep;
+ osep = (nargs >= 4) ? args[3] : osepd;
lp = trim_space_sep(args[1], sep);
if (!*lp)
return;
- /* find our object and attribute */
- parse_anon_attrib(executor, args[0], &thing, &attrib);
- if (!GoodObject(thing) || !attrib || !Can_Read_Attr(executor, thing, attrib)) {
- free_anon_attrib(attrib);
- return;
- }
- if (!CanEvalAttr(executor, thing, attrib)) {
- free_anon_attrib(attrib);
+ if (!fetch_ufun_attrib(args[0], executor, &ufun, 1))
return;
- }
- if (AF_Debug(attrib))
- pe_flags |= PE_DEBUG;
strcpy(place, "1");
- asave = safe_atr_value(attrib);
- /* save our stack */
- tptr[0] = global_eval_context.wenv[0];
- tptr[1] = global_eval_context.wenv[1];
- global_eval_context.wenv[1] = place;
+ /* Build our %0 args */
+ wenv[0] = split_token(&lp, sep);
+ wenv[1] = place;
- global_eval_context.wenv[0] = split_token(&lp, sep);
- ap = asave;
- process_expression(buff, bp, &ap, thing, executor, enactor,
- pe_flags, PT_DEFAULT, pe_info);
- oldbp = *bp;
+ call_ufun(&ufun, wenv, 2, rbuff, executor, enactor, pe_info);
funccount = pe_info->fun_invocations;
+ safe_str(rbuff, buff, bp);
while (lp) {
safe_str(osep, buff, bp);
strcpy(place, unparse_integer(++placenr));
- global_eval_context.wenv[0] = split_token(&lp, sep);
- ap = asave;
- if (process_expression(buff, bp, &ap, thing, executor, enactor,
- pe_flags, PT_DEFAULT, pe_info))
+ wenv[0] = split_token(&lp, sep);
+
+ if (call_ufun(&ufun, wenv, 2, rbuff, executor, enactor, pe_info))
break;
+ safe_str(rbuff, buff, bp);
if (*bp == (buff + BUFFER_LEN - 1) && pe_info->fun_invocations == funccount)
break;
- oldbp = *bp;
funccount = pe_info->fun_invocations;
}
-
- free((Malloc_t) asave);
- free_anon_attrib(attrib);
- global_eval_context.wenv[0] = tptr[0];
- global_eval_context.wenv[1] = tptr[1];
}
* This function takes delimiters.
*/
- dbref thing;
- ATTR *attrib;
- char const *ap;
- char *asave, *lp[10];
- char *tptr[10];
+ ufun_attrib ufun;
+ char rbuff[BUFFER_LEN];
+ char *lp[10];
+ char *list[10];
char sep;
int funccount;
int n;
int lists, words;
- char *oldbp;
- int pe_flags = PE_DEFAULT;
+ int first = 1;
if (nargs > 3) { /* Last arg must be the delimiter */
n = nargs;
lp[n] = trim_space_sep(args[n + 1], sep);
/* find our object and attribute */
- parse_anon_attrib(executor, args[0], &thing, &attrib);
- if (!GoodObject(thing) || !attrib || !Can_Read_Attr(executor, thing, attrib)) {
- free_anon_attrib(attrib);
- return;
- }
- if (!CanEvalAttr(executor, thing, attrib)) {
- free_anon_attrib(attrib);
+ if (!fetch_ufun_attrib(args[0], executor, &ufun, 1))
return;
- }
- if (AF_Debug(attrib))
- pe_flags |= PE_DEBUG;
-
- asave = safe_atr_value(attrib);
- /* save our stack */
- save_global_env("fun_mix", tptr);
-
- words = 0;
- for (n = 0; n < 10; n++) {
- if ((n < lists) && lp[n] && *lp[n]) {
- global_eval_context.wenv[n] = split_token(&lp[n], sep);
- if (global_eval_context.wenv[n])
- words++;
- } else
- global_eval_context.wenv[n] = NULL;
- }
- if (words == 0) {
- restore_global_env("fun_mix", tptr);
- free((Malloc_t) asave);
- free_anon_attrib(attrib);
- return;
- }
- ap = asave;
- process_expression(buff, bp, &ap, thing, executor, enactor,
- pe_flags, PT_DEFAULT, pe_info);
- oldbp = *bp;
- funccount = pe_info->fun_invocations;
+ first = 0;
while (1) {
words = 0;
- for (n = 0; n < 10; n++) {
- if ((n < lists) && lp[n] && *lp[n]) {
- global_eval_context.wenv[n] = split_token(&lp[n], sep);
- if (global_eval_context.wenv[n])
+ for (n = 0; n < lists; n++) {
+ if (lp[n] && *lp[n]) {
+ list[n] = split_token(&lp[n], sep);
+ if (list[n])
words++;
- } else
- global_eval_context.wenv[n] = NULL;
+ } else {
+ list[n] = NULL;
+ }
}
- if (words == 0)
- break;
- safe_chr(sep, buff, bp);
- ap = asave;
- if (process_expression(buff, bp, &ap, thing, executor, enactor,
- pe_flags, PT_DEFAULT, pe_info))
- break;
- if (*bp == (buff + BUFFER_LEN - 1) && pe_info->fun_invocations == funccount)
- break;
- oldbp = *bp;
+ if (!words)
+ return;
+ if (first)
+ first = 0;
+ else
+ safe_chr(sep, buff, bp);
funccount = pe_info->fun_invocations;
+ call_ufun(&ufun, list, lists, rbuff, executor, enactor, pe_info);
+ safe_str(rbuff, buff, bp);
}
-
- free((Malloc_t) asave);
- free_anon_attrib(attrib);
- restore_global_env("fun_mix", tptr);
}
/* ARGSUSED */
/* string, regexp, replacement string. Acts like sed or perl's s///g,
//with an ig version */
-int re_subpatterns = -1; /**< Number of subpatterns in regexp */
-int *re_offsets; /**< Array of offsets to subpatterns */
-char *re_from = NULL; /**< Pointer to last match position */
FUNCTION(fun_regreplace)
{
pcre *re;
char abuf[BUFFER_LEN], *abp;
char prebuf[BUFFER_LEN], *prep;
char postbuf[BUFFER_LEN], *postp;
-
int flags = 0, all = 0, match_offset = 0, len, funccount;
int i;
+ int old_re_subpatterns;
+ int *old_re_offsets;
+ char *old_re_from;
+
+ old_re_subpatterns = global_eval_context.re_subpatterns;
+ old_re_offsets = global_eval_context.re_offsets;
+ old_re_from = global_eval_context.re_from;
+
if (called_as[strlen(called_as) - 1] == 'I')
flags = PCRE_CASELESS;
/* Now copy in the replacement, putting in captured sub-expressions */
obp = args[i + 1];
- re_from = prebuf;
- re_offsets = offsets;
- re_subpatterns = subpatterns;
+ global_eval_context.re_from = prebuf;
+ global_eval_context.re_offsets = offsets;
+ global_eval_context.re_subpatterns = subpatterns;
process_expression(postbuf, &postp, &obp, executor, caller, enactor,
PE_DEFAULT | PE_DOLLAR, PT_DEFAULT, pe_info);
if ((*bp == (buff + BUFFER_LEN - 1))
if (study)
mush_free((Malloc_t) study, "pcre.extra");
- re_offsets = NULL;
- re_subpatterns = -1;
- re_from = NULL;
+ global_eval_context.re_offsets = old_re_offsets;
+ global_eval_context.re_subpatterns = old_re_subpatterns;
+ global_eval_context.re_from = old_re_from;
}
safe_str(postbuf, buff, bp);
/* ARGSUSED */
FUNCTION(fun_ufun)
{
- ATTR *attrib;
- dbref obj;
+ char rbuff[BUFFER_LEN];
+ ufun_attrib ufun;
BEGINOOREF_L
- /* find the user function attribute */
- parse_attrib(executor, args[0], &obj, &attrib);
- if (!GoodObject(obj)) {
- safe_str(T("#-1 INVALID OBJECT"), buff, bp);
- goto ufun_done;
- }
- if (attrib && Can_Read_Attr(executor, obj, attrib)) {
- if (!CanEvalAttr(executor, obj, attrib)) {
- safe_str(T(e_perm), buff, bp);
- goto ufun_done;
- }
- do_userfn(buff, bp, obj, attrib, nargs - 1, args + 1, executor, caller,
- enactor, pe_info);
- goto ufun_done;
- } else if (attrib || !Can_Examine(executor, obj)) {
- safe_str(T(e_atrperm), buff, bp);
- goto ufun_done;
+ if (!fetch_ufun_attrib(args[0], executor, &ufun, 0)) {
+ safe_str(T(ufun.errmess), buff, bp);
+ return;
}
-ufun_done:
+
+ call_ufun(&ufun, args + 1, nargs - 1, rbuff, executor, enactor, pe_info);
+
+ safe_str(rbuff, buff, bp);
+
ENDOOREF_L
+
return;
}
/* Like fun_ufun, but saves the state of the q0-q9 registers
* when called
*/
- ATTR *attrib;
- dbref obj;
char *preserve[NUMQ];
+ char rbuff[BUFFER_LEN];
+ ufun_attrib ufun;
- BEGINOOREF_L
-
- /* find the user function attribute */
- parse_attrib(executor, args[0], &obj, &attrib);
- if (!GoodObject(obj)) {
- safe_str(T("#-1 INVALID OBJECT"), buff, bp);
- ENDOOREF_L
- return;
- }
- if (attrib && Can_Read_Attr(executor, obj, attrib)) {
- if (!CanEvalAttr(executor, obj, attrib)) {
- safe_str(T(e_perm), buff, bp);
- ENDOOREF_L
- return;
- }
- save_global_regs("ulocal.save", preserve);
- do_userfn(buff, bp, obj, attrib, nargs - 1, args + 1, executor, caller,
- enactor, pe_info);
- restore_global_regs("ulocal.save", preserve);
- ENDOOREF_L
- return;
- } else if (attrib || !Can_Examine(executor, obj)) {
- safe_str(T(e_atrperm), buff, bp);
- ENDOOREF_L
+ if (!fetch_ufun_attrib(args[0], executor, &ufun, 0)) {
+ safe_str(T(ufun.errmess), buff, bp);
return;
}
+
+ BEGINOOREF_L
+
+ /* Save global regs */
+ save_global_regs("ulocal.save", preserve);
+
+ call_ufun(&ufun, args + 1, nargs - 1, rbuff, executor, enactor, pe_info);
+ safe_str(rbuff, buff, bp);
+
+ restore_global_regs("ulocal.save", preserve);
+
ENDOOREF_L
+
return;
}
#include "flags.h"
#include "dbdefs.h"
#include "attrib.h"
+#include "parse.h"
#include "lock.h"
#include "confmagic.h"
}
}
+/** Given an attribute [<object>/]<name> pair (which may include #lambda),
+ * fetch its value, owner (thing), and pe_flags, and store in the struct
+ * pointed to by ufun
+ */
+int
+fetch_ufun_attrib(char *attrname, dbref executor, ufun_attrib * ufun,
+ int accept_lambda)
+{
+ ATTR *attrib;
+ dbref thing;
+ int pe_flags = PE_UDEFAULT;
+
+ if (!ufun)
+ return 0; /* We should never NOT receive a ufun. */
+ ufun->errmess = (char *) "";
+
+ /* find our object and attribute */
+ if (accept_lambda) {
+ parse_anon_attrib(executor, attrname, &thing, &attrib);
+ } else {
+ parse_attrib(executor, attrname, &thing, &attrib);
+ }
+
+ /* Is it valid? */
+ if (!GoodObject(thing)) {
+ ufun->errmess = (char *) "#-1 INVALID OBJECT";
+ free_anon_attrib(attrib);
+ return 0;
+ } else if (!attrib) {
+ ufun->contents[0] = '\0';
+ ufun->thing = thing;
+ ufun->pe_flags = pe_flags;
+ free_anon_attrib(attrib);
+ return 1;
+ } else if (!Can_Read_Attr(executor, thing, attrib)) {
+ ufun->errmess = e_atrperm;
+ free_anon_attrib(attrib);
+ return 0;
+ }
+
+ /* Can we evaluate it? */
+ if (!CanEvalAttr(executor, thing, attrib)) {
+ ufun->errmess = e_perm;
+ free_anon_attrib(attrib);
+ return 0;
+ }
+
+ /* DEBUG attributes */
+ if (AF_Debug(attrib))
+ pe_flags |= PE_DEBUG;
+
+ /* Populate the ufun object */
+ strncpy(ufun->contents, atr_value(attrib), BUFFER_LEN);
+ ufun->thing = thing;
+ ufun->pe_flags = pe_flags;
+
+ /* Cleanup */
+ free_anon_attrib(attrib);
+
+ /* We're good */
+ return 1;
+}
+
+/** Given a ufun, executor, enactor, PE_Info, and arguments for %0-%9,
+ * call the ufun with appropriate permissions on values given for
+ * wenv_args. The value returned is stored in the buffer pointed to
+ * by retval, if given.
+ * \param ufun The ufun_attrib that was initialized by fetch_ufun_attrib
+ * \param wenv_args An array of string values for global_eval_context.wenv
+ * \param wenv_argc The number of wenv args to use.
+ * \param ret If desired, a pointer to a buffer in which the results
+ * of the process_expression are stored in.
+ * \param executor The executor.
+ * \param enactor The enactor.
+ * \param pe_info The pe_info passed to the FUNCTION
+ * \retval 0 success
+ * \retval 1 process_expression failed. (CPU time limit)
+ */
+int
+call_ufun(ufun_attrib * ufun, char **wenv_args, int wenv_argc, char *ret,
+ dbref executor, dbref enactor, PE_Info * pe_info)
+{
+ char rbuff[BUFFER_LEN];
+ char *rp;
+ char *old_wenv[10];
+ int old_args;
+ int i;
+ int pe_ret;
+ char const *ap;
+
+ int old_re_subpatterns;
+ int *old_re_offsets;
+ char *old_re_from;
+
+ old_re_subpatterns = global_eval_context.re_subpatterns;
+ old_re_offsets = global_eval_context.re_offsets;
+ old_re_from = global_eval_context.re_from;
+
+ /* Make sure we have a ufun first */
+ if (!ufun)
+ return 1;
+
+ /* If the user doesn't care about the return of the expression,
+ * then use our own rbuff.
+ */
+ if (!ret)
+ ret = rbuff;
+ rp = ret;
+
+ for (i = 0; i < wenv_argc; i++) {
+ old_wenv[i] = global_eval_context.wenv[i];
+ global_eval_context.wenv[i] = wenv_args[i];
+ }
+ for (; i < 10; i++) {
+ old_wenv[i] = global_eval_context.wenv[i];
+ global_eval_context.wenv[i] = NULL;
+ }
+
+ /* Set all the regexp patterns to NULL so they are not
+ * propogated */
+ global_eval_context.re_subpatterns = -1;
+ global_eval_context.re_offsets = NULL;
+ global_eval_context.re_from = NULL;
+
+ /* And now, make the call! =) */
+ if (pe_info) {
+ old_args = pe_info->arg_count;
+ pe_info->arg_count = wenv_argc;
+ }
+
+ ap = ufun->contents;
+ pe_ret = process_expression(ret, &rp, &ap, ufun->thing, executor,
+ enactor, ufun->pe_flags, PT_DEFAULT, pe_info);
+ *rp = '\0';
+
+ /* Restore the old wenv */
+ for (i = 0; i < 10; i++) {
+ global_eval_context.wenv[i] = old_wenv[i];
+ }
+ if (pe_info) {
+ pe_info->arg_count = old_args;
+ }
+
+ /* Restore regexp patterns */
+ global_eval_context.re_offsets = old_re_offsets;
+ global_eval_context.re_subpatterns = old_re_subpatterns;
+ global_eval_context.re_from = old_re_from;
+
+ return pe_ret;
+}
+
/** Given an exit, find the room that is its source through brute force.
* This is used in pathological cases where the exit's own source
* element is invalid.