mux/src/eval.cpp

Go to the documentation of this file.
00001 // eval.cpp -- Command evaluation and cracking.
00002 //
00003 // $Id: eval.cpp,v 1.34 2006/09/11 23:57:47 sdennis Exp $
00004 //
00005 // MUX 2.4
00006 // Copyright (C) 1998 through 2004 Solid Vertical Domains, Ltd. All
00007 // rights not explicitly given are reserved.
00008 //
00009 #include "copyright.h"
00010 #include "autoconf.h"
00011 #include "config.h"
00012 #include "externs.h"
00013 
00014 #include "ansi.h"
00015 #include "attrs.h"
00016 #include "functions.h"
00017 
00018 //-----------------------------------------------------------------------------
00019 // parse_to: Split a line at a character, obeying nesting.  The line is
00020 // destructively modified (a null is inserted where the delimiter was found)
00021 // dstr is modified to point to the char after the delimiter, and the function
00022 // return value points to the found string (space compressed if specified). If
00023 // we ran off the end of the string without finding the delimiter, dstr is
00024 // returned as NULL.
00025 //
00026 static char *parse_to_cleanup( int eval, int first, char *cstr, char *rstr,
00027                                char *zstr, char *strFirewall)
00028 {
00029     if (  (  mudconf.space_compress
00030           || (eval & EV_STRIP_TS))
00031        && !(eval & EV_NO_COMPRESS)
00032        && !first
00033        && strFirewall < cstr
00034        && cstr[-1] == ' ')
00035     {
00036         zstr--;
00037     }
00038 
00039     if (  (eval & EV_STRIP_AROUND)
00040        && *rstr == '{'
00041        && strFirewall < zstr
00042        && zstr[-1] == '}')
00043     {
00044         rstr++;
00045         if (  (  mudconf.space_compress
00046               && !(eval & EV_NO_COMPRESS))
00047            || (eval & EV_STRIP_LS))
00048         {
00049             while (mux_isspace(*rstr))
00050             {
00051                 rstr++;
00052             }
00053         }
00054         rstr[-1] = '\0';
00055         zstr--;
00056         if (  (  mudconf.space_compress
00057               && !(eval & EV_NO_COMPRESS))
00058            || (eval & EV_STRIP_TS))
00059         {
00060             while (  strFirewall < zstr
00061                   && mux_isspace(zstr[-1]))
00062             {
00063                 zstr--;
00064             }
00065         }
00066         *zstr = '\0';
00067     }
00068     *zstr = '\0';
00069     return rstr;
00070 }
00071 
00078 #define isSpecial(table, c) isSpecial_##table[(unsigned char)(c)]
00079 
00080 // During parsing, this table may be modified for a particular terminating delimeter.
00081 // The table is always restored it's original state.
00082 //
00083 // 0 means mundane character.
00084 // 1 is 0x20 ' '  delim overridable (only done by parse_to, not parse_to_lite)
00085 // 2 is 0x5B '['  delim overridable
00086 // 3 is 0x28 '('  delim overridable
00087 // 4 is 0x25 '%', 0x5C '\\', or 0x1B ESC not overridable.
00088 // 5 is 0x29 ')' or 0x5D ']'  not overridable.
00089 // 6 is 0x7B '{' not overridable.
00090 // 7 is 0x00 '\0' not overridable.
00091 // 8 is the client-specific terminator.
00092 //
00093 // A code 4 or above means that the client-specified delim cannot override it.
00094 // A code 8 is temporary.
00095 //
00096 static char isSpecial_L3[256] =
00097 {
00098     7, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F
00099     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 4, 0, 0, 0, 0, // 0x10-0x1F
00100     0, 0, 0, 0, 0, 4, 0, 0,  3, 5, 0, 0, 0, 0, 0, 0, // 0x20-0x2F
00101     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F
00102     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x4F
00103     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 2, 4, 5, 0, 0, // 0x50-0x5F
00104     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6F
00105     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 6, 0, 0, 0, 0, // 0x70-0x7F
00106     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F
00107     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F
00108     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF
00109     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF
00110     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF
00111     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF
00112     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF
00113     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0  // 0xF0-0xFF
00114 };
00115 
00116 static const char isSpecial_L4[256] =
00117 {
00118     4, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F
00119     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 1, 0, 0, 0, 0, // 0x10-0x1F
00120     0, 0, 0, 0, 0, 1, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2F
00121     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F
00122     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x4F
00123     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 1, 0, 0, 0, // 0x50-0x5F
00124     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6F
00125     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 2, 0, 3, 0, 0, // 0x70-0x7F
00126     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F
00127     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F
00128     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF
00129     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF
00130     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF
00131     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF
00132     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF
00133     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0  // 0xF0-0xFF
00134 };
00135 
00136 // Characters that are valid q-registers, and their offsets in the register
00137 // array. -1 for invalid registers.
00138 //
00139 const signed char mux_RegisterSet[256] =
00140 {
00141     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x00-0x0F
00142     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x10-0x1F
00143     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x20-0x2F
00144      0, 1, 2, 3, 4, 5, 6, 7,  8, 9,-1,-1,-1,-1,-1,-1, // 0x30-0x3F
00145     -1,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24, // 0x40-0x4F
00146     25,26,27,28,29,30,31,32, 33,34,35,-1,-1,-1,-1,-1, // 0x50-0x5F
00147     -1,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24, // 0x60-0x6F
00148     25,26,27,28,29,30,31,32, 33,34,35,-1,-1,-1,-1,-1, // 0x70-0x7F
00149     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x80-0x8F
00150     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0x90-0x9F
00151     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xA0-0xAF
00152     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xB0-0xBF
00153     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xC0-0xCF
00154     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xD0-0xDF
00155     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, // 0xE0-0xEF
00156     -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1  // 0xF0-0xFF
00157 };
00158 
00159 // Stephen: Some silly compilers don't handle aliased pointers well. For these
00160 // compilers, we can't change this to just '*zstr++ = *cstr++'. However all
00161 // up-to-date compilers that I know about handle this correctly.
00162 //
00163 #if 1
00164 #define NEXTCHAR *zstr++ = *cstr++;
00165 #else
00166 #define NEXTCHAR \
00167     if (cstr == zstr) \
00168     { \
00169         cstr++; \
00170         zstr++; \
00171     } \
00172     else \
00173     { \
00174         *zstr++ = *cstr++; \
00175     }
00176 #endif
00177 
00178 
00179 char *parse_to(char **dstr, char delim, int eval)
00180 {
00181 #define stacklim 32
00182     char stack[stacklim];
00183     char *rstr, *cstr, *zstr, *strFirewall;
00184     int sp, tp, bracketlev;
00185 
00186     if (  dstr == NULL
00187        || *dstr == NULL)
00188     {
00189         return NULL;
00190     }
00191 
00192     if (**dstr == '\0')
00193     {
00194         rstr = *dstr;
00195         *dstr = NULL;
00196         return rstr;
00197     }
00198     sp = 0;
00199     bool first = true;
00200     strFirewall = rstr = *dstr;
00201     if (  (  mudconf.space_compress
00202           || (eval & EV_STRIP_LS))
00203        && !(eval & EV_NO_COMPRESS))
00204     {
00205         while (mux_isspace(*rstr))
00206         {
00207             rstr++;
00208         }
00209         *dstr = rstr;
00210     }
00211     zstr = cstr = rstr;
00212     int iOriginalCode = isSpecial(L3, delim);
00213     isSpecial(L3, ' ') = 1; // Spaces are special.
00214     if (iOriginalCode <= 3)
00215     {
00216         // We can override this code.
00217         //
00218         isSpecial(L3, delim) = 8;
00219     }
00220 
00221     for (;;)
00222     {
00223         int iCode = isSpecial(L3, *cstr);
00224 
00225 TryAgain:
00226         if (iCode == 0)
00227         {
00228             // Mundane characters and not the delimiter we are looking for.
00229             //
00230             first = false;
00231             do
00232             {
00233                 NEXTCHAR
00234                 iCode = isSpecial(L3, *cstr);
00235             } while (iCode == 0);
00236         }
00237 
00238         if (iCode <= 4)
00239         {
00240             // 1 is 0x20 ' '  delim overridable
00241             // 2 is 0x5B '['  delim overridable
00242             // 3 is 0x28 '('  delim overridable
00243             // 4 is 0x25 '%', 0x5C '\\', or 0x1B ESC not overridable.
00244             //
00245             if (iCode <= 2)
00246             {
00247                 // 1 is 0x20 ' '  delim overridable
00248                 // 2 is 0x5B '['  delim overridable
00249                 //
00250                 if (iCode == 1)
00251                 {
00252                     // space
00253                     //
00254                     if (  mudconf.space_compress
00255                        && !(eval & EV_NO_COMPRESS))
00256                     {
00257                         if (first)
00258                         {
00259                             rstr++;
00260                         }
00261                         else if (  strFirewall < cstr
00262                                 && cstr[-1] == ' ')
00263                         {
00264                             zstr--;
00265                         }
00266                     }
00267                     NEXTCHAR
00268                 }
00269                 else
00270                 {
00271                     // '['
00272                     //
00273                     first = false;
00274                     if (sp < stacklim)
00275                     {
00276                         stack[sp++] = ']';
00277                     }
00278                     NEXTCHAR
00279                 }
00280             }
00281             else
00282             {
00283                 // 3 is 0x28 '('  delim overridable
00284                 // 4 is 0x25 '%', 0x5C '\\', or 0x1B ESC not overridable.
00285                 //
00286                 if (iCode == 3)
00287                 {
00288                     first = false;
00289                     if (sp < stacklim)
00290                     {
00291                         stack[sp++] = ')';
00292                     }
00293                     NEXTCHAR
00294                 }
00295                 else
00296                 {
00297                     // %, \, and ESC escapes.
00298                     //
00299                     first = false;
00300                     NEXTCHAR
00301                     if (*cstr)
00302                     {
00303                         NEXTCHAR
00304                     }
00305                 }
00306             }
00307         }
00308         else
00309         {
00310             // 5 is 0x29 ')' or 0x5D ']'  not overridable.
00311             // 6 is 0x7B '{' not overridable.
00312             // 7 is 0x00 '\0' not overridable.
00313             // 8 is the client-specific terminator.
00314             //
00315             if (iCode <= 6)
00316             {
00317                 // 5 is 0x29 ')' or 0x5D ']'  not overridable.
00318                 // 6 is 0x7B '{' not overridable.
00319                 //
00320                 if (iCode == 5)
00321                 {
00322                     // ) and ]
00323                     //
00324                     for (tp = sp - 1; tp >= 0 && stack[tp] != *cstr; tp--)
00325                     {
00326                         ; // Nothing.
00327                     }
00328 
00329                     // If we hit something on the stack, unwind to it. Otherwise (it's
00330                     // not on stack), if it's our delim we are done, and we convert the
00331                     // delim to a null and return a ptr to the char after the null. If
00332                     // it's not our delimiter, skip over it normally.
00333                     //
00334                     if (tp >= 0)
00335                     {
00336                         sp = tp;
00337                     }
00338                     else if (*cstr == delim)
00339                     {
00340                         rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr, strFirewall);
00341                         *dstr = ++cstr;
00342                         isSpecial(L3, delim) = iOriginalCode;
00343                         isSpecial(L3, ' ') = 0; // Spaces no longer special
00344                         return rstr;
00345                     }
00346                     first = false;
00347                     NEXTCHAR
00348                 }
00349                 else
00350                 {
00351                     // {
00352                     //
00353                     bracketlev = 1;
00354                     if (eval & EV_STRIP_CURLY)
00355                     {
00356                         cstr++;
00357                     }
00358                     else
00359                     {
00360                         NEXTCHAR;
00361                     }
00362                     for (;;)
00363                     {
00364                         int iCodeL4 = isSpecial(L4, *cstr);
00365                         if (iCodeL4 == 0)
00366                         {
00367                             // Mudane Characters
00368                             //
00369                             do
00370                             {
00371                                 NEXTCHAR
00372                                 iCodeL4 = isSpecial(L4, *cstr);
00373                             } while (iCodeL4 == 0);
00374                         }
00375 
00376 
00377                         if (iCodeL4 == 1)
00378                         {
00379                             // %, \, and ESC escapes.
00380                             //
00381                             if (cstr[1])
00382                             {
00383                                 NEXTCHAR
00384                             }
00385                         }
00386                         else if (iCodeL4 == 2)
00387                         {
00388                             // '{'
00389                             //
00390                             bracketlev++;
00391                         }
00392                         else if (iCodeL4 == 3)
00393                         {
00394                             // '}'
00395                             //
00396                             bracketlev--;
00397                             if (bracketlev <= 0)
00398                             {
00399                                 break;
00400                             }
00401                         }
00402                         else
00403                         {
00404                             // '\0'
00405                             //
00406                             break;
00407                         }
00408                         NEXTCHAR
00409                     }
00410 
00411                     if (bracketlev == 0)
00412                     {
00413                         if (eval & EV_STRIP_CURLY)
00414                         {
00415                             cstr++;
00416                         }
00417                         else
00418                         {
00419                             NEXTCHAR
00420                         }
00421                     }
00422                     first = false;
00423                 }
00424             }
00425             else
00426             {
00427                 // 7 is 0x00 '\0' not overridable.
00428                 // 8 is the client-specific terminator.
00429                 //
00430                 if (iCode == 7)
00431                 {
00432                     // '\0' - End of string.
00433                     //
00434                     isSpecial(L3, delim) = iOriginalCode;
00435                     isSpecial(L3, ' ') = 0; // Spaces no longer special
00436                     break;
00437                 }
00438                 else
00439                 {
00440                     // Client-Specific terminator
00441                     //
00442                     if (sp == 0)
00443                     {
00444                         rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr, strFirewall);
00445                         *dstr = ++cstr;
00446                         isSpecial(L3, delim) = iOriginalCode;
00447                         isSpecial(L3, ' ') = 0; // Spaces no longer special
00448                         return rstr;
00449                     }
00450 
00451                     // At this point, we need to process the iOriginalCode.
00452                     //
00453                     iCode = iOriginalCode;
00454                     goto TryAgain;
00455                 }
00456             }
00457         }
00458     }
00459     rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr, strFirewall);
00460     *dstr = NULL;
00461     return rstr;
00462 }
00463 
00464 // This version parse_to is less destructive. It only null-terminates the source
00465 // It doesn't process escapes. It's useful with mux_exec which will be copying
00466 // the characters to another buffer anyway and is more than able to perform the
00467 // escapes and trimming.
00468 //
00469 static char *parse_to_lite(char **dstr, char delim1, char delim2, int *nLen, int *iWhichDelim)
00470 {
00471 #define stacklim 32
00472     char stack[stacklim];
00473     char *rstr, *cstr;
00474     int sp, tp, bracketlev;
00475 
00476     if (  dstr == NULL
00477        || *dstr == NULL)
00478     {
00479         *nLen = 0;
00480         return NULL;
00481     }
00482 
00483     if (**dstr == '\0')
00484     {
00485         rstr = *dstr;
00486         *dstr = NULL;
00487         *nLen = 0;
00488         return rstr;
00489     }
00490     sp = 0;
00491     cstr = rstr = *dstr;
00492     int iOriginalCode1 = isSpecial(L3, delim1);
00493     int iOriginalCode2 = isSpecial(L3, delim2);
00494     if (iOriginalCode1 <= 3)
00495     {
00496         // We can override this code.
00497         //
00498         isSpecial(L3, delim1) = 8;
00499     }
00500     if (iOriginalCode2 <= 3)
00501     {
00502         // We can override this code.
00503         //
00504         isSpecial(L3, delim2) = 8;
00505     }
00506 
00507     for (;;)
00508     {
00509         int iCode = isSpecial(L3, *cstr);
00510 
00511 TryAgain:
00512         if (iCode == 0)
00513         {
00514             // Mundane characters and not the delimiter we are looking for.
00515             //
00516             do
00517             {
00518                 cstr++;
00519                 iCode = isSpecial(L3, *cstr);
00520             } while (iCode == 0);
00521         }
00522 
00523         if (iCode <= 4)
00524         {
00525             // 2 is 0x5B '['  delim overridable
00526             // 3 is 0x28 '('  delim overridable
00527             // 4 is 0x25 '%' or 0x5C '\\' not overridable.
00528             //
00529             if (iCode <= 3)
00530             {
00531                 // 2 is 0x5B '['  delim overridable
00532                 // 3 is 0x28 '('  delim overridable
00533                 //
00534                 if (sp < stacklim)
00535                 {
00536                     static char matcher[2] = { ']', ')'};
00537                     stack[sp++] = matcher[iCode-2];
00538                 }
00539                 cstr++;
00540             }
00541             else
00542             {
00543                 // 4 is 0x25 '%' or 0x5C '\\' not overridable.
00544                 //
00545                 cstr++;
00546                 if (*cstr)
00547                 {
00548                     cstr++;
00549                 }
00550             }
00551         }
00552         else
00553         {
00554             // 5 is 0x29 ')' or 0x5D ']'  not overridable.
00555             // 6 is 0x7B '{' not overridable.
00556             // 7 is 0x00 '\0' not overridable.
00557             // 8 is the client-specific terminator.
00558             //
00559             if (iCode <= 6)
00560             {
00561                 // 5 is 0x29 ')' or 0x5D ']'  not overridable.
00562                 // 6 is 0x7B '{' not overridable.
00563                 //
00564                 if (iCode == 5)
00565                 {
00566                     // ) and ]
00567                     //
00568                     for (tp = sp - 1; tp >= 0 && stack[tp] != *cstr; tp--)
00569                     {
00570                         ; // Nothing.
00571                     }
00572 
00573                     // If we hit something on the stack, unwind to it. Otherwise (it's
00574                     // not on stack), if it's our delim we are done, and we convert the
00575                     // delim to a null and return a ptr to the char after the null. If
00576                     // it's not our delimiter, skip over it normally.
00577                     //
00578                     if (0 <= tp)
00579                     {
00580                         sp = tp;
00581                     }
00582                     else if (  *cstr == delim1
00583                             || *cstr == delim2)
00584                     {
00585                         if (*cstr == delim1)
00586                         {
00587                             *iWhichDelim = 1;
00588                         }
00589                         else
00590                         {
00591                             *iWhichDelim = 2;
00592                         }
00593                         *cstr = '\0';
00594                         *nLen = (cstr - rstr);
00595                         *dstr = ++cstr;
00596                         isSpecial(L3, delim1) = iOriginalCode1;
00597                         isSpecial(L3, delim2) = iOriginalCode2;
00598                         return rstr;
00599                     }
00600                     cstr++;
00601                 }
00602                 else
00603                 {
00604                     // {
00605                     //
00606                     bracketlev = 1;
00607                     cstr++;
00608                     for (;;)
00609                     {
00610                         int iCodeL4 = isSpecial(L4, *cstr);
00611                         if (iCodeL4 == 0)
00612                         {
00613                             // Mudane Characters
00614                             //
00615                             do
00616                             {
00617                                 cstr++;
00618                                 iCodeL4 = isSpecial(L4, *cstr);
00619                             } while (iCodeL4 == 0);
00620                         }
00621 
00622 
00623                         if (iCodeL4 == 1)
00624                         {
00625                             // '\\' or '%'
00626                             //
00627                             if (cstr[1])
00628                             {
00629                                 cstr++;
00630                             }
00631                         }
00632                         else if (iCodeL4 == 2)
00633                         {
00634                             // '{'
00635                             //
00636                             bracketlev++;
00637                         }
00638                         else if (iCodeL4 == 3)
00639                         {
00640                             // '}'
00641                             //
00642                             bracketlev--;
00643                             if (bracketlev <= 0)
00644                             {
00645                                 break;
00646                             }
00647                         }
00648                         else
00649                         {
00650                             // '\0'
00651                             //
00652                             break;
00653                         }
00654                         cstr++;
00655                     }
00656 
00657                     if (bracketlev == 0)
00658                     {
00659                         cstr++;
00660                     }
00661                 }
00662             }
00663             else
00664             {
00665                 // 7 is 0x00 '\0' not overridable.
00666                 // 8 is the client-specific terminator.
00667                 //
00668                 if (iCode == 7)
00669                 {
00670                     // '\0' - End of string.
00671                     //
00672                     isSpecial(L3, delim1) = iOriginalCode1;
00673                     isSpecial(L3, delim2) = iOriginalCode2;
00674                     break;
00675                 }
00676                 else
00677                 {
00678                     // Client-Specific terminator
00679                     //
00680                     if (sp == 0)
00681                     {
00682                         if (*cstr == delim1)
00683                         {
00684                             *iWhichDelim = 1;
00685                         }
00686                         else
00687                         {
00688                             *iWhichDelim = 2;
00689                         }
00690                         *cstr = '\0';
00691                         *nLen = (cstr - rstr);
00692                         *dstr = ++cstr;
00693                         isSpecial(L3, delim1) = iOriginalCode1;
00694                         isSpecial(L3, delim2) = iOriginalCode2;
00695                         return rstr;
00696                     }
00697 
00698                     // At this point, we need to process the iOriginalCode.
00699                     //
00700                     if (*cstr == delim1)
00701                     {
00702                         iCode = iOriginalCode1;
00703                     }
00704                     else
00705                     {
00706                         iCode = iOriginalCode2;
00707                     }
00708                     goto TryAgain;
00709                 }
00710             }
00711         }
00712     }
00713     *iWhichDelim = 0;
00714     *cstr = '\0';
00715     *nLen = (cstr - rstr);
00716     *dstr = NULL;
00717     return rstr;
00718 }
00719 
00720 //-----------------------------------------------------------------------------
00721 // parse_arglist: Parse a line into an argument list contained in lbufs. A
00722 // pointer is returned to whatever follows the final delimiter. If the arglist
00723 // is unterminated, a NULL is returned.  The original arglist is destructively
00724 // modified.
00725 //
00726 char *parse_arglist( dbref executor, dbref caller, dbref enactor, char *dstr,
00727                      char delim, dbref eval, char *fargs[], dbref nfargs,
00728                      char *cargs[], dbref ncargs, int *nArgsParsed )
00729 {
00730     char *rstr, *tstr, *bp, *str;
00731     int arg, peval;
00732 
00733     if (dstr == NULL)
00734     {
00735         *nArgsParsed = 0;
00736         return NULL;
00737     }
00738 
00739     int nLen;
00740     int iWhichDelim;
00741     rstr = parse_to_lite(&dstr, delim, '\0', &nLen, &iWhichDelim);
00742     arg = 0;
00743 
00744     peval = (eval & ~EV_EVAL);
00745 
00746     while (  arg < nfargs
00747           && rstr)
00748     {
00749         if (arg < nfargs - 1)
00750         {
00751             tstr = parse_to(&rstr, ',', peval);
00752         }
00753         else
00754         {
00755             tstr = parse_to(&rstr, '\0', peval);
00756         }
00757 
00758         bp = fargs[arg] = alloc_lbuf("parse_arglist");
00759         if (eval & EV_EVAL)
00760         {
00761             str = tstr;
00762             mux_exec(fargs[arg], &bp, executor, caller, enactor,
00763                      eval | EV_FCHECK, &str, cargs, ncargs);
00764             *bp = '\0';
00765         }
00766         else
00767         {
00768             strcpy(fargs[arg], tstr);
00769         }
00770         arg++;
00771     }
00772     *nArgsParsed = arg;
00773     return dstr;
00774 }
00775 
00776 static char *parse_arglist_lite( dbref executor, dbref caller, dbref enactor,
00777                           char *dstr, char delim, int eval, char *fargs[],
00778                           dbref nfargs, char *cargs[], dbref ncargs,
00779                           int *nArgsParsed)
00780 {
00781     UNUSED_PARAMETER(delim);
00782 
00783     char *tstr, *bp, *str;
00784 
00785     if (dstr == NULL)
00786     {
00787         *nArgsParsed = 0;
00788         return NULL;
00789     }
00790 
00791     int nLen;
00792     int peval = eval;
00793     if (eval & EV_EVAL)
00794     {
00795         peval = eval | EV_FCHECK;
00796     }
00797     else
00798     {
00799         peval = ((eval & ~EV_FCHECK)|EV_NOFCHECK);
00800     }
00801     int arg = 0;
00802     int iWhichDelim = 0;
00803     while (  arg < nfargs
00804           && dstr
00805           && iWhichDelim != 2)
00806     {
00807         if (arg < nfargs - 1)
00808         {
00809             tstr = parse_to_lite(&dstr, ',', ')', &nLen, &iWhichDelim);
00810         }
00811         else
00812         {
00813             tstr = parse_to_lite(&dstr, '\0', ')', &nLen, &iWhichDelim);
00814         }
00815 
00816         if (  iWhichDelim == 2
00817            && arg == 0
00818            && tstr[0] == '\0')
00819         {
00820             break;
00821         }
00822 
00823         bp = fargs[arg] = alloc_lbuf("parse_arglist");
00824         str = tstr;
00825         mux_exec(fargs[arg], &bp, executor, caller, enactor, peval, &str,
00826                  cargs, ncargs);
00827         *bp = '\0';
00828         arg++;
00829     }
00830     *nArgsParsed = arg;
00831     return dstr;
00832 }
00833 
00834 //-----------------------------------------------------------------------------
00835 // exec: Process a command line, evaluating function calls and %-substitutions.
00836 //
00837 int get_gender(dbref player)
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 }
00858 
00859 //---------------------------------------------------------------------------
00860 // Trace cache routines.
00861 //
00862 typedef struct tcache_ent TCENT;
00863 static struct tcache_ent
00864 {
00865     dbref player;
00866     char *orig;
00867     char *result;
00868     struct tcache_ent *next;
00869 } *tcache_head;
00870 
00871 static bool tcache_top;
00872 static int  tcache_count;
00873 
00874 void tcache_init(void)
00875 {
00876     tcache_head = NULL;
00877     tcache_top = true;
00878     tcache_count = 0;
00879 }
00880 
00881 static bool tcache_empty(void)
00882 {
00883     if (tcache_top)
00884     {
00885         tcache_top = false;
00886         tcache_count = 0;
00887         return true;
00888     }
00889     return false;
00890 }
00891 
00892 static void tcache_add(dbref player, char *orig, char *result)
00893 {
00894     if (strcmp(orig, result))
00895     {
00896         tcache_count++;
00897         if (tcache_count <= mudconf.trace_limit)
00898         {
00899             TCENT *xp = (TCENT *) alloc_sbuf("tcache_add.sbuf");
00900             char *tp = alloc_lbuf("tcache_add.lbuf");
00901 
00902             int nvw;
00903             ANSI_TruncateToField(result, LBUF_SIZE, tp, LBUF_SIZE,
00904                 &nvw, ANSI_ENDGOAL_NORMAL);
00905             xp->result = tp;
00906 
00907             xp->player = player;
00908             xp->orig = orig;
00909             xp->next = tcache_head;
00910             tcache_head = xp;
00911         }
00912         else
00913         {
00914             free_lbuf(orig);
00915         }
00916     }
00917     else
00918     {
00919         free_lbuf(orig);
00920     }
00921 }
00922 
00923 static void tcache_finish(void)
00924 {
00925     while (tcache_head != NULL)
00926     {
00927         TCENT *xp = tcache_head;
00928         tcache_head = xp->next;
00929         notify(Owner(xp->player), tprintf("%s(#%d)} '%s' -> '%s'", Name(xp->player),
00930             xp->player, xp->orig, xp->result));
00931         free_lbuf(xp->orig);
00932         free_lbuf(xp->result);
00933         free_sbuf(xp);
00934     }
00935     tcache_top = true;
00936     tcache_count = 0;
00937 }
00938 
00939 const char *ColorTable[256] =
00940 {
00941     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x00-0x0F
00942     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x10-0x1F
00943     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x20-0x2F
00944     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x30-0x3F
00945     0,           0,             ANSI_BBLUE,  ANSI_BCYAN,  // 0x40-0x43
00946     0,           0,             0,           ANSI_BGREEN, // 0x44-0x47
00947     0,           0,             0,           0,           // 0x48-0x4B
00948     0,           ANSI_BMAGENTA, 0,           0,           // 0x4B-0x4F
00949     0,           0,             ANSI_BRED,   0,           // 0x50-0x53
00950     0,           0,             0,           ANSI_BWHITE, // 0x54-0x57
00951     ANSI_BBLACK, ANSI_BYELLOW,  0,           0,           // 0x58-0x5B
00952     0,           0,             0,           0,           // 0x5B-0x5F
00953     0,           0,             ANSI_BLUE,   ANSI_CYAN,   // 0x60-0x63
00954     0,           0,             ANSI_BLINK,  ANSI_GREEN,  // 0x64-0x67
00955     ANSI_HILITE, ANSI_INVERSE,  0,           0,           // 0x68-0x6B
00956     0,           ANSI_MAGENTA,  ANSI_NORMAL, 0,           // 0x6C-0x6F
00957     0,           0,             ANSI_RED,    0,           // 0x70-0x73
00958     0,           ANSI_UNDER,    0,           ANSI_WHITE,  // 0x74-0x77
00959     ANSI_BLACK,  ANSI_YELLOW,   0,           0,           // 0x78-0x7B
00960     0,           0,             0,           0,           // 0x7B-0x7F
00961     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x80-0x8F
00962     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0x90-0x9F
00963     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xA0-0xAF
00964     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xB0-0xBF
00965     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xC0-0xCF
00966     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xD0-0xDF
00967     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,      // 0xE0-0xEF
00968     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0       // 0xF0-0xFF
00969 };
00970 
00971 static bool isSpecial_L1[256] =
00972 {
00973     1, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x00-0x0F
00974     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 1, 0, 0, 0, 0, // 0x10-0x1F
00975     1, 0, 0, 0, 0, 1, 0, 0,  1, 0, 0, 0, 0, 0, 0, 0, // 0x20-0x2F
00976     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x30-0x3F
00977     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x40-0x4F
00978     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 1, 1, 0, 0, 0, // 0x50-0x5F
00979     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x60-0x6F
00980     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 1, 0, 0, 0, 0, // 0x70-0x7F
00981     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x80-0x8F
00982     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0x90-0x9F
00983     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xA0-0xAF
00984     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xB0-0xBF
00985     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xC0-0xCF
00986     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xD0-0xDF
00987     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0, // 0xE0-0xEF
00988     0, 0, 0, 0, 0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0  // 0xF0-0xFF
00989 };
00990 
00991 static const unsigned char isSpecial_L2[256] =
00992 {
00993      18,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0x00-0x0F
00994       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0x10-0x1F
00995       0,  4,  0,  3,  0, 11,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0x20-0x2F
00996       1,  1,  1,  1,  1,  1,  1,  1,   1,  1,  0,  0,  0,  0,  0,  0, // 0x30-0x3F
00997      20,145,  7,  6,  0,  0,  0,  0,   0,  0,  0,  0,  9,147,140,144, // 0x40-0x4F
00998     143,130,  5,142,  8,  0,138,  0,   6,  0,  0,  0,  0,  0,  0,  0, // 0x50-0x5F
00999      20, 17,  7,  6,  0,  0,  0,  0,   0,  0,  0,  0,  9, 19, 12, 16, // 0x60-0x6F
01000      15,  2,  5, 14,  8,  0, 10,  0,   6,  0,  0,  0, 13,  0,  0,  0, // 0x70-0x7F
01001       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0x80-0x8F
01002       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0x90-0x9F
01003       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0xA0-0xAF
01004       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0xB0-0xBF
01005       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0xC0-0xCF
01006       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0xD0-0xDF
01007       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0, // 0xE0-0xEF
01008       0,  0,  0,  0,  0,  0,  0,  0,   0,  0,  0,  0,  0,  0,  0,  0  // 0xF0-0xFF
01009 };
01010 
01011 #define PTRS_PER_FRAME ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(char *))
01012 typedef struct tag_ptrsframe
01013 {
01014     int   nptrs;
01015     char *ptrs[PTRS_PER_FRAME];
01016     struct tag_ptrsframe *next;
01017 } PtrsFrame;
01018 
01019 static PtrsFrame *pPtrsFrame = NULL;
01020 
01021 char **PushPointers(int nNeeded)
01022 {
01023     if (  !pPtrsFrame
01024        || pPtrsFrame->nptrs < nNeeded)
01025     {
01026         PtrsFrame *p = (PtrsFrame *)alloc_lbuf("PushPointers");
01027         p->next = pPtrsFrame;
01028         p->nptrs = PTRS_PER_FRAME;
01029         pPtrsFrame = p;
01030     }
01031     pPtrsFrame->nptrs -= nNeeded;
01032     return pPtrsFrame->ptrs + pPtrsFrame->nptrs;
01033 }
01034 
01035 void PopPointers(char **p, int nNeeded)
01036 {
01037     UNUSED_PARAMETER(p);
01038 
01039     if (pPtrsFrame->nptrs == PTRS_PER_FRAME)
01040     {
01041         PtrsFrame *q = pPtrsFrame->next;
01042         free_lbuf((char *)pPtrsFrame);
01043         pPtrsFrame = q;
01044     }
01045     //mux_assert(p == pPtrsFrame->ptrs + pPtrsFrame->nptrs);
01046     pPtrsFrame->nptrs += nNeeded;
01047 }
01048 
01049 #define INTS_PER_FRAME ((LBUF_SIZE - sizeof(char *) - sizeof(int))/sizeof(int))
01050 typedef struct tag_intsframe
01051 {
01052     int   nints;
01053     int   ints[INTS_PER_FRAME];
01054     struct tag_intsframe *next;
01055 } IntsFrame;
01056 
01057 static IntsFrame *pIntsFrame = NULL;
01058 
01059 int *PushIntegers(int nNeeded)
01060 {
01061     if (  !pIntsFrame
01062        || pIntsFrame->nints < nNeeded)
01063     {
01064         IntsFrame *p = (IntsFrame *)alloc_lbuf("PushIntegers");
01065         p->next = pIntsFrame;
01066         p->nints = INTS_PER_FRAME;
01067         pIntsFrame = p;
01068     }
01069     pIntsFrame->nints -= nNeeded;
01070     return pIntsFrame->ints + pIntsFrame->nints;
01071 }
01072 
01073 void PopIntegers(int *pi, int nNeeded)
01074 {
01075     UNUSED_PARAMETER(pi);
01076 
01077     if (pIntsFrame->nints == INTS_PER_FRAME)
01078     {
01079         IntsFrame *p = pIntsFrame->next;
01080         free_lbuf((char *)pIntsFrame);
01081         pIntsFrame = p;
01082     }
01083     //mux_assert(pi == pIntsFrame->ints + pIntsFrame->nints);
01084     pIntsFrame->nints += nNeeded;
01085 }
01086 
01087 void mux_exec( char *buff, char **bufc, dbref executor, dbref caller,
01088                dbref enactor, int eval, char **dstr, char *cargs[], int ncargs)
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 ANSI_Out_Context aoc;
02062 
02063         ANSI_String_Out_Init(&aoc, mux_scratch, sizeof(mux_scratch),
02064             sizeof(mux_scratch), ANSI_ENDGOAL_NORMAL);
02065         if (realbuff)
02066         {
02067             *realbp = '\0';
02068             ANSI_String_In_Init(&aic, realbuff, ANSI_ENDGOAL_NORMAL);
02069             ANSI_String_Copy(&aoc, &aic, sizeof(mux_scratch));
02070         }
02071         ANSI_String_In_Init(&aic, buff, ANSI_ENDGOAL_NORMAL);
02072         ANSI_String_Copy(&aoc, &aic, sizeof(mux_scratch));
02073         if (realbuff)
02074         {
02075             MEMFREE(buff);
02076             buff = realbuff;
02077         }
02078 
02079         int nVisualWidth;
02080         int nLen = ANSI_String_Finalize(&aoc, &nVisualWidth);
02081         memcpy(buff, mux_scratch, nLen+1);
02082         *bufc = buff + nLen;
02083     }
02084 
02085     *dstr = pdstr;
02086 
02087     // Restore Parser Mode.
02088     //
02089     isSpecial(L1, ' ') = bSpaceIsSpecialSave;
02090     isSpecial(L1, '(') = bParenthesisIsSpecialSave;
02091     isSpecial(L1, '[') = bBracketIsSpecialSave;
02092 }
02093 
02094 /* ---------------------------------------------------------------------------
02095  * save_global_regs, restore_global_regs:  Save and restore the global
02096  * registers to protect them from various sorts of munging.
02097  */
02098 
02099 void save_global_regs
02100 (
02101     const char *funcname,
02102     char *preserve[],
02103     int preserve_len[]
02104 )
02105 {
02106     int i;
02107 
02108     for (i = 0; i < MAX_GLOBAL_REGS; i++)
02109     {
02110         if (mudstate.global_regs[i])
02111         {
02112             preserve[i] = alloc_lbuf(funcname);
02113             int n = mudstate.glob_reg_len[i];
02114             memcpy(preserve[i], mudstate.global_regs[i], n);
02115             preserve[i][n] = '\0';
02116             preserve_len[i] = n;
02117         }
02118         else
02119         {
02120             preserve[i] = NULL;
02121             preserve_len[i] = 0;
02122         }
02123     }
02124 }
02125 
02126 void save_and_clear_global_regs
02127 (
02128     const char *funcname,
02129     char *preserve[],
02130     int preserve_len[]
02131 )
02132 {
02133     UNUSED_PARAMETER(funcname);
02134 
02135     int i;
02136 
02137     for (i = 0; i < MAX_GLOBAL_REGS; i++)
02138     {
02139         preserve[i] = mudstate.global_regs[i];
02140         preserve_len[i] = mudstate.glob_reg_len[i];
02141 
02142         mudstate.global_regs[i] = NULL;
02143         mudstate.glob_reg_len[i] = 0;
02144     }
02145 }
02146 
02147 void restore_global_regs
02148 (
02149     const char *funcname,
02150     char *preserve[],
02151     int preserve_len[]
02152 )
02153 {
02154     UNUSED_PARAMETER(funcname);
02155 
02156     int i;
02157 
02158     for (i = 0; i < MAX_GLOBAL_REGS; i++)
02159     {
02160         if (preserve[i])
02161         {
02162             if (mudstate.global_regs[i])
02163             {
02164                 free_lbuf(mudstate.global_regs[i]);
02165             }
02166             mudstate.global_regs[i] = preserve[i];
02167             mudstate.glob_reg_len[i] = preserve_len[i];
02168         }
02169         else
02170         {
02171             if (mudstate.global_regs[i])
02172             {
02173                 mudstate.global_regs[i][0] = '\0';
02174             }
02175             mudstate.glob_reg_len[i] = 0;
02176         }
02177     }
02178 }

Generated on Mon May 28 04:40:09 2007 for MUX by  doxygen 1.4.7