/* * Shell. */ #include #define SU 0 #define SIGQUIT 0 #define SIGINTR 0 #define LSIZE 40 #define CSIZE 128 #define TSIZE 256 #define T_WORD 0 #define T_NL 1 #define T_SEMI 2 #define T_LESS 3 #define T_GREAT 4 #define T_APPND 5 #define T_AMPER 6 #define T_LPAR 7 #define T_RPAR 8 struct tree { int t_op; int t_flag; struct tree *t_lp; struct tree *t_rp; char *t_ifp; char *t_ofp; char *t_word[]; }; #define APPND 01 #define ASYNC 02 int dolc; int eflag; int iflag; int peekc; int ecode; char **dolv; char *dolp; char *cmdp; char *ttop; char *vbls[52]; int line[LSIZE]; char chrs[CSIZE]; char tree[TSIZE]; char *tmesg[] = { "Killed utterly", "Killed", "Hangup", "Quit", 0, 0, "FPP trap", "Sig 7", "Sig 8", "Sig 9", "Sig 10", "Sig 11", "Sig 12", "Sig 13", "Sig 14", "Sig 15", "Odd address trap", "Segmentation trap", "Illegal instruction", "FPP simulation trap", "BPT/Trace trap", "IOT trap", "Bad system call", "TRAP trap", 0 }; char *emesg[] = { "Unterminated string", "Command too long", "Syntax error", "Command too complex" }; main(argc, argv) char *argv[]; { register struct tree *tp; register char *p; register c; int *lp, uid[2]; p = ": "; getuid(uid); if(uid[1] == SU) p = "# "; vbls['P'-'A'] = saves(p); --argc; ++argv; if(argc>0 && argv[0][0]=='-') { p = &argv[0][1]; --argc; ++argv; while(c = *p++) switch(c) { case 'c': case 'C': vbls['P'-'A'] = 0; if(argc > 0) { --argc; cmdp = *argv++; } break; case 'e': case 'E': ++eflag; break; case 'i': case 'I': ++iflag; } } if(argc > 0) { fclose(stdin); stdin = fopen(argv[0], "r"); if(stdin == NULL) { printf("%s: cannot open.\n", argv[0]); exit(1); } --argc; ++argv; if(!eflag) vbls['P'-'A'] = 0; } if(iflag) { catch(SIGQUIT, 1); catch(SIGINTR, 1); } dolc = argc; dolv = argv; vbls['N'-'A'] = saven(dolc); for(;;) { if(p = vbls['P'-'A']) printf("%s", p); ecode = 0; setexit(); if(ecode) { printf("%s.\n", emesg[ecode-1]); if(ecode < 3) while((c=get())!=EOF && c!='\n') ; continue; } if((lp=readline()) == 0) break; ttop = tree; tp = parse(line, lp); execute(tp); } } readline() { register char *cp; register c, *lp; lp = line; cp = chrs; for(;;) { c = get(); if(c==' ' || c=='\t') continue; if(c == EOF) return(0); if(lp >= &line[LSIZE-1]) oops(2); if(c == '\n') { *lp++ = T_NL; break; } if(c == ';') { *lp++ = T_SEMI; continue; } if(c == '(') { *lp++ = T_LPAR; continue; } if(c == ')') { *lp++ = T_RPAR; continue; } if(c == '<') { *lp++ = T_LESS; continue; } if(c == '&') { *lp++ = T_AMPER; continue; } if(c == '>') { c = get(); if(c == '>') *lp++ = T_APPND; else { peekc = c; *lp++ = T_GREAT; } continue; } *lp++ = T_WORD; *lp++ = cp; if(c == '"') while((c=get1(1)) != '"') { if(c == '\n') { peekc = c; oops(1); } if(cp >= &chrs[CSIZE]) oops(2); *cp++ = c|0200; } else { for(;;) { if(cp >= &chrs[CSIZE]) oops(2); *cp++ = c; c = get(); if(any(c, " \t'\"();&<>\n")) break; } peekc = c; } if(cp >= &chrs[CSIZE]) oops(2); *cp++ = 0; } return(lp); } get() { register c; if(c = peekc) { peekc = 0; return(c); } for(;;) { if(dolp) { if(c = *dolp++) { echo(c); return(c); } dolp = 0; } if((c=get1(0)) == '\\') { if((c=get1(0)) == '\n') { echo(' '); return(' '); } echo(c); return(c|0200); } if(c == '$') { c = get1(0); if(c>='0' && c<='9') { c -= '0'; if(c < dolc) dolp = dolv[c]; continue; } if(c>='a' && c<='z' || c>='A' && c<='Z') { if(c >= 'a') c += 'Z' + 1 - 'a'; dolp = vbls[c-'A']; continue; } } echo(c); return(c); } } get1(ef) { register c; if(cmdp) { if(cmdp == -1) return(EOF); c = *cmdp++; if(c == 0) { cmdp = -1; c = '\n'; } } else { c = getchar(); if(c == EOF) return(EOF); } if(ef) echo(c); return(c); } parse(p1, p2) int *p1, *p2; { register struct tree *tp; register o, *p; struct tree *lp; int l; p = p1; while(p!=p2 && (*p==T_NL || *p==T_SEMI || *p==T_AMPER)) ++p; if(p == p2) return(0); l = 0; for( ; p!=p2; ++p) { o = *p; if(o == T_LPAR) { ++l; continue; } if(o == T_RPAR) { --l; if(l < 0) oops(3); continue; } if(o==T_NL || o==T_SEMI || o==T_AMPER) { if(l == 0) { tp = pcmnd(p1, p); if(o == T_AMPER) tp->t_flag |= ASYNC; if(o!=T_NL && (p[1]!=T_NL && p[1]!=T_RPAR)) { lp = treealloc(sizeof(*lp)); lp->t_op = T_SEMI; lp->t_lp = tp; lp->t_rp = parse(p+1, p2); tp = lp; } return(tp); } continue; } if(o == T_WORD) ++p; } if(l == 0) return(pcmnd(p1, p2)); oops(3); } pcmnd(p1, p2) int *p1, *p2; { register struct tree *tp; register o, *p; int f, l, n; int *lp, *rp; char *ifp, *ofp; l = 0; f = 0; n = 0; lp = 0; rp = 0; ifp = 0; ofp = 0; for(p=p1; p!=p2; ++p) { o = *p; if(o == T_LPAR) { if(l == 0) { if(lp) oops(3); lp = p+1; } ++l; continue; } if(o == T_RPAR) { --l; if(l == 0) rp = p; continue; } if(o==T_GREAT || o==T_APPND || o==T_LESS) { if(l == 0) { if(++p==p2 || (*p++)!=T_WORD) oops(3); if(o == T_LESS) { if(ifp) oops(3); ifp = *p; } else { if(ofp) oops(3); ofp = *p; if(o == T_APPND) f |= APPND; } } continue; } if(o == T_WORD) { ++p; if(l == 0) p1[n++] = *p; } } if(lp) { if(rp==0 || n) oops(3); tp = treealloc(sizeof(*tp)); tp->t_op = T_LPAR; tp->t_lp = parse(lp, rp); } else { if(n == 0) oops(3); p1[n++] = 0; tp = treealloc(sizeof(*tp) + n*sizeof(tp->t_word[0])); tp->t_op = T_WORD; for(l=0; lt_word[l] = p1[l]; } tp->t_flag = f; tp->t_ifp = ifp; tp->t_ofp = ofp; return(tp); } treealloc(n) register n; { register char *p1, *p2; if(ttop+n > &tree[TSIZE]) oops(4); p1 = p2 = ttop; ttop += n; while(n--) *p2++ = 0; return(p1); } execute(tp) register struct tree *tp; { register char *s; register i; int c; if(tp == 0) return; switch(tp->t_op) { case T_SEMI: execute(tp->t_lp); execute(tp->t_rp); break; case T_WORD: s = tp->t_word[0]; if(equal(s, "chdir")) { if((s=tp->t_word[1]) == 0) printf("Usage: chdir directory\n"); else if(chwdir(s) < 0) printf("%s: bad directory\n", s); break; } if(equal(s, "shift")) { if(dolc < 1) printf("No args to shift.\n"); else { --dolc; ++dolv; free(vbls['N'-'A']); vbls['N'-'A'] = saven(dolc); } break; } if(equal(s, "set")) { set(tp); break; } if(equal(s, "ask")) { ask(tp); break; } if(equal(s, "vars")) { for(i=0; it_ifp) printf("Execute: ifp=%s\n", tp->t_ifp); if(tp->t_ofp) printf("Execute: ofp=%s\n", tp->t_ofp); if(tp->t_op == T_LPAR) { execute(tp->t_lp); break; } printf("Execute:"); for(i=0; s=tp->t_word[i]; ++i) printf(" %s", s); if((tp->t_flag&ASYNC) != 0) printf(" (Asyncronous)"); printf("\n"); } } set(tp) register struct tree *tp; { register char *p, *s; char *v; int c, n1, n2, r; if((r=getr(tp->t_word[1])) < 0) return; if(tp->t_word[2]==0 || (s=tp->t_word[3])==0) goto bad; switch(c = tp->t_word[2][0]) { case '=': v = p = alloc(sizes(s)); while(c = *s++) *p++ = c&0177; *p = 0; break; case '+': case '-': if(vbls[r] == 0) goto bad; n1 = grabn(vbls[r]); n2 = grabn(s); if(c == '+') n1 += n2; else n1 -= n2; v = saven(n1); break; default: bad: printf("Bad set command.\n"); return; } free(vbls[r]); vbls[r] = v; } ask(tp) register struct tree *tp; { register char *s; register r; char b[30]; if((r=getr(tp->t_word[1])) < 0) return; if((s=tp->t_word[2]) == 0) s = "Ask? "; printf("%s", s); if((s=gets(b)) == 0) s = "(End of file)"; free(vbls[r]); vbls[r] = saves(s); } getr(s) register char *s; { register r; if(s == 0) { printf("Missing variable\n"); return(-1); } r = *s; if(!(r>='A' && r<='Z') && !(r>='a' && r<='z')) { printf("Bad variable\n"); return(-1); } if(r > 'Z') r += 'Z' + 1 - 'a'; return(r-'A'); } saves(s) register char *s; { register char *p1, *p2; p1 = s; while(*p1++) ; p1 = p2 = alloc(p1-s); while(*p2++ = *s++) ; return(p1); } grabn(s) register char *s; { register m, n; m = 0; if(*s == '-') { ++s; ++m; } for(n=0; *s; ++s) n = (10*n) + (*s-'0'); if(m) n = -n; return(n); } sizes(s) register char *s; { register char *p; p = s; while(*p++) ; return(p-s); } saven(n) { register char *p; p = alloc(7); sprintf(p, "%d", n); return(p); } echo(c) { if(eflag) putchar(c); } any(c, s) register c; register char *s; { while(*s) if(*s++ == c) return(1); return(0); } oops(n) { ecode = n; reset(); } /* * RSX fakes */ catch() { } chwdir() { return(-1); } getuid(u) int u[]; { u[0] = u[1] = SU; }