/** Take an action on an object and trigger attributes. * \verbatim * executes the @attr, @oattr, @aattr for a command - gives a message * to the enactor and others in the room with the enactor, and executes * an action. We optionally load pe_regs into the queue. * \endverbatim * * \param player the enactor. * \param thing object being triggered. * \param what message attribute for enactor. * \param def default message to enactor. * \param owhat message attribute for others. * \param odef default message to others. * \param awhat action attribute to trigger. * \param loc location in which action is taking place. * \param pe_regs the pe_regs arguments for the evaluation/queueing * \param flags flags controlling type of interaction involved. * \retval 0 no attributes were present, only defaults were used if given. * \retval 1 some attributes were evaluated and used. */ int real_did_it(dbref player, dbref thing, const char *what, const char *def, const char *owhat, const char *odef, const char *awhat, dbref loc, PE_REGS *pe_regs, int flags, int an_flags) { char buff[BUFFER_LEN], *bp; int attribs_used = 0; NEW_PE_INFO *pe_info = NULL; ufun_attrib ufun; if (!pe_info) { pe_info = make_pe_info("pe_info-real_did_it2"); } loc = (loc == NOTHING) ? Location(player) : loc; /* only give messages if the location is good */ if (GoodObject(loc)) { /* message to player */ if (what && *what) { if (fetch_ufun_attrib (what, thing, &ufun, UFUN_LOCALIZE | UFUN_REQUIRE_ATTR | UFUN_IGNORE_PERMS)) { attribs_used = 1; if (!call_ufun(&ufun, buff, thing, player, pe_info, pe_regs) && buff[0]) notify_by(thing, player, buff); } else if (def && *def) notify_by(thing, player, def); } /* message to neighbors */ if (!DarkLegal(player)) { if (owhat && *owhat && fetch_ufun_attrib(owhat, thing, &ufun, UFUN_LOCALIZE | UFUN_REQUIRE_ATTR | UFUN_IGNORE_PERMS | UFUN_NAME)) { attribs_used = 1; if (!call_ufun_int (&ufun, buff, thing, player, pe_info, pe_regs, (void *) AName(player, an_flags, NULL)) && buff[0]) notify_except2(player, loc, player, thing, buff, flags); } else if (odef && *odef) { bp = buff; safe_format(buff, &bp, "%s %s", AName(player, an_flags, NULL), odef); *bp = '\0'; notify_except2(player, loc, player, thing, buff, flags); } } } if (pe_info) { free_pe_info(pe_info); } if (awhat && *awhat) attribs_used = queue_attribute_base(thing, awhat, player, 0, pe_regs, 0) || attribs_used; return attribs_used; }
/** 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); } }
/** 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 ret, if given. * \param ufun The ufun_attrib that was initialized by fetch_ufun_attrib * \param ret If desired, a pointer to a buffer in which the results * of the process_expression are stored in. * \param caller The caller (%@). * \param enactor The enactor. (%#) * \param pe_info The pe_info passed to the FUNCTION * \param user_regs Other arguments that may want to be added. This nests BELOW * the pe_regs created by call_ufun. (It is checked first) * \param data a void pointer to extra data. Currently only used to pass the * name to use, when UFUN_NAME is given. * \retval 0 success * \retval 1 process_expression failed. (CPU time limit) */ bool call_ufun_int(ufun_attrib * ufun, char *ret, dbref caller, dbref enactor, NEW_PE_INFO *pe_info, PE_REGS *user_regs, void *data) { char rbuff[BUFFER_LEN]; char *rp, *np = NULL; int pe_ret; char const *ap; char old_attr[BUFFER_LEN]; int made_pe_info = 0; PE_REGS *pe_regs; PE_REGS *pe_regs_old; int pe_reg_flags = 0; /* Make sure we have a ufun first */ if (!ufun) return 1; if (!pe_info) { pe_info = make_pe_info("pe_info.call_ufun"); made_pe_info = 1; } else { strcpy(old_attr, pe_info->attrname); } pe_regs_old = pe_info->regvals; if (ufun->ufun_flags & UFUN_LOCALIZE) pe_reg_flags |= PE_REGS_Q; else { pe_reg_flags |= PE_REGS_NEWATTR; if (ufun->ufun_flags & UFUN_SHARE_STACK) pe_reg_flags |= PE_REGS_ARGPASS; } pe_regs = pe_regs_localize(pe_info, pe_reg_flags, "call_ufun"); rp = pe_info->attrname; if (*ufun->attrname == '\0') { safe_str("#LAMBDA", pe_info->attrname, &rp); safe_chr('/', pe_info->attrname, &rp); safe_str(ufun->contents, pe_info->attrname, &rp); } else { safe_dbref(ufun->thing, pe_info->attrname, &rp); safe_chr('/', pe_info->attrname, &rp); safe_str(ufun->attrname, pe_info->attrname, &rp); } *rp = '\0'; /* If the user doesn't care about the return of the expression, * then use our own rbuff. */ if (!ret) ret = rbuff; rp = ret; /* Anything the caller wants available goes on the bottom of the stack */ if (user_regs) { user_regs->prev = pe_info->regvals; pe_info->regvals = user_regs; } if (ufun->ufun_flags & UFUN_NAME) { char *name = (char *) data; if (!name || !*name) name = (char *) Name(enactor); safe_str(name, ret, &rp); if (!(ufun->ufun_flags & UFUN_NAME_NOSPACE)) safe_chr(' ', ret, &rp); np = rp; } /* And now, make the call! =) */ ap = ufun->contents; pe_ret = process_expression(ret, &rp, &ap, ufun->thing, caller, enactor, ufun->pe_flags, PT_DEFAULT, pe_info); *rp = '\0'; if ((ufun->ufun_flags & UFUN_NAME) && np == rp) { /* Attr was empty, so we take off the name again */ *ret = '\0'; } /* Restore call_ufun's pe_regs */ if (user_regs) { pe_info->regvals = user_regs->prev; } /* Restore the pe_regs stack. */ pe_regs_restore(pe_info, pe_regs); pe_regs_free(pe_regs); pe_info->regvals = pe_regs_old; if (!made_pe_info) { /* Restore the old attrname. */ strcpy(pe_info->attrname, old_attr); } else { free_pe_info(pe_info); } return pe_ret; }