| 1 | /** |
|---|
| 2 | * \file funufun.c |
|---|
| 3 | * |
|---|
| 4 | * \brief Evaluation and user-function functions for mushcode. |
|---|
| 5 | * |
|---|
| 6 | * |
|---|
| 7 | */ |
|---|
| 8 | |
|---|
| 9 | #include "copyrite.h" |
|---|
| 10 | |
|---|
| 11 | #include "config.h" |
|---|
| 12 | #include "conf.h" |
|---|
| 13 | #include "externs.h" |
|---|
| 14 | #include "match.h" |
|---|
| 15 | #include "parse.h" |
|---|
| 16 | #include "mymalloc.h" |
|---|
| 17 | #include "attrib.h" |
|---|
| 18 | #include "mushdb.h" |
|---|
| 19 | #include "dbdefs.h" |
|---|
| 20 | #include "flags.h" |
|---|
| 21 | #include "lock.h" |
|---|
| 22 | #include "confmagic.h" |
|---|
| 23 | |
|---|
| 24 | void do_userfn(char *buff, char **bp, dbref obj, ATTR *attrib, int nargs, |
|---|
| 25 | char **args, dbref executor, dbref caller, dbref enactor, |
|---|
| 26 | PE_Info *pe_info, int extra_flags); |
|---|
| 27 | |
|---|
| 28 | /* ARGSUSED */ |
|---|
| 29 | FUNCTION(fun_s) |
|---|
| 30 | { |
|---|
| 31 | char const *p; |
|---|
| 32 | p = args[0]; |
|---|
| 33 | process_expression(buff, bp, &p, executor, caller, enactor, PE_DEFAULT, |
|---|
| 34 | PT_DEFAULT, pe_info); |
|---|
| 35 | } |
|---|
| 36 | |
|---|
| 37 | /* ARGSUSED */ |
|---|
| 38 | FUNCTION(fun_fn) |
|---|
| 39 | { |
|---|
| 40 | /* First argument is name of a function, remaining are arguments |
|---|
| 41 | * for that function. |
|---|
| 42 | */ |
|---|
| 43 | char tbuf[BUFFER_LEN]; |
|---|
| 44 | char *tp = tbuf; |
|---|
| 45 | char const *p; |
|---|
| 46 | int i; |
|---|
| 47 | if (!args[0] || !*args[0]) |
|---|
| 48 | return; /* No function name */ |
|---|
| 49 | /* Evaluate first argument */ |
|---|
| 50 | p = args[0]; |
|---|
| 51 | process_expression(tbuf, &tp, &p, executor, caller, |
|---|
| 52 | enactor, PE_DEFAULT, PT_DEFAULT, pe_info); |
|---|
| 53 | safe_chr('(', tbuf, &tp); |
|---|
| 54 | for (i = 1; i < nargs; i++) { |
|---|
| 55 | if (i > 1) |
|---|
| 56 | safe_chr(',', tbuf, &tp); |
|---|
| 57 | safe_strl(args[i], arglens[i], tbuf, &tp); |
|---|
| 58 | } |
|---|
| 59 | safe_chr(')', tbuf, &tp); |
|---|
| 60 | *tp = '\0'; |
|---|
| 61 | p = tbuf; |
|---|
| 62 | process_expression(buff, bp, &p, executor, caller, enactor, |
|---|
| 63 | PE_DEFAULT | PE_BUILTINONLY, PT_DEFAULT, pe_info); |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | /* ARGSUSED */ |
|---|
| 67 | FUNCTION(fun_localize) |
|---|
| 68 | { |
|---|
| 69 | char const *p; |
|---|
| 70 | char *saver[NUMQ]; |
|---|
| 71 | |
|---|
| 72 | save_global_regs("localize", saver); |
|---|
| 73 | |
|---|
| 74 | p = args[0]; |
|---|
| 75 | process_expression(buff, bp, &p, executor, caller, enactor, PE_DEFAULT, |
|---|
| 76 | PT_DEFAULT, pe_info); |
|---|
| 77 | |
|---|
| 78 | restore_global_regs("localize", saver); |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | /* ARGSUSED */ |
|---|
| 82 | FUNCTION(fun_objeval) |
|---|
| 83 | { |
|---|
| 84 | char name[BUFFER_LEN]; |
|---|
| 85 | char *s; |
|---|
| 86 | char const *p; |
|---|
| 87 | dbref obj; |
|---|
| 88 | |
|---|
| 89 | /* First, we evaluate our first argument so people can use |
|---|
| 90 | * functions on it. |
|---|
| 91 | */ |
|---|
| 92 | s = name; |
|---|
| 93 | p = args[0]; |
|---|
| 94 | process_expression(name, &s, &p, executor, caller, enactor, PE_DEFAULT, |
|---|
| 95 | PT_DEFAULT, pe_info); |
|---|
| 96 | *s = '\0'; |
|---|
| 97 | |
|---|
| 98 | if (FUNCTION_SIDE_EFFECTS) { |
|---|
| 99 | /* The security hole created by function side effects is too great |
|---|
| 100 | * to allow a see_all player to evaluate functions from someone else's |
|---|
| 101 | * standpoint. We require control. |
|---|
| 102 | */ |
|---|
| 103 | if (((obj = match_thing(executor, name)) == NOTHING) |
|---|
| 104 | || !controls(executor, obj)) |
|---|
| 105 | obj = executor; |
|---|
| 106 | } else { |
|---|
| 107 | /* In order to evaluate from something else's viewpoint, you |
|---|
| 108 | * must control it, or be able to see_all. |
|---|
| 109 | */ |
|---|
| 110 | if (((obj = match_thing(executor, name)) == NOTHING) |
|---|
| 111 | || (!controls(executor, obj) && !See_All(executor))) |
|---|
| 112 | obj = executor; |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | p = args[1]; |
|---|
| 116 | process_expression(buff, bp, &p, obj, executor, enactor, PE_DEFAULT, |
|---|
| 117 | PT_DEFAULT, pe_info); |
|---|
| 118 | } |
|---|
| 119 | |
|---|
| 120 | /** Helper function for ufun and family. |
|---|
| 121 | * \param buff string to store result of evaluation. |
|---|
| 122 | * \param bp pointer into end of buff. |
|---|
| 123 | * \param obj object on which the ufun is stored. |
|---|
| 124 | * \param attrib pointer to attribute on which the ufun is stored. |
|---|
| 125 | * \param nargs number of arguments passed to the ufun. |
|---|
| 126 | * \param args array of arguments passed to the ufun. |
|---|
| 127 | * \param executor executor. |
|---|
| 128 | * \param caller caller (unused). |
|---|
| 129 | * \param enactor enactor. |
|---|
| 130 | * \param pe_info pointer to structure for process_expression data. |
|---|
| 131 | * \param extra_flags extra PE_ flags to pass in (PE_USERFN or 0). |
|---|
| 132 | */ |
|---|
| 133 | void |
|---|
| 134 | do_userfn(char *buff, char **bp, dbref obj, ATTR *attrib, int nargs, |
|---|
| 135 | char **args, dbref executor, dbref caller |
|---|
| 136 | __attribute__ ((__unused__)), dbref enactor, PE_Info *pe_info, |
|---|
| 137 | int extra_flags) |
|---|
| 138 | { |
|---|
| 139 | int j; |
|---|
| 140 | char *tptr[10]; |
|---|
| 141 | char *tbuf; |
|---|
| 142 | char const *tp; |
|---|
| 143 | int pe_flags = PE_DEFAULT | extra_flags; |
|---|
| 144 | int old_args = 0; |
|---|
| 145 | |
|---|
| 146 | /* save our stack */ |
|---|
| 147 | for (j = 0; j < 10; j++) |
|---|
| 148 | tptr[j] = global_eval_context.wenv[j]; |
|---|
| 149 | |
|---|
| 150 | /* copy the appropriate args into the stack */ |
|---|
| 151 | if (nargs > 10) |
|---|
| 152 | nargs = 10; /* maximum ten args */ |
|---|
| 153 | for (j = 0; j < nargs; j++) |
|---|
| 154 | global_eval_context.wenv[j] = args[j]; |
|---|
| 155 | for (; j < 10; j++) |
|---|
| 156 | global_eval_context.wenv[j] = NULL; |
|---|
| 157 | if (pe_info) { |
|---|
| 158 | old_args = pe_info->arg_count; |
|---|
| 159 | pe_info->arg_count = nargs; |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | tp = tbuf = safe_atr_value(attrib); |
|---|
| 163 | if (attrib->flags & AF_DEBUG) |
|---|
| 164 | pe_flags |= PE_DEBUG; |
|---|
| 165 | process_expression(buff, bp, &tp, obj, executor, enactor, pe_flags, |
|---|
| 166 | PT_DEFAULT, pe_info); |
|---|
| 167 | free(tbuf); |
|---|
| 168 | |
|---|
| 169 | /* restore the stack */ |
|---|
| 170 | for (j = 0; j < 10; j++) |
|---|
| 171 | global_eval_context.wenv[j] = tptr[j]; |
|---|
| 172 | if (pe_info) |
|---|
| 173 | pe_info->arg_count = old_args; |
|---|
| 174 | } |
|---|
| 175 | |
|---|
| 176 | /* ARGSUSED */ |
|---|
| 177 | FUNCTION(fun_ufun) |
|---|
| 178 | { |
|---|
| 179 | char rbuff[BUFFER_LEN]; |
|---|
| 180 | ufun_attrib ufun; |
|---|
| 181 | |
|---|
| 182 | if (!fetch_ufun_attrib(args[0], executor, &ufun, 0)) { |
|---|
| 183 | safe_str(T(ufun.errmess), buff, bp); |
|---|
| 184 | return; |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | call_ufun(&ufun, args + 1, nargs - 1, rbuff, executor, enactor, pe_info); |
|---|
| 188 | |
|---|
| 189 | safe_str(rbuff, buff, bp); |
|---|
| 190 | |
|---|
| 191 | return; |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | /* ARGSUSED */ |
|---|
| 195 | FUNCTION(fun_ulambda) |
|---|
| 196 | { |
|---|
| 197 | char rbuff[BUFFER_LEN]; |
|---|
| 198 | ufun_attrib ufun; |
|---|
| 199 | |
|---|
| 200 | if (!fetch_ufun_attrib(args[0], executor, &ufun, 1)) { |
|---|
| 201 | safe_str(T(ufun.errmess), buff, bp); |
|---|
| 202 | return; |
|---|
| 203 | } |
|---|
| 204 | |
|---|
| 205 | call_ufun(&ufun, args + 1, nargs - 1, rbuff, executor, enactor, pe_info); |
|---|
| 206 | |
|---|
| 207 | safe_str(rbuff, buff, bp); |
|---|
| 208 | |
|---|
| 209 | return; |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | /* ARGSUSED */ |
|---|
| 213 | FUNCTION(fun_ulocal) |
|---|
| 214 | { |
|---|
| 215 | /* Like fun_ufun, but saves the state of the q0-q9 registers |
|---|
| 216 | * when called |
|---|
| 217 | */ |
|---|
| 218 | char *preserve[NUMQ]; |
|---|
| 219 | char rbuff[BUFFER_LEN]; |
|---|
| 220 | ufun_attrib ufun; |
|---|
| 221 | |
|---|
| 222 | if (!fetch_ufun_attrib(args[0], executor, &ufun, 0)) { |
|---|
| 223 | safe_str(T(ufun.errmess), buff, bp); |
|---|
| 224 | return; |
|---|
| 225 | } |
|---|
| 226 | |
|---|
| 227 | /* Save global regs */ |
|---|
| 228 | save_global_regs("ulocal.save", preserve); |
|---|
| 229 | |
|---|
| 230 | call_ufun(&ufun, args + 1, nargs - 1, rbuff, executor, enactor, pe_info); |
|---|
| 231 | safe_str(rbuff, buff, bp); |
|---|
| 232 | |
|---|
| 233 | restore_global_regs("ulocal.save", preserve); |
|---|
| 234 | |
|---|
| 235 | return; |
|---|
| 236 | } |
|---|
| 237 | |
|---|
| 238 | /* Like fun_ufun, but takes as second argument a default message |
|---|
| 239 | * to use if the attribute isn't there. If called as uldefault, |
|---|
| 240 | * then preserve registers, too. |
|---|
| 241 | */ |
|---|
| 242 | /* ARGSUSED */ |
|---|
| 243 | FUNCTION(fun_uldefault) |
|---|
| 244 | { |
|---|
| 245 | dbref thing; |
|---|
| 246 | ATTR *attrib; |
|---|
| 247 | char *dp; |
|---|
| 248 | char const *sp; |
|---|
| 249 | char mstr[BUFFER_LEN]; |
|---|
| 250 | char **xargs; |
|---|
| 251 | int i; |
|---|
| 252 | char *preserve[NUMQ]; |
|---|
| 253 | |
|---|
| 254 | /* find our object and attribute */ |
|---|
| 255 | dp = mstr; |
|---|
| 256 | sp = args[0]; |
|---|
| 257 | process_expression(mstr, &dp, &sp, executor, caller, enactor, |
|---|
| 258 | PE_DEFAULT, PT_DEFAULT, pe_info); |
|---|
| 259 | *dp = '\0'; |
|---|
| 260 | parse_attrib(executor, mstr, &thing, &attrib); |
|---|
| 261 | if (GoodObject(thing) && attrib && CanEvalAttr(executor, thing, attrib) |
|---|
| 262 | && Can_Read_Attr(executor, thing, attrib)) { |
|---|
| 263 | /* Ok, we've got it */ |
|---|
| 264 | /* We must now evaluate all the arguments from args[2] on and |
|---|
| 265 | * pass them to the function */ |
|---|
| 266 | xargs = NULL; |
|---|
| 267 | if (nargs > 2) { |
|---|
| 268 | xargs = mush_calloc(nargs - 2, sizeof(char *), "udefault.xargs"); |
|---|
| 269 | for (i = 0; i < nargs - 2; i++) { |
|---|
| 270 | xargs[i] = mush_malloc(BUFFER_LEN, "udefault"); |
|---|
| 271 | dp = xargs[i]; |
|---|
| 272 | sp = args[i + 2]; |
|---|
| 273 | process_expression(xargs[i], &dp, &sp, executor, caller, enactor, |
|---|
| 274 | PE_DEFAULT, PT_DEFAULT, pe_info); |
|---|
| 275 | *dp = '\0'; |
|---|
| 276 | } |
|---|
| 277 | } |
|---|
| 278 | if (called_as[1] == 'L') |
|---|
| 279 | save_global_regs("uldefault.save", preserve); |
|---|
| 280 | do_userfn(buff, bp, thing, attrib, nargs - 2, xargs, |
|---|
| 281 | executor, caller, enactor, pe_info, 0); |
|---|
| 282 | if (called_as[1] == 'L') |
|---|
| 283 | restore_global_regs("uldefault.save", preserve); |
|---|
| 284 | |
|---|
| 285 | /* Free the xargs */ |
|---|
| 286 | if (nargs > 2) { |
|---|
| 287 | for (i = 0; i < nargs - 2; i++) |
|---|
| 288 | mush_free(xargs[i], "udefault"); |
|---|
| 289 | mush_free(xargs, "udefault.xargs"); |
|---|
| 290 | } |
|---|
| 291 | return; |
|---|
| 292 | } |
|---|
| 293 | /* We couldn't get it. Evaluate args[1] and return it */ |
|---|
| 294 | sp = args[1]; |
|---|
| 295 | |
|---|
| 296 | if (called_as[1] == 'L') |
|---|
| 297 | save_global_regs("uldefault.save", preserve); |
|---|
| 298 | process_expression(buff, bp, &sp, executor, caller, enactor, |
|---|
| 299 | PE_DEFAULT, PT_DEFAULT, pe_info); |
|---|
| 300 | if (called_as[1] == 'L') |
|---|
| 301 | restore_global_regs("uldefault.save", preserve); |
|---|
| 302 | return; |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | |
|---|
| 306 | /* ARGSUSED */ |
|---|
| 307 | FUNCTION(fun_zfun) |
|---|
| 308 | { |
|---|
| 309 | ATTR *attrib; |
|---|
| 310 | dbref zone; |
|---|
| 311 | |
|---|
| 312 | zone = Zone(executor); |
|---|
| 313 | |
|---|
| 314 | if (zone == NOTHING) { |
|---|
| 315 | safe_str(T("#-1 INVALID ZONE"), buff, bp); |
|---|
| 316 | return; |
|---|
| 317 | } |
|---|
| 318 | /* find the user function attribute */ |
|---|
| 319 | attrib = atr_get(zone, upcasestr(args[0])); |
|---|
| 320 | if (attrib && Can_Read_Attr(executor, zone, attrib)) { |
|---|
| 321 | if (!CanEvalAttr(executor, zone, attrib)) { |
|---|
| 322 | safe_str(T(e_perm), buff, bp); |
|---|
| 323 | return; |
|---|
| 324 | } |
|---|
| 325 | do_userfn(buff, bp, zone, attrib, nargs - 1, args + 1, executor, caller, |
|---|
| 326 | enactor, pe_info, 0); |
|---|
| 327 | return; |
|---|
| 328 | } else if (attrib || !Can_Examine(executor, zone)) { |
|---|
| 329 | safe_str(T(e_atrperm), buff, bp); |
|---|
| 330 | return; |
|---|
| 331 | } |
|---|
| 332 | safe_str(T("#-1 NO SUCH USER FUNCTION"), buff, bp); |
|---|
| 333 | return; |
|---|
| 334 | } |
|---|