mux/src/boolexp.cpp

Go to the documentation of this file.
00001 // boolexp.cpp
00002 //
00003 // $Id: boolexp.cpp,v 1.18 2006/01/08 04:28:44 sdennis Exp $
00004 //
00005 #include "copyright.h"
00006 #include "autoconf.h"
00007 #include "config.h"
00008 #include "externs.h"
00009 
00010 #include "attrs.h"
00011 
00012 static bool parsing_internal = false;
00013 
00014 /* ---------------------------------------------------------------------------
00015  * check_attr: indicate if attribute ATTR on player passes key when checked by
00016  * the object lockobj
00017  */
00018 
00019 static bool check_attr(dbref player, dbref lockobj, ATTR *attr, char *key)
00020 {
00021     dbref aowner;
00022     int aflags;
00023     bool bCheck = false;
00024 
00025     char *buff = atr_pget(player, attr->number, &aowner, &aflags);
00026 
00027     if (attr->number == A_LENTER)
00028     {
00029         // We can see enterlocks... else we'd break zones.
00030         //
00031         bCheck = true;
00032     }
00033     else if (See_attr(lockobj, player, attr))
00034     {
00035         bCheck = true;
00036     }
00037     else if (attr->number == A_NAME)
00038     {
00039         bCheck = true;
00040     }
00041 
00042     if (  bCheck
00043        && !wild_match(key, buff))
00044     {
00045         bCheck = false;
00046     }
00047     free_lbuf(buff);
00048     return bCheck;
00049 }
00050 
00051 bool eval_boolexp(dbref player, dbref thing, dbref from, BOOLEXP *b)
00052 {
00053     if (b == TRUE_BOOLEXP)
00054     {
00055         return true;
00056     }
00057 
00058     dbref aowner, obj, source;
00059     int aflags;
00060     char *key, *buff, *buff2, *bp, *str;
00061     ATTR *a;
00062     bool bCheck, c;
00063 
00064     switch (b->type)
00065     {
00066     case BOOLEXP_AND:
00067         return   eval_boolexp(player, thing, from, b->sub1)
00068               && eval_boolexp(player, thing, from, b->sub2);
00069 
00070     case BOOLEXP_OR:
00071         return   eval_boolexp(player, thing, from, b->sub1)
00072               || eval_boolexp(player, thing, from, b->sub2);
00073 
00074     case BOOLEXP_NOT:
00075         return !eval_boolexp(player, thing, from, b->sub1);
00076 
00077     case BOOLEXP_INDIR:
00078 
00079         // BOOLEXP_INDIR (i.e. @) is a unary operation which is replaced at
00080         // evaluation time by the lock of the object whose number is the
00081         // argument of the operation.
00082         //
00083         mudstate.lock_nest_lev++;
00084         if (mudstate.lock_nest_lev >= mudconf.lock_nest_lim)
00085         {
00086             if (mudstate.bStandAlone)
00087             {
00088                 Log.WriteString("Lock exceeded recursion limit." ENDLINE);
00089             }
00090             else
00091             {
00092                 STARTLOG(LOG_BUGS, "BUG", "LOCK");
00093                 log_name_and_loc(player);
00094                 log_text(": Lock exceeded recursion limit.");
00095                 ENDLOG;
00096                 notify(player, "Sorry, broken lock!");
00097             }
00098             mudstate.lock_nest_lev--;
00099             return false;
00100         }
00101         if (  b->sub1->type != BOOLEXP_CONST
00102            || b->sub1->thing < 0)
00103         {
00104             if (mudstate.bStandAlone)
00105             {
00106                 Log.WriteString("Broken lock." ENDLINE);
00107             }
00108             else
00109             {
00110                 STARTLOG(LOG_BUGS, "BUG", "LOCK");
00111                 log_name_and_loc(player);
00112                 buff = alloc_mbuf("eval_boolexp.LOG.indir");
00113                 sprintf(buff, ": Lock had bad indirection (%c, type %d)",
00114                     INDIR_TOKEN, b->sub1->type);
00115                 log_text(buff);
00116                 free_mbuf(buff);
00117                 ENDLOG;
00118                 notify(player, "Sorry, broken lock!");
00119             }
00120             mudstate.lock_nest_lev--;
00121             return false;
00122         }
00123         key = atr_get(b->sub1->thing, A_LOCK, &aowner, &aflags);
00124         c = eval_boolexp_atr(player, b->sub1->thing, from, key);
00125         free_lbuf(key);
00126         mudstate.lock_nest_lev--;
00127         return c;
00128 
00129     case BOOLEXP_CONST:
00130         return   b->thing == player
00131               || member(b->thing, Contents(player));
00132 
00133     case BOOLEXP_ATR:
00134         a = atr_num(b->thing);
00135         if (!a)
00136         {
00137             // No such attribute.
00138             //
00139             return false;
00140         }
00141 
00142         // First check the object itself, then its contents.
00143         //
00144         if (check_attr(player, from, a, (char *)b->sub1))
00145         {
00146             return true;
00147         }
00148         DOLIST(obj, Contents(player))
00149         {
00150             if (check_attr(obj, from, a, (char *)b->sub1))
00151             {
00152                 return true;
00153             }
00154         }
00155         return false;
00156 
00157     case BOOLEXP_EVAL:
00158 
00159         a = atr_num(b->thing);
00160         if (  !a
00161            || MuxAlarm.bAlarmed)
00162         {
00163             // No such attribute.
00164             //
00165             return false;
00166         }
00167         source = from;
00168         buff = atr_pget(from, a->number, &aowner, &aflags);
00169         if (!buff || !*buff)
00170         {
00171             free_lbuf(buff);
00172             buff = atr_pget(thing, a->number, &aowner, &aflags);
00173             source = thing;
00174         }
00175         bCheck = false;
00176 
00177         if (  a->number == A_NAME
00178            || a->number == A_LENTER)
00179         {
00180             bCheck = true;
00181         }
00182         else if (bCanReadAttr(source, source, a, false))
00183         {
00184             bCheck = true;
00185         }
00186         if (bCheck)
00187         {
00188             char **preserve = NULL;
00189             int *preserve_len = NULL;
00190             preserve = PushPointers(MAX_GLOBAL_REGS);
00191             preserve_len = PushIntegers(MAX_GLOBAL_REGS);
00192             save_global_regs("eval_boolexp_save", preserve, preserve_len);
00193 
00194             buff2 = bp = alloc_lbuf("eval_boolexp");
00195             str = buff;
00196             mux_exec(buff2, &bp, source, player, player,
00197                 EV_FIGNORE | EV_EVAL | EV_FCHECK | EV_TOP, &str,
00198                 (char **)NULL, 0);
00199             *bp = '\0';
00200 
00201             restore_global_regs("eval_boolexp_save", preserve, preserve_len);
00202             PopIntegers(preserve_len, MAX_GLOBAL_REGS);
00203             PopPointers(preserve, MAX_GLOBAL_REGS);
00204 
00205             bCheck = !string_compare(buff2, (char *)b->sub1);
00206             free_lbuf(buff2);
00207         }
00208         free_lbuf(buff);
00209         return bCheck;
00210 
00211     case BOOLEXP_IS:
00212 
00213         // If an object check, do that.
00214         //
00215         if (b->sub1->type == BOOLEXP_CONST)
00216         {
00217             return (b->sub1->thing == player);
00218         }
00219 
00220         // Nope, do an attribute check
00221         //
00222         a = atr_num(b->sub1->thing);
00223         if (!a)
00224         {
00225             return false;
00226         }
00227         return check_attr(player, from, a, (char *)(b->sub1)->sub1);
00228 
00229     case BOOLEXP_CARRY:
00230 
00231         // If an object check, do that
00232         //
00233         if (b->sub1->type == BOOLEXP_CONST)
00234         {
00235             return member(b->sub1->thing, Contents(player));
00236         }
00237 
00238         // Nope, do an attribute check
00239         //
00240         a = atr_num(b->sub1->thing);
00241         if (!a)
00242         {
00243             return false;
00244         }
00245         DOLIST(obj, Contents(player))
00246         {
00247             if (check_attr(obj, from, a, (char *)(b->sub1)->sub1))
00248             {
00249                 return true;
00250             }
00251         }
00252         return false;
00253 
00254     case BOOLEXP_OWNER:
00255 
00256         return (Owner(b->sub1->thing) == Owner(player));
00257 
00258     default:
00259 
00260         // Bad type
00261         //
00262         mux_assert(0);
00263         return false;
00264     }
00265 }
00266 
00267 bool eval_boolexp_atr(dbref player, dbref thing, dbref from, char *key)
00268 {
00269     bool ret_value;
00270 
00271     BOOLEXP *b = parse_boolexp(player, key, true);
00272     if (b == NULL)
00273     {
00274         ret_value = true;
00275     }
00276     else
00277     {
00278         ret_value = eval_boolexp(player, thing, from, b);
00279         free_boolexp(b);
00280     }
00281     return ret_value;
00282 }
00283 
00284 // If the parser returns TRUE_BOOLEXP, you lose
00285 // TRUE_BOOLEXP cannot be typed in by the user; use @unlock instead
00286 //
00287 static const char *parsebuf;
00288 static char parsestore[LBUF_SIZE];
00289 static dbref parse_player;
00290 
00291 static void skip_whitespace(void)
00292 {
00293     while (mux_isspace(*parsebuf))
00294     {
00295         parsebuf++;
00296     }
00297 }
00298 
00299 // Defined below.
00300 //
00301 static BOOLEXP *parse_boolexp_E(void);
00302 
00303 static BOOLEXP *test_atr(char *s)
00304 {
00305     char *s1;
00306     int anum;
00307     boolexp_type locktype;
00308 
00309     char *buff = alloc_lbuf("test_atr");
00310     strcpy(buff, s);
00311     for (s = buff; *s && (*s != ':') && (*s != '/'); s++)
00312     {
00313         ; // Nothing.
00314     }
00315     if (!*s)
00316     {
00317         free_lbuf(buff);
00318         return TRUE_BOOLEXP;
00319     }
00320     if (*s == '/')
00321     {
00322         locktype = BOOLEXP_EVAL;
00323     }
00324     else
00325     {
00326         locktype = BOOLEXP_ATR;
00327     }
00328 
00329     *s++ = '\0';
00330 
00331     // See if left side is valid attribute.  Access to attr is checked on eval
00332     // Also allow numeric references to attributes. It can't hurt us, and lets
00333     // us import stuff that stores attr locks by number instead of by name.
00334     //
00335     ATTR *attrib = atr_str(buff);
00336     if (!attrib)
00337     {
00338         // Only #1 can lock on numbers
00339         //
00340         if (!God(parse_player))
00341         {
00342             free_lbuf(buff);
00343             return TRUE_BOOLEXP;
00344         }
00345         for (s1 = buff; mux_isdigit(*s1); s1++)
00346         {
00347             ; // Nothing.
00348         }
00349         if (*s1)
00350         {
00351             free_lbuf(buff);
00352             return TRUE_BOOLEXP;
00353         }
00354         anum = mux_atol(buff);
00355         if (anum <= 0)
00356         {
00357             free_lbuf(buff);
00358             return TRUE_BOOLEXP;
00359         }
00360     }
00361     else
00362     {
00363         anum = attrib->number;
00364     }
00365 
00366     // made it now make the parse tree node
00367     //
00368     BOOLEXP *b = alloc_bool("test_str");
00369     b->type = locktype;
00370     b->thing = (dbref) anum;
00371     b->sub1 = (BOOLEXP *) StringClone(s);
00372     free_lbuf(buff);
00373     return b;
00374 }
00375 
00376 // L -> (E); L -> object identifier
00377 //
00378 static BOOLEXP *parse_boolexp_L(void)
00379 {
00380     BOOLEXP *b;
00381     char    *p;
00382     char    *buf;
00383     MSTATE  mstate;
00384 
00385     buf = NULL;
00386     skip_whitespace();
00387 
00388     switch (*parsebuf)
00389     {
00390     case '(':
00391         parsebuf++;
00392         b = parse_boolexp_E();
00393         skip_whitespace();
00394         if (  b == TRUE_BOOLEXP
00395            || *parsebuf++ != ')')
00396         {
00397             free_boolexp(b);
00398             return TRUE_BOOLEXP;
00399         }
00400         break;
00401     default:
00402 
00403         // Must have hit an object ref.  Load the name into our buffer.
00404         //
00405         buf = alloc_lbuf("parse_boolexp_L");
00406         p = buf;
00407         while (  *parsebuf
00408               && *parsebuf != AND_TOKEN
00409               && *parsebuf != OR_TOKEN
00410               && *parsebuf != ')'
00411               && p < buf + LBUF_SIZE)
00412         {
00413             *p++ = *parsebuf++;
00414         }
00415 
00416         // Strip trailing whitespace.
00417         //
00418         *p-- = '\0';
00419         while (mux_isspace(*p))
00420         {
00421             *p-- = '\0';
00422         }
00423 
00424         // Check for an attribute.
00425         //
00426         if ((b = test_atr(buf)) != NULL)
00427         {
00428             free_lbuf(buf);
00429             return (b);
00430         }
00431         b = alloc_bool("parse_boolexp_L");
00432         b->type = BOOLEXP_CONST;
00433 
00434         // do the match.
00435         //
00436 
00437         if (!mudstate.bStandAlone)
00438         {
00439             // If we are parsing a boolexp that was a stored lock then we
00440             // know that object refs are all dbrefs, so we skip the
00441             // expensive match code.
00442             //
00443             if (parsing_internal)
00444             {
00445                 if (buf[0] != '#')
00446                 {
00447                     free_lbuf(buf);
00448                     free_bool(b);
00449                     return TRUE_BOOLEXP;
00450                 }
00451                 b->thing = mux_atol(&buf[1]);
00452                 if (!Good_dbref(b->thing))
00453                 {
00454                     free_lbuf(buf);
00455                     free_bool(b);
00456                     return TRUE_BOOLEXP;
00457                 }
00458             }
00459             else
00460             {
00461                 save_match_state(&mstate);
00462                 init_match(parse_player, buf, TYPE_THING);
00463                 match_everything(MAT_EXIT_PARENTS);
00464                 b->thing = match_result();
00465                 restore_match_state(&mstate);
00466             }
00467 
00468             if (b->thing == NOTHING)
00469             {
00470                 notify(parse_player, tprintf("I don't see %s here.", buf));
00471                 free_lbuf(buf);
00472                 free_bool(b);
00473                 return TRUE_BOOLEXP;
00474             }
00475             if (b->thing == AMBIGUOUS)
00476             {
00477                 notify(parse_player, tprintf("I don't know which %s you mean!",
00478                     buf));
00479                 free_lbuf(buf);
00480                 free_bool(b);
00481                 return TRUE_BOOLEXP;
00482             }
00483         }
00484         else
00485         {
00486             // Had better be #<num> or we're hosed.
00487             //
00488             if (buf[0] != '#')
00489             {
00490                 free_lbuf(buf);
00491                 free_bool(b);
00492                 return TRUE_BOOLEXP;
00493             }
00494             b->thing = mux_atol(&buf[1]);
00495             if (b->thing < 0)
00496             {
00497                 free_lbuf(buf);
00498                 free_bool(b);
00499                 return TRUE_BOOLEXP;
00500             }
00501         }
00502         free_lbuf(buf);
00503     }
00504     return b;
00505 }
00506 
00507 // F -> !F; F -> @L; F -> =L; F -> +L; F -> $L
00508 // The argument L must be type BOOLEXP_CONST
00509 //
00510 static BOOLEXP *parse_boolexp_F(void)
00511 {
00512     BOOLEXP *b2;
00513 
00514     skip_whitespace();
00515     switch (*parsebuf)
00516     {
00517     case NOT_TOKEN:
00518 
00519         parsebuf++;
00520         b2 = alloc_bool("parse_boolexp_F.not");
00521         b2->type = BOOLEXP_NOT;
00522         if ((b2->sub1 = parse_boolexp_F()) == TRUE_BOOLEXP)
00523         {
00524             free_boolexp(b2);
00525             return (TRUE_BOOLEXP);
00526         }
00527         else
00528         {
00529             return (b2);
00530         }
00531 
00532         // NOTREACHED
00533         //
00534 
00535     case INDIR_TOKEN:
00536 
00537         parsebuf++;
00538         b2 = alloc_bool("parse_boolexp_F.indir");
00539         b2->type = BOOLEXP_INDIR;
00540         b2->sub1 = parse_boolexp_L();
00541         if ((b2->sub1) == TRUE_BOOLEXP)
00542         {
00543             free_boolexp(b2);
00544             return (TRUE_BOOLEXP);
00545         }
00546         else if ((b2->sub1->type) != BOOLEXP_CONST)
00547         {
00548             free_boolexp(b2);
00549             return (TRUE_BOOLEXP);
00550         }
00551         else
00552         {
00553             return (b2);
00554         }
00555 
00556         // NOTREACHED
00557         //
00558 
00559     case IS_TOKEN:
00560 
00561         parsebuf++;
00562         b2 = alloc_bool("parse_boolexp_F.is");
00563         b2->type = BOOLEXP_IS;
00564         b2->sub1 = parse_boolexp_L();
00565         if (b2->sub1 == TRUE_BOOLEXP)
00566         {
00567             free_boolexp(b2);
00568             return (TRUE_BOOLEXP);
00569         }
00570         else if (  b2->sub1->type != BOOLEXP_CONST
00571                 && b2->sub1->type != BOOLEXP_ATR)
00572         {
00573             free_boolexp(b2);
00574             return TRUE_BOOLEXP;
00575         }
00576         else
00577         {
00578             return (b2);
00579         }
00580 
00581         // NOTREACHED
00582         //
00583 
00584     case CARRY_TOKEN:
00585 
00586         parsebuf++;
00587         b2 = alloc_bool("parse_boolexp_F.carry");
00588         b2->type = BOOLEXP_CARRY;
00589         b2->sub1 = parse_boolexp_L();
00590         if (b2->sub1 == TRUE_BOOLEXP)
00591         {
00592             free_boolexp(b2);
00593             return TRUE_BOOLEXP;
00594         }
00595         else if (  b2->sub1->type != BOOLEXP_CONST
00596                 && b2->sub1->type != BOOLEXP_ATR)
00597         {
00598             free_boolexp(b2);
00599             return TRUE_BOOLEXP;
00600         }
00601         else
00602         {
00603             return b2;
00604         }
00605 
00606         // NOTREACHED
00607         //
00608 
00609     case OWNER_TOKEN:
00610 
00611         parsebuf++;
00612         b2 = alloc_bool("parse_boolexp_F.owner");
00613         b2->type = BOOLEXP_OWNER;
00614         b2->sub1 = parse_boolexp_L();
00615         if (b2->sub1 == TRUE_BOOLEXP)
00616         {
00617             free_boolexp(b2);
00618             return TRUE_BOOLEXP;
00619         }
00620         else if (b2->sub1->type != BOOLEXP_CONST)
00621         {
00622             free_boolexp(b2);
00623             return TRUE_BOOLEXP;
00624         }
00625         else
00626         {
00627             return b2;
00628         }
00629 
00630         // NOTREACHED
00631         //
00632 
00633     default:
00634         return parse_boolexp_L();
00635     }
00636 }
00637 
00638 // T -> F; T -> F & T
00639 //
00640 static BOOLEXP *parse_boolexp_T(void)
00641 {
00642     BOOLEXP *b, *b2;
00643 
00644     if ((b = parse_boolexp_F()) != TRUE_BOOLEXP)
00645     {
00646         skip_whitespace();
00647         if (*parsebuf == AND_TOKEN)
00648         {
00649             parsebuf++;
00650 
00651             b2 = alloc_bool("parse_boolexp_T");
00652             b2->type = BOOLEXP_AND;
00653             b2->sub1 = b;
00654             if ((b2->sub2 = parse_boolexp_T()) == TRUE_BOOLEXP)
00655             {
00656                 free_boolexp(b2);
00657                 return TRUE_BOOLEXP;
00658             }
00659             b = b2;
00660         }
00661     }
00662     return b;
00663 }
00664 
00665 // E -> T; E -> T | E
00666 //
00667 static BOOLEXP *parse_boolexp_E(void)
00668 {
00669     BOOLEXP *b, *b2;
00670 
00671     if ((b = parse_boolexp_T()) != TRUE_BOOLEXP)
00672     {
00673         skip_whitespace();
00674         if (*parsebuf == OR_TOKEN)
00675         {
00676             parsebuf++;
00677 
00678             b2 = alloc_bool("parse_boolexp_E");
00679             b2->type = BOOLEXP_OR;
00680             b2->sub1 = b;
00681             if ((b2->sub2 = parse_boolexp_E()) == TRUE_BOOLEXP)
00682             {
00683                 free_boolexp(b2);
00684                 return TRUE_BOOLEXP;
00685             }
00686             b = b2;
00687         }
00688     }
00689     return b;
00690 }
00691 
00692 BOOLEXP *parse_boolexp(dbref player, const char *buf, bool internal)
00693 {
00694     size_t n = strlen(buf);
00695     if (n > sizeof(parsestore)-1)
00696     {
00697         n = sizeof(parsestore)-1;
00698     }
00699     memcpy(parsestore, buf, n+1);
00700     parsebuf = parsestore;
00701     parse_player = player;
00702     if (  buf == NULL
00703        || *buf == '\0')
00704     {
00705         return TRUE_BOOLEXP;
00706     }
00707     if (!mudstate.bStandAlone)
00708     {
00709         parsing_internal = internal;
00710     }
00711     return parse_boolexp_E();
00712 }

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