src/eval.c

Go to the documentation of this file.
00001 /*
00002  * eval.c - command evaluation and cracking 
00003  */
00004 
00005 #include "copyright.h"
00006 #include "config.h"
00007 
00008 #include "db.h"
00009 #include "externs.h"
00010 #include "attrs.h"
00011 #include "functions.h"
00012 #include "alloc.h"
00013 #include "ansi.h"
00014 
00024 static char *parse_to_cleanup(int eval, int first, char *cstr, char *rstr,
00025                                                           char *zstr)
00026 {
00027         if((mudconf.space_compress || (eval & EV_STRIP_TS)) &&
00028            !(eval & EV_NO_COMPRESS) && !first && (cstr[-1] == ' '))
00029                 zstr--;
00030         if((eval & EV_STRIP_AROUND) && (*rstr == '{') && (zstr[-1] == '}')) {
00031                 rstr++;
00032                 if(mudconf.space_compress && (!(eval & EV_NO_COMPRESS) ||
00033                                                                           (eval & EV_STRIP_LS)))
00034                         while (*rstr && isspace(*rstr))
00035                                 rstr++;
00036                 rstr[-1] = '\0';
00037                 zstr--;
00038                 if(mudconf.space_compress && (!(eval & EV_NO_COMPRESS) ||
00039                                                                           (eval & EV_STRIP_TS)))
00040                         while (zstr[-1] && isspace(zstr[-1]))
00041                                 zstr--;
00042                 *zstr = '\0';
00043         }
00044         *zstr = '\0';
00045         return rstr;
00046 }
00047 
00048 /* We can't change this to just '*zstr++ = *cstr++', because of the inherent
00049 problems with copying a memory location to itself. */
00050 
00051 #define NEXTCHAR \
00052         do {if (cstr == zstr) { \
00053                 cstr++; \
00054                 zstr++; \
00055         } else \
00056                 *zstr++ = *cstr++;} while (0)
00057 
00058 char *parse_to(char **dstr, char delim, int eval)
00059 {
00060 #define stacklim 32
00061         char stack[stacklim];
00062         char *rstr, *cstr, *zstr;
00063         int sp, tp, first, bracketlev;
00064 
00065         if((dstr == NULL) || (*dstr == NULL))
00066                 return NULL;
00067         if(**dstr == '\0') {
00068                 rstr = *dstr;
00069                 *dstr = NULL;
00070                 return rstr;
00071         }
00072         sp = 0;
00073         first = 1;
00074         rstr = *dstr;
00075         if((mudconf.space_compress || (eval & EV_STRIP_LS)) &&
00076            !(eval & EV_NO_COMPRESS)) {
00077                 while (*rstr && isspace(*rstr))
00078                         rstr++;
00079                 *dstr = rstr;
00080         }
00081         zstr = cstr = rstr;
00082         while (*cstr) {
00083                 switch (*cstr) {
00084                 case '\\':                              /*
00085                                                                  * general escape 
00086                                                                  */
00087                 case '%':                               /*
00088                                                                  * also escapes chars 
00089                                                                  */
00090                         if((*cstr == '\\') && (eval & EV_STRIP_ESC))
00091                                 cstr++;
00092                         else
00093                                 NEXTCHAR;
00094                         if(*cstr)
00095                                 NEXTCHAR;
00096                         first = 0;
00097                         break;
00098                 case ']':
00099                 case ')':
00100                         for(tp = sp - 1; (tp >= 0) && (stack[tp] != *cstr); tp--);
00101 
00102                         /*
00103                          * If we hit something on the stack, unwind to it 
00104                          * Otherwise (it's not on stack), if it's our
00105                          * delim  we are done, and we convert the 
00106                          * delim to a null and return a ptr to the
00107                          * char after the null. If it's not our
00108                          * delimiter, skip over it normally  
00109                          */
00110 
00111                         if(tp >= 0)
00112                                 sp = tp;
00113                         else if(*cstr == delim) {
00114                                 rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr);
00115                                 *dstr = ++cstr;
00116                                 return rstr;
00117                         }
00118                         first = 0;
00119                         NEXTCHAR;
00120                         break;
00121                 case '{':
00122                         bracketlev = 1;
00123                         if(eval & EV_STRIP) {
00124                                 cstr++;
00125                         } else {
00126                                 NEXTCHAR;
00127                         }
00128                         while (*cstr && (bracketlev > 0)) {
00129                                 switch (*cstr) {
00130                                 case '\\':
00131                                 case '%':
00132                                         if(cstr[1]) {
00133                                                 if((*cstr == '\\') && (eval & EV_STRIP_ESC))
00134                                                         cstr++;
00135                                                 else
00136                                                         NEXTCHAR;
00137                                         }
00138                                         break;
00139                                 case '{':
00140                                         bracketlev++;
00141                                         break;
00142                                 case '}':
00143                                         bracketlev--;
00144                                         break;
00145                                 }
00146                                 if(bracketlev > 0) {
00147                                         NEXTCHAR;
00148                                 }
00149                         }
00150                         if((eval & EV_STRIP) && (bracketlev == 0)) {
00151                                 cstr++;
00152                         } else if(bracketlev == 0) {
00153                                 NEXTCHAR;
00154                         }
00155                         first = 0;
00156                         break;
00157                 default:
00158                         if((*cstr == delim) && (sp == 0)) {
00159                                 rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr);
00160                                 *dstr = ++cstr;
00161                                 return rstr;
00162                         }
00163                         switch (*cstr) {
00164                         case ' ':                       /*
00165                                                                  * space 
00166                                                                  */
00167                                 if(mudconf.space_compress && !(eval & EV_NO_COMPRESS)) {
00168                                         if(first)
00169                                                 rstr++;
00170                                         else if(cstr[-1] == ' ')
00171                                                 zstr--;
00172                                 }
00173                                 break;
00174                         case '[':
00175                                 if(cstr != rstr && cstr[-1] == ESC_CHAR) {
00176                                         first = 0;
00177                                         break;
00178                                 }
00179                                 if(sp < stacklim)
00180                                         stack[sp++] = ']';
00181                                 first = 0;
00182                                 break;
00183                         case '(':
00184                                 if(sp < stacklim)
00185                                         stack[sp++] = ')';
00186                                 first = 0;
00187                                 break;
00188                         default:
00189                                 first = 0;
00190                         }
00191                         NEXTCHAR;
00192                 }
00193         }
00194         rstr = parse_to_cleanup(eval, first, cstr, rstr, zstr);
00195         *dstr = NULL;
00196         return rstr;
00197 }
00198 
00199 /*
00200  * ---------------------------------------------------------------------------
00201  * * parse_arglist: Parse a line into an argument list contained in lbufs.
00202  * * A pointer is returned to whatever follows the final delimiter.
00203  * * If the arglist is unterminated, a NULL is returned.  The original arglist 
00204  * * is destructively modified.
00205  */
00206 
00207 char *parse_arglist(dbref player, dbref cause, char *dstr, char delim,
00208                                         dbref eval, char *fargs[], dbref nfargs, char *cargs[],
00209                                         dbref ncargs)
00210 {
00211         char *rstr, *tstr, *bp, *str;
00212         int arg, peval;
00213 
00214         for(arg = 0; arg < nfargs; arg++)
00215                 fargs[arg] = NULL;
00216         if(dstr == NULL)
00217                 return NULL;
00218         rstr = parse_to(&dstr, delim, 0);
00219         arg = 0;
00220 
00221         peval = (eval & ~EV_EVAL);
00222 
00223         while ((arg < nfargs) && rstr) {
00224                 if(arg < (nfargs - 1))
00225                         tstr = parse_to(&rstr, ',', peval);
00226                 else
00227                         tstr = parse_to(&rstr, '\0', peval);
00228                 if(eval & EV_EVAL) {
00229                         bp = fargs[arg] = alloc_lbuf("parse_arglist");
00230                         str = tstr;
00231                         exec(fargs[arg], &bp, 0, player, cause, eval | EV_FCHECK, &str,
00232                                  cargs, ncargs);
00233                         *bp = '\0';
00234                 } else {
00235                         fargs[arg] = alloc_lbuf("parse_arglist");
00236                         StringCopy(fargs[arg], tstr);
00237                 }
00238                 arg++;
00239         }
00240         return dstr;
00241 }
00242 
00243 /*
00244  * ---------------------------------------------------------------------------
00245  * * exec: Process a command line, evaluating function calls and %-substitutions.
00246  */
00247 
00248 int get_gender(dbref player)
00249 {
00250         char first, *atr_gotten;
00251         dbref aowner;
00252         int aflags;
00253 
00254         atr_gotten = atr_pget(player, A_SEX, &aowner, &aflags);
00255         first = *atr_gotten;
00256         free_lbuf(atr_gotten);
00257         switch (first) {
00258         case 'P':
00259         case 'p':
00260                 return 4;
00261         case 'M':
00262         case 'm':
00263                 return 3;
00264         case 'F':
00265         case 'f':
00266         case 'W':
00267         case 'w':
00268                 return 2;
00269         default:
00270                 return 1;
00271         }
00272 }
00273 
00274 /*
00275  * ---------------------------------------------------------------------------
00276  * * Trace cache routines.
00277  */
00278 
00279 typedef struct tcache_ent TCENT;
00280 struct tcache_ent {
00281         char *orig;
00282         char *result;
00283         struct tcache_ent *next;
00284 } *tcache_head;
00285 int tcache_top, tcache_count;
00286 
00287 void tcache_init(void)
00288 {
00289         tcache_head = NULL;
00290         tcache_top = 1;
00291         tcache_count = 0;
00292 }
00293 
00294 int tcache_empty(void)
00295 {
00296         if(tcache_top) {
00297                 tcache_top = 0;
00298                 tcache_count = 0;
00299                 return 1;
00300         }
00301         return 0;
00302 }
00303 
00304 static void tcache_add(char *orig, char *result)
00305 {
00306         char *tp;
00307         TCENT *xp;
00308 
00309         if(strcmp(orig, result)) {
00310                 tcache_count++;
00311                 if(tcache_count <= mudconf.trace_limit) {
00312                         xp = (TCENT *) alloc_sbuf("tcache_add.sbuf");
00313                         tp = alloc_lbuf("tcache_add.lbuf");
00314                         StringCopy(tp, result);
00315                         xp->orig = orig;
00316                         xp->result = tp;
00317                         xp->next = tcache_head;
00318                         tcache_head = xp;
00319                 } else {
00320                         free_lbuf(orig);
00321                 }
00322         } else {
00323                 free_lbuf(orig);
00324         }
00325 }
00326 
00327 static void tcache_finish(dbref player)
00328 {
00329         TCENT *xp;
00330 
00331         while (tcache_head != NULL) {
00332                 xp = tcache_head;
00333                 tcache_head = xp->next;
00334                 notify_printf(Owner(player), "%s(#%d)} '%s' -> '%s'",
00335                                           Name(player), player, xp->orig, xp->result);
00336                 free_lbuf(xp->orig);
00337                 free_lbuf(xp->result);
00338                 free_sbuf(xp);
00339         }
00340         tcache_top = 1;
00341         tcache_count = 0;
00342 }
00343 
00344 void exec(char *buff, char **bufc, int tflags, dbref player, dbref cause,
00345                   int eval, char **dstr, char *cargs[], int ncargs)
00346 {
00347 #define NFARGS  30
00348         char *fargs[NFARGS];
00349         char *preserve[MAX_GLOBAL_REGS];
00350         char *tstr, *tbuf, *tbufc, *savepos, *atr_gotten, *start, *oldp, *savestr;
00351         char savec, ch, *str;
00352         char *realbuff = NULL, *realbp = NULL;
00353         dbref aowner;
00354         int at_space, nfargs, gender, i, j, alldone, aflags, feval;
00355         int is_trace, is_top, save_count;
00356         int ansi;
00357         FUN *fp;
00358         UFUN *ufp;
00359 
00360         static const char *subj[5] = { "", "it", "she", "he", "they" };
00361         static const char *poss[5] = { "", "its", "her", "his", "their" };
00362         static const char *obj[5] = { "", "it", "her", "him", "them" };
00363         static const char *absp[5] = { "", "its", "hers", "his", "theirs" };
00364 
00365         if(*dstr == NULL)
00366                 return;
00367 
00368         // dprintk("%d/%s", player, *dstr);
00369 
00370         at_space = 1;
00371         gender = -1;
00372         alldone = 0;
00373         ansi = 0;
00374 
00375         is_trace = Trace(player) && !(eval & EV_NOTRACE);
00376         is_top = 0;
00377 
00378         /* Extend the buffer if we need to. */
00379 
00380         if(((*bufc) - buff) > (LBUF_SIZE - SBUF_SIZE)) {
00381                 realbuff = buff;
00382                 realbp = *bufc;
00383                 buff = (char *) malloc(LBUF_SIZE);
00384                 *bufc = buff;
00385         }
00386 
00387         oldp = start = *bufc;
00388 
00389         /*
00390          * If we are tracing, save a copy of the starting buffer 
00391          */
00392 
00393         savestr = NULL;
00394         if(is_trace) {
00395                 is_top = tcache_empty();
00396                 savestr = alloc_lbuf("exec.save");
00397                 StringCopy(savestr, *dstr);
00398         }
00399         while (**dstr && !alldone) {
00400                 switch (**dstr) {
00401                 case ' ':
00402                         /*
00403                          * A space.  Add a space if not compressing or if * * 
00404                          * 
00405                          * *  * * previous char was not a space 
00406                          */
00407 
00408                         if(!(mudconf.space_compress && at_space) ||
00409                            (eval & EV_NO_COMPRESS)) {
00410                                 safe_chr(' ', buff, bufc);
00411                                 at_space = 1;
00412                         }
00413                         break;
00414                 case '\\':
00415                         /*
00416                          * General escape.  Add the following char without *
00417                          * * * * special processing 
00418                          */
00419 
00420                         at_space = 0;
00421                         (*dstr)++;
00422                         if(**dstr)
00423                                 safe_chr(**dstr, buff, bufc);
00424                         else
00425                                 (*dstr)--;
00426                         break;
00427                 case '[':
00428                         /*
00429                          * Function start.  Evaluate the contents of the * *
00430                          * * * square brackets as a function.  If no closing
00431                          * * * * * bracket, insert the [ and continue. 
00432                          */
00433 
00434                         at_space = 0;
00435                         tstr = (*dstr)++;
00436                         if(eval & EV_NOFCHECK) {
00437                                 safe_chr('[', buff, bufc);
00438                                 *dstr = tstr;
00439                                 break;
00440                         }
00441                         tbuf = parse_to(dstr, ']', 0);
00442                         if(*dstr == NULL) {
00443                                 safe_chr('[', buff, bufc);
00444                                 *dstr = tstr;
00445                         } else {
00446                                 str = tbuf;
00447                                 exec(buff, bufc, 0, player, cause,
00448                                          (eval | EV_FCHECK | EV_FMAND), &str, cargs, ncargs);
00449                                 (*dstr)--;
00450                         }
00451                         break;
00452                 case '{':
00453                         /*
00454                          * Literal start.  Insert everything up to the * * *
00455                          * * terminating } without parsing.  If no closing *
00456                          * * * * brace, insert the { and continue. 
00457                          */
00458 
00459                         at_space = 0;
00460                         tstr = (*dstr)++;
00461                         tbuf = parse_to(dstr, '}', 0);
00462                         if(*dstr == NULL) {
00463                                 safe_chr('{', buff, bufc);
00464                                 *dstr = tstr;
00465                         } else {
00466                                 if(!(eval & EV_STRIP)) {
00467                                         safe_chr('{', buff, bufc);
00468                                 }
00469                                 /*
00470                                  * Preserve leading spaces (Felan) 
00471                                  */
00472 
00473                                 if(*tbuf == ' ') {
00474                                         safe_chr(' ', buff, bufc);
00475                                         tbuf++;
00476                                 }
00477                                 str = tbuf;
00478                                 exec(buff, bufc, 0, player, cause,
00479                                          (eval & ~(EV_STRIP | EV_FCHECK)), &str, cargs, ncargs);
00480                                 if(!(eval & EV_STRIP)) {
00481                                         safe_chr('}', buff, bufc);
00482                                 }
00483                                 (*dstr)--;
00484                         }
00485                         break;
00486                 case '%':
00487                         /*
00488                          * Percent-replace start.  Evaluate the chars * * *
00489                          * following * and perform the appropriate * * *
00490                          * substitution. 
00491                          */
00492 
00493                         at_space = 0;
00494                         (*dstr)++;
00495                         savec = **dstr;
00496                         savepos = *bufc;
00497                         switch (savec) {
00498                         case '\0':                      /*
00499                                                                  * Null - all done 
00500                                                                  */
00501                                 (*dstr)--;
00502                                 break;
00503                         case '|':                       /* piped command output */
00504                                 safe_str(mudstate.pout, buff, bufc);
00505                                 break;
00506                         case '%':                       /*
00507                                                                  * Percent - a literal % 
00508                                                                  */
00509                                 safe_chr('%', buff, bufc);
00510                                 break;
00511                         case 'c':
00512                         case 'C':
00513                                 (*dstr)++;
00514                                 if(!**dstr)
00515                                         (*dstr)--;
00516                                 ansi = 1;
00517                                 switch (**dstr) {
00518                                 case 'h':               /*
00519                                                                  * hilite 
00520                                                                  */
00521                                         safe_str(ANSI_HILITE, buff, bufc);
00522                                         break;
00523                                 case 'i':               /*
00524                                                                  * inverse 
00525                                                                  */
00526                                         safe_str(ANSI_INVERSE, buff, bufc);
00527                                         break;
00528                                 case 'f':               /*
00529                                                                  * flash 
00530                                                                  */
00531                                         safe_str(ANSI_BLINK, buff, bufc);
00532                                         break;
00533                                 case 'u':               /* underline */
00534                                         safe_str(ANSI_UNDER, buff, bufc);
00535                                         break;
00536                                 case 'n':               /*
00537                                                                  * normal 
00538                                                                  */
00539                                         safe_str(ANSI_NORMAL, buff, bufc);
00540                                         ansi = 0;
00541                                         break;
00542                                 case 'x':               /*
00543                                                                  * black fg 
00544                                                                  */
00545                                         safe_str(ANSI_BLACK, buff, bufc);
00546                                         break;
00547                                 case 'r':               /*
00548                                                                  * red fg 
00549                                                                  */
00550                                         safe_str(ANSI_RED, buff, bufc);
00551                                         break;
00552                                 case 'g':               /*
00553                                                                  * green fg 
00554                                                                  */
00555                                         safe_str(ANSI_GREEN, buff, bufc);
00556                                         break;
00557                                 case 'y':               /*
00558                                                                  * yellow fg 
00559                                                                  */
00560                                         safe_str(ANSI_YELLOW, buff, bufc);
00561                                         break;
00562                                 case 'b':               /*
00563                                                                  * blue fg 
00564                                                                  */
00565                                         safe_str(ANSI_BLUE, buff, bufc);
00566                                         break;
00567                                 case 'm':               /*
00568                                                                  * magenta fg 
00569                                                                  */
00570                                         safe_str(ANSI_MAGENTA, buff, bufc);
00571                                         break;
00572                                 case 'c':               /*
00573                                                                  * cyan fg 
00574                                                                  */
00575                                         safe_str(ANSI_CYAN, buff, bufc);
00576                                         break;
00577                                 case 'w':               /*
00578                                                                  * white fg 
00579                                                                  */
00580                                         safe_str(ANSI_WHITE, buff, bufc);
00581                                         break;
00582                                 case 'X':               /*
00583                                                                  * black bg 
00584                                                                  */
00585                                         safe_str(ANSI_BBLACK, buff, bufc);
00586                                         break;
00587                                 case 'R':               /*
00588                                                                  * red bg 
00589                                                                  */
00590                                         safe_str(ANSI_BRED, buff, bufc);
00591                                         break;
00592                                 case 'G':               /*
00593                                                                  * green bg 
00594                                                                  */
00595                                         safe_str(ANSI_BGREEN, buff, bufc);
00596                                         break;
00597                                 case 'Y':               /*
00598                                                                  * yellow bg 
00599                                                                  */
00600                                         safe_str(ANSI_BYELLOW, buff, bufc);
00601                                         break;
00602                                 case 'B':               /*
00603                                                                  * blue bg 
00604                                                                  */
00605                                         safe_str(ANSI_BBLUE, buff, bufc);
00606                                         break;
00607                                 case 'M':               /*
00608                                                                  * magenta bg 
00609                                                                  */
00610                                         safe_str(ANSI_BMAGENTA, buff, bufc);
00611                                         break;
00612                                 case 'C':               /*
00613                                                                  * cyan bg 
00614                                                                  */
00615                                         safe_str(ANSI_BCYAN, buff, bufc);
00616                                         break;
00617                                 case 'W':               /*
00618                                                                  * white bg 
00619                                                                  */
00620                                         safe_str(ANSI_BWHITE, buff, bufc);
00621                                         break;
00622                                 default:
00623                                         safe_chr(**dstr, buff, bufc);
00624                                 }
00625                                 break;
00626                         case 'r':                       /*
00627                                                                  * Carriage return 
00628                                                                  */
00629                         case 'R':
00630                                 safe_str((char *) "\r\n", buff, bufc);
00631                                 break;
00632                         case 't':                       /*
00633                                                                  * Tab 
00634                                                                  */
00635                         case 'T':
00636                                 safe_chr('\t', buff, bufc);
00637                                 break;
00638                         case 'B':                       /*
00639                                                                  * Blank 
00640                                                                  */
00641                         case 'b':
00642                                 safe_chr(' ', buff, bufc);
00643                                 break;
00644                         case '0':                       /*
00645                                                                  * Command argument number N 
00646                                                                  */
00647                         case '1':
00648                         case '2':
00649                         case '3':
00650                         case '4':
00651                         case '5':
00652                         case '6':
00653                         case '7':
00654                         case '8':
00655                         case '9':
00656                                 i = (**dstr - '0');
00657                                 if((i < ncargs) && (cargs[i] != NULL))
00658                                         safe_str(cargs[i], buff, bufc);
00659                                 break;
00660                         case 'V':                       /*
00661                                                                  * Variable attribute 
00662                                                                  */
00663                         case 'v':
00664                                 (*dstr)++;
00665                                 ch = ToUpper(**dstr);
00666                                 if(!**dstr)
00667                                         (*dstr)--;
00668                                 if((ch < 'A') || (ch > 'Z'))
00669                                         break;
00670                                 i = 100 + ch - 'A';
00671                                 atr_gotten = atr_pget(player, i, &aowner, &aflags);
00672                                 safe_str(atr_gotten, buff, bufc);
00673                                 free_lbuf(atr_gotten);
00674                                 break;
00675                         case 'Q':
00676                         case 'q':
00677                                 (*dstr)++;
00678                                 i = (**dstr - '0');
00679                                 if((i >= 0) && (i <= 9) && mudstate.global_regs[i]) {
00680                                         safe_str(mudstate.global_regs[i], buff, bufc);
00681                                 }
00682                                 if(!**dstr)
00683                                         (*dstr)--;
00684                                 break;
00685                         case 'O':                       /*
00686                                                                  * Objective pronoun 
00687                                                                  */
00688                         case 'o':
00689                                 if(gender < 0)
00690                                         gender = get_gender(cause);
00691                                 if(!gender)
00692                                         tbuf = Name(cause);
00693                                 else
00694                                         tbuf = (char *) obj[gender];
00695                                 safe_str(tbuf, buff, bufc);
00696                                 break;
00697                         case 'P':                       /*
00698                                                                  * Personal pronoun 
00699                                                                  */
00700                         case 'p':
00701                                 if(gender < 0)
00702                                         gender = get_gender(cause);
00703                                 if(!gender) {
00704                                         safe_str(Name(cause), buff, bufc);
00705                                         safe_chr('s', buff, bufc);
00706                                 } else {
00707                                         safe_str((char *) poss[gender], buff, bufc);
00708                                 }
00709                                 break;
00710                         case 'S':                       /*
00711                                                                  * Subjective pronoun 
00712                                                                  */
00713                         case 's':
00714                                 if(gender < 0)
00715                                         gender = get_gender(cause);
00716                                 if(!gender)
00717                                         tbuf = Name(cause);
00718                                 else
00719                                         tbuf = (char *) subj[gender];
00720                                 safe_str(tbuf, buff, bufc);
00721                                 break;
00722                         case 'A':                       /*
00723                                                                  * Absolute posessive 
00724                                                                  */
00725                         case 'a':                       /*
00726                                                                  * idea from Empedocles 
00727                                                                  */
00728                                 if(gender < 0)
00729                                         gender = get_gender(cause);
00730                                 if(!gender) {
00731                                         safe_str(Name(cause), buff, bufc);
00732                                         safe_chr('s', buff, bufc);
00733                                 } else {
00734                                         safe_str((char *) absp[gender], buff, bufc);
00735                                 }
00736                                 break;
00737                         case '#':                       /*
00738                                                                  * Invoker DB number 
00739                                                                  */
00740                                 tbuf = alloc_sbuf("exec.invoker");
00741                                 sprintf(tbuf, "#%d", cause);
00742                                 safe_str(tbuf, buff, bufc);
00743                                 free_sbuf(tbuf);
00744                                 break;
00745                         case '!':                       /*
00746                                                                  * Executor DB number 
00747                                                                  */
00748                                 tbuf = alloc_sbuf("exec.executor");
00749                                 sprintf(tbuf, "#%d", player);
00750                                 safe_str(tbuf, buff, bufc);
00751                                 free_sbuf(tbuf);
00752                                 break;
00753                         case 'N':                       /*
00754                                                                  * Invoker name 
00755                                                                  */
00756                         case 'n':
00757                                 safe_str(Name(cause), buff, bufc);
00758                                 break;
00759                         case 'L':                       /*
00760                                                                  * Invoker location db# 
00761                                                                  */
00762                         case 'l':
00763                                 if(!(eval & EV_NO_LOCATION)) {
00764                                         tbuf = alloc_sbuf("exec.exloc");
00765                                         sprintf(tbuf, "#%d", where_is(cause));
00766                                         safe_str(tbuf, buff, bufc);
00767                                         free_sbuf(tbuf);
00768                                 }
00769 
00770                                 break;
00771                         default:                        /*
00772                                                                  * Just copy 
00773                                                                  */
00774                                 safe_chr(**dstr, buff, bufc);
00775                         }
00776                         if(isupper(savec))
00777                                 *savepos = ToUpper(*savepos);
00778                         break;
00779                 case '(':
00780                         /*
00781                          * Arglist start.  See if what precedes is a function. If so,
00782                          * execute it if we should.
00783                          */
00784 
00785                         at_space = 0;
00786                         if(!(eval & EV_FCHECK)) {
00787                                 safe_chr('(', buff, bufc);
00788                                 break;
00789                         }
00790                         /*
00791                          * Load an sbuf with an uppercase version of the func name, and
00792                          * see if the func exists.  Trim trailing spaces from the name
00793                          * if configured.
00794                          */
00795 
00796                         **bufc = '\0';
00797                         tbufc = tbuf = alloc_sbuf("exec.tbuf");
00798                         safe_sb_str(oldp, tbuf, &tbufc);
00799                         *tbufc = '\0';
00800                         if(mudconf.space_compress) {
00801                                 while ((--tbufc >= tbuf) && isspace(*tbufc));
00802                                 tbufc++;
00803                                 *tbufc = '\0';
00804                         }
00805                         for(tbufc = tbuf; *tbufc; tbufc++)
00806                                 *tbufc = ToLower(*tbufc);
00807                         fp = (FUN *) hashfind(tbuf, &mudstate.func_htab);
00808 
00809                         /*
00810                          * If not a builtin func, check for global func 
00811                          */
00812 
00813                         ufp = NULL;
00814                         if(fp == NULL) {
00815                                 ufp = (UFUN *) hashfind(tbuf, &mudstate.ufunc_htab);
00816                         }
00817                         /*
00818                          * Do the right thing if it doesn't exist 
00819                          */
00820 
00821                         if(!fp && !ufp) {
00822                                 if(eval & EV_FMAND) {
00823                                         *bufc = oldp;
00824                                         safe_str((char *) "#-1 FUNCTION (", buff, bufc);
00825                                         safe_str(tbuf, buff, bufc);
00826                                         safe_str((char *) ") NOT FOUND", buff, bufc);
00827                                         alldone = 1;
00828                                 } else {
00829                                         safe_chr('(', buff, bufc);
00830                                 }
00831                                 free_sbuf(tbuf);
00832                                 eval &= ~EV_FCHECK;
00833                                 break;
00834                         }
00835                         free_sbuf(tbuf);
00836 
00837                         /*
00838                          * Get the arglist and count the number of args * Neg 
00839                          * 
00840                          * *  * *  * * # of args means catenate subsequent
00841                          * args 
00842                          */
00843 
00844                         if(ufp)
00845                                 nfargs = NFARGS;
00846                         else if(fp->nargs < 0)
00847                                 nfargs = -fp->nargs;
00848                         else
00849                                 nfargs = NFARGS;
00850                         tstr = *dstr;
00851                         if(fp && (fp->flags & FN_NO_EVAL))
00852                                 feval = (eval & ~EV_EVAL) | EV_STRIP_ESC;
00853                         else
00854                                 feval = eval;
00855                         *dstr =
00856                                 parse_arglist(player, cause, *dstr + 1, ')', feval, fargs,
00857                                                           nfargs, cargs, ncargs);
00858 
00859                         /*
00860                          * If no closing delim, just insert the '(' and * * * 
00861                          * 
00862                          * * continue normally 
00863                          */
00864 
00865                         if(!*dstr) {
00866                                 *dstr = tstr;
00867                                 safe_chr(**dstr, buff, bufc);
00868                                 for(i = 0; i < nfargs; i++)
00869                                         if(fargs[i] != NULL)
00870                                                 free_lbuf(fargs[i]);
00871                                 eval &= ~EV_FCHECK;
00872                                 break;
00873                         }
00874                         /*
00875                          * Count number of args returned 
00876                          */
00877 
00878                         (*dstr)--;
00879                         j = 0;
00880                         for(i = 0; i < nfargs; i++)
00881                                 if(fargs[i] != NULL)
00882                                         j = i + 1;
00883                         nfargs = j;
00884 
00885                         /*
00886                          * If it's a user-defined function, perform it now. 
00887                          */
00888 
00889                         if(ufp) {
00890                                 mudstate.func_nest_lev++;
00891                                 if(!check_access(player, ufp->perms)) {
00892                                         safe_str("#-1 PERMISSION DENIED", buff, &oldp);
00893                                         *bufc = oldp;
00894                                 } else {
00895                                         tstr = atr_get(ufp->obj, ufp->atr, &aowner, &aflags);
00896                                         if(ufp->flags & FN_PRIV)
00897                                                 i = ufp->obj;
00898                                         else
00899                                                 i = player;
00900                                         str = tstr;
00901 
00902                                         if(ufp->flags & FN_PRES) {
00903                                                 for(j = 0; j < MAX_GLOBAL_REGS; j++) {
00904                                                         if(!mudstate.global_regs[j])
00905                                                                 preserve[j] = NULL;
00906                                                         else {
00907                                                                 preserve[j] = alloc_lbuf("eval_regs");
00908                                                                 StringCopy(preserve[j],
00909                                                                                    mudstate.global_regs[j]);
00910                                                         }
00911                                                 }
00912                                         }
00913 
00914                                         exec(buff, &oldp, 0, i, cause, feval, &str, fargs,
00915                                                  nfargs);
00916                                         *bufc = oldp;
00917 
00918                                         if(ufp->flags & FN_PRES) {
00919                                                 for(j = 0; j < MAX_GLOBAL_REGS; j++) {
00920                                                         if(preserve[j]) {
00921                                                                 if(!mudstate.global_regs[j])
00922                                                                         mudstate.global_regs[j] =
00923                                                                                 alloc_lbuf("eval_regs");
00924                                                                 StringCopy(mudstate.global_regs[j],
00925                                                                                    preserve[j]);
00926                                                                 free_lbuf(preserve[j]);
00927                                                         } else {
00928                                                                 if(mudstate.global_regs[j])
00929                                                                         *(mudstate.global_regs[i]) = '\0';
00930                                                         }
00931                                                 }
00932                                         }
00933 
00934                                         free_lbuf(tstr);
00935                                 }
00936 
00937                                 /*
00938                                  * Return the space allocated for the args 
00939                                  */
00940 
00941                                 mudstate.func_nest_lev--;
00942                                 for(i = 0; i < nfargs; i++)
00943                                         if(fargs[i] != NULL)
00944                                                 free_lbuf(fargs[i]);
00945                                 eval &= ~EV_FCHECK;
00946                                 break;
00947                         }
00948                         /*
00949                          * If the number of args is right, perform the func.
00950                          * Otherwise return an error message.  Note
00951                          * that parse_arglist returns zero args as one
00952                          * null arg, so we have to handle that case
00953                          * specially. 
00954                          */
00955 
00956                         if((fp->nargs == 0) && (nfargs == 1)) {
00957                                 if(!*fargs[0]) {
00958                                         free_lbuf(fargs[0]);
00959                                         fargs[0] = NULL;
00960                                         nfargs = 0;
00961                                 }
00962                         }
00963                         if((nfargs == fp->nargs) || (nfargs == -fp->nargs) ||
00964                            (fp->flags & FN_VARARGS)) {
00965 
00966                                 /*
00967                                  * Check recursion limit 
00968                                  */
00969 
00970                                 mudstate.func_nest_lev++;
00971                                 mudstate.func_invk_ctr++;
00972                                 if(mudstate.func_nest_lev >= mudconf.func_nest_lim) {
00973                                         safe_str("#-1 FUNCTION RECURSION LIMIT EXCEEDED", buff,
00974                                                          bufc);
00975                                 } else if(mudstate.func_invk_ctr == mudconf.func_invk_lim) {
00976                                         safe_str("#-1 FUNCTION INVOCATION LIMIT EXCEEDED",
00977                                                          buff, bufc);
00978                                 } else if(!check_access(player, fp->perms)) {
00979                                         safe_str("#-1 PERMISSION DENIED", buff, &oldp);
00980                                         *bufc = oldp;
00981                                 } else if(mudstate.func_invk_ctr < mudconf.func_invk_lim) {
00982                                         fp->fun(buff, &oldp, player, cause, fargs, nfargs,
00983                                                         cargs, ncargs);
00984                                         *bufc = oldp;
00985                                 } else {
00986                                         **bufc = '\0';
00987                                 }
00988                                 mudstate.func_nest_lev--;
00989                         } else {
00990                                 *bufc = oldp;
00991                                 tstr = alloc_sbuf("exec.funcargs");
00992                                 sprintf(tstr, "%d", fp->nargs);
00993                                 safe_str((char *) "#-1 FUNCTION (", buff, bufc);
00994                                 safe_str((char *) fp->name, buff, bufc);
00995                                 safe_str((char *) ") EXPECTS ", buff, bufc);
00996                                 safe_str(tstr, buff, bufc);
00997                                 safe_str((char *) " ARGUMENTS", buff, bufc);
00998                                 free_sbuf(tstr);
00999                         }
01000 
01001                         /*
01002                          * Return the space allocated for the arguments 
01003                          */
01004 
01005                         for(i = 0; i < nfargs; i++)
01006                                 if(fargs[i] != NULL)
01007                                         free_lbuf(fargs[i]);
01008                         eval &= ~EV_FCHECK;
01009                         break;
01010                 default:
01011                         /*
01012                          * A mundane character.  Just copy it 
01013                          */
01014 
01015                         at_space = 0;
01016                         safe_chr(**dstr, buff, bufc);
01017                 }
01018                 (*dstr)++;
01019         }
01020 
01021         /*
01022          * If we're eating spaces, and the last thing was a space, eat it
01023          * up. Complicated by the fact that at_space is initially
01024          * true. So check to see if we actually put something in the
01025          * buffer, too. 
01026          */
01027 
01028         if(mudconf.space_compress && at_space && !(eval & EV_NO_COMPRESS)
01029            && (start != *bufc))
01030                 (*bufc)--;
01031 
01032         /*
01033          * The ansi() function knows how to take care of itself. However, 
01034          * if the player used a %c sub in the string, and hasn't yet
01035          * terminated the color with a %cn yet, we'll have to do it for 
01036          * them. 
01037          */
01038 
01039         if(ansi == 1)
01040                 safe_str(ANSI_NORMAL, buff, bufc);
01041 
01042         **bufc = '\0';
01043 
01044         /*
01045          * Report trace information 
01046          */
01047 
01048         if(realbuff) {
01049                 **bufc = '\0';
01050                 *bufc = realbp;
01051                 safe_str(buff, realbuff, bufc);
01052                 free(buff);
01053                 buff = realbuff;
01054         }
01055 
01056         if(is_trace) {
01057                 tcache_add(savestr, start);
01058                 save_count = tcache_count - mudconf.trace_limit;;
01059                 if(is_top || !mudconf.trace_topdown)
01060                         tcache_finish(player);
01061                 if(is_top && (save_count > 0)) {
01062                         tbuf = alloc_mbuf("exec.trace_diag");
01063                         sprintf(tbuf, "%d lines of trace output discarded.", save_count);
01064                         notify(player, tbuf);
01065                         free_mbuf(tbuf);
01066                 }
01067         }
01068 }

Generated on Mon May 28 04:25:19 2007 for BattletechMUX by  doxygen 1.4.7