home *** CD-ROM | disk | FTP | other *** search
- /* $Copyright: $
- * Copyright (c) 1991,1992,1993 by Steve Baker
- * All rights reserved
- *
- * This software is provided as is without any express or implied
- * warranties, including, without limitation, the implied warranties
- * of merchantability and fitness for a particular purpose.
- */
- #include "shell.h"
-
- #define T_EOL 0
- #define T_OR 1
- #define T_AND 2
-
- #define T_NOT 3
-
- #define T_EQ 5
- #define T_NE 6
- #define T_GE 7
- #define T_GT 8
- #define T_LE 9
- #define T_LT 10
- #define T_TEQ 11
- #define T_TNE 12
-
- #define T_STR 15
- #define T_NUM 16
- #define T_SVAR 17
- #define T_NVAR 18
-
- #define T_OP 20
- #define T_CP 21
- #define T_PLUS 25
- #define T_MINUS 26
- #define T_DIV 27
- #define T_MUL 28
- #define T_MOD 29
-
- #define T_PP 30
- #define T_MM 31
- #define T_LAND 32
- #define T_LOR 33
- #define T_TILD 34
-
- #define T_EXSIST 35
- #define T_READ 36
- #define T_WRITE 37
- #define T_EXECUTE 38
- #define T_OWNER 39
- #define T_ZERO 40
- #define T_PLAIN 41
- #define T_DIR 42
- #define T_SIZE 43
- #define T_USER 44
- #define T_GROUP 45
- #define T_PROT 46
- #define T_MODE 47
-
- #define T_SHL 50
- #define T_SHR 51
- #define T_XOR 52
-
- #define T_ERR 55
-
- struct tlist {
- union _v {
- char *str;
- long num;
- struct _setvar *var;
- } v;
- short vp;
- char tok;
- } *tlst;
- static char *exp;
- static long num, lp;
- static short vp;
- static char *str;
- struct _setvar *_set, *getvalidset();
- extern int err;
-
- long expr(), eval(), doconditionals(), domath();
- long domuldiv(), dounary(), doprimary();
- char *getvalidenv();
-
- long expr(wrd)
- char *wrd;
- {
- int nt,tp,tok;
- long res;
- struct tlist *tsav;
- char *sav;
-
- /* hack to save previous value of exp and tlst to make expr() re-intrant */
- sav = exp;
- tsav = tlst;
- exp = wrd;
- err = tp = 0;
- tlst = (struct tlist *)calloc(nt=5,sizeof(struct tlist));
-
- while(tok = get_next(exp)) {
- if (tp == nt) tlst = (struct tlist *)realloc(tlst,sizeof(struct tlist) * (nt+=5));
- tlst[tp].tok = tok;
- switch(tok) {
- case T_STR:
- tlst[tp].v.str = str;
- break;
- case T_NUM:
- tlst[tp].v.num = num;
- break;
- case T_SVAR:
- tlst[tp].vp = vp;
- case T_NVAR:
- tlst[tp].v.var = _set;
- break;
- }
- tp++;
- }
- if (tp == nt) tlst = (struct tlist *)realloc(tlst,sizeof(struct tlist) * ++nt);
- tlst[tp].tok = T_EOL;
- lp = 0;
- res = eval();
- if (!err && tlst[lp].tok == T_CP) error(3);
- else if (!err && tlst[lp].tok != T_EOL) error(1);
- for(tp=0;tlst[tp].tok;tp++)
- if (tlst[tp].tok == T_STR) free(tlst[tp].v.str);
- free(tlst);
- exp = sav;
- tlst = tsav;
- return err? 0 : res;
- }
-
- long eval()
- {
- int res,res2;
-
- res = doconditionals();
- if (err) return 0;
-
- switch(tlst[lp++].tok) {
- case T_OR:
- res2 = eval();
- res = res || res2;
- break;
- case T_AND:
- res2 = eval();
- res = res && res2;
- break;
- case T_EOL:
- lp--;
- return res;
- case T_CP:
- lp--;
- return res;
- default:
- error(2);
- break;
- }
- return res;
- }
-
- long doconditionals()
- {
- int ans;
-
- if (tlst[lp].tok == T_STR || tlst[lp].tok == T_SVAR) return dostrcmp();
- ans = domath();
- if (err) return 0;
-
- switch(tlst[lp++].tok) {
- case T_EQ:
- ans = ans == doconditionals();
- break;
- case T_NE:
- ans = ans != doconditionals();
- break;
- case T_GE:
- ans = ans >= doconditionals();
- break;
- case T_LE:
- ans = ans <= doconditionals();
- break;
- case T_GT:
- ans = ans > doconditionals();
- break;
- case T_LT:
- ans = ans < doconditionals();
- break;
- default:
- lp--;
- return ans;
- }
- return ans;
- }
-
- long domath()
- {
- int res;
-
- res = domuldiv();
- if (err) return 0;
-
- switch(tlst[lp++].tok) {
- case T_PLUS:
- res += domath();
- break;
- case T_MINUS:
- res -= domath();
- break;
- case T_LAND:
- res &= domath();
- break;
- case T_LOR:
- res |= domath();
- break;
- case T_SHL:
- res <<= domath();
- break;
- case T_SHR:
- res >>= domath();
- break;
- case T_XOR:
- res ^= domath();
- break;
- default:
- lp--;
- return res;
- }
- return res;
- }
-
- long domuldiv()
- {
- int res;
-
- res = dounary();
- if (err) return 0;
-
- switch(tlst[lp++].tok) {
- case T_MUL:
- res *= domuldiv();
- break;
- case T_DIV:
- res /= domuldiv();
- break;
- case T_MOD:
- res %= domuldiv();
- break;
- default:
- lp--;
- return res;
- }
- return res;
- }
-
- long dounary()
- {
- int res, tok;
- char *fil = NULL;
- struct stat buf;
-
- if (err) return 0;
- tok = tlst[lp++].tok;
- if (tok >= T_EXSIST && tok <= T_MODE) {
- if (tlst[lp].tok == T_STR) {
- fil = tlst[lp++].v.str;
- } else if (tlst[lp].tok == T_SVAR) {
- fil = tlst[lp].v.var->sv.wrd[tlst[lp].vp];
- lp++;
- } else {
- error(7);
- return 0;
- }
- if ((tok >= T_OWNER) && (stat(fil,&buf) < 0)) fil = NULL;
- }
-
- switch(tok) {
- case T_MINUS:
- res = -dounary();
- break;
- case T_NOT:
- res = !dounary();
- break;
- case T_TILD:
- res = ~dounary();
- break;
- case T_PLUS:
- res = dounary();
- break;
- case T_MM:
- case T_PP:
- if (tlst[lp].tok != T_NVAR) {
- error(8);
- break;
- }
- if (!tlst[lp-1].v.var->protect) {
- if (tok == T_PP) tlst[lp].v.var->sv.val++;
- else tlst[lp].v.var->sv.val--;
- }
- res = dounary();
- break;
- case T_EXSIST:
- if (!fil) return res = 0;
- res = access(fil,F_OK)? 0 : 1;
- break;
- case T_READ:
- if (!fil) return res = 0;
- res = access(fil,R_OK)? 0 : 1;
- break;
- case T_WRITE:
- if (!fil) return res = 0;
- res = access(fil,W_OK)? 0 : 1;
- break;
- case T_EXECUTE:
- if (!fil) return res = 0;
- res = access(fil,X_OK)? 0 : 1;
- break;
- case T_OWNER:
- if (!fil) return res = 0;
- res = (buf.st_uid == getuid()? 1 : 0);
- break;
- case T_ZERO:
- if (!fil) return res = 0;
- res = (buf.st_size == 0? 1 : 0);
- break;
- case T_SIZE:
- if (!fil) return res = 0;
- res = buf.st_size;
- break;
- case T_PLAIN:
- if (!fil) return res = 0;
- res = (buf.st_mode & S_IFMT) == S_IFREG? 1 : 0;
- break;
- case T_DIR:
- if (!fil) return res = 0;
- res = (buf.st_mode & S_IFMT) == S_IFDIR? 1 : 0;
- break;
- case T_USER:
- if (!fil) return res = -1;
- res = buf.st_uid;
- break;
- case T_GROUP:
- if (!fil) return res = -1;
- res = buf.st_gid;
- break;
- case T_PROT:
- if (!fil) return res = 0;
- res = buf.st_mode & 0777;
- break;
- case T_MODE:
- if (!fil) return res = 0;
- res = buf.st_mode;
- break;
- default:
- lp--;
- res = doprimary();
- }
- return res;
- }
-
- long doprimary()
- {
- long res;
- int tok;
-
- if (tlst[lp++].tok == T_OP) {
- res = eval();
- if (tlst[lp].tok != T_CP) error(3);
- lp++;
- return res;
- }
- switch(tlst[--lp].tok) {
- case T_NUM:
- return tlst[lp++].v.num;
- case T_NVAR:
- res = tlst[lp++].v.var->sv.val;
- tok = tlst[lp].tok;
- if (tok == T_PP || tok == T_MM) {
- if (!tlst[lp-1].v.var->protect) {
- if (tok == T_PP) tlst[lp-1].v.var->sv.val++;
- else tlst[lp-1].v.var->sv.val--;
- }
- lp++;
- }
- return res;
- case T_SVAR:
- case T_STR:
- error(4);
- break;
- case T_EOL:
- error(5);
- break;
- case T_ERR:
- error(6);
- break;
- default:
- error(7);
- break;
- }
- return 0;
- }
-
- dostrcmp()
- {
- int ans,tok;
- char *s, *s2;
-
- if (tlst[lp].tok == T_STR) s = tlst[lp++].v.str;
- else {
- s = tlst[lp].v.var->sv.wrd[tlst[lp].vp];
- lp++;
- }
-
- tok = tlst[lp++].tok;
- if (tok < T_EQ || tok > T_TNE) return 1;
- if (tlst[lp].tok != T_STR && tlst[lp].tok != T_SVAR) {
- error(7);
- return 0;
- }
- if (tlst[lp].tok == T_STR) s2 = tlst[lp++].v.str;
- else {
- s2 = tlst[lp].v.var->sv.wrd[tlst[lp].vp];
- lp++;
- }
- switch(tok) {
- case T_TEQ:
- ans = patmatch(s,s2);
- break;
- case T_TNE:
- ans = !patmatch(s,s2);
- break;
- case T_EQ:
- ans = !strcmp(s,s2);
- break;
- case T_NE:
- ans = strcmp(s,s2);
- break;
- case T_GE:
- ans = strcmp(s,s2) >= 0;
- break;
- case T_LE:
- ans = strcmp(s,s2) <= 0;
- break;
- case T_GT:
- ans = strcmp(s,s2) > 0;
- break;
- case T_LT:
- ans = strcmp(s,s2) < 0;
- break;
- }
- return ans;
- }
-
-
- error(n)
- int n;
- {
- switch(n) {
- case 1:
- case 2:
- fprintf(stderr,"End of expression expected.\n");
- break;
- case 3:
- fprintf(stderr,"Mismatched parentheses.\n");
- break;
- case 4:
- fprintf(stderr,"String found when numeric expected.\n");
- break;
- case 5:
- fprintf(stderr,"Unexpected end of expression.\n");
- break;
- case 6:
- fprintf(stderr,"Illegal character.\n");
- break;
- case 7:
- fprintf(stderr,"String literal expected.\n");
- break;
- case 8:
- fprintf(stderr,"Variable expected for ++ or --.\n");
- break;
- }
- err = 1;
- }
-
-
- get_next()
- {
- int i,pos;
- char *s, *t, c;
- static char numbuf[33];
-
- while(isspace(*exp)) exp++;
- switch(*exp++) {
- case '+':
- if (*exp == '+') {
- exp++;
- return T_PP;
- }
- return T_PLUS;
- case '-':
- switch(*exp++) {
- case 'e':
- return T_EXSIST;
- case 'r':
- return T_READ;
- case 'w':
- return T_WRITE;
- case 'x':
- return T_EXECUTE;
- case 'o':
- return T_OWNER;
- case 'z':
- return T_ZERO;
- case 'f':
- return T_PLAIN;
- case 'd':
- return T_DIR;
- case 's':
- return T_SIZE;
- case 'u':
- return T_USER;
- case 'g':
- return T_GROUP;
- case 'p':
- return T_PROT;
- case 'm':
- return T_MODE;
- case '-':
- return T_MM;
- }
- exp--;
- return T_MINUS;
- case '/':
- return T_DIV;
- case '*':
- return T_MUL;
- case '%':
- return T_MOD;
- case '|':
- if (*exp != '|') return T_LOR;
- exp++;
- return T_OR;
- case '&':
- if (*exp != '&') return T_LAND;
- exp++;
- return T_AND;
- case '^':
- return T_XOR;
- case '~':
- return T_TILD;
- case '<':
- if (*exp == '<') {
- exp++;
- return T_SHL;
- }
- if (*exp == '=') {
- exp++;
- return T_LE;
- }
- return T_LT;
- case '>':
- if (*exp == '>') {
- exp++;
- return T_SHR;
- }
- if (*exp == '=') {
- exp++;
- return T_GE;
- }
- return T_GT;
- case '=':
- if (*exp == '~') {
- exp++;
- return T_TEQ;
- }
- if (*exp++ != '=') return T_ERR;
- return T_EQ;
- case '!':
- if (*exp == '=') {
- exp++;
- return T_NE;
- }
- if (*exp == '~') {
- exp++;
- return T_TNE;
- }
- return T_NOT;
- case 0:
- return T_EOL;
- case '(':
- return T_OP;
- case ')':
- return T_CP;
- case '$':
- if (*exp == '$') {
- exp++;
- if (*exp == '?') {
- exp++;
- s = getvalidenv(&exp,&pos);
- if (s) {
- num = 1;
- free(s);
- } else num = 0;
- return T_NUM;
- }
- if (*exp == '#') {
- exp++;
- s = getvalidenv(&exp,&pos);
- if (s) {
- if (pos < 0) {
- for(num=1,i=0;s[i];i++) if (s[i] == ':') num++;
- } else num = strlen(s);
- free(s);
- } else num = 0;
- return T_NUM;
- }
- s = getvalidenv(&exp,&pos);
- str = s;
- return T_STR;
- }
- if (*exp == '?') {
- exp++;
- if (getvalidset(&exp,&pos)) num = 1;
- else num = 0;
- return T_NUM;
- }
- if (*exp == '#') {
- exp++;
- if (_set = getvalidset(&exp,&pos)) {
- if (pos < 0) num = _set->nwrds;
- else num = strlen(_set->sv.wrd[pos]);
- } else num = 0;
- return T_NUM;
- }
- if (!(_set = getvalidset(&exp,&pos))) return T_ERR;
- if (_set->type != T_STRING) return T_NVAR;
- vp = pos < 0? 0 : pos;
- return T_SVAR;
- break;
- case '\'':
- case '"':
- c = *(exp-1);
- s = exp;
- while(*exp && *exp != c) {
- if (*exp == '\\') exp++;
- exp++;
- }
- t = (char *)malloc((exp-s)+1);
- for(i=0;s < exp;i++) t[i] = *s++;
- t[i] = 0;
- str = t;
- if (*exp == c) exp++;
- return T_STR;
- default:
- exp--;
- i = num = 0;
- if (isdigit(*exp)) {
- if (*exp == '0') {
- exp++;
- switch(*exp++) {
- case 'x':
- case 'X':
- while((isdigit(*exp) || (*exp >= 'a' && *exp <= 'f') || (*exp >= 'A' && *exp <= 'F')) && i < 8)
- numbuf[i++] = *exp++;
- if (!i || i > 8) return T_ERR;
- numbuf[i] = 0;
- for(i=0;numbuf[i];i++) {
- num <<= 4;
- num |= (isdigit(numbuf[i]) ? numbuf[i]-'0' : (islower(numbuf[i]) ? (numbuf[i] - 'a') + 10 : (numbuf[i] - 'A') + 10));
- }
- return T_NUM;
- break;
- case 'b':
- case 'B':
- while((*exp == '1' || *exp == '0') && i < 32) numbuf[i++] = *exp++;
- if (!i || i > 32) return T_ERR;
- numbuf[i] = 0;
- for(i=0;numbuf[i];i++) {
- num <<= 1;
- if (numbuf[i] == '1') num |= 1;
- }
- return T_NUM;
- break;
- default:
- exp--;
- while(*exp >= '0' && *exp < '8' && i < 10) numbuf[i++] = *exp++;
- if (!i) return T_NUM;
- if (i > 10) return T_ERR;
- numbuf[i] = 0;
- for (i=0;numbuf[i];i++) {
- num <<= 3;
- num |= numbuf[i] - '0';
- }
- return T_NUM;
- break;
- }
- }
- while(isdigit(*exp) && i < 11) numbuf[i++] = *exp++;
- if (i > 11) return T_ERR;
- numbuf[i] = 0;
- num = atoi(numbuf);
- return T_NUM;
- }
- s = exp;
- while(*exp && !isspace(*exp)) exp++;
- str = t = (char *)malloc((exp-s)+1);
- for(i=0;s<exp;i++) t[i] = *s++;
- t[i] = 0;
- return T_STR;
- }
- /*NOTREACHED*/
- }
-