/* Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ #ifndef lint static char RCSid[] = "$Header: /usr/users/mjr/hacks/umud/RCS/bool.c,v 1.3 91/09/19 12:56:24 mjr Exp $"; #endif /* configure all options BEFORE including system stuff. */ #include "config.h" #include <ctype.h> #include "mud.h" #include "match.h" #include "vars.h" #include "sbuf.h" /* Zen recursive descent boolean evaluation. Code by Molly, 1991. Some of this code is deliberately weird. live with it. */ /* test if x is a token char */ #define ISTOK(x) (x =='!'||x =='('||x ==')'||x == '&'||x=='|') /* WARNING! this is initted statically and deinnited in the main evaluator. */ static Sbuf sb; static char *bp; static int lasttok = '$'; static char *whop; static char *wherep; static int checkmode = 0; static int b_expr(); static int evaluate_truth(s,withflg) char *s; int withflg; { char *lp; if(whop == (char *)0) return(0); if(!strcmp(s,whop)) return(1); /* check the stuff the guy is carrying */ if(ut_listchk(whop,var_cont,s)) return(1); /* check the stuff the guy is using */ if((lp = ut_getatt(whop,0,typ_obj,var_using,(char *)0)) != (char *)0) { if(!strcmp(s,lp)) return(1); } /* if with flag is set, then check if the thing is in the room or is another player in the room */ if(withflg && wherep != (char *)0) { if(ut_listchk(wherep,var_ply,s) || ut_listchk(wherep,var_cont,s)) return(1); } return(0); } static int nexttok() { int quot = 0; while(isspace(*bp)) bp++; if(ISTOK(*bp)) { quot = *bp++; return(quot); } if((*bp == 'T' || *bp == 'F') && (ISTOK(*(bp+1)) || isspace(*(bp+1)) || *(bp+1) == '\0')) { quot = *bp++; return(quot); } sbuf_reset(&sb); while(*bp != '\0') { /* enter quote */ if(!quot && (*bp == '\'' || *bp == '\"')) { quot = *bp++; continue; } /* done quote */ if(quot && *bp == quot) { quot = 0; bp++; continue; } /* done word */ if(!quot && (isspace(*bp) || ISTOK(*bp))) { sbuf_put('\0',&sb); break; } /* handle escapes */ if(*bp == '\\') { bp++; if(*bp != '\0') { sbuf_put(*bp,&sb); bp++; } continue; } /* default - just copy */ sbuf_put(*bp,&sb); bp++; } if(sbuf_len(&sb) >= 0) { /* sbuf_len() return char count - 1 */ sbuf_put('\0',&sb); if(!strcmp(sbuf_buf(&sb),"with")) return('+'); return('^'); } return('$'); } static int b_subexpr() { int x; switch(lasttok = nexttok()) { case 'T': return(1); case 'F': return(0); case '^': if(checkmode) return(1); return(evaluate_truth(sbuf_buf(&sb),0)); case '+': lasttok = nexttok(); if(lasttok != '^') { if(checkmode && whop != (char *)0) say(whop,"missing WITH item\n",(char *)0); return(-1); } if(checkmode) return(1); return(evaluate_truth(sbuf_buf(&sb),1)); case '!': if((x = b_subexpr()) == -1) { if(checkmode && whop != (char *)0) say(whop,"missing subexpression after '!'\n",(char *)0); return(-1); } return(!x); case '(': x = b_expr(); if(lasttok != ')') { if(checkmode && whop != (char *)0) say(whop,"missing right parenthesis\n",(char *)0); return(-1); } return(x); case '$': return('$'); default: if(checkmode && whop != (char *)0) { say(whop,"syntax error",(char *)0); if(bp != (char *)0 && *bp != '\0') say(whop," near \"",bp,"\"",(char *)0); say(whop,"\n",(char *)0); } return(-1); } } static int b_expr() { int ret = b_subexpr(); int x; for(;;) { switch(lasttok = nexttok()) { case '&': if((x = b_subexpr()) == -1) { if(checkmode && whop != (char *)0) say(whop,"missing AND clause\n",(char *)0); return(-1); } if(x == '$') { if(checkmode && whop != (char *)0) say(whop,"missing subexpression\n",(char *)0); return(-1); } ret = (ret && x); break; case '|': if((x = b_subexpr()) == -1) { if(checkmode && whop != (char *)0) say(whop,"missing OR clause\n",(char *)0); return(-1); } if(x == '$') { if(checkmode && whop != (char *)0) say(whop,"missing subexpression\n",(char *)0); return(-1); } ret = (ret || x); break; default: return(ret); } } } int bool_eval(who,where,s,check) char *who; char *where; char *s; int check; { int ret; bp = s; whop = who; wherep = where; checkmode = check; sbuf_initstatic(&sb); ret = b_expr(); if(ret < 0 && checkmode && whop != (char *)0) say(whop,"invalid boolean expression.\n",(char *)0); sbuf_freestatic(&sb); whop = (char *)0; wherep = (char *)0; checkmode = 0; return(ret); } /* check a lock. */ int bool_locked(who,what,where,lockvar,deflt) char *who; char *what; char *where; char *lockvar; int deflt; { char *lockp; lockp = ut_getatt(what,0,typ_bool,lockvar,(char *)0); if(lockp == (char *)0) return(deflt); return(bool_eval(who,where,lockp,0) == 0); } /* check a lock's syntax. */ int bool_syntax(who,exp) char *who; char *exp; { int ret; ret = bool_eval(who,(char *)0,exp,1); if(ret == -1) return(1); return(0); } /* Match a string against the environment, and paste the object ID in to the specified Sbuf. */ static int bool_pasteID(who,what,s) char *who; char *what; Sbuf *s; { char objid[MAXOID]; char *where; where = ut_loc(who); if(!matchlocal(who,what,where, MTCH_UNIQ | MTCH_NONLOC | MTCH_MEOK,objid)){ sbuf_strcat(objid,s); sbuf_unput(s); /* lose trailing \0 */ return(0); } return(-1); } /* Re-write a lock, matching junk against the environment and generating object IDs. */ bool_rewrite(who,s,out) char *who; char *s; Sbuf *out; /* pre-initted */ { char quot = '\0'; char ch; char *thing = ""; char *p; while(*s){ /* End a quoted thing */ if(quot && *s == quot){ *s = '\0'; if(bool_pasteID(who,thing,out)){ *s = quot; return(-1); } *s++ = quot; quot = '\0'; continue; } /* Make the rest of these clauses if(!quot && <stuff> */ if(quot) { s++; continue; } /* Skip white-boy space. Marcus-like */ if(isspace(*s)) { s++; continue; } /* Copy TOK type things blindly */ if(ISTOK(*s) || ((*s == 'T' || *s == 'F') && (ISTOK(*(s+1)) || isspace(*(s+1)) || *(s+1) == '\0'))){ sbuf_put(*s++,out); continue; } /* Start quoted thing */ if(*s == '\'' || *s == '\"'){ quot = *s++; thing = s; continue; } if(!strncmp("with ",s,5)){ s += 5; sbuf_strcat("with ",out); sbuf_unput(out); /* lose trailing \0 */ continue; } /* Grub out an un-quoted thing name */ thing = s; p = (char *)0; while(!ISTOK(*s) && *s){ if(!isspace(*s) && isspace(s[1])) p = s + 1; s++; } if(!p) p = s; ch = *p; *p = '\0'; if(bool_pasteID(who,thing,out)){ *s = ch; return(-1); } *p = ch; } /* OK. Fell off end of string. Check for unclosed quoted thing */ if(quot){ if(bool_pasteID(who,thing,out)) return(-1); } sbuf_put('\0',out); return(0); }