/* Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ #ifndef lint static char RCSid[] = "$Header: /usr/users/mjr/hacks/umud/DB/RCS/expr.c,v 1.2 91/08/07 00:48:16 mjr Exp $"; #endif /* configure all options BEFORE including system stuff. */ #include "config.h" #include <stdio.h> #include <ctype.h> #include "mud.h" #define ISPUN(x) (x=='#'||x=='['||x==']'||x =='!'||x =='('||x ==')'||x=='&'||x=='|'||x=='=') typedef struct _b_exp { int typ; char *str; struct _b_exp *rhs; struct _b_exp *lhs; } b_exp; static b_exp *build_expr(); static char *tokp; static char *bufp; static int lasttok; static char *curnam; static Obj *curobj; b_exp *compiled; static b_exp * new_b_exp() { b_exp *ret; ret = (b_exp *)malloc(sizeof(b_exp)); if(ret == (b_exp *)0) fatal("malloc new expression node: ",(char *)-1,"\n",(char *)0); ret->typ = '$'; ret->str = (char *)0; ret->rhs = ret->lhs = (b_exp *)0; return(ret); } static int nexttok() { int quot = 0; int ghoti = 0; char tbuf[512]; char *top; while(isspace(*bufp)) bufp++; top = tbuf; if(ISPUN(*bufp)) { quot = *bufp++; return(quot); } if((*bufp == 'T' || *bufp == 'F') && (isspace(*(bufp + 1)) || *(bufp + 1) == '\0')) { quot = *bufp++; bufp++; return(quot); } while(*bufp != '\0') { ghoti = 1; if(!quot && (*bufp == '\'' || *bufp == '\"')) { quot = *bufp++; continue; } /* done quote */ if(quot && *bufp == quot) { quot = 0; bufp++; continue; } /* done word */ if(!quot && (isspace(*bufp) || ISPUN(*bufp))) break; /* handle escapes */ if(*bufp == '\\') { bufp++; if(*bufp != '\0') { *top++ = *bufp++; } continue; } /* default - just copy */ *top++ = *bufp++; } if(top - tbuf > sizeof(tbuf) - 2) fatal("string buffer overrun in expression\n",(char *)0); if(ghoti) { *top = '\0'; tokp = (char *)malloc(top - tbuf + 1); if(tokp == (char *)0) fatal("cannot allocate string: ",(char *)-1,"\n",(char *)0); strcpy(tokp,tbuf); return('W'); } return('$'); } static b_exp * build_subexpr() { b_exp *ret; switch(lasttok = nexttok()) { case 'W': ret = new_b_exp(); ret->typ = 'W'; ret->str = tokp; return(ret); case '!': ret = new_b_exp(); if((ret->rhs = build_subexpr()) == (b_exp *)0) return((b_exp *)0); ret->typ = '!'; return(ret); case '(': ret = build_expr(); if((lasttok = nexttok()) != ')') { fprintf(stderr,"missing right parenthesis\n"); return((b_exp *)0); } return(ret); case '[': lasttok = nexttok(); if(lasttok != 'W') { fprintf(stderr,"missing regular expression\n"); return((b_exp *)0); } if((lasttok = nexttok()) != ']') { fprintf(stderr,"missing regular expression terminator \n"); return((b_exp *)0); } ret = new_b_exp(); ret->typ = 'R'; ret->str = tokp; return(ret); case '#': lasttok = nexttok(); if(lasttok != 'W') { fprintf(stderr,"missing object ID\n"); return((b_exp *)0); } ret = new_b_exp(); ret->typ = 'O'; ret->str = tokp; return(ret); case '$': case 'T': case 'F': ret = new_b_exp(); ret->typ = lasttok; return(ret); default: fprintf(stderr,"syntax error"); if(lasttok == 'W') { fprintf(stderr," near \"%s\"",tokp); } else { if(bufp != (char *)0 && *bufp != '\0') fprintf(stderr," near \"%c %s\"",lasttok,bufp); } fprintf(stderr,"\n"); return((b_exp *)0); } } static b_exp * build_expr() { b_exp *ret; b_exp *lhs; int x; if((lhs = build_subexpr()) == (b_exp *)0) return((b_exp *)0); switch(lasttok = nexttok()) { case '&': ret = new_b_exp(); if((ret->rhs = build_subexpr()) == (b_exp *)0) return((b_exp *)0); if(ret->rhs->typ == '$') { fprintf(stderr,"missing AND clause\n"); return((b_exp *)0); } ret->typ = '&'; ret->lhs = lhs; return(ret); case '=': ret = new_b_exp(); if((ret->rhs = build_subexpr()) == (b_exp *)0) return((b_exp *)0); if(lhs->typ != 'W') { fprintf(stderr,"missing attribute for comparison\n"); return((b_exp *)0); } if(ret->rhs->typ != 'W' && ret->rhs->typ != 'R') { fprintf(stderr,"missing string for comparison\n"); return((b_exp *)0); } ret->typ = '='; ret->lhs = lhs; return(ret); case '|': ret = new_b_exp(); if((ret->rhs = build_subexpr()) == (b_exp *)0) return((b_exp *)0); if(ret->rhs->typ == '$') { fprintf(stderr,"missing OR clause\n"); return((b_exp *)0); } ret->typ = '|'; ret->lhs = lhs; return(ret); default: return(lhs); } } static int eval_subexpr(ex) b_exp *ex; { switch(ex->typ) { case 'W': fprintf(stderr,"meaningless evaluation"); if(ex->str != (char *)0) fprintf(stderr,": \"%s\"",ex->str); fprintf(stderr,"\n"); return(1); case 'O': if(!strcmp(ex->str,curnam)) return(1); return(0); case 'T': return(1); case 'F': return(0); default: return(-1); } } static int eval_truthof(s1,s2,re) char *s1; char *s2; int re; { #ifdef REGEX extern char *regcmp(); extern char *regex(); #else extern char *re_comp(); #endif char *xp; char *vp; char *ap; char *tp; int tl = 0; /* look for a '.' in the attribute name */ for(xp = s1; *xp != '\0' && *xp != '.'; xp++) ; if(*xp == '.') { tl = xp - s1; ap = ++xp; tp = s1; } else { ap = s1; tp = (char *)0; } /* feh */ if(*ap == '\0' || (vp = objattr(curobj,ap,0)) == (char *)0) return(0); /* specified type ? must match */ if(tp != (char *)0 && (strncmp(vp,tp,tl) || vp[tl] != ' ')) return(0); /* this eats - already done in objattr really */ xp = vp; /* skip to end of type */ while(*xp != ' ' && *xp != '\0') xp++; if(*xp == '\0') return(0); xp++; /* skip to end of attribute name */ while(*xp != '=' && *xp != '\0') xp++; if(*xp == '\0') return(0); xp++; /* if not a regular expression, this is simplicty */ if(!re) { if(!strcmp(xp,s2)) return(1); return(0); } #ifdef REGEX if((vp = regcmp(s2, (char *)0)) == (char *)0) { fprintf(stderr,"bad regular expression\n"); exit(1); } tp = regex(vp,xp); free(vp); return(tp != (char *)0); #else if((vp = re_comp(s2)) != (char *)0) { fprintf(stderr,"bad regular expression: %s\n",vp); exit(1); } return(re_exec(xp)); #endif } static int eval_expr(ex) b_exp *ex; { int rh; int lh; switch(ex->typ) { case '|': rh = eval_expr(ex->rhs); lh = eval_expr(ex->lhs); return(lh || rh); case '&': rh = eval_expr(ex->rhs); lh = eval_expr(ex->lhs); return(rh == lh); case '=': if(ex->lhs->typ != 'W' || (ex->rhs->typ != 'W' && ex->rhs->typ != 'R')) return(0); return(eval_truthof(ex->lhs->str,ex->rhs->str,ex->rhs->typ == 'R' ? 1 : 0)); default: return(eval_subexpr(ex)); } } setexpr(s) char *s; { bufp = s; if((compiled = build_expr()) == (b_exp *)0) return(1); return(0); } checkexpr(nam,op) char *nam; Obj *op; { int ret; curnam = nam; curobj = op; ret = eval_expr(compiled); curnam = (char *)0; curobj = (Obj *)0; return(ret); }