#include "copyright.h"#include "autoconf.h"#include "config.h"#include "externs.h"#include "ansi.h"#include "attrs.h"#include "functions.h"Include dependency graph for eval.cpp:

Go to the source code of this file.
Data Structures | |
| struct | tcache_ent |
| struct | tag_ptrsframe |
| struct | tag_intsframe |
Defines | |
| #define | isSpecial(table, c) isSpecial_##table[(unsigned char)(c)] |
| Accesses the isSpecial_ tables with proper typecast. | |
| #define | NEXTCHAR *zstr++ = *cstr++; |
| #define | stacklim 32 |
| #define | stacklim 32 |
| #define | PTRS_PER_FRAME ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(char *)) |
| #define | INTS_PER_FRAME ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(int)) |
Typedefs | |
| typedef tcache_ent | TCENT |
| typedef tag_ptrsframe | PtrsFrame |
| typedef tag_intsframe | IntsFrame |
Functions | |
| static char * | parse_to_cleanup (int eval, int first, char *cstr, char *rstr, char *zstr, char *strFirewall) |
| char * | parse_to (char **dstr, char delim, int eval) |
| static char * | parse_to_lite (char **dstr, char delim1, char delim2, int *nLen, int *iWhichDelim) |
| char * | parse_arglist (dbref executor, dbref caller, dbref enactor, char *dstr, char delim, dbref eval, char *fargs[], dbref nfargs, char *cargs[], dbref ncargs, int *nArgsParsed) |
| static char * | parse_arglist_lite (dbref executor, dbref caller, dbref enactor, char *dstr, char delim, int eval, char *fargs[], dbref nfargs, char *cargs[], dbref ncargs, int *nArgsParsed) |
| int | get_gender (dbref player) |
| void | tcache_init (void) |
| static bool | tcache_empty (void) |
| static void | tcache_add (dbref player, char *orig, char *result) |
| static void | tcache_finish (void) |
| char ** | PushPointers (int nNeeded) |
| void | PopPointers (char **p, int nNeeded) |
| int * | PushIntegers (int nNeeded) |
| void | PopIntegers (int *pi, int nNeeded) |
| void | mux_exec (char *buff, char **bufc, dbref executor, dbref caller, dbref enactor, int eval, char **dstr, char *cargs[], int ncargs) |
| void | save_global_regs (const char *funcname, char *preserve[], int preserve_len[]) |
| void | save_and_clear_global_regs (const char *funcname, char *preserve[], int preserve_len[]) |
| void | restore_global_regs (const char *funcname, char *preserve[], int preserve_len[]) |
Variables | |
| static char | isSpecial_L3 [256] |
| static const char | isSpecial_L4 [256] |
| const signed char | mux_RegisterSet [256] |
| static struct tcache_ent * | tcache_head |
| static bool | tcache_top |
| static int | tcache_count |
| const char * | ColorTable [256] |
| static bool | isSpecial_L1 [256] |
| static const unsigned char | isSpecial_L2 [256] |
| static PtrsFrame * | pPtrsFrame = NULL |
| static IntsFrame * | pIntsFrame = NULL |
| #define INTS_PER_FRAME ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(int)) |
| #define isSpecial | ( | table, | |||
| c | ) | isSpecial_##table[(unsigned char)(c)] |
Accesses the isSpecial_ tables with proper typecast.
| table | indicates which table: L1, L2, L3, or L4. | |
| c | character being looked up. |
Definition at line 78 of file eval.cpp.
Referenced by mux_exec(), parse_to(), and parse_to_lite().
| #define NEXTCHAR *zstr++ = *cstr++; |
| #define PTRS_PER_FRAME ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(char *)) |
| #define stacklim 32 |
| #define stacklim 32 |
Referenced by parse_to(), and parse_to_lite().
| typedef struct tag_intsframe IntsFrame |
| typedef struct tag_ptrsframe PtrsFrame |
| typedef struct tcache_ent TCENT |
| int get_gender | ( | dbref | player | ) |
Definition at line 837 of file eval.cpp.
References A_SEX, atr_pget, free_lbuf, and mux_tolower.
Referenced by handle_ears(), and mux_exec().
00838 { 00839 dbref aowner; 00840 int aflags; 00841 char *atr_gotten = atr_pget(player, A_SEX, &aowner, &aflags); 00842 char first = atr_gotten[0]; 00843 free_lbuf(atr_gotten); 00844 switch (mux_tolower(first)) 00845 { 00846 case 'p': 00847 return 4; 00848 00849 case 'm': 00850 return 3; 00851 00852 case 'f': 00853 case 'w': 00854 return 2; 00855 } 00856 return 1; 00857 }
| void mux_exec | ( | char * | buff, | |
| char ** | bufc, | |||
| dbref | executor, | |||
| dbref | caller, | |||
| dbref | enactor, | |||
| int | eval, | |||
| char ** | dstr, | |||
| char * | cargs[], | |||
| int | ncargs | |||
| ) |
Definition at line 1087 of file eval.cpp.
References A_VA, alloc_lbuf, alloc_mbuf, ANSI_ENDGOAL_NORMAL, ANSI_String_Copy(), ANSI_String_Finalize(), ANSI_String_In_Init(), ANSI_String_Out_Init(), ufun::atr, atr_get, atr_pget_str_LEN(), CMuxAlarm::bAlarmed, statedata::bStackLimitReached, check_access(), statedata::curr_cmd, EV_EVAL, EV_FCHECK, EV_FMAND, EV_NO_LOCATION, EV_NOFCHECK, EV_NOTRACE, EV_STRIP_CURLY, EV_TOP, tagFun::flags, ufun::flags, FN_NOEVAL, FN_PRES, FN_PRIV, free_lbuf, free_mbuf, tagFun::fun, statedata::func_htab, statedata::func_invk_ctr, confdata::func_invk_lim, statedata::func_nest_lev, confdata::func_nest_lim, get_gender(), statedata::glob_reg_len, statedata::global_regs, Going, hashfindLEN(), ISOUTOFMEMORY, isSpecial, LBUF_SIZE, MAX_ARG, MAX_GLOBAL_REGS, tagFun::maxArgs, tagFun::maxArgsParsed, MEMALLOC, MEMFREE, tagFun::minArgs, mudconf, mudstate, mux_exec(), mux_isazAZ, mux_isspace, mux_ltoa(), mux_RegisterSet, mux_tolower, mux_toupper, MuxAlarm, tagFun::name, Name, notify, confdata::nStackLimit, statedata::nStackNest, ufun::obj, parse_arglist_lite(), parse_to_lite(), ufun::perms, tagFun::perms, PopIntegers(), PopPointers(), statedata::pout, PushIntegers(), PushPointers(), restore_global_regs(), safe_copy_buf(), safe_noperm, safe_str, save_global_regs(), SBUF_SIZE, confdata::space_compress, tcache_add(), tcache_empty(), tcache_finish(), Trace, confdata::trace_limit, confdata::trace_topdown, statedata::ufunc_htab, and where_is().
Referenced by add_mail_message(), add_prefix(), BuildChannelMessage(), check_filter(), default_handler(), delim_check(), did_it(), do_if(), do_postpend(), do_prepend(), do_switch(), do_think(), do_ufun(), eval_boolexp(), filter_handler(), FUNCTION(), get_exit_dest(), get_handler(), look_contents(), look_exits(), look_in(), mail_return(), modSpeech(), mux_exec(), page_return(), parse_arglist(), parse_arglist_lite(), process_cmdent(), process_command(), process_hook(), process_sex(), ReportTopic(), search_perform(), show_a_desc(), switch_handler(), and u_comp().
01089 { 01090 if ( *dstr == NULL 01091 || **dstr == '\0' 01092 || MuxAlarm.bAlarmed) 01093 { 01094 return; 01095 } 01096 01097 // Stack Limit checking with thanks to RhostMUSH. 01098 // 01099 if (mudconf.nStackLimit < mudstate.nStackNest) 01100 { 01101 mudstate.bStackLimitReached = true; 01102 return; 01103 } 01104 01105 char *TempPtr; 01106 char *tstr, *tbuf, *start, *oldp, *savestr; 01107 const char *constbuf; 01108 int ch; 01109 char *realbuff = NULL, *realbp = NULL; 01110 dbref aowner; 01111 int nfargs, aflags, feval, i; 01112 bool ansi = false; 01113 FUN *fp; 01114 UFUN *ufp; 01115 01116 static const char *subj[5] = {"", "it", "she", "he", "they"}; 01117 static const char *poss[5] = {"", "its", "her", "his", "their"}; 01118 static const char *obj[5] = {"", "it", "her", "him", "them"}; 01119 static const char *absp[5] = {"", "its", "hers", "his", "theirs"}; 01120 01121 // This is scratch buffer is used potentially on every invocation of 01122 // mux_exec. Do not assume that its contents are valid after you 01123 // execute any function that could re-enter mux_exec. 01124 // 01125 static char mux_scratch[LBUF_SIZE]; 01126 01127 char *pdstr = *dstr; 01128 01129 int at_space = 1; 01130 int gender = -1; 01131 01132 bool is_trace = Trace(executor) && !(eval & EV_NOTRACE); 01133 bool is_top = false; 01134 01135 // Extend the buffer if we need to. 01136 // 01137 if (LBUF_SIZE - SBUF_SIZE < (*bufc) - buff) 01138 { 01139 realbuff = buff; 01140 realbp = *bufc; 01141 buff = (char *)MEMALLOC(LBUF_SIZE); 01142 ISOUTOFMEMORY(buff); 01143 *bufc = buff; 01144 } 01145 01146 oldp = start = *bufc; 01147 01148 // If we are tracing, save a copy of the starting buffer. 01149 // 01150 savestr = NULL; 01151 if (is_trace) 01152 { 01153 is_top = tcache_empty(); 01154 savestr = alloc_lbuf("exec.save"); 01155 strcpy(savestr, pdstr); 01156 } 01157 01158 // Save Parser Mode. 01159 // 01160 bool bSpaceIsSpecialSave = isSpecial(L1, ' '); 01161 bool bParenthesisIsSpecialSave = isSpecial(L1, '('); 01162 bool bBracketIsSpecialSave = isSpecial(L1, '['); 01163 01164 // Setup New Parser Mode. 01165 // 01166 bool bSpaceIsSpecial = mudconf.space_compress && !(eval & EV_NO_COMPRESS); 01167 isSpecial(L1, ' ') = bSpaceIsSpecial; 01168 isSpecial(L1, '(') = (eval & EV_FCHECK) != 0; 01169 isSpecial(L1, '[') = (eval & EV_NOFCHECK) == 0; 01170 01171 size_t nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01172 for (;;) 01173 { 01174 // Handle mundane characters specially. There are usually a lot of them. 01175 // Just copy them. 01176 // 01177 if (!isSpecial(L1, *pdstr)) 01178 { 01179 char *p = pdstr + 1; 01180 while (!isSpecial(L1, *p++)) 01181 { 01182 ; // Nothing. 01183 } 01184 size_t n = p - pdstr - 1; 01185 if (nBufferAvailable < n) 01186 { 01187 n = nBufferAvailable; 01188 } 01189 memcpy(*bufc, pdstr, n); 01190 nBufferAvailable -= n; 01191 *bufc += n; 01192 at_space = 0; 01193 pdstr = p - 1; 01194 } 01195 01196 01197 // At this point, **dstr must be one of the following characters: 01198 // 01199 // 0x00 0x20 0x25 0x28 0x5B 0x5C 0x7B 01200 // NULL SP % ( [ \ { 01201 // 01202 // Test softcode shows the following distribution: 01203 // 01204 // NULL occurs 116948 times 01205 // ( occurs 49567 times 01206 // % occurs 24553 times 01207 // [ occurs 7618 times 01208 // SP occurs 1323 times 01209 // 01210 if (*pdstr == '\0') 01211 { 01212 break; 01213 } 01214 else if (*pdstr == '(') 01215 { 01216 // *pdstr == '(' 01217 // 01218 // Arglist start. See if what precedes is a function. If so, 01219 // execute it if we should. 01220 // 01221 at_space = 0; 01222 01223 // Load an sbuf with an lowercase version of the func name, and 01224 // see if the func exists. Trim trailing spaces from the name if 01225 // configured. 01226 // 01227 char *pEnd = *bufc - 1; 01228 if (mudconf.space_compress && (eval & EV_FMAND)) 01229 { 01230 while ( oldp <= pEnd 01231 && mux_isspace(*pEnd)) 01232 { 01233 pEnd--; 01234 } 01235 } 01236 01237 // _strlwr(tbuf); 01238 // 01239 char *p2 = mux_scratch; 01240 for (char *p = oldp; p <= pEnd; p++) 01241 { 01242 *p2++ = mux_tolower(*p); 01243 } 01244 *p2 = '\0'; 01245 01246 int ntbuf = p2 - mux_scratch; 01247 fp = (FUN *)hashfindLEN(mux_scratch, ntbuf, &mudstate.func_htab); 01248 01249 // If not a builtin func, check for global func. 01250 // 01251 ufp = NULL; 01252 if (fp == NULL) 01253 { 01254 ufp = (UFUN *)hashfindLEN(mux_scratch, ntbuf, &mudstate.ufunc_htab); 01255 } 01256 01257 // Do the right thing if it doesn't exist. 01258 // 01259 if (!fp && !ufp) 01260 { 01261 if (eval & EV_FMAND) 01262 { 01263 *bufc = oldp; 01264 safe_str("#-1 FUNCTION (", buff, bufc); 01265 safe_str(mux_scratch, buff, bufc); 01266 safe_str(") NOT FOUND", buff, bufc); 01267 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01268 break; 01269 } 01270 else if (nBufferAvailable) 01271 { 01272 *(*bufc)++ = '('; 01273 nBufferAvailable--; 01274 } 01275 } 01276 else 01277 { 01278 // Get the arglist and count the number of args. Neg # of args 01279 // means catenate subsequent args. 01280 // 01281 if (ufp) 01282 { 01283 nfargs = MAX_ARG; 01284 } 01285 else 01286 { 01287 nfargs = fp->maxArgsParsed; 01288 } 01289 01290 tstr = pdstr; 01291 if ( fp 01292 && (fp->flags & FN_NOEVAL)) 01293 { 01294 feval = eval & ~(EV_EVAL|EV_TOP|EV_STRIP_CURLY); 01295 } 01296 else 01297 { 01298 feval = eval & ~EV_TOP; 01299 } 01300 01301 char **fargs = PushPointers(MAX_ARG); 01302 pdstr = parse_arglist_lite(executor, caller, enactor, 01303 pdstr + 1, ')', feval, fargs, nfargs, cargs, ncargs, 01304 &nfargs); 01305 01306 01307 // If no closing delim, just insert the '(' and continue normally. 01308 // 01309 if (!pdstr) 01310 { 01311 pdstr = tstr; 01312 if (nBufferAvailable) 01313 { 01314 *(*bufc)++ = *pdstr; 01315 nBufferAvailable--; 01316 } 01317 } 01318 else 01319 { 01320 pdstr--; 01321 01322 // If it's a user-defined function, perform it now. 01323 // 01324 mudstate.func_nest_lev++; 01325 mudstate.func_invk_ctr++; 01326 if (mudconf.func_nest_lim <= mudstate.func_nest_lev) 01327 { 01328 safe_str("#-1 FUNCTION RECURSION LIMIT EXCEEDED", buff, &oldp); 01329 } 01330 else if (mudconf.func_invk_lim <= mudstate.func_invk_ctr) 01331 { 01332 safe_str("#-1 FUNCTION INVOCATION LIMIT EXCEEDED", buff, &oldp); 01333 } 01334 else if (Going(executor)) 01335 { 01336 safe_str("#-1 BAD EXECUTOR", buff, &oldp); 01337 } 01338 else if (!check_access(executor, ufp ? ufp->perms : fp->perms)) 01339 { 01340 safe_noperm(buff, &oldp); 01341 } 01342 else if (MuxAlarm.bAlarmed) 01343 { 01344 safe_str("#-1 CPU LIMITED", buff, &oldp); 01345 } 01346 else if (ufp) 01347 { 01348 tstr = atr_get(ufp->obj, ufp->atr, &aowner, &aflags); 01349 if (ufp->flags & FN_PRIV) 01350 { 01351 i = ufp->obj; 01352 } 01353 else 01354 { 01355 i = executor; 01356 } 01357 TempPtr = tstr; 01358 01359 char **preserve = NULL; 01360 int *preserve_len = NULL; 01361 01362 if (ufp->flags & FN_PRES) 01363 { 01364 preserve = PushPointers(MAX_GLOBAL_REGS); 01365 preserve_len = PushIntegers(MAX_GLOBAL_REGS); 01366 save_global_regs("eval_save", preserve, preserve_len); 01367 } 01368 01369 mux_exec(buff, &oldp, i, executor, enactor, feval, 01370 &TempPtr, fargs, nfargs); 01371 01372 if (ufp->flags & FN_PRES) 01373 { 01374 restore_global_regs("eval_restore", preserve, preserve_len); 01375 PopIntegers(preserve_len, MAX_GLOBAL_REGS); 01376 PopPointers(preserve, MAX_GLOBAL_REGS); 01377 preserve = NULL; 01378 preserve_len = NULL; 01379 } 01380 free_lbuf(tstr); 01381 } 01382 else 01383 { 01384 // If the number of args is right, perform the func. 01385 // Otherwise, return an error message. 01386 // 01387 if ( fp->minArgs <= nfargs 01388 && nfargs <= fp->maxArgs 01389 && !MuxAlarm.bAlarmed) 01390 { 01391 fp->fun(buff, &oldp, executor, caller, enactor, 01392 fargs, nfargs, cargs, ncargs); 01393 } 01394 else 01395 { 01396 if (fp->minArgs == fp->maxArgs) 01397 { 01398 sprintf(mux_scratch, 01399 "#-1 FUNCTION (%s) EXPECTS %d ARGUMENTS", 01400 fp->name, fp->minArgs); 01401 } 01402 else if (fp->minArgs + 1 == fp->maxArgs) 01403 { 01404 sprintf(mux_scratch, 01405 "#-1 FUNCTION (%s) EXPECTS %d OR %d ARGUMENTS", 01406 fp->name, fp->minArgs, fp->maxArgs); 01407 } 01408 else if (MuxAlarm.bAlarmed) 01409 { 01410 sprintf(mux_scratch, "#-1 CPU LIMITED"); 01411 } 01412 else 01413 { 01414 sprintf(mux_scratch, 01415 "#-1 FUNCTION (%s) EXPECTS BETWEEN %d AND %d ARGUMENTS", 01416 fp->name, fp->minArgs, fp->maxArgs); 01417 } 01418 safe_str(mux_scratch, buff, &oldp); 01419 } 01420 } 01421 *bufc = oldp; 01422 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01423 mudstate.func_nest_lev--; 01424 } 01425 01426 // Return the space allocated for the arguments. 01427 // 01428 for (i = 0; i < nfargs; i++) 01429 { 01430 free_lbuf(fargs[i]); 01431 } 01432 PopPointers(fargs, MAX_ARG); 01433 fargs = NULL; 01434 } 01435 eval &= ~EV_FCHECK; 01436 isSpecial(L1, '(') = false; 01437 } 01438 else if (*pdstr == '%') 01439 { 01440 // Percent-replace start. Evaluate the chars following and 01441 // perform the appropriate substitution. 01442 // 01443 at_space = 0; 01444 if (!(eval & EV_EVAL)) 01445 { 01446 if (nBufferAvailable) 01447 { 01448 *(*bufc)++ = '%'; 01449 nBufferAvailable--; 01450 } 01451 pdstr++; 01452 if (nBufferAvailable) 01453 { 01454 *(*bufc)++ = *pdstr; 01455 nBufferAvailable--; 01456 } 01457 } 01458 else 01459 { 01460 pdstr++; 01461 ch = *pdstr; 01462 unsigned char cType_L2 = isSpecial(L2, ch); 01463 TempPtr = *bufc; 01464 int iCode = cType_L2 & 0x7F; 01465 if (iCode == 1) 01466 { 01467 // 30 31 32 33 34 35 36 37 38 39 01468 // 0 1 2 3 4 5 6 7 8 9 01469 // 01470 // Command argument number N. 01471 // 01472 i = ch - '0'; 01473 if ( i < ncargs 01474 && cargs[i]) 01475 { 01476 safe_str(cargs[i], buff, bufc); 01477 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01478 } 01479 } 01480 else if (iCode == 2) 01481 { 01482 // 51 01483 // Q 01484 // 01485 pdstr++; 01486 i = mux_RegisterSet[(unsigned char)*pdstr]; 01487 if ( 0 <= i 01488 && i < MAX_GLOBAL_REGS) 01489 { 01490 if ( mudstate.glob_reg_len[i] > 0 01491 && mudstate.global_regs[i]) 01492 { 01493 safe_copy_buf(mudstate.global_regs[i], 01494 mudstate.glob_reg_len[i], buff, bufc); 01495 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01496 } 01497 } 01498 else if (*pdstr == '\0') 01499 { 01500 pdstr--; 01501 } 01502 } 01503 else if (iCode <= 4) 01504 { 01505 if (iCode == 3) 01506 { 01507 // 23 01508 // # 01509 // 01510 // Enactor DB number. 01511 // 01512 mux_scratch[0] = '#'; 01513 i = mux_ltoa(enactor, mux_scratch+1); 01514 safe_copy_buf(mux_scratch, i+1, buff, bufc); 01515 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01516 } 01517 else if (iCode == 4) 01518 { 01519 // 21 01520 // ! 01521 // 01522 // iCode == '!' 01523 // Executor DB number. 01524 // 01525 mux_scratch[0] = '#'; 01526 i = mux_ltoa(executor, mux_scratch+1); 01527 safe_copy_buf(mux_scratch, i+1, buff, bufc); 01528 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01529 } 01530 else 01531 { 01532 // iCode == 0 01533 // 01534 // Just copy 01535 // 01536 if (nBufferAvailable) 01537 { 01538 *(*bufc)++ = ch; 01539 nBufferAvailable--; 01540 } 01541 } 01542 } 01543 else if (iCode <= 6) 01544 { 01545 if (iCode == 6) 01546 { 01547 // 43 58 01548 // C X 01549 // 01550 // Color 01551 // 01552 const char *pColor = ColorTable[(unsigned char)pdstr[1]]; 01553 if (pColor) 01554 { 01555 pdstr++; 01556 ansi = true; 01557 safe_str(pColor, buff, bufc); 01558 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01559 } 01560 else if (pdstr[1] && nBufferAvailable) 01561 { 01562 *(*bufc)++ = *pdstr; 01563 nBufferAvailable--; 01564 } 01565 } 01566 else 01567 { 01568 // 52 01569 // R 01570 // 01571 // Carriage return. 01572 // 01573 safe_copy_buf("\r\n", 2, buff, bufc); 01574 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01575 } 01576 } 01577 else if (iCode <= 8) 01578 { 01579 if (iCode == 7) 01580 { 01581 // 42 01582 // B 01583 // 01584 // Blank. 01585 // 01586 if (nBufferAvailable) 01587 { 01588 *(*bufc)++ = ' '; 01589 nBufferAvailable--; 01590 } 01591 } 01592 else 01593 { 01594 // 54 01595 // T 01596 // 01597 // Tab. 01598 // 01599 if (nBufferAvailable) 01600 { 01601 *(*bufc)++ = '\t'; 01602 nBufferAvailable--; 01603 } 01604 } 01605 } 01606 else if (iCode <= 10) 01607 { 01608 if (iCode == 9) 01609 { 01610 // 4C 01611 // L 01612 // 01613 // Enactor Location DB Ref 01614 // 01615 if (!(eval & EV_NO_LOCATION)) 01616 { 01617 mux_scratch[0] = '#'; 01618 i = mux_ltoa(where_is(enactor), mux_scratch+1); 01619 safe_copy_buf(mux_scratch, i+1, buff, bufc); 01620 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01621 } 01622 } 01623 else 01624 { 01625 // 56 01626 // V 01627 // 01628 // Variable attribute. 01629 // 01630 pdstr++; 01631 if (mux_isazAZ(*pdstr)) 01632 { 01633 i = A_VA + mux_toupper(*pdstr) - 'A'; 01634 size_t nAttrGotten; 01635 atr_pget_str_LEN(mux_scratch, executor, i, 01636 &aowner, &aflags, &nAttrGotten); 01637 if (0 < nAttrGotten) 01638 { 01639 if (nAttrGotten > nBufferAvailable) 01640 { 01641 nAttrGotten = nBufferAvailable; 01642 } 01643 memcpy(*bufc, mux_scratch, nAttrGotten); 01644 *bufc += nAttrGotten; 01645 nBufferAvailable -= nAttrGotten; 01646 } 01647 } 01648 else if (*pdstr == '\0') 01649 { 01650 pdstr--; 01651 } 01652 } 01653 } 01654 else if (iCode <= 14) 01655 { 01656 if (iCode <= 12) 01657 { 01658 if (iCode == 11) 01659 { 01660 // 25 01661 // % 01662 // 01663 // Percent - a literal % 01664 // 01665 if (nBufferAvailable) 01666 { 01667 *(*bufc)++ = '%'; 01668 nBufferAvailable--; 01669 } 01670 } 01671 else 01672 { 01673 // 4E 01674 // N 01675 // 01676 // Enactor name 01677 // 01678 safe_str(Name(enactor), buff, bufc); 01679 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01680 } 01681 } 01682 else 01683 { 01684 if (iCode == 13) 01685 { 01686 // 7C 01687 // | 01688 // 01689 // piped command output. 01690 // 01691 safe_str(mudstate.pout, buff, bufc); 01692 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01693 } 01694 else 01695 { 01696 // 53 01697 // S 01698 // 01699 // Subjective pronoun. 01700 // 01701 if (gender < 0) 01702 { 01703 gender = get_gender(enactor); 01704 } 01705 if (!gender) 01706 { 01707 constbuf = Name(enactor); 01708 } 01709 else 01710 { 01711 constbuf = subj[gender]; 01712 } 01713 safe_str(constbuf, buff, bufc); 01714 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01715 } 01716 } 01717 } 01718 else 01719 { 01720 if (iCode <= 16) 01721 { 01722 if (iCode == 15) 01723 { 01724 // 50 01725 // P 01726 // 01727 // Personal pronoun. 01728 // 01729 if (gender < 0) 01730 { 01731 gender = get_gender(enactor); 01732 } 01733 01734 if (!gender) 01735 { 01736 safe_str(Name(enactor), buff, bufc); 01737 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01738 if (nBufferAvailable) 01739 { 01740 *(*bufc)++ = 's'; 01741 nBufferAvailable--; 01742 } 01743 } 01744 else 01745 { 01746 safe_str((char *)poss[gender], buff, bufc); 01747 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01748 } 01749 } 01750 else 01751 { 01752 // 4F 01753 // O 01754 // 01755 // Objective pronoun. 01756 // 01757 if (gender < 0) 01758 { 01759 gender = get_gender(enactor); 01760 } 01761 if (!gender) 01762 { 01763 constbuf = Name(enactor); 01764 } 01765 else 01766 { 01767 constbuf = obj[gender]; 01768 } 01769 safe_str(constbuf, buff, bufc); 01770 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01771 } 01772 } 01773 else 01774 { 01775 if (iCode == 17) 01776 { 01777 // 41 01778 // A 01779 // 01780 // Absolute posessive. 01781 // Idea from Empedocles. 01782 // 01783 if (gender < 0) 01784 { 01785 gender = get_gender(enactor); 01786 } 01787 01788 if (!gender) 01789 { 01790 safe_str(Name(enactor), buff, bufc); 01791 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01792 if (nBufferAvailable) 01793 { 01794 *(*bufc)++ = 's'; 01795 nBufferAvailable--; 01796 } 01797 } 01798 else 01799 { 01800 safe_str(absp[gender], buff, bufc); 01801 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01802 } 01803 } 01804 else if (iCode == 18) 01805 { 01806 // 00 01807 // \0 01808 // 01809 // All done. 01810 // 01811 pdstr--; 01812 } 01813 else if (iCode == 19) 01814 { 01815 // 4D 01816 // M 01817 // 01818 // Last command 01819 // 01820 safe_str(mudstate.curr_cmd, buff, bufc); 01821 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01822 } 01823 else 01824 { 01825 // 40 01826 // @ 01827 // 01828 // iCode == '@' 01829 // Caller DB number. 01830 // 01831 mux_scratch[0] = '#'; 01832 i = mux_ltoa(caller, mux_scratch+1); 01833 safe_copy_buf(mux_scratch, i+1, buff, bufc); 01834 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01835 } 01836 } 01837 } 01838 01839 // For some escape letters, if the escape letter 01840 // was upper-case, then upper-case the first 01841 // letter of the value. 01842 // 01843 if (cType_L2 & 0x80) 01844 { 01845 *TempPtr = mux_toupper(*TempPtr); 01846 } 01847 } 01848 } 01849 else if (*pdstr == '[') 01850 { 01851 // Function start. Evaluate the contents of the square brackets 01852 // as a function. If no closing bracket, insert the '[' and 01853 // continue. 01854 // 01855 tstr = pdstr++; 01856 mudstate.nStackNest++; 01857 tbuf = parse_to_lite(&pdstr, ']', '\0', &at_space, &at_space); 01858 at_space = 0; 01859 if (pdstr == NULL) 01860 { 01861 if (nBufferAvailable) 01862 { 01863 *(*bufc)++ = '['; 01864 nBufferAvailable--; 01865 } 01866 pdstr = tstr; 01867 } 01868 else 01869 { 01870 mudstate.nStackNest--; 01871 TempPtr = tbuf; 01872 mux_exec(buff, bufc, executor, caller, enactor, 01873 (eval | EV_FCHECK | EV_FMAND) & ~EV_TOP, &TempPtr, cargs, 01874 ncargs); 01875 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01876 pdstr--; 01877 } 01878 } 01879 01880 // At this point, *pdstr must be one of the following characters: 01881 // 01882 // 0x20 0x5C 0x7B 01883 // SP \ { 01884 // 01885 else if (*pdstr == ' ') 01886 { 01887 // A space. Add a space if not compressing or if previous char was 01888 // not a space. 01889 // 01890 if (bSpaceIsSpecial && !at_space) 01891 { 01892 if (nBufferAvailable) 01893 { 01894 *(*bufc)++ = ' '; 01895 nBufferAvailable--; 01896 } 01897 at_space = 1; 01898 } 01899 } 01900 else if (*pdstr == '{') 01901 { 01902 // *pdstr == '{' 01903 // 01904 // Literal start. Insert everything up to the terminating '}' 01905 // without parsing. If no closing brace, insert the '{' and 01906 // continue. 01907 // 01908 tstr = pdstr++; 01909 mudstate.nStackNest++; 01910 tbuf = parse_to_lite(&pdstr, '}', '\0', &at_space, &at_space); 01911 at_space = 0; 01912 if (pdstr == NULL) 01913 { 01914 if (nBufferAvailable) 01915 { 01916 *(*bufc)++ = '{'; 01917 nBufferAvailable--; 01918 } 01919 pdstr = tstr; 01920 } 01921 else 01922 { 01923 mudstate.nStackNest--; 01924 if (!(eval & EV_STRIP_CURLY)) 01925 { 01926 if (nBufferAvailable) 01927 { 01928 *(*bufc)++ = '{'; 01929 nBufferAvailable--; 01930 } 01931 } 01932 01933 if (eval & EV_EVAL) 01934 { 01935 // Preserve leading spaces (Felan) 01936 // 01937 if (*tbuf == ' ') 01938 { 01939 if (nBufferAvailable) 01940 { 01941 *(*bufc)++ = ' '; 01942 nBufferAvailable--; 01943 } 01944 tbuf++; 01945 } 01946 01947 TempPtr = tbuf; 01948 mux_exec(buff, bufc, executor, caller, enactor, 01949 (eval & ~(EV_STRIP_CURLY | EV_FCHECK | EV_TOP)), 01950 &TempPtr, cargs, ncargs); 01951 } 01952 else 01953 { 01954 TempPtr = tbuf; 01955 mux_exec(buff, bufc, executor, caller, enactor, 01956 eval & ~EV_TOP, &TempPtr, cargs, ncargs); 01957 } 01958 nBufferAvailable = LBUF_SIZE - (*bufc - buff) - 1; 01959 01960 if (!(eval & EV_STRIP_CURLY)) 01961 { 01962 if (nBufferAvailable) 01963 { 01964 *(*bufc)++ = '}'; 01965 nBufferAvailable--; 01966 } 01967 } 01968 pdstr--; 01969 } 01970 } 01971 else if (*pdstr == '\\') 01972 { 01973 // *pdstr must be \. 01974 // 01975 // General escape. Add the following char without special 01976 // processing. 01977 // 01978 at_space = 0; 01979 pdstr++; 01980 if (*pdstr) 01981 { 01982 if (nBufferAvailable) 01983 { 01984 *(*bufc)++ = *pdstr; 01985 nBufferAvailable--; 01986 } 01987 } 01988 else 01989 { 01990 pdstr--; 01991 } 01992 } 01993 else 01994 { 01995 // *pdstr must be ESC. 01996 // 01997 at_space = 0; 01998 if (nBufferAvailable) 01999 { 02000 *(*bufc)++ = *pdstr; 02001 nBufferAvailable--; 02002 } 02003 pdstr++; 02004 if (*pdstr) 02005 { 02006 if (nBufferAvailable) 02007 { 02008 *(*bufc)++ = *pdstr; 02009 nBufferAvailable--; 02010 } 02011 } 02012 else 02013 { 02014 pdstr--; 02015 } 02016 } 02017 pdstr++; 02018 } 02019 02020 // If we're eating spaces, and the last thing was a space, eat it up. 02021 // Complicated by the fact that at_space is initially true. So check to 02022 // see if we actually put something in the buffer, too. 02023 // 02024 if ( bSpaceIsSpecial 02025 && at_space 02026 && start != *bufc) 02027 { 02028 (*bufc)--; 02029 } 02030 02031 **bufc = '\0'; 02032 02033 // Collect and report trace information. 02034 // 02035 if (is_trace) 02036 { 02037 tcache_add(executor, savestr, start); 02038 if ( is_top 02039 || !mudconf.trace_topdown) 02040 { 02041 tcache_finish(); 02042 } 02043 if ( is_top 02044 && 0 < tcache_count - mudconf.trace_limit) 02045 { 02046 tbuf = alloc_mbuf("exec.trace_diag"); 02047 sprintf(tbuf, "%d lines of trace output discarded.", tcache_count 02048 - mudconf.trace_limit); 02049 notify(executor, tbuf); 02050 free_mbuf(tbuf); 02051 } 02052 } 02053 02054 if ( realbuff 02055 || ansi 02056 || (eval & EV_TOP)) 02057 { 02058 // We need to transfer and/or ANSI optimize the result. 02059 // 02060 static struct ANSI_In_Context aic; 02061 static struct