src/boolexp.c

Go to the documentation of this file.
00001 /*
00002  * boolexp.c 
00003  */
00004 
00005 #include "copyright.h"
00006 #include "config.h"
00007 
00008 #include "db.h"
00009 #include "match.h"
00010 #include "mudconf.h"
00011 #include "externs.h"
00012 #include "interface.h"
00013 #include "attrs.h"
00014 #include "flags.h"
00015 #include "powers.h"
00016 #include "alloc.h"
00017 
00018 static int parsing_internal = 0;
00019 
00024 static int check_attr(dbref player, dbref lockobj, ATTR * attr, char *key)
00025 {
00026         char *buff;
00027         dbref aowner;
00028         int aflags, checkit;
00029 
00030         buff = atr_pget(player, attr->number, &aowner, &aflags);
00031         checkit = 0;
00032 
00033         if(attr->number == A_LENTER) {
00034                 /* We can see enterlocks... else we'd break zones */
00035                 checkit = 1;
00036         } else if(See_attr(lockobj, player, attr, aowner, aflags)) {
00037                 checkit = 1;
00038         } else if(attr->number == A_NAME) {
00039                 checkit = 1;
00040         }
00041         if(checkit && (!wild_match(key, buff))) {
00042                 checkit = 0;
00043         }
00044         free_lbuf(buff);
00045         return checkit;
00046 }                                                               /* end check_attr() */
00047 
00048 int eval_boolexp(dbref player, dbref thing, dbref from, BOOLEXP * b)
00049 {
00050         dbref aowner, obj, source;
00051         int aflags, c, checkit;
00052         char *key, *buff, *buff2, *bp, *str;
00053         ATTR *a;
00054 
00055         if(b == TRUE_BOOLEXP)
00056                 return 1;
00057 
00058         switch (b->type) {
00059         case BOOLEXP_AND:
00060                 return (eval_boolexp(player, thing, from, b->sub1) &&
00061                                 eval_boolexp(player, thing, from, b->sub2));
00062         case BOOLEXP_OR:
00063                 return (eval_boolexp(player, thing, from, b->sub1) ||
00064                                 eval_boolexp(player, thing, from, b->sub2));
00065         case BOOLEXP_NOT:
00066                 return !eval_boolexp(player, thing, from, b->sub1);
00067         case BOOLEXP_INDIR:
00068                 /*
00069                  * BOOLEXP_INDIR (i.e. @) is a unary operation which is replaced at
00070                  * evaluation time by the lock of the object whose number is the
00071                  * argument of the operation.
00072                  */
00073 
00074                 mudstate.lock_nest_lev++;
00075                 if(mudstate.lock_nest_lev >= mudconf.lock_nest_lim) {
00076 //            log_error(LOG_BUGS, "BUG", "LOCK", "
00077                         STARTLOG(LOG_BUGS, "BUG", "LOCK") {
00078                                 log_name_and_loc(player);
00079                                 log_text((char *) ": Lock exceeded recursion limit.");
00080                                 ENDLOG;
00081                         } notify(player, "Sorry, broken lock!");
00082                         mudstate.lock_nest_lev--;
00083                         return (0);
00084                 }
00085                 if((b->sub1->type != BOOLEXP_CONST) || (b->sub1->thing < 0)) {
00086                         STARTLOG(LOG_BUGS, "BUG", "LOCK") {
00087                                 log_name_and_loc(player);
00088                                 buff = alloc_mbuf("eval_boolexp.LOG.indir");
00089                                 sprintf(buff, ": Lock had bad indirection (%c, type %d)",
00090                                                 INDIR_TOKEN, b->sub1->type);
00091                                 log_text(buff);
00092                                 free_mbuf(buff);
00093                                 ENDLOG;
00094                         }
00095                         notify(player, "Sorry, broken lock!");
00096                         mudstate.lock_nest_lev--;
00097                         return (0);
00098                 }
00099                 key = atr_get(b->sub1->thing, A_LOCK, &aowner, &aflags);
00100                 c = eval_boolexp_atr(player, b->sub1->thing, from, key);
00101                 free_lbuf(key);
00102                 mudstate.lock_nest_lev--;
00103                 return (c);
00104         case BOOLEXP_CONST:
00105                 return (b->thing == player || member(b->thing, Contents(player)));
00106         case BOOLEXP_ATR:
00107                 a = atr_num(b->thing);
00108                 if(!a)
00109                         return 0;                       /*
00110                                                                  * no such attribute 
00111                                                                  */
00112 
00113                 /*
00114                  * First check the object itself, then its contents 
00115                  */
00116 
00117                 if(check_attr(player, from, a, (char *) b->sub1))
00118                         return 1;
00119                 DOLIST(obj, Contents(player)) {
00120                         if(check_attr(obj, from, a, (char *) b->sub1))
00121                                 return 1;
00122                 }
00123                 return 0;
00124         case BOOLEXP_EVAL:
00125                 a = atr_num(b->thing);
00126                 if(!a)
00127                         return 0;                       /*
00128                                                                  * no such attribute 
00129                                                                  */
00130                 source = from;
00131                 buff = atr_pget(from, a->number, &aowner, &aflags);
00132                 if(!buff || !*buff) {
00133                         free_lbuf(buff);
00134                         buff = atr_pget(thing, a->number, &aowner, &aflags);
00135                         source = thing;
00136                 }
00137                 checkit = 0;
00138 
00139                 if((a->number == A_NAME) || (a->number == A_LENTER)) {
00140                         checkit = 1;
00141                 } else if(Read_attr(source, source, a, aowner, aflags)) {
00142                         checkit = 1;
00143                 }
00144                 if(checkit) {
00145                         buff2 = bp = alloc_lbuf("eval_boolexp");
00146                         str = buff;
00147                         exec(buff2, &bp, 0, source, player,
00148                                  EV_FIGNORE | EV_EVAL | EV_TOP, &str, (char **) NULL, 0);
00149                         *bp = '\0';
00150                         checkit = !string_compare(buff2, (char *) b->sub1);
00151                         free_lbuf(buff2);
00152                 }
00153                 free_lbuf(buff);
00154                 return checkit;
00155         case BOOLEXP_IS:
00156 
00157                 /*
00158                  * If an object check, do that 
00159                  */
00160 
00161                 if(b->sub1->type == BOOLEXP_CONST)
00162                         return (b->sub1->thing == player);
00163 
00164                 /*
00165                  * Nope, do an attribute check 
00166                  */
00167 
00168                 a = atr_num(b->sub1->thing);
00169                 if(!a)
00170                         return 0;
00171                 return (check_attr(player, from, a, (char *) (b->sub1)->sub1));
00172         case BOOLEXP_CARRY:
00173 
00174                 /*
00175                  * If an object check, do that 
00176                  */
00177 
00178                 if(b->sub1->type == BOOLEXP_CONST)
00179                         return (member(b->sub1->thing, Contents(player)));
00180 
00181                 /*
00182                  * Nope, do an attribute check 
00183                  */
00184 
00185                 a = atr_num(b->sub1->thing);
00186                 if(!a)
00187                         return 0;
00188                 DOLIST(obj, Contents(player)) {
00189                         if(check_attr(obj, from, a, (char *) (b->sub1)->sub1))
00190                                 return 1;
00191                 }
00192                 return 0;
00193         case BOOLEXP_OWNER:
00194                 return (Owner(b->sub1->thing) == Owner(player));
00195         default:
00196                 abort();                                /*
00197                                                                  * bad type 
00198                                                                  */
00199                 return 0;
00200         }
00201 }                                                               /* end eval_boolexp() */
00202 
00203 int eval_boolexp_atr(dbref player, dbref thing, dbref from, char *key)
00204 {
00205         BOOLEXP *b;
00206         int ret_value;
00207 
00208         b = parse_boolexp(player, key, 1);
00209         if(b == NULL) {
00210                 ret_value = 1;
00211         } else {
00212                 ret_value = eval_boolexp(player, thing, from, b);
00213                 free_boolexp(b);
00214         }
00215         return (ret_value);
00216 }                                                               /* end eval_boolexp_atr() */
00217 
00218 /*
00219  * If the parser returns TRUE_BOOLEXP, you lose 
00220  */
00221 
00222 /*
00223  * TRUE_BOOLEXP cannot be typed in by the user; use @unlock instead 
00224  */
00225 
00226 static const char *parsebuf;
00227 static char parsestore[LBUF_SIZE];
00228 static dbref parse_player;
00229 
00230 static void skip_whitespace(void)
00231 {
00232         while (*parsebuf && isspace(*parsebuf))
00233                 parsebuf++;
00234 }
00235 
00236 static BOOLEXP *parse_boolexp_E(void);  /* defined below */
00237 
00238 static BOOLEXP *test_atr(char *s)
00239 {
00240         ATTR *attrib;
00241         BOOLEXP *b;
00242         char *buff, *s1;
00243         int anum, locktype;
00244 
00245         buff = alloc_lbuf("test_atr");
00246         StringCopy(buff, s);
00247         for(s = buff; *s && (*s != ':') && (*s != '/'); s++);
00248         if(!*s) {
00249                 free_lbuf(buff);
00250                 return ((BOOLEXP *) NULL);
00251         }
00252         if(*s == '/')
00253                 locktype = BOOLEXP_EVAL;
00254         else
00255                 locktype = BOOLEXP_ATR;
00256 
00257         *s++ = '\0';
00258         /*
00259          * see if left side is valid attribute.  Access to attr is checked on 
00260          * 
00261          * *  * *  * *  * *  * * eval * Also allow numeric references to *
00262          * attributes. * It * can't * hurt  * us, and * lets us import stuff
00263          * * that stores * attr * locks by * number * instead of by * name. 
00264          */
00265         if(!(attrib = atr_str(buff))) {
00266 
00267                 /*
00268                  * Only #1 can lock on numbers 
00269                  */
00270                 if(!God(parse_player)) {
00271                         free_lbuf(buff);
00272                         return ((BOOLEXP *) NULL);
00273                 }
00274                 s1 = buff;
00275                 for(s1 = buff; isdigit(*s1); s1++);
00276                 if(*s1) {
00277                         free_lbuf(buff);
00278                         return ((BOOLEXP *) NULL);
00279                 }
00280                 anum = atoi(buff);
00281         } else {
00282                 anum = attrib->number;
00283         }
00284 
00285         /*
00286          * made it now make the parse tree node 
00287          */
00288         b = alloc_bool("test_str");
00289         b->type = locktype;
00290         b->thing = (dbref) anum;
00291         b->sub1 = (BOOLEXP *) strsave(s);
00292         free_lbuf(buff);
00293         return (b);
00294 }                                                               /* end test_atr() */
00295 
00296 /*
00297  * L -> (E); L -> object identifier 
00298  */
00299 static BOOLEXP *parse_boolexp_L(void)
00300 {
00301         BOOLEXP *b;
00302         char *p, *buf;
00303         MSTATE mstate;
00304 
00305         buf = NULL;
00306         skip_whitespace();
00307 
00308         switch (*parsebuf) {
00309         case '(':
00310                 parsebuf++;
00311                 b = parse_boolexp_E();
00312                 skip_whitespace();
00313                 if(b == TRUE_BOOLEXP || *parsebuf++ != ')') {
00314                         free_boolexp(b);
00315                         return TRUE_BOOLEXP;
00316                 }
00317                 break;
00318         default:
00319 
00320                 /*
00321                  * Must have hit an object ref. Load the name into our  
00322                  * buffer
00323                  */
00324 
00325                 buf = alloc_lbuf("parse_boolexp_L");
00326                 p = buf;
00327                 while (*parsebuf && (*parsebuf != AND_TOKEN) &&
00328                            (*parsebuf != OR_TOKEN) && (*parsebuf != ')')) {
00329                         *p++ = *parsebuf++;
00330                 }
00331 
00332                 /*
00333                  * strip trailing whitespace 
00334                  */
00335 
00336                 *p-- = '\0';
00337                 while (isspace(*p))
00338                         *p-- = '\0';
00339 
00340                 /*
00341                  * check for an attribute 
00342                  */
00343 
00344                 if((b = test_atr(buf)) != NULL) {
00345                         free_lbuf(buf);
00346                         return (b);
00347                 }
00348                 b = alloc_bool("parse_boolexp_L");
00349                 b->type = BOOLEXP_CONST;
00350 
00351                 /*
00352                  * do the match 
00353                  */
00354 
00355                 /*
00356                  * If we are parsing a boolexp that was a stored lock then 
00357                  * we know that object refs are all dbrefs, so we  
00358                  * skip the expensive match code. 
00359                  */
00360 
00361                 if(parsing_internal) {
00362                         if(buf[0] != '#') {
00363                                 free_lbuf(buf);
00364                                 free_bool(b);
00365                                 return TRUE_BOOLEXP;
00366                         }
00367                         b->thing = atoi(&buf[1]);
00368                         if(!Good_obj(b->thing)) {
00369                                 free_lbuf(buf);
00370                                 free_bool(b);
00371                                 return TRUE_BOOLEXP;
00372                         }
00373                 } else {
00374                         save_match_state(&mstate);
00375                         init_match(parse_player, buf, TYPE_THING);
00376                         match_everything(MAT_EXIT_PARENTS);
00377                         b->thing = match_result();
00378                         restore_match_state(&mstate);
00379                 }
00380 
00381                 if(b->thing == NOTHING) {
00382                         notify_printf(parse_player, "I don't see %s here.", buf);
00383                         free_lbuf(buf);
00384                         free_bool(b);
00385                         return TRUE_BOOLEXP;
00386                 }
00387                 if(b->thing == AMBIGUOUS) {
00388                         notify_printf(parse_player, "I don't know which %s you mean!",
00389                                                   buf);
00390                         free_lbuf(buf);
00391                         free_bool(b);
00392                         return TRUE_BOOLEXP;
00393                 }
00394                 free_lbuf(buf);
00395         }
00396         return b;
00397 }                                                               /* end parse_boolexp_L() */
00398 
00399 /*
00400  * F -> !F; F -> @L; F -> =L; F -> +L; F -> $L 
00401  */
00402 
00403 /*
00404  * The argument L must be type BOOLEXP_CONST 
00405  */
00406 
00407 static BOOLEXP *parse_boolexp_F(void)
00408 {
00409         BOOLEXP *b2;
00410 
00411         skip_whitespace();
00412         switch (*parsebuf) {
00413         case NOT_TOKEN:
00414                 parsebuf++;
00415                 b2 = alloc_bool("parse_boolexp_F.not");
00416                 b2->type = BOOLEXP_NOT;
00417                 if((b2->sub1 = parse_boolexp_F()) == TRUE_BOOLEXP) {
00418                         free_boolexp(b2);
00419                         return (TRUE_BOOLEXP);
00420                 } else
00421                         return (b2);
00422                 /*
00423                  * NOTREACHED 
00424                  */
00425                 break;
00426         case INDIR_TOKEN:
00427                 parsebuf++;
00428                 b2 = alloc_bool("parse_boolexp_F.indir");
00429                 b2->type = BOOLEXP_INDIR;
00430                 b2->sub1 = parse_boolexp_L();
00431                 if((b2->sub1) == TRUE_BOOLEXP) {
00432                         free_boolexp(b2);
00433                         return (TRUE_BOOLEXP);
00434                 } else if((b2->sub1->type) != BOOLEXP_CONST) {
00435                         free_boolexp(b2);
00436                         return (TRUE_BOOLEXP);
00437                 } else
00438                         return (b2);
00439                 /*
00440                  * NOTREACHED 
00441                  */
00442                 break;
00443         case IS_TOKEN:
00444                 parsebuf++;
00445                 b2 = alloc_bool("parse_boolexp_F.is");
00446                 b2->type = BOOLEXP_IS;
00447                 b2->sub1 = parse_boolexp_L();
00448                 if((b2->sub1) == TRUE_BOOLEXP) {
00449                         free_boolexp(b2);
00450                         return (TRUE_BOOLEXP);
00451                 } else if(((b2->sub1->type) != BOOLEXP_CONST) &&
00452                                   ((b2->sub1->type) != BOOLEXP_ATR)) {
00453                         free_boolexp(b2);
00454                         return (TRUE_BOOLEXP);
00455                 } else
00456                         return (b2);
00457                 /*
00458                  * NOTREACHED 
00459                  */
00460                 break;
00461         case CARRY_TOKEN:
00462                 parsebuf++;
00463                 b2 = alloc_bool("parse_boolexp_F.carry");
00464                 b2->type = BOOLEXP_CARRY;
00465                 b2->sub1 = parse_boolexp_L();
00466                 if((b2->sub1) == TRUE_BOOLEXP) {
00467                         free_boolexp(b2);
00468                         return (TRUE_BOOLEXP);
00469                 } else if(((b2->sub1->type) != BOOLEXP_CONST) &&
00470                                   ((b2->sub1->type) != BOOLEXP_ATR)) {
00471                         free_boolexp(b2);
00472                         return (TRUE_BOOLEXP);
00473                 } else
00474                         return (b2);
00475                 /*
00476                  * NOTREACHED 
00477                  */
00478                 break;
00479         case OWNER_TOKEN:
00480                 parsebuf++;
00481                 b2 = alloc_bool("parse_boolexp_F.owner");
00482                 b2->type = BOOLEXP_OWNER;
00483                 b2->sub1 = parse_boolexp_L();
00484                 if((b2->sub1) == TRUE_BOOLEXP) {
00485                         free_boolexp(b2);
00486                         return (TRUE_BOOLEXP);
00487                 } else if((b2->sub1->type) != BOOLEXP_CONST) {
00488                         free_boolexp(b2);
00489                         return (TRUE_BOOLEXP);
00490                 } else
00491                         return (b2);
00492                 /*
00493                  * NOTREACHED 
00494                  */
00495                 break;
00496         default:
00497                 return (parse_boolexp_L());
00498         }
00499 }                                                               /* end parse_boolexp_F() */
00500 
00501 /*
00502  * T -> F; T -> F & T 
00503  */
00504 
00505 static BOOLEXP *parse_boolexp_T(void)
00506 {
00507         BOOLEXP *b, *b2;
00508 
00509         if((b = parse_boolexp_F()) != TRUE_BOOLEXP) {
00510                 skip_whitespace();
00511                 if(*parsebuf == AND_TOKEN) {
00512                         parsebuf++;
00513 
00514                         b2 = alloc_bool("parse_boolexp_T");
00515                         b2->type = BOOLEXP_AND;
00516                         b2->sub1 = b;
00517                         if((b2->sub2 = parse_boolexp_T()) == TRUE_BOOLEXP) {
00518                                 free_boolexp(b2);
00519                                 return TRUE_BOOLEXP;
00520                         }
00521                         b = b2;
00522                 }
00523         }
00524         return b;
00525 }                                                               /* end parse_boolexp_T() */
00526 
00527 /*
00528  * E -> T; E -> T | E 
00529  */
00530 static BOOLEXP *parse_boolexp_E(void)
00531 {
00532         BOOLEXP *b, *b2;
00533 
00534         if((b = parse_boolexp_T()) != TRUE_BOOLEXP) {
00535                 skip_whitespace();
00536                 if(*parsebuf == OR_TOKEN) {
00537                         parsebuf++;
00538 
00539                         b2 = alloc_bool("parse_boolexp_E");
00540                         b2->type = BOOLEXP_OR;
00541                         b2->sub1 = b;
00542                         if((b2->sub2 = parse_boolexp_E()) == TRUE_BOOLEXP) {
00543                                 free_boolexp(b2);
00544                                 return TRUE_BOOLEXP;
00545                         }
00546                         b = b2;
00547                 }
00548         }
00549         return b;
00550 }                                                               /* parse_boolexp_E */
00551 
00552 BOOLEXP *parse_boolexp(dbref player, const char *buf, int internal)
00553 {
00554         StringCopy(parsestore, buf);
00555         parsebuf = parsestore;
00556         parse_player = player;
00557         if((buf == NULL) || (*buf == '\0'))
00558                 return (TRUE_BOOLEXP);
00559         parsing_internal = internal;
00560         return parse_boolexp_E();
00561 }                                                               /* end parse_boolexp() */

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