# include # include # include # define OK 0 # define FAIL 1 # define ISIZE 256 # define PUSHLIMIT 256 # define ESCAPE '\\' # define NEGATE '^' # define LISTSIZE 256 # define POOLSIZE 1024 # define LOOKAHEAD 256 struct pipe { int read, write; }; oldi = 0, oldq = 0; char *ibuf = 0, **list = 0, **lp = 0; char background = NO; struct pipe p = {0, 0}; char pflag = NO; int carry = -1; char *ap = NULL, *pool = NULL; char semi = NO; char subshell = NO; char **AV = 0; int AC = 0; int input = STDIN; char *ip = 0; int icount = 0; main (ac, av) char **av; int ac; { char buf [BUFSIZE]; char *li [LISTSIZE]; char ib [BUFSIZE]; char pl [POOLSIZE]; lowinit (); AC = ac; AV = av; oldi = _signal (SIGINT, SIG_IGN); oldq = _signal (SIGQUIT, SIG_IGN); ibuf = ib + BUFSIZE / 2; list = li; pool = pl; list [0] = "upm"; list [1] = "a:/cpm"; list [2] = "b:./"; list [3] = "b:"; if (AC > 1) /* hsh with arguments */ { subshell = YES; /* * hsh -c command * Take input from a command line argument. */ if (AC == 3 && cmpstr ("-c", AV[1])) { ip = AV [2]; icount = lenstr (ip); ip [icount++] = '\n'; input = -1; } /* * hsh script arg1 arg2 arg3 ... * Take input from a file. */ else { input = open (*++AV, READ); AC--; } } /* if (gtty (STDIN, buf)) subshell = YES; */ for (;;) { if (!pflag && !semi && !subshell) prompt (); gets (buf); parse (buf); run (list + 4); } } run (a) register char **a; { static s, pid; extern null (); if (!*a) return; /* * built in commands */ if (cmpstr ("cd", *a)) { if (chdir (a[1])) huh (); return; } if (cmpstr ("wait", *a)) { if (oldi == SIG_DFL) _signal (SIGINT, null); while (wait (&s) >= 0); _signal (SIGINT, SIG_IGN); return; } if (pflag) pipe (&p); pid = fork (); if (pid < 0) return huh (); if (pid) /* parent */ { close (carry); /* close previous carry */ carry = -1; if (pflag) { close (p.write); carry = p.read; } if (background == NO && pflag == NO) { while (pid != wait (&s)); if (subshell && (s & 0377)) exit (); } } else /* child */ { if (!background) { _signal (SIGINT, oldi); _signal (SIGQUIT, oldq); } ex (a); /* execute in child */ huh (); exit (); } return YES; } ex (a) register char **a; { char buf [BUFSIZE]; static char **b; static char *c; static char d; if (input != STDIN) close (input); if (pflag) { close (STDOUT); dup (p.write); close (p.read); close (p.write); } if (carry >= 0) { close (STDIN); dup (carry); close (carry); } for (b = a; *b; b++) { /* if (b[0][1]) continue; */ d = **b; /* first char of current word */ c = b[1]; /* next word */ if (d == '<') { close (STDIN); open (c, READ); } else if (d == '>') { close (STDOUT); if (b[0][1] == '>') { open (c, WRITE); seek (STDOUT, 0, 2); } else { creat (c, 0600); } } else { continue; } *b = 0; } cpystr (buf, "/usr/bin/", *a, NULL); c = buf + 9; if (cmpstr (c, "source")) { a++; execute (*a, a); return; } execute (c, a); c -= 5; execute (c, a); c -= 4; execute (c, a); cpystr (buf, "/cpm/", *a, ".com", NULL); *a = buf; if (fexists (*a)) execv ("/bin/upm", a - 4); } parse (a) char *a; { static char *b, c; extern char *skipword (); ap = pool; lp = list + 4; for (;;) { a = skipbl (a); /* find next word */ if (!*a) break; /* no more words */ b = skipword (a); /* find end of word */ c = *b; /* save character */ *b = 0; /* null terminate */ expand (a); if (!c) break; /* end of line */ a = b + 1; /* skip over the word */ } /* l--; if (**l == '&') { background = YES; } else { l++; } */ *lp = 0; } char * skipbl (a) char *a; { while (*a && !black (*a)) a++; return a; } char * skipword (a) register char *a; { for (;;) { if (*a == '"') { for (a++; *a != 0 && *a != '"'; a++) ; } if (!black (*a)) break; a++; } return a; } fexists (a) char *a; { struct stat s; return stat (a, &s) >= 0; } gets (a) register char *a; { static unsigned char c; static char *astart; astart = a; background = NO; pflag = NO; semi = NO; for (;;) { c = ugetc (); if (!c) exit (); if (c == '"') { for (;;) { *a++ = c; c = ugetc (); if (c == '"' || c == '\n') break; } } if (c == '\n') { break; } if (c == ';') { if (lookahead ()) { a = astart; /* start over */ continue; } semi = YES; break; } if (c == '|') { if (lookahead ()) { a = astart; continue; } pflag = YES; break; } if (c == '&') { background = YES; continue; } /* if (c == '>' || c == '<') { *a++ = ' '; *a++ = c; *a++ = ' '; continue; } */ *a++ = c; } *a = 0; } char ugetc () { if (icount <= 0) ifill (); icount--; return *ip++; } ifill () { ip = ibuf; icount = read (input, ibuf, ISIZE); if (icount <= 0) exit (); } black (a) register unsigned char a; { return '!' <= a && a <= '~'; } /* huh () { write (STDOUT, "?\n", 2); } */ /* pushc (c) char c; { *--ip = c; icount++; } */ /* pushs (a) char *a; { static char *b; for (b = a + lenstr (a) - 1; b >= a; b--) pushc (*b); } */ /* * a is the file name * b is the matching expression */ match (a, b) register char *a, *b; { if (*a == NULL && *b == NULL) /* end simultaneously */ return YES; if (*b == NULL) /* pattern ends */ return NO; if (*b == '*') { register char *p; for (p = a + lenstr (a); a <= p; p--) if (match (p, b + 1)) return YES; return NO; } if (*a == NULL) /* text ends */ return NO; if (omatch (a, b)) return match (a + 1, b + 1); else return NO; } BOOL omatch (a, b) register char *a, *b; { /* char sense; */ /* TEXT *start; */ if (*a != NULL && *b == '?') return YES; /* else if (*b == ESCAPE && b[1]) return *a == b[1]; */ /* else if (*b != '[') */ return *a == *b; /* b++; /* [ .... ] form */ /* if (*b == NEGATE) { sense = NO; b++; } else { sense = YES; } */ /* start = b; /* mark the starting pos. */ /* for (;;) { if (*b == ']' || !*b) { return !sense; return NO; } else if (*b == ESCAPE && b[1]) { if (*a == b[1]) return sense; else b += 2; } else if ( *b == '-' && b != start && alphanum (b[1]) && alphanum (b[-1]) ) { if (b[-1] <= *a && *a <= b[1]) return sense; else b += 2; } else { if (*a == *b) return sense; else b++; } } return NO; */ } /* TEXT * nextpat (a) register char *a; { if (*a == ESCAPE && a[1]) return a + 2; if (*a == '[') { a++; while (*a) { if (*a == ESCAPE && a[1]) a += 2; else if (*a == ']') return a + 1; else a++; } return a; } return a + 1; } */ /* BOOL alphanum (a) { return isdigit (a) || isalpha (a); } */ struct { int number; char name [15]; } dir = {0}; expand (a) register char *a; { static unsigned f; static char *c; if (*a == '"') { c = a + lenstr (a) - 1; if (*c == '"') *c = 0; newword (a + 1); } else if (*a == '$') { f = a[1] - '0'; if (f < AC) newword (AV[f]); } else if (!ismagic (a)) { newword (a); } else { f = open (".", READ); for (;;) { if (read (f, &dir, 16) != 16) break; if (dir.number && *dir.name != '.' && match (dir.name, a)) { c = cpystr (ap, dir.name, NULL) + 1; if (c < pool + POOLSIZE) /* if it fit */ { newword (ap); ap = c; } } } close (f); } } ismagic (a) register char *a; { return inter ("*?", a); } /* * character set intersection detector */ inter (a, b) register char *a, *b; { static char *c; for (; *a; a++) for (c = b; *c; c++) if (*a == *c) return YES; return NO; } lookahead () { char buf [BUFSIZE]; static char *p, c; static n; p = buf; for (n = 0; n < LOOKAHEAD; n++) { c = *p++ = ugetc (); if (c == '\n') { break; } if (c == '&') { if (fork ()) return YES; close (STDIN); open ("/dev/null", READ); icount = 0; ip = ibuf; p [-1] = '\n'; oldi = SIG_IGN; oldq = SIG_IGN; subshell = YES; break; } } while (buf < p) pushc (*--p); return NO; } newword (a) char *a; { if (lp < list + LISTSIZE) *lp++ = a; } execute (a, b) register char *a, **b; { static f; static char c; struct stat s; /* * test for shell script */ if (stat (a, &s) || (s.flags & S_TYPE)) return; /* no file or special file */ f = open (a, READ); c = 0; read (f, &c, 1); close (f); c--; if (!(c & 0200)) /* ascii */ *--b = a = "/bin/hsh"; execv (a, b); }