/* * Csh - a shell by PJAC * eval.c - the expression evaluayion routines */ #include "csh.h" #include #include /* * evaluate the argv array - given by argv */ #define OROR 1 #define ANDAND 2 #define EQUEQU 3 #define NOTEQU 4 #define LESEQU 5 #define MOREQU 6 #define LSHIFT 7 #define RSHIFT 8 struct m { int mval; char *msval; char mcmd; char mlevel; }; arg_eval(argc, argv, res) char **argv; int *res; { int val = 0; int lastlchar = 0; int tval; int cmd; char *p, *q; int level; char *sval, *stval; struct m *j; struct m restab[18]; struct cmd T; /* * single char operators, | is used as a seperator as well as an * an op, offset into o1char == precedence */ static char o1char[] = "|^&||||<>||+-*/%"; static char o2char[] = "|&|||=|||||<>"; static char o2cmd[] = { OROR, ANDAND, 0, 0, 0, EQUEQU, 0, 0, 0, 0, 0, LSHIFT, RSHIFT }; static char o3char[] = "!=<=>="; static char o3cmd[] = { NOTEQU, LESEQU, MOREQU }; j = restab; j->mlevel = 0; for(;;){ if(--argc < 0) p = ""; else p = *argv++; if(strcmp("(", p) == 0){ /* a bracketed expression - call the function */ for(tval = 0 ; tval < argc && strcmp(argv[tval], ")");) tval++; if(tval >= argc) return(ERR); if(tval){ /* if got a command execute it */ T.cm_parent = 0; T.cm_child = 0; T.cm_next = 0; T.cm_ofile = 0; T.cm_ifile = 0; stval = argv[tval]; argv[tval] = 0; /* hack the last arg */ T.cm_argv = argv; T.cm_argc = tval; val = r_tree(&T); argv[tval] = stval; } else val = 1; tval++; argc -= tval; argv += tval; val = val ? 0 : 1; /* invert the logic */ p = val ? "1" : "0"; } else if(*p == '-'){ if(p[1] == 0){ /* a normal minus sign */ if(!argc) return(ERR); lastlchar ^= 4; continue; } if(p[2] == 0 && index("rwxeozfd", p[1])){ if(!argc) return(ERR); --argc; if(tst_file(*argv++, p[1])) p = "1"; else p = "0"; val = atoi(p); } else val = 0; } else { if(p[1] == 0){ if(*p == '~'){ if(!argc) return(ERR); lastlchar ^= 1; continue; } else if(*p == '^'){ if(!argc) return(ERR); lastlchar ^= 2; continue; } } if(*p >= '0' && *p <= '9') val = atoi(p); else val = 0; } sval = p; if(lastlchar){ if(lastlchar & 1) val = ~val; if(lastlchar & 2) val = !val; if(lastlchar & 4) val = -val; lastlchar = 0; } if(--argc < 0) p = "XXX"; else p = *argv++; if(p[1] == 0){ q = index(o1char, *p); if(q == 0) return(ERR); cmd = *p; level = q - o1char + 2; /* +2 for || and && */ } else if(*p == p[1] && !p[2]){ q = index(o2char, *p); if(q == 0) return(ERR); level = q - o2char; cmd = o2cmd[level]; } else { level = -1; for(q = o3char ; *q ; q+=2) if(*q == *p && q[1] == p[1] && !p[2]) break; if(*q){ level = (q - o3char)/2; cmd = o3cmd[level]; level += 6; /* get it to the right precedence */ } } level++; /* * now do the ame loop */ ame: if(j->mlevel < (char)level){ /* current operator has */ (++j)->mcmd = cmd; /* higher precedence */ j->mval = val; j->msval = sval; j->mlevel = level; continue; } if(!j->mlevel){ /* end of expression */ *res = val; if(argc > 0) return(ERR); return(OK); } tval = j->mval; stval = j->msval; switch(j->mcmd){ case '+': val += tval; break; case '-': val = tval - val; break; case '*': val *= tval; break; case '/': val = tval / val; break; case '%': val = tval % val; break; case '&': val &= tval; break; case '|': val |= tval; break; case '^': val ^= tval; break; case '<': val = (tval < val); break; case '>': val = (tval > val); break; case NOTEQU: val = (strcmp(stval, sval) != 0); break; case EQUEQU: val = (strcmp(stval, sval) == 0); break; case OROR: val = (val || tval); break; case ANDAND: val = (val && tval); break; case LESEQU: val = (tval <= val); break; case MOREQU: val = (tval >= val); break; case LSHIFT: val = tval << val; break; case RSHIFT: val = tval >> val; break; } sval = val ? "1" : "0"; /* give it a value */ j--; /* execute it then pop the stack and */ goto ame; /* deal with the next operator */ } /* return(ERR); */ } /* * test for file existance and satisfying condition mode */ tst_file(file, mode) char *file; { struct stat statbuf; if(stat(file, &statbuf) < 0) return(FALSE); switch(mode){ case 'r': if(statbuf.st_mode & S_IREAD) break; return(FALSE); case 'w': if(statbuf.st_mode & S_IWRITE) break; return(FALSE); case 'x': if(statbuf.st_mode & S_IEXEC) break; return(FALSE); case 'e': /* exist */ break; case 'o': /* on msdos we always own it */ #ifndef MSDOS if(getuid() != statbuf.st_uid) return(FALSE); #endif break; case 'z': if(statbuf.st_size) return(FALSE); break; case 'f': if((statbuf.st_mode & S_IFMT) != S_IFREG) return(FALSE); break; case 'd': if((statbuf.st_mode & S_IFMT) != S_IFDIR) return(FALSE); break; } return(TRUE); }