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