|
|
1.1 ! root 1: %{ ! 2: /* ! 3: * Set return status based on ! 4: * various specified conditions, ! 5: * mostly related to files. ! 6: * Used mostly in shell files. ! 7: */ ! 8: ! 9: #include <stdio.h> ! 10: #include <sys/stat.h> ! 11: #include <access.h> ! 12: #include "testnode.h" ! 13: ! 14: #define NPRIM (sizeof(prims)/sizeof(prims[0])) ! 15: #define NFNAME 500 /* size of filename buffer */ ! 16: %} ! 17: %start command ! 18: ! 19: %union { ! 20: NODE *nodeptr; ! 21: char *fname; ! 22: } ! 23: ! 24: %left OR ! 25: %left AND ! 26: %left '!' ! 27: %token _R _W _F _D _S _T _Z _N ! 28: %token SEQ SNEQ ! 29: %token _EQ _NE _GT _GE _LT _LE ! 30: %type <nodeptr> exp ! 31: %token <fname> STR ! 32: %% ! 33: ! 34: command: ! 35: exp '\n' { code = $1; return; } ! 36: ; ! 37: ! 38: exp: ! 39: '(' exp ')' { $$ = $2; } ! 40: | '!' exp { $$ = bnode('!', $2, NULL); } ! 41: | exp OR exp { $$ = bnode(OR, $1, $3); } ! 42: | exp AND exp { $$ = bnode(AND, $1, $3); } ! 43: | _R STR { $$ = lnode(xr, $2, NULL); } ! 44: | _W STR { $$ = lnode(xw, $2, NULL); } ! 45: | _F STR { $$ = lnode(xf, $2, NULL); } ! 46: | _D STR { $$ = lnode(xd, $2, NULL); } ! 47: | _S STR { $$ = lnode(xs, $2, NULL); } ! 48: | _T STR { $$ = lnode(xt, $2, NULL); } ! 49: | _T { $$ = lnode(xt, "1", NULL); } ! 50: | _Z STR { $$ = lnode(xz, $2, NULL); } ! 51: | _N STR { $$ = lnode(xn, $2, NULL); } ! 52: | STR SEQ STR { $$ = lnode(xseq, $1, $3); } ! 53: | STR SNEQ STR { $$ = lnode(xsneq, $1, $3); } ! 54: | STR _EQ STR { $$ = lnode(xeq, $1, $3); } ! 55: | STR _NE STR { $$ = lnode(xne, $1, $3); } ! 56: | STR _GT STR { $$ = lnode(xgt, $1, $3); } ! 57: | STR _GE STR { $$ = lnode(xge, $1, $3); } ! 58: | STR _LT STR { $$ = lnode(xlt, $1, $3); } ! 59: | STR _LE STR { $$ = lnode(xle, $1, $3); } ! 60: | STR { $$ = lnode(xn, $1, NULL); } ! 61: ; ! 62: ! 63: %% ! 64: struct prim { ! 65: char *p_name; ! 66: int p_lval; ! 67: int p_bin; ! 68: } prims[] = { ! 69: "-r", _R, 0, ! 70: "-w", _W, 0, ! 71: "-f", _F, 0, ! 72: "-d", _D, 0, ! 73: "-s", _S, 0, ! 74: "-t", _T, 0, ! 75: "-z", _Z, 0, ! 76: "-n", _N, 0, ! 77: "-eq", _EQ, 1, ! 78: "-ne", _NE, 1, ! 79: "-gt", _GT, 1, ! 80: "-ge", _GE, 1, ! 81: "-lt", _LT, 1, ! 82: "-le", _LE, 1, ! 83: "-o", OR, 1, ! 84: "-a", AND, 1 ! 85: }; ! 86: ! 87: ! 88: char **gav; ! 89: int gac; ! 90: ! 91: struct stat sb; ! 92: ! 93: NODE *code; ! 94: ! 95: char *next(); ! 96: NODE *bnode(); ! 97: NODE *lnode(); ! 98: long atol(); ! 99: int xr(); ! 100: int xw(); ! 101: int xf(); ! 102: int xd(); ! 103: int xs(); ! 104: int xt(); ! 105: int xz(); ! 106: int xn(); ! 107: int xseq(); ! 108: int xsneq(); ! 109: int xeq(); ! 110: int xne(); ! 111: int xgt(); ! 112: int xge(); ! 113: int xlt(); ! 114: ! 115: main(argc, argv) ! 116: char *argv[]; ! 117: { ! 118: gav = argv+1; ! 119: gac = argc-1; ! 120: if (argv[0][0]=='[' && argv[0][1]=='\0') { ! 121: if (strcmp(argv[gac], "]") != 0) ! 122: tsterr("unbalanced [..]"); ! 123: gac--; ! 124: } ! 125: if (gac == 0) ! 126: exit(1); ! 127: yyparse(); ! 128: exit(!execute(code)); ! 129: } ! 130: ! 131: /* ! 132: * Lexical analyser ! 133: */ ! 134: yylex() ! 135: { ! 136: static char laststr = 0; /* 1 if last token was string */ ! 137: register char *ap; ! 138: register struct prim *pp; ! 139: ! 140: if ((yylval.fname = ap = next()) == NULL) ! 141: return ('\n'); ! 142: ! 143: if (*ap == '-') { ! 144: for (pp = prims; pp < &prims[NPRIM]; pp++) { ! 145: if (strcmp(pp->p_name, ap) == 0) { ! 146: if (!laststr && pp->p_bin) ! 147: break; ! 148: laststr = 0; ! 149: return (pp->p_lval); ! 150: } ! 151: } ! 152: } ! 153: else { ! 154: laststr = 0; ! 155: if (strcmp("!=", ap) == 0) ! 156: return (SNEQ); ! 157: ! 158: if (ap[1] == '\0') { ! 159: if (ap[0]==')') { ! 160: laststr = 1; ! 161: return(')'); ! 162: } ! 163: if (ap[0]=='(' || ap[0]=='!') ! 164: return (ap[0]); ! 165: if (ap[0]=='=') ! 166: return (SEQ); ! 167: } ! 168: } ! 169: laststr = 1; ! 170: return (STR); ! 171: } ! 172: ! 173: yyerror() ! 174: { ! 175: fprintf(stderr, "Test expression syntax error\n"); ! 176: usage(); ! 177: } ! 178: ! 179: /* ! 180: * Return the next argument from the arg list. ! 181: */ ! 182: char * ! 183: next() ! 184: { ! 185: if (gac < 1) ! 186: return (NULL); ! 187: gac--; ! 188: return (*gav++); ! 189: } ! 190: ! 191: /* ! 192: * Build an expression tree node (non-leaf) ! 193: */ ! 194: NODE * ! 195: bnode(op, left, right) ! 196: int op; ! 197: NODE *left, *right; ! 198: { ! 199: register NODE *np; ! 200: char *malloc(); ! 201: ! 202: if ((np = (NODE *)malloc(sizeof (NODE))) == NULL) ! 203: tsterr("Out of space"); ! 204: np->n_un.n_op = op; ! 205: np->n_left = left; ! 206: np->n_right = right; ! 207: return (np); ! 208: } ! 209: ! 210: /* ! 211: * Build a leaf node in expression tree. ! 212: */ ! 213: NODE * ! 214: lnode(fn, str1, str2) ! 215: int (*fn)(); ! 216: char *str1, *str2; ! 217: { ! 218: register NODE *np; ! 219: char *malloc(); ! 220: ! 221: if ((np = (NODE *)malloc(sizeof (NODE))) == NULL) ! 222: tsterr("Out of space"); ! 223: np->n_left = np->n_right = NULL; ! 224: np->n_un.n_fun = fn; ! 225: np->n_s1 = str1; ! 226: np->n_s2 = str2; ! 227: return (np); ! 228: } ! 229: ! 230: /* ! 231: * Execute compiled code. ! 232: */ ! 233: execute(np) ! 234: register NODE *np; ! 235: { ! 236: if (np->n_left != NULL) ! 237: switch (np->n_un.n_op) { ! 238: case AND: ! 239: if (execute(np->n_left) && execute(np->n_right)) ! 240: return (1); ! 241: return (0); ! 242: ! 243: case OR: ! 244: if (execute(np->n_left) || execute(np->n_right)) ! 245: return (1); ! 246: return (0); ! 247: ! 248: case '!': ! 249: return (!execute(np->n_left)); ! 250: ! 251: default: ! 252: tsterr("Panic: bad tree (op %d)", np->n_un.n_op); ! 253: } ! 254: else ! 255: return ((*np->n_un.n_fun)(np)); ! 256: /* NOTREACHED */ ! 257: } ! 258: ! 259: /* ! 260: * Check to see if the file exists ! 261: * and if readable. ! 262: */ ! 263: xr(np) ! 264: NODE *np; ! 265: { ! 266: return (access(np->n_s1, AREAD) >= 0); ! 267: } ! 268: ! 269: /* ! 270: * Check if the file exists and is ! 271: * writeable. ! 272: */ ! 273: xw(np) ! 274: NODE *np; ! 275: { ! 276: return (access(np->n_s1, AWRITE) >= 0); ! 277: } ! 278: ! 279: /* ! 280: * Check if the file exists and is not ! 281: * a directory. ! 282: */ ! 283: xf(np) ! 284: NODE *np; ! 285: { ! 286: return (stat(np->n_s1, &sb)>=0 && (sb.st_mode&S_IFMT)!=S_IFDIR); ! 287: } ! 288: ! 289: /* ! 290: * Check to see if the file exists ! 291: * and is a directory. ! 292: */ ! 293: xd(np) ! 294: NODE *np; ! 295: { ! 296: return (stat(np->n_s1, &sb)>=0 && (sb.st_mode&S_IFMT)==S_IFDIR); ! 297: } ! 298: ! 299: /* ! 300: * Check to see if the file exists ! 301: * and has a non-zero size. ! 302: */ ! 303: xs(np) ! 304: NODE *np; ! 305: { ! 306: return (stat(np->n_s1, &sb)>=0 && sb.st_size>0); ! 307: } ! 308: ! 309: /* ! 310: * Check to see if the file ! 311: * descriptor is associated ! 312: * with a terminal. ! 313: */ ! 314: xt(np) ! 315: NODE *np; ! 316: { ! 317: return (isatty(atoi(np->n_s1))); ! 318: } ! 319: ! 320: /* ! 321: * True if the length of the given ! 322: * string is zero. ! 323: */ ! 324: xz(np) ! 325: NODE *np; ! 326: { ! 327: return (np->n_s1[0] == '\0'); ! 328: } ! 329: ! 330: /* ! 331: * True if the length of the given ! 332: * string is non-zero. ! 333: */ ! 334: xn(np) ! 335: NODE *np; ! 336: { ! 337: return (np->n_s1[0] != '\0'); ! 338: } ! 339: ! 340: /* ! 341: * True if the two strings are ! 342: * lexicographically equal. ! 343: */ ! 344: xseq(np) ! 345: register NODE *np; ! 346: { ! 347: return (strcmp(np->n_s1, np->n_s2) == 0); ! 348: } ! 349: ! 350: /* ! 351: * True if the two strings are ! 352: * lexicographically unequal. ! 353: */ ! 354: xsneq(np) ! 355: register NODE *np; ! 356: { ! 357: return (strcmp(np->n_s1, np->n_s2) != 0); ! 358: } ! 359: ! 360: /* ! 361: * True if the two numbers are ! 362: * equal. ! 363: */ ! 364: xeq(np) ! 365: register NODE *np; ! 366: { ! 367: return (atol(np->n_s1) == atol(np->n_s2)); ! 368: } ! 369: ! 370: /* ! 371: * True if the two numbers are ! 372: * not equal. ! 373: */ ! 374: xne(np) ! 375: register NODE *np; ! 376: { ! 377: return (atol(np->n_s1) != atol(np->n_s2)); ! 378: } ! 379: ! 380: /* ! 381: * True if the first number is ! 382: * greater than the second. ! 383: */ ! 384: xgt(np) ! 385: register NODE *np; ! 386: { ! 387: return (atol(np->n_s1) > atol(np->n_s2)); ! 388: } ! 389: ! 390: /* ! 391: * True if the first number is ! 392: * greater than or equal to the second. ! 393: */ ! 394: xge(np) ! 395: register NODE *np; ! 396: { ! 397: return (atol(np->n_s1) >= atol(np->n_s2)); ! 398: } ! 399: ! 400: /* ! 401: * True if the first number is ! 402: * less than the second. ! 403: */ ! 404: xlt(np) ! 405: register NODE *np; ! 406: { ! 407: return (atol(np->n_s1) < atol(np->n_s2)); ! 408: } ! 409: ! 410: /* ! 411: * True if the first number is ! 412: * less than or equal to the second. ! 413: */ ! 414: xle(np) ! 415: register NODE *np; ! 416: { ! 417: return (atol(np->n_s1) <= atol(np->n_s2)); ! 418: } ! 419: ! 420: /* ! 421: * Error messages. ! 422: */ ! 423: /* VARARGS */ ! 424: tsterr(x) ! 425: { ! 426: fprintf(stderr, "test: %r\n", &x); ! 427: exit(1); ! 428: } ! 429: ! 430: usage() ! 431: { ! 432: fprintf(stderr, "Usage: test expression\n"); ! 433: exit(1); ! 434: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.