00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #define main exprcmd
00011
00012 #include "bltin.h"
00013 #include "operators.h"
00014 #include <sys/types.h>
00015 #include <sys/stat.h>
00016
00017 #ifndef S_ISLNK
00018 #define lstat stat
00019 #define S_ISLNK(mode) (0)
00020 #endif
00021
00022 #define STACKSIZE 12
00023 #define NESTINCR 16
00024
00025
00026 #define STRING 0
00027 #define INTEGER 1
00028 #define BOOLEAN 2
00029
00030
00031
00032
00033
00034
00035
00036
00037 struct value {
00038 int type;
00039 union {
00040 char *string;
00041 long num;
00042 } u;
00043 };
00044
00045
00046 struct operator {
00047 short op;
00048 short pri;
00049 };
00050
00051
00052 struct filestat {
00053 int op;
00054 char *name;
00055 int rcode;
00056 struct stat stat;
00057 };
00058
00059
00060 extern char *match_begin[10];
00061 extern short match_length[10];
00062 extern short number_parens;
00063
00064
00065 #ifdef __STDC__
00066 int expr_is_false(struct value *);
00067 void expr_operator(int, struct value *, struct filestat *);
00068 int lookup_op(char *, char *const*);
00069 char *re_compile(char *);
00070 int re_match(char *, char *);
00071 long atol(const char *);
00072 #else
00073 int expr_is_false();
00074 void expr_operator();
00075 int lookup_op();
00076 char *re_compile();
00077 int re_match();
00078 long atol();
00079 #endif
00080
00081
00082
00083 main(argc, argv) char **argv; {
00084 char **ap;
00085 char *opname;
00086 char c;
00087 char *p;
00088 int print;
00089 int nest;
00090 int op;
00091 int pri;
00092 int skipping;
00093 int binary;
00094 struct operator opstack[STACKSIZE];
00095 struct operator *opsp;
00096 struct value valstack[STACKSIZE + 1];
00097 struct value *valsp;
00098 struct filestat fs;
00099
00100 INITARGS(argv);
00101 c = **argv;
00102 print = 1;
00103 if (c == 't')
00104 print = 0;
00105 else if (c == '[') {
00106 if (! equal(argv[argc - 1], "]"))
00107 error("missing ]");
00108 argv[argc - 1] = NULL;
00109 print = 0;
00110 }
00111 ap = argv + 1;
00112 fs.name = NULL;
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 nest = 0;
00125 skipping = 0;
00126 opsp = opstack + STACKSIZE;
00127 valsp = valstack;
00128 if (*ap == NULL) {
00129 valstack[0].type = BOOLEAN;
00130 valstack[0].u.num = 0;
00131 goto done;
00132 }
00133 for (;;) {
00134 opname = *ap++;
00135 if (opname == NULL)
00136 syntax: error("syntax error");
00137 if (opname[0] == '(' && opname[1] == '\0') {
00138 nest += NESTINCR;
00139 continue;
00140 } else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
00141 if (opsp == &opstack[0])
00142 overflow: error("Expression too complex");
00143 --opsp;
00144 opsp->op = op;
00145 opsp->pri = op_priority[op] + nest;
00146 continue;
00147
00148 } else {
00149 valsp->type = STRING;
00150 valsp->u.string = opname;
00151 valsp++;
00152 }
00153 for (;;) {
00154 opname = *ap++;
00155 if (opname == NULL) {
00156 if (nest != 0)
00157 goto syntax;
00158 pri = 0;
00159 break;
00160 }
00161 if (opname[0] != ')' || opname[1] != '\0') {
00162 if ((op = lookup_op(opname, binary_op)) < 0)
00163 goto syntax;
00164 op += FIRST_BINARY_OP;
00165 pri = op_priority[op] + nest;
00166 break;
00167 }
00168 if ((nest -= NESTINCR) < 0)
00169 goto syntax;
00170 }
00171 while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
00172 binary = opsp->op;
00173 for (;;) {
00174 valsp--;
00175 c = op_argflag[opsp->op];
00176 if (c == OP_INT) {
00177 if (valsp->type == STRING)
00178 valsp->u.num = atol(valsp->u.string);
00179 valsp->type = INTEGER;
00180 } else if (c >= OP_STRING) {
00181 if (valsp->type == INTEGER) {
00182 p = stalloc(32);
00183 #ifdef SHELL
00184 fmtstr(p, 32, "%d", valsp->u.num);
00185 #else
00186 sprintf(p, "%d", valsp->u.num);
00187 #endif
00188 valsp->u.string = p;
00189 } else if (valsp->type == BOOLEAN) {
00190 if (valsp->u.num)
00191 valsp->u.string = "true";
00192 else
00193 valsp->u.string = "";
00194 }
00195 valsp->type = STRING;
00196 if (c >= OP_FILE
00197 && (fs.op != c
00198 || fs.name == NULL
00199 || ! equal(fs.name, valsp->u.string))) {
00200 fs.op = c;
00201 fs.name = valsp->u.string;
00202 if (c == OP_FILE) {
00203 fs.rcode = stat(valsp->u.string,
00204 &fs.stat);
00205 } else {
00206 fs.rcode = lstat(valsp->u.string,
00207 &fs.stat);
00208 }
00209 }
00210 }
00211 if (binary < FIRST_BINARY_OP)
00212 break;
00213 binary = 0;
00214 }
00215 if (! skipping)
00216 expr_operator(opsp->op, valsp, &fs);
00217 else if (opsp->op == AND1 || opsp->op == OR1)
00218 skipping--;
00219 valsp++;
00220 opsp++;
00221 }
00222 if (opname == NULL)
00223 break;
00224 if (opsp == &opstack[0])
00225 goto overflow;
00226 if (op == AND1 || op == AND2) {
00227 op = AND1;
00228 if (skipping || expr_is_false(valsp - 1))
00229 skipping++;
00230 }
00231 if (op == OR1 || op == OR2) {
00232 op = OR1;
00233 if (skipping || ! expr_is_false(valsp - 1))
00234 skipping++;
00235 }
00236 opsp--;
00237 opsp->op = op;
00238 opsp->pri = pri;
00239 }
00240 done:
00241 if (print) {
00242 if (valstack[0].type == STRING)
00243 printf("%s\n", valstack[0].u.string);
00244 else if (valstack[0].type == INTEGER)
00245 printf("%ld\n", valstack[0].u.num);
00246 else if (valstack[0].u.num != 0)
00247 printf("true\n");
00248 }
00249 return expr_is_false(&valstack[0]);
00250 }
00251
00252
00253 int
00254 expr_is_false(val)
00255 struct value *val;
00256 {
00257 if (val->type == STRING) {
00258 if (val->u.string[0] == '\0')
00259 return 1;
00260 } else {
00261 if (val->u.num == 0)
00262 return 1;
00263 }
00264 return 0;
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 void
00278 expr_operator(op, sp, fs)
00279 int op;
00280 struct value *sp;
00281 struct filestat *fs;
00282 {
00283 int i;
00284 struct stat st1, st2;
00285
00286 switch (op) {
00287 case NOT:
00288 sp->u.num = expr_is_false(sp);
00289 sp->type = BOOLEAN;
00290 break;
00291 case ISREAD:
00292 i = 04;
00293 goto permission;
00294 case ISWRITE:
00295 i = 02;
00296 goto permission;
00297 case ISEXEC:
00298 i = 01;
00299 permission:
00300 if (fs->stat.st_uid == geteuid())
00301 i <<= 6;
00302 else if (fs->stat.st_gid == getegid())
00303 i <<= 3;
00304 goto filebit;
00305 case ISFILE:
00306 i = S_IFREG;
00307 goto filetype;
00308 case ISDIR:
00309 i = S_IFDIR;
00310 goto filetype;
00311 case ISCHAR:
00312 i = S_IFCHR;
00313 goto filetype;
00314 case ISBLOCK:
00315 i = S_IFBLK;
00316 goto filetype;
00317 case ISFIFO:
00318 #ifdef S_IFIFO
00319 i = S_IFIFO;
00320 goto filetype;
00321 #else
00322 goto false;
00323 #endif
00324 filetype:
00325 if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) {
00326 true:
00327 sp->u.num = 1;
00328 } else {
00329 false:
00330 sp->u.num = 0;
00331 }
00332 sp->type = BOOLEAN;
00333 break;
00334 case ISSETUID:
00335 i = S_ISUID;
00336 goto filebit;
00337 case ISSETGID:
00338 i = S_ISGID;
00339 goto filebit;
00340 case ISSTICKY:
00341 i = S_ISVTX;
00342 filebit:
00343 if (fs->stat.st_mode & i && fs->rcode >= 0)
00344 goto true;
00345 goto false;
00346 case ISSIZE:
00347 sp->u.num = fs->rcode >= 0? fs->stat.st_size : 0L;
00348 sp->type = INTEGER;
00349 break;
00350 case ISLINK1:
00351 case ISLINK2:
00352 if (S_ISLNK(fs->stat.st_mode) && fs->rcode >= 0)
00353 goto true;
00354 fs->op = OP_FILE;
00355 goto false;
00356 case NEWER:
00357 if (stat(sp->u.string, &st1) != 0) {
00358 sp->u.num = 0;
00359 } else if (stat((sp + 1)->u.string, &st2) != 0) {
00360 sp->u.num = 1;
00361 } else {
00362 sp->u.num = st1.st_mtime >= st2.st_mtime;
00363 }
00364 sp->type = INTEGER;
00365 break;
00366 case ISTTY:
00367 sp->u.num = isatty(sp->u.num);
00368 sp->type = BOOLEAN;
00369 break;
00370 case NULSTR:
00371 if (sp->u.string[0] == '\0')
00372 goto true;
00373 goto false;
00374 case STRLEN:
00375 sp->u.num = strlen(sp->u.string);
00376 sp->type = INTEGER;
00377 break;
00378 case OR1:
00379 case AND1:
00380
00381
00382
00383
00384
00385 *sp = *(sp + 1);
00386 break;
00387 case STREQ:
00388 case STRNE:
00389 i = 0;
00390 if (equal(sp->u.string, (sp + 1)->u.string))
00391 i++;
00392 if (op == STRNE)
00393 i = 1 - i;
00394 sp->u.num = i;
00395 sp->type = BOOLEAN;
00396 break;
00397 case EQ:
00398 if (sp->u.num == (sp + 1)->u.num)
00399 goto true;
00400 goto false;
00401 case NE:
00402 if (sp->u.num != (sp + 1)->u.num)
00403 goto true;
00404 goto false;
00405 case GT:
00406 if (sp->u.num > (sp + 1)->u.num)
00407 goto true;
00408 goto false;
00409 case LT:
00410 if (sp->u.num < (sp + 1)->u.num)
00411 goto true;
00412 goto false;
00413 case LE:
00414 if (sp->u.num <= (sp + 1)->u.num)
00415 goto true;
00416 goto false;
00417 case GE:
00418 if (sp->u.num >= (sp + 1)->u.num)
00419 goto true;
00420 goto false;
00421 case PLUS:
00422 sp->u.num += (sp + 1)->u.num;
00423 break;
00424 case MINUS:
00425 sp->u.num -= (sp + 1)->u.num;
00426 break;
00427 case TIMES:
00428 sp->u.num *= (sp + 1)->u.num;
00429 break;
00430 case DIVIDE:
00431 if ((sp + 1)->u.num == 0)
00432 error("Division by zero");
00433 sp->u.num /= (sp + 1)->u.num;
00434 break;
00435 case REM:
00436 if ((sp + 1)->u.num == 0)
00437 error("Division by zero");
00438 sp->u.num %= (sp + 1)->u.num;
00439 break;
00440 case MATCHPAT:
00441 {
00442 char *pat;
00443
00444 pat = re_compile((sp + 1)->u.string);
00445 if (re_match(pat, sp->u.string)) {
00446 if (number_parens > 0) {
00447 sp->u.string = match_begin[1];
00448 sp->u.string[match_length[1]] = '\0';
00449 } else {
00450 sp->u.num = match_length[0];
00451 sp->type = INTEGER;
00452 }
00453 } else {
00454 if (number_parens > 0) {
00455 sp->u.string[0] = '\0';
00456 } else {
00457 sp->u.num = 0;
00458 sp->type = INTEGER;
00459 }
00460 }
00461 }
00462 break;
00463 }
00464 }
00465
00466
00467 int
00468 lookup_op(name, table)
00469 char *name;
00470 char *const*table;
00471 {
00472 register char *const*tp;
00473 register char const *p;
00474 char c = name[1];
00475
00476 for (tp = table ; (p = *tp) != NULL ; tp++) {
00477 if (p[1] == c && equal(p, name))
00478 return tp - table;
00479 }
00480 return -1;
00481 }