/** Helper function for calling \@functioned funs. * \param buff string to store result of evaluation. * \param bp pointer into end of buff. * \param obj object on which the ufun is stored. * \param attrib pointer to attribute on which the ufun is stored. * \param nargs number of arguments passed to the ufun. * \param args array of arguments passed to the ufun. * \param executor executor. * \param caller caller (unused). * \param enactor enactor. * \param pe_info pointer to structure for process_expression data. * \param extra_flags extra PE_ flags to pass in (PE_USERFN or 0). */ void do_userfn(char *buff, char **bp, dbref obj, ATTR *attrib, int nargs, char **args, dbref executor, dbref caller __attribute__ ((__unused__)), dbref enactor, NEW_PE_INFO *pe_info, int extra_flags) { int j; int made_pe_info = 0; char *tbuf; char const *tp; int pe_flags = PE_DEFAULT | extra_flags; PE_REGS *pe_regs; if (nargs > 10) nargs = 10; /* maximum ten args */ /* save our stack */ if (!pe_info) { made_pe_info = 1; pe_info = make_pe_info("pe_info-do_userfn"); } /* copy the appropriate args into pe_regs */ pe_regs = pe_regs_localize(pe_info, PE_REGS_ARG, "do_userfn"); for (j = 0; j < nargs; j++) { pe_regs_setenv_nocopy(pe_regs, j, args[j]); } tp = tbuf = safe_atr_value(attrib); if (AF_NoDebug(attrib)) pe_flags |= PE_NODEBUG; /* no_debug overrides debug */ else if (AF_Debug(attrib)) pe_flags |= PE_DEBUG; process_expression(buff, bp, &tp, obj, executor, enactor, pe_flags, PT_DEFAULT, pe_info); free(tbuf); pe_regs_restore(pe_info, pe_regs); pe_regs_free(pe_regs); if (made_pe_info) { free_pe_info(pe_info); } }
/** Populate a ufun_attrib struct from an obj/attr pair. * \verbatim 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 * \endverbatim * \param attrstring The obj/name of attribute. * \param executor Dbref of the executing object. * \param ufun Pointer to an allocated ufun_attrib struct to fill in. * \param flags A bitwise or of desired UFUN_* flags. * \return 0 on failure, true on success. */ bool fetch_ufun_attrib(const char *attrstring, dbref executor, ufun_attrib * ufun, int flags) { char *thingname, *attrname; char astring[BUFFER_LEN]; ATTR *attrib; if (!ufun) return 0; ufun->contents[0] = '\0'; ufun->errmess = (char *) ""; ufun->thing = executor; ufun->pe_flags = PE_UDEFAULT; ufun->ufun_flags = flags; ufun->thing = executor; thingname = NULL; if (!attrstring) return 0; strncpy(astring, attrstring, BUFFER_LEN); /* Split obj/attr */ if ((flags & UFUN_OBJECT) && ((attrname = strchr(astring, '/')) != NULL)) { thingname = astring; *(attrname++) = '\0'; } else { attrname = astring; } if (thingname && (flags & UFUN_LAMBDA) && (strcasecmp(thingname, "#lambda") == 0 || strncasecmp(thingname, "#apply", 6) == 0)) { /* It's a lambda. */ ufun->ufun_flags &= ~UFUN_NAME; ufun->thing = executor; if (strcasecmp(thingname, "#lambda") == 0) mush_strncpy(ufun->contents, attrname, BUFFER_LEN); else { /* #apply */ char *ucb = ufun->contents; unsigned nargs = 1, n; thingname += 6; if (*thingname) nargs = parse_uinteger(thingname); /* Limit between 1 and 10 arguments (%0-%9) */ if (nargs == 0) nargs = 1; if (nargs > 10) nargs = 10; safe_str(attrname, ufun->contents, &ucb); safe_chr('(', ufun->contents, &ucb); for (n = 0; n < nargs; n++) { if (n > 0) safe_chr(',', ufun->contents, &ucb); safe_format(ufun->contents, &ucb, "%%%u", n); } safe_chr(')', ufun->contents, &ucb); *ucb = '\0'; } ufun->attrname[0] = '\0'; return 1; } if (thingname) { /* Attribute is on something else. */ ufun->thing = noisy_match_result(executor, thingname, NOTYPE, MAT_EVERYTHING); if (!GoodObject(ufun->thing)) { ufun->errmess = (char *) "#-1 INVALID OBJECT"; return 0; } } attrib = (ATTR *) atr_get(ufun->thing, upcasestr(attrname)); if (attrib && AF_Internal(attrib)) { /* Regardless of whether we're doing permission checks, we should * never be showing internal attributes here */ attrib = NULL; } /* An empty attrib is the same as no attrib. */ if (attrib == NULL) { if (flags & UFUN_REQUIRE_ATTR) { if (!(flags & UFUN_IGNORE_PERMS) && !Can_Examine(executor, ufun->thing)) ufun->errmess = e_atrperm; return 0; } else { mush_strncpy(ufun->attrname, attrname, ATTRIBUTE_NAME_LIMIT + 1); return 1; } } if (!(flags & UFUN_IGNORE_PERMS) && !Can_Read_Attr(executor, ufun->thing, attrib)) { ufun->errmess = e_atrperm; return 0; } if (!(flags & UFUN_IGNORE_PERMS) && !CanEvalAttr(executor, ufun->thing, attrib)) { ufun->errmess = e_perm; return 0; } /* DEBUG attributes */ if (AF_NoDebug(attrib)) ufun->pe_flags |= PE_NODEBUG; /* No_Debug overrides Debug */ else if (AF_Debug(attrib)) ufun->pe_flags |= PE_DEBUG; if (flags & UFUN_NAME) { if (attrib->flags & AF_NONAME) ufun->ufun_flags &= ~UFUN_NAME; else if (attrib->flags & AF_NOSPACE) ufun->ufun_flags |= UFUN_NAME_NOSPACE; } /* Populate the ufun object */ mush_strncpy(ufun->contents, atr_value(attrib), BUFFER_LEN); mush_strncpy(ufun->attrname, AL_NAME(attrib), ATTRIBUTE_NAME_LIMIT + 1); /* We're good */ return 1; }