mux/src/eval.cpp File Reference

#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_enttcache_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 PtrsFramepPtrsFrame = NULL
static IntsFramepIntsFrame = NULL


Define Documentation

#define INTS_PER_FRAME   ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(int))

Definition at line 1049 of file eval.cpp.

Referenced by PopIntegers(), and PushIntegers().

#define isSpecial ( table,
 )     isSpecial_##table[(unsigned char)(c)]

Accesses the isSpecial_ tables with proper typecast.

Parameters:
table indicates which table: L1, L2, L3, or L4.
c character being looked up.
Returns:
lvalue of table entry.

Definition at line 78 of file eval.cpp.

Referenced by mux_exec(), parse_to(), and parse_to_lite().

#define NEXTCHAR   *zstr++ = *cstr++;

Definition at line 164 of file eval.cpp.

Referenced by parse_to().

#define PTRS_PER_FRAME   ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(char *))

Definition at line 1011 of file eval.cpp.

Referenced by PopPointers(), and PushPointers().

#define stacklim   32

#define stacklim   32

Referenced by parse_to(), and parse_to_lite().


Typedef Documentation

typedef struct tag_intsframe IntsFrame

typedef struct tag_ptrsframe PtrsFrame

typedef struct tcache_ent TCENT

Definition at line 862 of file eval.cpp.


Function Documentation

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