From 1a5078b80f22401cef3d56dc91028319efc0424a Mon Sep 17 00:00:00 2001 From: Bill Joy Date: Wed, 23 Nov 1977 12:45:02 -0800 Subject: [PATCH] BSD 1 development Work on file ashell/sh_func.c Work on file ashell/sh_glob.c Work on file ashell/errs Work on file ashell/printsh Work on file ashell/sh_parse.c Work on file ashell/makesh Work on file ashell/install Work on file ashell/sh_exec.c Work on file ashell/sh.c Work on file ashell/sh.h Work on file ashell/sh_lex.c Work on file ashell/sh_set.c Work on file ashell/sh_sem.c Work on file ashell/sh_wait.c Work on file ashell/READ_ME Work on file pxref/READ_ME Work on file pxref/printpxref Work on file pxref/pxref.p Work on file pxref/pxref.c Work on file pxref/install Work on file pxref/makepxref Synthesized-from: 1bsd --- ashell/READ_ME | 24 +++ ashell/errs | 10 + ashell/install | 2 + ashell/makesh | 1 + ashell/printsh | 2 + ashell/sh.c | 452 ++++++++++++++++++++++++++++++++++++++++++++ ashell/sh.h | 73 +++++++ ashell/sh_exec.c | 180 ++++++++++++++++++ ashell/sh_func.c | 363 +++++++++++++++++++++++++++++++++++ ashell/sh_glob.c | 260 +++++++++++++++++++++++++ ashell/sh_lex.c | 470 ++++++++++++++++++++++++++++++++++++++++++++++ ashell/sh_parse.c | 303 ++++++++++++++++++++++++++++++ ashell/sh_sem.c | 138 ++++++++++++++ ashell/sh_set.c | 346 ++++++++++++++++++++++++++++++++++ ashell/sh_wait.c | 189 +++++++++++++++++++ pxref/READ_ME | 10 + pxref/install | 6 + pxref/makepxref | 2 + pxref/printpxref | 3 + pxref/pxref.c | 31 +++ pxref/pxref.p | 344 +++++++++++++++++++++++++++++++++ 21 files changed, 3209 insertions(+) create mode 100644 ashell/READ_ME create mode 100644 ashell/errs create mode 100644 ashell/install create mode 100644 ashell/makesh create mode 100755 ashell/printsh create mode 100644 ashell/sh.c create mode 100644 ashell/sh.h create mode 100644 ashell/sh_exec.c create mode 100644 ashell/sh_func.c create mode 100644 ashell/sh_glob.c create mode 100644 ashell/sh_lex.c create mode 100644 ashell/sh_parse.c create mode 100644 ashell/sh_sem.c create mode 100644 ashell/sh_set.c create mode 100644 ashell/sh_wait.c create mode 100644 pxref/READ_ME create mode 100755 pxref/install create mode 100755 pxref/makepxref create mode 100755 pxref/printpxref create mode 100644 pxref/pxref.c create mode 100644 pxref/pxref.p diff --git a/ashell/READ_ME b/ashell/READ_ME new file mode 100644 index 0000000000..16072b16a2 --- /dev/null +++ b/ashell/READ_ME @@ -0,0 +1,24 @@ +Wed Oct 19, 1977 + +This directory contains the source for a shell. +It requires floating point to do the time command which is built-in +so you will have to cc it -f on machines without floating point. +It also requires a version 7 C compiler. + +Accurate documentation is in the file "sh.6" to be nroffed with +/usr/man/man0/naa and a new "version 7" nroff. + +This shell requires the "htmp" data base also used by the editor "ex". +If you do not set it up so that the "sethome" command is done by "login" +then you should use the old "osethome" routine in ../s6 rather than "sethome" +and reenable the execl of this sethome in the file "sh.c" (with the correct +pathname). + + Bill Joy + CS Division + Department of EE and CS + UC Berkeley + Berkeley, California 94704 + + (415) 524-4510 [HOME] + (415) 642-4948 [SCHOOL] diff --git a/ashell/errs b/ashell/errs new file mode 100644 index 0000000000..1a8c89f20d --- /dev/null +++ b/ashell/errs @@ -0,0 +1,10 @@ +cc -f -n -O *.c ../lib/libX.a -lS +sh.c: +sh_exec.c: +sh_func.c: +sh_glob.c: +sh_lex.c: +sh_parse.c: +sh_sem.c: +sh_set.c: +sh_wait.c: diff --git a/ashell/install b/ashell/install new file mode 100644 index 0000000000..0ff8bf38dc --- /dev/null +++ b/ashell/install @@ -0,0 +1,2 @@ +cp a.out /usr/bin/ashell +echo New ashell installed diff --git a/ashell/makesh b/ashell/makesh new file mode 100644 index 0000000000..7a313703d5 --- /dev/null +++ b/ashell/makesh @@ -0,0 +1 @@ +cc -f -n -O *.c ../lib/libX.a -lS diff --git a/ashell/printsh b/ashell/printsh new file mode 100755 index 0000000000..8e795ca4f9 --- /dev/null +++ b/ashell/printsh @@ -0,0 +1,2 @@ +pr printsh +pr sh.h sh.c sh_*.c diff --git a/ashell/sh.c b/ashell/sh.c new file mode 100644 index 0000000000..c638bbc4b6 --- /dev/null +++ b/ashell/sh.c @@ -0,0 +1,452 @@ +#include "sh.h" +/* + * Shell + * + * Modified by Bill Joy + * UC Berkeley 1976/1977 + * + + Features remaining to be fixed up and/or implemented + ======== ========= == == ===== == === == =========== + + * Commands insert and delete on argument lists should be + * implemented also set 3= when have 2 arguments should be + * handled somehow (perhaps optionally valid). + * Also note that $12 should really be done correctly. + + * A notion of terse ? + + * time time ... time time date etc. are funny + * These should be implemented correctly with the internal versions + * of exit repeat if goto etc. Probably want to maintain a timed + * process number list and check this when processes die (this uses + * less processes than forking a time). + + * Better facilities for string manipulation ? + + * The exit status variable should be implemented (status) + * and set too by the internal commands. When do this get + * rid of kludge about prompt not set for exit on error or + * fix up in some way. Also should rewrite the argument + * processing section to be cleaner and make some sense. + + * Do verbose more cleanly. + + * Implement next (recursively!) + + * Implement shell filters and <<. This probably involves some more + * modularization of the scanner and deciphering of the two different + * options available in the bell shell. + + * Other stuff from Bell shell - + * + * Any more control facilities ? + * || && + * <>, ><, >2, 2 >, etc. + * Terminate + * Can we build high level commands out of gotos which have + * optional defaults and ifs that set variables which one + * can test ? Think so ! + * but what about "for" ? + * Prompt for more input ? + * Command substitution ` ` ? + * Trap ? + * Exec ? + * Eval ? + * .acct ? + * Some way to set stdin to be input when filters can happen. + + * What about file name substitution and quoting in set. + + * Conditional expressions should be fixed up with set name@ + * and to allow quoting at least between ? ... : ... }. + + * internal if, repeat, nohup, goto, exit, echo, echononl + * Repeat, time, nohup, etc. should allow + * + * repeat 10 { sleep 5; echo hi } & + * time { pc -l *.p ; obj } + * or perhaps with ('s since that is illegal now anyways + * although the above is more like if. + + * Changes to glob to allow ~, prevent too long path, and prevent + * perhaps running out of directories. Also change it so it doesn't + * exit so ungracefully, i.e. on: + * chdir /asdf/adfas/a* + * In error diagnostics the command name is often not set or set + * wrong on calls to bferr. Could have more calls to bferr2. + * Should be able to distinguish between ``No more processes'' and + * ``Too many processes.'' + + * Shell flags to exit on error, make undefined variables an error. + + * Interrupted waits and errors in glob cost storage. + * Scratch should go away. + * Set a="abc" should print back similarly. + + * Last, but certainly not least, some of the INTERLISP redo etc features. + + */ + +char prompt[] "prompt"; +char pcs[] "pcs"; +char shell[] "shell"; +char pid[] "pid"; +char home[] "home"; +char path[] "path"; +char n_args[] "nargs"; +char tim[] "time"; + +char *narginp, nonelflg, nverbose; + +main(c, av) + int c; + char **av; +{ + register f; + register char **v, *cp; + + settimes(); + v = av; + uid = getuid(); + loginsh = **v == '-'; + set(home, gethome() == 0 ? savestr(hentry.home) : "."); + set1("0404", "/usr/bin/px", &interps); + set(prompt, uid == 0 ? "#\240" : "\246\240"); + set(shell, "/usr/bin/ashell"); + set(pid, putn(getpid())); + set1(tim, "tyme", &aliases); + for (f = 3; f < 15; f++) + close(f); + if (c > 1) { + if (*(cp = v[1]) == '-') { + do + switch (*cp++) { + case 'V': + verbose = 1; + case 'v': + nverbose = 1; + break; + case 'c': + if (c > 2) + narginp = v[2]; + goto l1; + case 't': + nonelflg = 2; + case '\0': +l1: + set(prompt, ""); + unsetv(prompt); + case 'i': + **v = '-'; + nofile++; + break; + } + while (*cp); + v++; + c--; + } + if (nofile == 0 && c > 1) { + set(prompt, ""); + unsetv(prompt); + close(0); + if (open(cp = v[1], 0) < 0) { + prs(v[1]); + err(": Cannot open"); + exit(1); + } + } + } + if (gtty(0, scratch) == 0 && gtty(1, scratch) == 0) + **v = '-'; + c--; + v++; + if (c == 0) { + c = 1; + v = av; + } + setargs(c, v); + set(path, "-/bin-/usr/bin"); + pfile("/.profile"); + if (loginsh) + pfile("/.login"); + arginp = narginp; + onelflg = nonelflg; + verbose = nverbose; + if (**av == '-') { + setintr++; + signal(QUIT, 1); + signal(INTR, 1); + } + /* mask the name ?? */ + process(1); + if (loginsh) + prs("logout\n"); + goodbye(loginsh); +} + +pfile(cp) + char *cp; +{ + int oldinput, c; + + strcpy(scratch, hentry.home); + strcat(scratch, cp); + oldinput = dup(0); + close(0); + c = open(scratch, 0); + if (c == 0) { + process(0); + close(0); + } + dup(oldinput); + close(oldinput); +} + +goodbye(f) + int f; +{ + + if (f) { + signal(QUIT, 1); + signal(INTR, 1); + setintr = 0; + pfile("/.logout"); + } + exit(0); +} + +process(pro) +{ + register char *cp; + + setexit(); + if (doneinp) { + doneinp = 0; + return; + } + for (;;) { + cp = value(prompt); + if (pro) + prs(cp); + for (; *cp; cp++) + echo(*cp); + main1(); + } +} + +main1() +{ + register int *t; + + error = 0; + lex(¶ml); + if (error) { + err(error); + freelex(¶ml); + return; + } + t = syntax(paraml.next, ¶ml); + if (error) + err(error); + else + execute(t); + freesyn(t); + freelex(¶ml); +} + +echo(c) + char c; +{ + + c =& 0177; + if (verbose) + write(2, &c, 1); + return (c); +} + +err(s) + char *s; +{ + + prs(s); + prs("\n"); + s = value(prompt); + if (*s == 0) { + seek(0, 0, 2); + exit(1); + } +} + +prs(os) + register char *os; +{ + register char *s; + + s = os; + if (s != 0) { + while (*s) + s++; + write(2, os, s-os); + } +} + +digit(c) + char c; +{ + c =& 0177; + return (c >= '0' && c <= '9'); +} + +letter(c) + char c; +{ + c =& 0177; + return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'); +} + +any(c, s) + int c; + register char *s; +{ + + while (*s) + if (*s++ == c) + return(1); + return(0); +} + +char htmp[] "/etc/htmp"; +int tty; + +gethome() +{ + char buf[100]; + register int i; + register char *bufp, *cp; + + if (loginsh) + exechome(); + tty = ttyn(2); + if (readhome() == 0 && hentry.uid == uid) + return (0); + if (getpw(uid, buf) && sleep(15), getpw(uid, buf)) + return (-1); + bufp = buf; + for (i = 1; i < 6; i++) { + while (*bufp != ':') + if (*bufp++ == 0) + return (-1); + bufp++; + } +/* printf("buf %s bufp %s", buf, bufp); */ + for (cp = bufp; *cp && *cp != ':'; cp++) + continue; + *cp = 0; +/* printf("bufp %s\n", bufp); */ + hentry.uid == uid; + for (i = 0; i < (sizeof hentry.home - 1); i++) + hentry.home[i] = *bufp ? *bufp++ : 0; + return (0); +} + +readhome() +{ + int htmpf; + + htmpf = open(htmp, 0); + if (htmpf < 0) + return (-1); + if (seek(htmpf, tty * sizeof hentry, 0) < 0) { + close(htmpf); + return (-1); + } + if (read(htmpf, &hentry, sizeof hentry) != sizeof hentry) { + close(htmpf); + return (-1); + } + close (htmpf); + return (0); +} + +exechome() +{ + int status; + static reenter; + + if (reenter) + return; + reenter = 1; +/* + if (fork()) { + wait(&status); + if (tty == 'x') + tty = status >> 8; + } else { + execl("/usr/bin/sethome", loginsh ? "-" : "x", 0); + exit(0177); + } +*/ +} + +getpw(uid, buf) + int uid; + char buf[]; +{ + char pbuf[512]; + register int n; + register char *bp, *pbufp; + int pwf, m, pbufc; + + pwf = open("/etc/passwd", 0); + if (pwf < 0) + return (1); + pbufc = 0; + for (;;) { + bp = buf; + do { + if (pbufc == 0) { + pbufc = read(pwf, &pbuf, 512); + if (pbufc <= 0) + return (1); + pbufp = pbuf; + } + pbufc--; + } while ((*bp++ = *pbufp++) != '\n'); + *bp++ = '\0'; +/* printf("uid %d xid %d buf %s", uid, xid(buf), buf); */ + if (xid(buf) == uid) + return (0); + } +} + +xid(buf) + char buf[]; +{ + register int i; + int uid; + register char *bp; + register c; + + bp = buf; + for (i = 1; i < 3; i++) { + while (*bp != ':') + if (*bp++ == 0) + return (-1); + bp++; + } + i = 0; + while ((c = *bp++) != ':') + if (c == 0) + return (-1); + else if (digit(c)) + i = i * 10 + c - '0'; + uid = i; + i = 0; + while ((c = *bp++) != ':') + if (c == 0) + return (-1); + else if (digit(c)) + i = i * 10 + c - '0'; + return (i << 8 | uid); +} diff --git a/ashell/sh.h b/ashell/sh.h new file mode 100644 index 0000000000..b645ebf04b --- /dev/null +++ b/ashell/sh.h @@ -0,0 +1,73 @@ +/* + * Shell header file + */ +#define E +#define INTR 2 +#define QUIT 3 + +#define QUOTE 0200 + +#define FAND 1 +#define FCAT 2 +#define FPIN 4 +#define FPOU 8 +#define FPAR 16 +#define FINT 32 +#define FPRS 64 +#define FDIAG 128 + +#define TCOM 1 +#define TPAR 2 +#define TFIL 3 +#define TLST 4 + +#define DTYP 0 +#define DLEF 1 +#define DRIT 2 +#define DFLG 3 +#define DSPR 4 +#define DCOM 5 + +#define ENOENT 2 +#define ENOEXEC 8 +#define ENOMEM 12 +#define EACCES 13 +#define ENOTDIR 20 + +struct shvar { + char *value; + char *name; + struct shvar *next; +} shvhed, paraml, aliases, interps; + +struct shvar2 { + char *value; + struct shvar *prev; + struct shvar *next; +}; + +char verbose; +char nofile; +char *error; +int uid; +char loginsh; +char doneinp; +char setintr; +char *arginp; +char onelflg; +char scratch[100]; + +char prompt[], shell[], pid[], pcs[], home[], path[], n_args[], tim[]; + +char *value(), *value1(); +char **glob(); +struct shvar *adrof(), *adrof1(); + +#define seterr(s) if (error == 0) error = s; +int errno; + +struct htmp { + int uid; + char home[28]; + int ttytype; +} hentry; diff --git a/ashell/sh_exec.c b/ashell/sh_exec.c new file mode 100644 index 0000000000..609796d9cd --- /dev/null +++ b/ashell/sh_exec.c @@ -0,0 +1,180 @@ +#include "sh.h" + +int tglob(), trim(); +static int gflag; +static char *exerr, *expath; + +char nic[] "nice"; + +doexec(t) + int *t; +{ + register char *cp, *pp; + register char **av; + char slash, pathc; + char *vp; + + if (adrof(nic)) + nice(getn(value(nic))); + cp = globone(t[DCOM]); + if (cp == 0) + exit(1); + exerr = 0; + expath = t[DCOM] = cp; + slash = gflag || any ('/', cp); + gflag = 0; + av = &t[DCOM+1]; + scan(av, &tglob); + if (gflag) { + av = glob(av); + if (av == 0) { + prs("No match\n"); + exit(1); + } + } + *--av = t[DCOM]; + scan(av, &trim); + pp = value(path); + if (*pp == 0 || slash) + pp = ""; + do { + for (cp = pp; *pp && *pp != '-' ; pp++) + *pp =& ~QUOTE; + pathc = *pp; + *pp = 0; + vp = strcpy(calloc(1, strlen(cp) + strlen(*av) + 2), cp); + if (cp == pp || slash == 0) { + if (cp[0]) + strcat(vp, "/"); + strcat(vp, *av); + texec(vp, av-DCOM); + xfree(vp); + } + } while ((*pp++ = pathc) != 0); + prs(expath); + if (exerr) { + err(exerr); + xfree(exerr); + } else + err(": Cannot find"); + exit(1); +} + +texec(f, t) + register int *t; +{ + extern errno; + register int *t1; + register i; + int w; + + execv(f, (t1 = &t[DCOM])); + switch (errno) { + case ENOEXEC: + *t1 = f; + i = open(f, 0); + if (i < 0) { + prs(*t1); + prs(": Cannot open"); + exit(1); + } + w = 0; + read(i, &w, 2); + close(i); + f = interp(w); + if (f != 0) + *--t1 = f; + else if (w & 0100200) { + prs(*t1); + prs(": No interpreter\n"); + exit(1); + } else + *--t1 = value(shell); + execv(*t1, t1); + prs(*t1); + /* + * should give better message but can't goto + * top because could loop + */ + err(": Execute failed"); + exit(1); + case ENOMEM: + prs(*t1); + err(": Not enough core"); + exit(1); + case EACCES: + if (exerr == 0) { + expath = savestr(f); + exerr = ": No execute access"; + } + return; + } +} + + +scan(t, f) + register int *t; + int (*f)(); +{ + register char *p, c; + + while (p = *t++) + while (c = *p) + *p++ = (*f)(c); +} + +tglob(c) + char c; +{ + if (any(c, "[?*")) + gflag = 1; + return (c); +} + +trim(c) + char c; +{ + + return (c & 0177); +} + +prn(n) + int n; +{ + register a; + + a = n / 10; + if (a != 0) + prn(a); + n = n % 10 + '0'; + write(2, &n, 1); +} + +globone(str) + register char *str; +{ + int gv[2]; + register char **gvp; + + setname(str); + gv[0] = str; + gv[1] = 0; + gflag = 0; + scan(gv, &tglob); + if (gflag) { + gvp = glob(gv); + if (gvp == 0) { + bferr(": No match"); + return (0); + } + str = *gvp++; + if (*gvp) { + bferr(": Ambiguous"); + return (0); + } + } else { + scan(gv, &trim); + str = gv[0]; + } + return (str); +} diff --git a/ashell/sh_func.c b/ashell/sh_func.c new file mode 100644 index 0000000000..816e3b1a87 --- /dev/null +++ b/ashell/sh_func.c @@ -0,0 +1,363 @@ +#include "sh.h" + +int gimme(), normal(); +int chngd(), shift(), doset(), goodbye(), await(), dozip(); +int rewind(), doalias(), unalias(), dotimes(), doalloc(); +int dointerp(), uninterp(), noquit(), quit(), abort(); + +#define INF 127 +#define FRET 1 + +static struct biltins { + char *bname; + int (*bfunct)(); + char minargs, maxargs; + int flags; +} bfunc[] { + "chdir", &chngd, 0, 1, 0, + "wait", &await, 0, 1, 0, + "shift", &shift, 0, 1, 0, + "rewind", &rewind, 0, 0, 0, + "set", &doset, 0, INF, 0, + "unset", &unset, 1, INF, 0, + "alias", &doalias, 0, 2, 0, + "unalias", &unalias, 1, INF, 0, + "interp", &dointerp, 0, 2, 0, + "uninterp", &uninterp, 1, INF, 0, + "logout", &goodbye, 0, 0, 0, + "quit", &quit, 0, 0, 0, + "noquit", &noquit, 0, 0, 0, + "alloc", &doalloc, 0, 0, 0, + "abort", &abort, 0, 0, 0, + ":", &dozip, 0, INF, 0, + /* "verbose" */ + "tyme", &dotimes, 0, INF, FRET, + /* "nohup" */ + /* "repeat" */ + /* "if" */ + /* "goto" */ + /* "exit" */ + 0, 0, 0, 0, 0 +}; +static char *bname; + +func(t) + register int *t; +{ + register struct biltins *bp; + register int *tp; + int i; + + bp = bfunc; + for (;;) { + if (bp->bname == 0) + return(0); + if (strcmp(bp->bname, t[DCOM]) == 0) + break; + bp++; + } + bname = bp->bname; + i = 0; + for (tp = &t[DCOM+1]; *tp; tp++) + i++; + if (i < bp->minargs) { + bferr(": Too few arguments"); + return (1); + } + if (i > bp->maxargs) { + bferr(": Too many arguments"); + return (1); + } + i = (*bp->bfunct)(&t[DCOM]); + return (bp->flags & FRET ? i : 1); +} + +noquit() +{ + + signal(QUIT, 1); +} + +quit() +{ + + signal(QUIT, 0); +} + +abort() +{ + + abort(); +} + +dozip() +{ + ; +} + +chngd(vp) + register char **vp; +{ + register char *dp; + + vp++; + dp = *vp++; + if (dp) { + dp = globone(dp); + if (dp == 0) + return; + } else { + dp = value(home); + if (*dp == 0) { + bferr(": No home"); + return; + } + } + if (chdir(dp) < 0) + switch (errno) { + case ENOTDIR: + bferr2(dp, ": Not a directory"); + return; + case ENOENT: + bferr2(dp, ": No such file or directory"); + return; + case EACCES: + bferr2(dp, ": No execute access"); + return; + default: + prs("errno = "); + prn(errno); + prs("\n"); + bferr2(dp, ": bad directory !?!"); + return; + } +} + +prvars() +{ + + plist(&shvhed); +} +/* +prvars() +{ + register struct shvar *vp; + register char *cp; + register int col; + + vp = shvhed.next; + if (vp == 0) + return; + col = 0; + cp = unquote(vp->value); + for(;;) { + prs(vp->name); + col =+ strlen(vp->name); + if (cp[0]) { + prs("="); + prs(cp); + col =+ strlen(cp) + 1; + } + xfree(cp); + col++; + vp = vp->next; + if (vp == 0) + break; + cp = unquote(vp->value); + if (col + strlen(vp->name) + strlen(cp) + 1 > 79) { + prs("\n"); + col = 0; + } else + prs(" "); + } + if (col) + prs("\n"); +} +*/ + +unquote(s) + char *s; +{ + char *s2; + int i; + register char *cp, *dp; + register c; + + i = 0; + for (cp = s; c = *cp++;) { + if ((c & QUOTE) == 0) + continue; + c =& 0177; + i++; + if (c == '"' || (*cp & QUOTE) == 0) + continue; + while ((c = *cp) && (c & QUOTE)) { + c =& 0177; + if (c == '"') + break; + cp++; + } + i++; + } + s2 = calloc(1, strlen(s) + i + 1); + for (dp = s2, cp = s; c = *cp++;) { + if ((c & QUOTE) == 0) { + *dp++ = c; + continue; + } + c =& 0177; + if (c == '"' || (*cp & QUOTE) == 0) { + *dp++ = '\\'; + *dp++ = c; + continue; + } + *dp++ = '"'; + *dp++ = c; + while ((c = *cp) && (c & QUOTE)) { + c =& 0177; + if (c == '"') + break; + cp++; + *dp++ = c; + } + *dp++ = '"'; + } + return (s2); +} + +setname(cp) + char *cp; +{ + + bname = cp; +} + +bferr(cp) + char *cp; +{ + prs(bname); + err(cp); +} + +bferr2(cp, cp2) + char *cp, *cp2; +{ + prs(cp); + err(cp2); +} + +doalias(v) + register char *v[]; +{ + register struct shvar *vp; + register char *p; + + v++; + p = *v++; + if (p == 0) + plist(&aliases); + else if (*v == 0) { + p = value1(p, &aliases); + if (*p != 0) { + prs(p); + prs("\n"); + } + } else + set1(p, savestr(*v), &aliases); +} + +unalias(v) + register char *v[]; +{ + + unset1(v, &aliases); +} + +dointerp(v) + register char *v[]; +{ + register int i; + register char *p; + + v++; + p = *v++; + if (p == 0) { + plist(&interps); + return; + } + if (*v == 0) { + p = value1(p, &interps); + if (*p != 0) { + prs(p); + prs("\n"); + } + return; + } + i = getn(p); + if (i == 0) + return; + set1(p, savestr(*v), &interps); +} + +uninterp(v) + register char *v[]; +{ + unset1(v, &interps); +} + +interp(w) + int w; +{ + register struct shvar *vp; + + for (vp = interps.next; vp != 0; vp = vp->next) + if (getn(vp->name) == w) + return (vp->value); + return (0); +} + +plist(vp) + register struct shvar *vp; +{ + register char *cp; + + for (vp = vp->next; vp != 0; vp = vp->next) { + prs(vp->name); + if (vp->value[0]) { + cp = unquote(vp->value); + prs("\t"); + prs(cp); + xfree(cp); + } + prs("\n"); + } +} + +alias(t) + int *t; +{ + register struct shvar *ap; + + for (ap = aliases.next; ap != 0; ap = ap->next) + if (strcmp(ap->name, *t) == 0) { + xfree(*t); + if (ap->value[0] == 0) { + bferr2(*t, ": Restricted"); + *t = ":"; + } else + *t = savestr(ap->value); + return (1); + } + return (0); +} + +extern char end[]; + +doalloc() +{ + char *cp; + + cp = sbrk(0); + prn(cp - &end); + prs("\n"); +} diff --git a/ashell/sh_glob.c b/ashell/sh_glob.c new file mode 100644 index 0000000000..4af2ac1df8 --- /dev/null +++ b/ashell/sh_glob.c @@ -0,0 +1,260 @@ +#include "sh.h" + +#define STRSIZ 522 +#define PTHSIZ 100 + +static char ab[STRSIZ]; +static char *ava[200]; +static char **av; +static char *string; +static int ncoll; + +static char gpath[100], *gpathp; +static int globbed; +static char *entp; + +static int stbuff[18]; + +char ** +glob(v) + register char *v[]; +{ + + if (adrof("noglob")) + return (v); + ginit(); + while (*v) + collect(*v++); + *av++ = 0; + return (ncoll == 0 ? 0 : &ava[2]); +} + +ginit() +{ + av = &ava[2]; + string = ab; + ncoll = 0; + globbed = 0; + gpathp = gpath; +} + +collect(as) +{ + char **oav; + + oav = av; + globbed = 0; + expand(as); + sort(oav); +} + +sort(oav) +char **oav; +{ + register char **p1, **p2, **c; + + p1 = oav; + while (p1 < av-1) { + p2 = p1; + while(++p2 < av) { + if (strcmp(*p1, *p2) > 0) { + c = *p1; + *p1 = *p2; + *p2 = c; + } + } + p1++; + } +} + +expand(as) +char *as; +{ + register char *cs; + char *sgpathp; + register int dirf; + static struct { + int ino; + char name[16]; + } entry; + + sgpathp = gpathp; + cs = as; + while (*cs != '*' && *cs != '?' && *cs != '[') { + if (gpathp >= &gpath[PTHSIZ]) + gpatherr(); + else if ((*gpathp++ = *cs++) == 0) { + if (!globbed) + *av++ = cat(as, ""); + else if (stat(gpath, &stbuff) >= 0) { + *av++ = cat(gpath, ""); + ncoll++; + } + goto endit; + } + } + gpathp = sgpathp; + cs--; + while (cs >= as && *cs != '/') + cs--; + while (as <= cs) + if (gpathp >= &gpath[PTHSIZ]) + gpatherr(); + else + *gpathp++ = *as++; + *gpathp = 0; + dirf = open(gpath, 0); + if (dirf<0) + if (globbed) + goto endit; + else { + prs(gpath); + panic(": cannot open"); + } + globbed++; + cs++; + while (read(dirf, &entry, 16) == 16) { + if (entry.ino==0) + continue; + if (match(entry.name, cs)) { + *av++ = cat(gpath, entry.name); + ncoll++; + } + } + close(dirf); +endit: + gpathp = sgpathp; + *gpathp = 0; +} + +toolong() +{ + panic("Arg list too long"); +} + +gpatherr() +{ + prs("Path too long: "); + panic(gpath); +} + +match(s, p) +char *s, *p; +{ + register c, sentp; + + if (*s == '.' && *p != '.') + return(0); + sentp = entp; + entp = s; + c = amatch(s, p); + entp = sentp; + return(c); +} + +amatch(as, ap) +char *as, *ap; +{ + register char *s, *p; + register scc; + int c, cc, ok, lc; + char *sgpathp; + + s = as; + p = ap; +nextc: + if(scc = *s++ & 0177) + if ((scc =& 0177) == 0) + scc = 0200; + switch (c = *p++) { + case '[': + ok = 0; + lc = 077777; + while (cc = *p++) { + if (cc == ']') { + if (ok) + goto nextc; + else + return(0); + } else if (cc == '-') { + if (lc <= scc && scc <= *p++) + ok++; + } else + if (scc == (lc = cc)) + ok++; + } + panic("missing ]"); + case '*': + if(*p == '\0') + return(1); + else if (*p == '/') { + p++; + goto slash; + } + s--; + while(*s) + if (amatch(s, p)) + return(1); + else + s++; + return(0); + case '\0': + return(scc == '\0'); + default: + if (c == scc) + goto nextc; + else + return(0); + case '?': + if (scc != '\0') + goto nextc; + else + return(0); + case '/': + if (scc == '\0') { +slash: + s = entp; + sgpathp = gpathp; + while (*gpathp = *s++) + gpathp++; + *gpathp++ = '/'; + *gpathp = 0; + if (stat(gpath, &stbuff) == 0) + if ((stbuff[2] & 060000) == 040000) + if (*p == 0) { + *av++ = cat(gpath, ""); + ncoll++; + } else + expand(p); + gpathp = sgpathp; + *gpathp = 0; + } + return(0); + } +} + +cat(as1, as2) +char *as1, *as2; +{ + register char *s1, *s2; + + s2 = string; + s1 = as1; + while (*s2++ = (*s1++ & 0177)) + if (s2 >= &ab[STRSIZ]) + toolong(); + s1 = as2; + s2--; + while (*s2++ = *s1++) + if (s2 > &ab[STRSIZ]) + toolong(); + s1 = string; + string = s2; + return(s1); +} + +panic(str) +{ + err(str); + reset(); +} diff --git a/ashell/sh_lex.c b/ashell/sh_lex.c new file mode 100644 index 0000000000..e6735b91f4 --- /dev/null +++ b/ashell/sh_lex.c @@ -0,0 +1,470 @@ +#include "sh.h" +/* + * Shell: + * Lexical and argument processing routines + * + * lex - driver for lexical analysis + * word - reads next word into line and pointer thereto via args + * getc - gets a character from the logical input stream + * readc - reads a character from the 'input device' + * setargs - sets up the parameter variables initially + * rewind - backs up the shell arguments to their original values + * setnargs - resets nargs variable after changes to arg list + * shift - manipulates the shell parameters + */ +struct shvar2 *word(); + +/* + * lex is the driver routine for the lexical input of the shell. + * Basic strategy is to read a logical line into linebuf + * with successive words pointed to by successive elements of args. + * Termination condition is a newline. + * Returns a pointer to a linked list of the words. + */ +lex(hp) + register struct shvar2 *hp; +{ + register struct shvar2 *wdp; + + wdp = hp; + do { + wdp->next = calloc(1, sizeof *wdp); + wdp->next->prev = wdp; + wdp = wdp->next; + wdp->value = word(); + } while (wdp->value[0] != '\n'); + hp->prev = wdp; + wdp->next = hp; +} + +freelex(vp) + register struct shvar *vp; +{ + register struct shvar *fp; + + while (vp->next != vp) { + fp = vp->next; + vp->next = fp->next; + xfree(fp->value); + cfree(fp); + } + vp->prev = vp; +} + +/* static */ char peekc, peekx; +/* + * word breaks the input character stream into words. + * Blanks and tabs in the input are ignored, the characters + * &;<>()|^ and \n + * are considered to be separators. + * Characters may be escaped here by surrounding them with + * 's or "s. This causes the QUOTE (high order) bit of the + * corresponding character to be set so the character will + * fail subsequent comparisons. The quoting is eventually + * stripped off. More quoting by QUOTE is also done in readc. + * Note importantly that quoted character strings do not undergo + * parameter substitution! + * Return value is a pointer to a structure containing the word. + */ +struct shvar2 * +word() +{ + register c; + char c1; + register char *lp; + char lbuf[514]; + int i; + + lp = lbuf; + i = 512; + /* + * Loop to get something solid + */ + for (;;) { + c = getc(); + switch (c) { + case ' ': + case '\t': + continue; + case '\'': + case '"': + c1 = c; + while ((c = echo(readc())) != c1) { + if (c == '\n') { + seterr("Unmatched ' or \""); + *lp++ = 0; + peekc = c; + goto ret; + } + if (--i == 0) + goto toochars; + *lp++ = c | QUOTE; + } + break; + case '&': + case ';': + case '<': + case '>': + case '(': + case ')': + case '|': + case '^': + case '\n': + *lp++ = c; + *lp++ = '\0'; + goto ret; + default: + peekc = c; + break; + } + /* + * We have discovered something solid (not a separator). + * We want to gather in as many characters + * as possible but don't want to grab a separator. + * If we find another quotation in this word we go back to + * the top to take it. + */ + for (;;) { + c = getc(); + if (any(c, " '\"\t;&<>()|^\n")) { + peekc = c; + if (any(c, "\"'")) + break; + *lp++ = '\0'; + goto ret; + } + if (--i == 0) + goto toochars; + *lp++ = c; + } + } +toochars: + seterr("Too many characters"); + lbuf[1] = 0; +ret: + return (savestr(lbuf)); +} + +/* static */ char *dolp; +/* static */ struct shvar2 paramhd, *paramp, *dolnxt; +/* static */ int dolc; +/* + * setargs sets up the initial argument linked list. + * paramp is a working pointer to the front of the list (actually + * one before the front), paramhd the actual origin which contains + * the true value of $0. + * + * dolnxt is used in expanding $*. + * dolc is maintained by setnargs who also maintains the nargs variable + * dolp is the pointer into the expanding string in getc + */ +setargs(c, v) + int c; + char *v[]; +{ + register struct shvar2 *vp, *lvp; + + vp = ¶mhd; + for (;;) { + vp->value = *v++; + c--; + if (c == 0) + break; + lvp = vp; + vp = calloc(1, sizeof *vp); + lvp->next = vp; + vp->prev = lvp; + } + rewind(); +} + +/* + * rewind the shell arguments + */ +rewind() +{ + paramp = ¶mhd; + setnargs(); +} + +/* + * set up nargs variable after a parameter list change + */ +setnargs() +{ + register struct shvar2 *vp; + + dolc = 0; + for (vp = paramp; vp != 0; vp = vp->next) + dolc++; + set(n_args, putn(dolc - 1)); + if (dolc == 1) + unsetv(n_args); +} + +/* + * shift the shell arguments + */ +shift(v) + register char *v[]; +{ + register int n; + register struct shvar2 *vp; + + v++; + n = *v == 0 ? 1 : getn(*v++); + for (vp = paramp; vp && n;) + if (n > 0) { + n--; + vp = vp->next; + } else { + n++; + vp = vp->prev; + } + if (n || vp == 0) { + bferr(": Count too large"); + return; + } + paramp = vp; + setnargs(); +} + +/* static */ char dol2bra; +/* + * getc gets a character from the logical input stream. + * It handles parameter expansion via $[0-9], all parameters + * via $*, shell variables via $[A-Za-z], and the process number via $$. + * Also handled is the trimming of the sufficies from expanded + * names via the . notation. For example if $1 is "foo.p" then + * $.1 will be "foo". + * + * The variable dol2bra's value has the following meaning: + * + * 2 echo characters to : or }, if : discard chars to } + * 1 echo characters to : + * -1 discard characters to } + * -2 discard characters to : or }, if : echo to } + * + * This handles the constructs + * + * ${name?str1:str2} name set -> str1 ; t -> str2 + * ${name:default} name set -> $name ; t -> default + * ${name?string} name set -> strings ; t -> "" + */ +getc() +{ + register c; + static char doldot; + + if (peekc) { + c = peekc; + peekc = 0; + return (c); + } + for (;;) { + if (dolp) { + c = *dolp++; + if (c && (c != '.' || !doldot || any('.', dolp))) + return (echo(c)); + if (dolnxt && (dolnxt = dolnxt->next)) { + dolp = dolnxt->value; + return (echo(' ')); + } + dolp = 0; + echo(']'); + continue; + } + if (peekx) { + c = peekx; + peekx = 0; + } else + c = readc(); + if (c == '\\') { + echo(c); + c = readc(); + if (c == '\n') + c = ' '; + else + c =| QUOTE; + } + if (dol2bra) { + switch (c) { + case '}': + if (dol2bra > 0) + echo(']'); + dol2bra = 0; + echo('}'); + continue; + case '\n': + dol2bra = 0; + seterr("Missing }"); + return (echo('\n')); + case ':': + switch (dol2bra) { + case 2: + dol2bra = -1; + echo(']'); + echo(':'); + continue; + case -2: + dol2bra = 1; + echo(':'); + echo('['); + continue; + } + default: + echo(c); + } + if (dol2bra < 0) + continue; + return (c); + } + if (c == '$') { + echo(c); + doldot = 0; + c = readc(); + echo(c); + if (c == '.') { + doldot = 1; + c = readc(); + echo(c); + } + switch (c) { + default: + if (digit(c)) { + dolp = rgadrof(c); + if (dolp == 0) + continue; + dolp = dolp->value; + break; + } + if (c == '{' || letter(c)) { + dolp = dolvbl(c); + if (dolp || dol2bra > 0) + break; + continue; + } + return (c & 0177); + case '$': + dolp = value(pid); + break; + case '*': + if (dolc <= 1) + break; + dolnxt = paramp->next; + dolp = dolnxt->value; + break; + } + echo('['); + continue; + } + echo(c); + return (c); + } +} + +dolvbl(sc) + char sc; +{ + register char *np; + register struct shvar *vp; + char name[20], c; + + np = name; + if (sc != '{') + *np++ = sc; + for (c = readc(); letter(c); c = readc()) + if (np < &name[sizeof name - 1]) { + echo(c); + *np++ = c; + } + *np++ = 0; + vp = adrof(name); + if (sc != '{') + peekx = c; + else { + switch (c) { + case ':': + if (vp) + dol2bra = -1; + else + dol2bra = -2; + peekx = ':'; + break; + case '}': + peekx = c; + dol2bra = -1; + break; + case '?': + echo('?'); + if (vp) + dol2bra = 2; + else + dol2bra = -2; + return (0); + default: + echo(c); + seterr("Variable syntax"); + return (0); + } + } + if (vp == 0) { + seterr("Undefined variable"); + return (0); + } + return (vp->value); +} + +/* + * read a character from the input device. + * this may be an argument e.g. for sh -c. + * also for sh -t stop after one line. + */ +readc() +{ + char cc; + register c; + register char *cp; + +again: + if (arginp) { + if (arginp == 1) + exit(0); + else if ((c = *arginp++) == '\0') { + arginp = 1; + c = '\n'; + } + } else if (onelflg == 1) + exit(0); + else if (read(0, &cc, 1) != 1) { + doneinp = 1; + reset(); + } else if ((c = cc) == '\n' && onelflg) + onelflg--; + if (c == 0) + goto again; + return (c); +} + +rgadrof(r) + register int r; +{ + register struct shvar *tp; + + if (!digit(r) || (r =- '0') > dolc) + return (0); + if (r == 0) + return (¶mhd); + for (tp = paramp; r > 0; tp = tp->next) + r--; + return (tp); +} + +rgvalue(r) + int r; +{ + register struct shvar *tp; + + tp = rgadrof(r); + return (tp ? tp->value : ""); +} diff --git a/ashell/sh_parse.c b/ashell/sh_parse.c new file mode 100644 index 0000000000..071c4f9b6f --- /dev/null +++ b/ashell/sh_parse.c @@ -0,0 +1,303 @@ +#include "sh.h" + +/* + * syntax + * empty + * syn0 + */ +syntax(p1, p2) + register struct shvar2 *p1, *p2; +{ + + while (p1 != p2) + if (any(p1->value[0], ";&\n")) + p1 = p1->next; + else + return (syn0(p1, p2)); + return (0); +} + +/* + * syn0 + * syn1 + * syn1 & syntax + */ +syn0(p1, p2) + struct shvar2 *p1, *p2; +{ + register struct shvar2 *p; + register *t, *t1; + int l; + + l = 0; + for (p = p1; p != p2; p = p->next) + switch (p->value[0]) { + case '(': + l++; + continue; + case ')': + l--; + if (l < 0) + seterr("Too many )'s"); + continue; + case '&': + if (l != 0) + break; + t1 = syn1(p1, p); + if (t1[DTYP] == TLST) { + t = calloc(2, 5); + t[DTYP] = TPAR; + t[DFLG] = FAND|FPRS|FINT; + t[DSPR] = t1; + t1 = t; + } else + t1[DFLG] =| FAND|FPRS|FINT; + t = calloc(2, 4); + t[DTYP] = TLST; + t[DFLG] = 0; + t[DLEF] = t1; + t[DRIT] = syntax(p, p2); + return(t); + } + if (l == 0) + return (syn1(p1, p2)); + seterr("Too many ('s"); + return(0); +} + +/* + * syn1 + * syn2 + * syn2 ; syn1 + */ +syn1(p1, p2) + struct shvar2 *p1, *p2; +{ + register struct shvar *p; + register *t; + int l; + + l = 0; + for (p = p1; p != p2; p = p->next) + switch (p->value[0]) { + case '(': + l++; + continue; + case ')': + l--; + continue; + case ';': + case '\n': + if (l != 0) + break; + t = calloc(2, 4); + t[DTYP] = TLST; + t[DLEF] = syn2(p1, p); + t[DRIT] = syntax(p->next, p2); + return (t); + } + return (syn2(p1, p2)); +} + +/* + * syn2 + * syn3 + * syn3 | syn2 + * syn3 |* syn2 + */ +syn2(p1, p2) + struct shvar2 *p1, *p2; +{ + register struct shvar2 *p, *pn; + register int *t; + int l; + + l = 0; + for (p = p1; p != p2; p = p->next) + switch (p->value[0]) { + case '(': + l++; + continue; + case ')': + l--; + continue; + case '|': + case '^': + if (l != 0) + continue; + t = calloc(2, 4); + t[DTYP] = TFIL; + t[DLEF] = syn3(p1, p); + pn = p->next; + if (pn != p2 && pn->value[0] == '*') { + t[DFLG] = FDIAG; + if (pn->value[1] != 0) + pn->value++; + else + p = pn; + } + t[DRIT] = syn2(p->next, p2); + return (t); + } + return (syn3(p1, p2)); +} + +/* + * syn3 + * ( syn0 ) [ < in ] [ > out ] + * word word* [ < in ] [ > out ] + */ +syn3(p1, p2) + struct shvar2 *p1, *p2; +{ + register struct shvar2 *p; + struct shvar *lp, *rp; + register int *t; + int n, l, c; + + n = 0; + l = 0; + for (p = p1; p != p2; p = p->next) + switch (p->value[0]) { + case '(': + l++; + continue; + case ')': + l--; + continue; + case '>': + case '<': + if (l != 0) + continue; + if (p->next == p2) + continue; + if (any(p->next->value[0], "<>(*")) + continue; + n--; + continue; + default: + if (l != 0) + continue; + n++; + continue; + } + if (n < 0) + n = 0; + t = calloc(2, 5 + n + 1); + n = 0; + if (p2->value[0] == ')') + t[DFLG] = FPAR; + lp = 0; + rp = 0; + l = 0; + for (p = p1; p != p2; p = p->next) { + c = p->value[0]; + switch (c) { + case '(': + if (l == 0) { + if (lp != 0) + seterr("Badly placed ("); + lp = p->next; + } + l++; + continue; + case ')': + l--; + if (l == 0) + rp = p; + continue; + case '>': + if (l != 0) + continue; + if (p->next != p2) { + p = p->next; + if (p->value[0] == '>') + t[DFLG] =| FCAT; + else + p = p->prev; + } + if (p->next != p2) { + p = p->next; + if (p->value[0] == '*') { + t[DFLG] =| FDIAG; + if (p->value[1]) { + p->value++; + p = p->prev; + } + } else + p = p->prev; + } + case '<': + if (l != 0) + continue; + if (p->next == p2) { + seterr("Missing file for redirect"); + continue; + } + p = p->next; + if (any(p->value[0], "<>(")) { + seterr("Syntax error in redirection"); + continue; + } + if (c == '<') { + if (t[DLEF] != 0) { + seterr("Multiple < redirect"); + continue; + } + t[DLEF] = p->value; + continue; + } + if (t[DRIT] != 0) { + seterr("Multiple output redirect"); + continue; + } + t[DRIT] = p->value; + continue; + default: + if (l != 0) + continue; + t[DCOM + n] = p->value; + n++; + continue; + } + } + if (lp != 0) { + if (n != 0) + seterr("Only redirect allowed outside ()'s"); + t[DTYP] = TPAR; + t[DSPR] = syn0(lp, rp); + } else { + if (n == 0) + seterr("Inappropriate empty command"); + t[DCOM + n] = 0; + t[DTYP] = TCOM; + } + return (t); +} + +freesyn(t) + register int *t; +{ + register char **v; + + if (t == 0) + return; + switch (t[DTYP]) { + case TCOM: + for (v = &t[DCOM]; *v; v++) + xfree(*v); + goto lr; + case TPAR: + freesyn(t[DSPR]); +lr: + xfree(t[DLEF]); + xfree(t[DRIT]); + break; + case TFIL: + case TLST: + freesyn(t[DLEF]); + freesyn(t[DRIT]); + break; + } + cfree(t); +} diff --git a/ashell/sh_sem.c b/ashell/sh_sem.c new file mode 100644 index 0000000000..0091abdab6 --- /dev/null +++ b/ashell/sh_sem.c @@ -0,0 +1,138 @@ +#include "sh.h" + +execute(t, pf1, pf2) + int *t, *pf1, *pf2; +{ + int i, f, pv[2]; + register *t1; + char *cp1, *cp2; + char *scp; + + if (t == 0) + return; + switch(t[DTYP]) { + case TCOM: + i = 100; + do + if (func(t)) + return; + while (--i && alias(&t[DCOM])); + if (i == 0) { + bferr2(t[DCOM], ": Alias loop detected"); + return; + } + case TPAR: + t1 = t; + f = t1[DFLG]; + i = 0; + if ((f&FPAR) == 0) + i = fork(); + if (i == -1) { + err("No more processes"); + return; + } + if (i != 0) { + if ((f&FPIN) != 0) { + close(pf1[0]); + close(pf1[1]); + } + if ((f&FPRS) != 0) { + prn(i); + prs("\n"); + set(pcs, putn(i)); + } + if ((f&FAND) != 0) + return; + if ((f&FPOU) == 0) + pwait(i); + return; + } + set(prompt,""); + unsetv(prompt); + if ((cp1 = t1[DLEF]) != 0) { + close(0); + cp1 = globone(cp1); + if (cp1 == 0) + exit(1); + strip(cp1); + if (open(cp1, 0) < 0) { + prs(cp1); + err(": Cannot open"); + exit(1); + } + } + if ((cp2 = t1[DRIT]) != 0) { + while (*cp2) + *cp2++ =& 0177; + strip(cp2); + cp2 = t1[DRIT]; + close(1); + if ((f&FCAT) != 0 && open(cp2, 1) >= 0) + seek(1, 0, 2); + else if (creat(cp2, 0644) < 0) { + prs(t1[DRIT]); + err(": Cannot create"); + exit(1); + } + } + if ((f&FPIN) != 0) { + close(0); + dup(pf1[0]); + close(pf1[0]); + close(pf1[1]); + } + if ((f&FPOU) != 0) { + close(1); + dup(pf2[1]); + close(pf2[0]); + close(pf2[1]); + } + if (f&FDIAG) { + close(2); + dup(1); + } + if ((f&FINT)!=0 && t1[DLEF]==0 && (f&FPIN)==0) { + close(0); + open("/dev/null", 0); + } + if ((f&FINT) == 0 && setintr) { + signal(INTR, 0); + signal(QUIT, 0); + } + if (t1[DTYP] == TPAR) { + if (t1 = t1[DSPR]) + t1[DFLG] =| f&FINT; + execute(t1); + exit(1); + } + doexec(t1); + /* no return */ + case TFIL: + f = t[DFLG]; + pipe(pv); + t1 = t[DLEF]; + t1[DFLG] =| FPOU | (f&(FPIN|FINT|FPRS|FDIAG)); + execute(t1, pf1, pv); + t1 = t[DRIT]; + t1[DFLG] =| FPIN | (f&(FPOU|FINT|FAND|FPRS)); + execute(t1, pv, pf2); + return; + case TLST: + f = t[DFLG]&FINT; + if (t1 = t[DLEF]) + t1[DFLG] =| f; + execute(t1); + if (t1 = t[DRIT]) + t1[DFLG] =| f; + execute(t1); + return; + } +} + +strip(cp) + register char *cp; +{ + + while (*cp++ =& 0177) + continue; +} diff --git a/ashell/sh_set.c b/ashell/sh_set.c new file mode 100644 index 0000000000..38c201a08a --- /dev/null +++ b/ashell/sh_set.c @@ -0,0 +1,346 @@ +#include "sh.h" + +/* + * Shell: + * "set" and associated routines + * + *---------- + * doset - performs the logic of the set command + * operate - performs arithmetic function of the set command + * unset - undefines variables + * xfree - frees argument storage if it is dynamic + * savestr - salts away a copy of the argument string in a safe place + * putn - returns a pointer to a string representing the argument integer + * getn - returns the number which the string argument represents or 0 + *---------- + * value - returns the value of a variable which is argument + * adrof - returns a pointer to the structure for the variable argument + * set - sets the argument variable to the second argument value + */ + +/* + * doset performs the logic of the set command. + * command syntax is + * set [ rOPvalue ] * + * current ops are += -= ++ -- &= |= *= /= %= and = + * + * Magic operator @ actually does an unset. Good for use conditionally! + */ +doset(v) + register char *v[]; +{ + register int *rp; + register char *p; + char *vp, c, op; + + v++; + p = *v++; + if (p == 0) { + prvars(); + return; + } + do { + if (digit(*p)) { + vp = p; + p++; + } else + for (vp = p; letter(*p); p++) + continue; + if (vp == p) { + bferr(": No variable"); + return; + } + op = *p; + *p++ = 0; + switch (op) { + case 0: + p--; + case '=': + set(vp, savestr(p)); + continue; + case '@': + if (*p != 0) { + bferr(": Garbage after @"); + return; + } + unsetv(vp); + continue; + } + c = *p++; + if (c != '=') { + if (!any(op, "+-") || c != op || *p) { + bferr(": Missing ="); + return; + } + *--p = '1'; + } + set(vp, operate(op, vp, p)); + } while (p = *v++); +} + +operate(op, vp, p) + char op, *vp, *p; +{ + register int vl, vr; + + vl = getn(value(vp)); + vr = getn(p); + switch (op & 0177) { + case '+': + vl =+ vr; + break; + case '-': + vl =- vr; + break; + case '&': + vl =& vr; + break; + case '|': + vl =| vr; + break; + case '/': + if (vr == 0) + bferr(": Divide check"); + else + vl =/ vr; + break; + case '%': + if (vr == 0) + bferr(": Mod check"); + else + vl =% vr; + break; + case '*': + vl =* vr; + break; + default: + bferr(": Bad operator"); + } + return (putn(vl)); +} + +/* + * xfree frees possibly non-dynamic storage. + * It insures thats its argument is in the heap + * before freeing it. + */ +xfree(cp) + char *cp; +{ + extern char end[]; + + cp = (cp + 1) &~ 1; + if (cp >= end && cp < &cp) + cfree(cp); +} + +savestr(s) + char *s; +{ + + if (s == 0) + s = ""; + return (strcpy(calloc(1, strlen(s) + 1), s)); +} + +/* static */char *putp; +/* + * putn takes an integer and returns a pointer to + * its string representation. + * putp indexes the number as it is formed. + */ +putn(n) +{ + static char number[7]; + +/* + sprintf(number, "%d", n); +*/ + putp = number; + if (n < 0) { + n = -n; + *putp++ = '-'; + } + putn1(n); + *putp = 0; + return (savestr(number)); +} + +putn1(n) + int n; +{ + if (n > 9) + putn1(n / 10); + *putp++ = n % 10 + '0'; +} + +/* + * getn is used by doset to get numbers from strings. + * null string is considered to be 0 (ala SNOBOL). + */ +getn(cp) + register char *cp; +{ + register n; + int sign, base; + + sign = 0; + base = 10; + if (*cp == '-') { + sign++; + cp++; + if (!digit(*cp)) + goto badnum; + } else if (*cp == '0') + base = 8; + n = 0; + while (digit(*cp)) + n = n * base + *cp++ - '0'; + if (*cp) + goto badnum; + return (sign ? -n : n); +badnum: + bferr(": Badly formed number"); + return (0); +} + +/* + * value takes a string name of shell + * variable and returns a pointer to its value + */ +char * +value(var) + char *var; +{ + return (value1(var, &shvhed)); +} + +char * +value1(var, head) + char *var; + struct shvar *head; +{ + register struct shvar *vp; + + vp = adrof1(var, head); + return (vp == 0 ? "" : vp->value); +} + +/* static */ struct shvar *shprev; +/* + * adrof takes a variable name and returns + * a pointer to its structure or 0. + * A side effect is to make shprev point to the + * structure before this one for obvious reasons. + */ +struct shvar * +adrof(var) + char *var; +{ + register struct shvar *vp; + + if (digit(var[0])) { + vp = rgadrof(var[0]); + if (vp == 0) { + bferr(": Bad parameter"); + vp = &shvhed; + } + return (vp); + } + return (adrof1(var, &shvhed)); +} + +struct shvar * +adrof1(var, head) + char *var; + struct shvar *head; +{ + register struct shvar *vp; + int cmp; + + shprev = head; + for (vp = shprev->next; vp != 0; vp = vp->next) { + cmp = strcmp(vp->name, var); + if (cmp == 0) + return (vp); + else if (cmp > 0) + return (0); + shprev = vp; + } + return (0); +} + +/* + * set sets the variable argument to + * the given value. + * The caller is responsible for putting value + * in a safe place! + */ +set(var, value) + char *var, *value; +{ + + set1(var, value, &shvhed); +} + +set1(var, value, head) + char *var, *value; + struct shvar *head; +{ + register struct shvar *vp; + + vp = adrof1(var, head); + if (vp == 0) { + vp = calloc(1, sizeof *vp); + vp->name = savestr(var); + vp->next = shprev->next; + shprev->next = vp; + } + if (value == 0) + value = ""; + else + xfree(vp->value); + vp->value = value; +} + +unset(v) + register char *v[]; +{ + + unset1(v, &shvhed); +} + +unset1(v, head) + register char *v[]; + struct shvar *head; +{ + register char *var; + + v++; + while (var = *v++) + unsetv1(var, head); +} + +unsetv(var) + char *var; +{ + + unsetv1(var, &shvhed); +} + +unsetv1(var, head) + char *var; + struct shvar *head; +{ + register struct shvar *vp; + + vp = adrof1(var, head); + if (vp == 0) { + bferr2(var, ": Undefined"); + return; + } + vp = shprev->next; + shprev->next = vp->next; + xfree(vp->value); + xfree(vp); +} diff --git a/ashell/sh_wait.c b/ashell/sh_wait.c new file mode 100644 index 0000000000..067f18ee53 --- /dev/null +++ b/ashell/sh_wait.c @@ -0,0 +1,189 @@ +#include "sh.h" + +static char *mesg[] { + 0, + "Hangup", + 0, + "Quit", + "Illegal instruction", + "Trace/BPT trap", + "IOT trap", + "EMT trap", + "Floating exception", + "Killed", + "Bus error", + "Segmentation violation", + "Bad system call", + 0, + "Alarm clock", + "Terminate", + "Sig 16", +}; + +static struct tbuffer { + int put, pst; + long cut, cst; +} times0; +static long time0; +static char timflg; + +double +secs(bef, aft) + struct tbuffer *bef, *aft; +{ + + return ((aft->cut - bef->cut + aft->cst - bef->cst) / 60.0); +} + +settimes() +{ + + time(&time0); + times(×0); +} + +dotimes(v0) + char *v0[]; +{ + register char **v; + struct tbuffer timesdol; + long timedol; + + v = v0; + if (v[1] != 0) { + timflg = 1; + do { + v[0] = v[1]; + v++; + } while (*v != 0); + return (func(v0 - DCOM)); + } + time(&timedol); + times(×dol); + ptimes(timedol - time0, ×0, ×dol); + return (1); +} + +pwait(i) + register int i; +{ + register p, e; + int s; + struct tbuffer bef, aft; + long btim, atim; + + if (i == 0) + return; + time(&btim); + do { + times(&bef); + p = wait(&s); + if (p == getn(value(pcs))) + unsetv(pcs); + time(&atim); + if (p == -1) + return; + e = s & 0177; + if (mesg[e] != 0) { + if (p != i) { + prn(p); + prs(": "); + } + prs(mesg[e]); + if (s & 0200) + prs(" -- Core dumped"); + } + if (e != 0) + err(""); + } while (i != p); + times(&aft); + if (timflg || (adrof(tim) && secs(&bef, &aft) >= getn(value(tim)))) { + timflg = 0; + ptimes(atim - btim, &bef, &aft); + } +} + +ptimes(sec, bef, aft) + long sec; + struct tbuffer *bef, *aft; +{ + register int i; + + p60ths(aft->cut - bef->cut); + prs("u "); + p60ths(aft->cst - bef->cst); + prs("s "); + psecs(sec); + prs(" "); + i = 100.0 * secs(bef, aft) / (sec ? sec : 1); + prn(i); + prs("%\n"); +} + +p60ths(l) + long l; +{ + register int i; + + l =+ 3; + i = l / 60; + prn(i); + prs("."); + i = l % 60; + prn(i / 6); +} + +psecs(l) + long l; +{ + register int i; + + i = l / 3600.0; + if (i) { + prn(i); + prs(":"); + i = l % 3600; + p2dig(i / 60); + goto minsec; + } + i = l; + prn(i / 60); +minsec: + i =% 60; + prs(":"); + p2dig(i); +} + +p2dig(i) + int i; +{ + prn(i / 10); + prn(i % 10); +} + +endwait() +{ + signal(INTR, 1); + prs("wait: Interrupted\n"); + reset(); /* URK! */ +} + +await(v) + register char *v[]; +{ + register int i; + + v++; + if (*v) { + i = getn(*v); + if (i == 0) + return; + } else + i = -1; + if (setintr && *value(prompt)) { + signal(INTR, endwait); + pwait(i); + signal(INTR, 1); + } else + pwait(i); +} diff --git a/pxref/READ_ME b/pxref/READ_ME new file mode 100644 index 0000000000..6951881aa8 --- /dev/null +++ b/pxref/READ_ME @@ -0,0 +1,10 @@ +To make a pxref do + makepxref +It can be installed using + install +If you have a shell which recognizes Pascal objects it is not necessary +to use both the Pascal and C programs... the Pascal object can be put in +/usr/bin... but it will have the same status as shell scripts (essentially) +thus + time pxref pxref.p +would not work then. diff --git a/pxref/install b/pxref/install new file mode 100755 index 0000000000..18ce0ad9c8 --- /dev/null +++ b/pxref/install @@ -0,0 +1,6 @@ +cp a.out /usr/bin/pxref +cp obj /usr/lib/pxref +chown bin /usr/bin/pxref /usr/lib/pxref +chmod 711 /usr/bin/pxref +chmod 644 /usr/lib/pxref +rm -f a.out obj diff --git a/pxref/makepxref b/pxref/makepxref new file mode 100755 index 0000000000..e6efd9b494 --- /dev/null +++ b/pxref/makepxref @@ -0,0 +1,2 @@ +cc -O pxref.c +pi -pbt pxref.p diff --git a/pxref/printpxref b/pxref/printpxref new file mode 100755 index 0000000000..4a4b1339ce --- /dev/null +++ b/pxref/printpxref @@ -0,0 +1,3 @@ +pr pxref.c +pi -l pxref.p +rm obj diff --git a/pxref/pxref.c b/pxref/pxref.c new file mode 100644 index 0000000000..1f2cf9d75d --- /dev/null +++ b/pxref/pxref.c @@ -0,0 +1,31 @@ +/* + * pxref - driver to put in /usr/bin/ to call pxref as a Pascal program + * + * Bill Joy UCB July 29, 1977 + * + * This program is not needed if the shell in use understands Pascal + * objects. + */ + +char *progname; + +main(argc, argv) + int argc; + char *argv[]; +{ + + argc--, progname = *argv++; + if (argc == 0 || argc > 2) { + printf("usage: %s [ - ] file\n", progname); + exit(1); + } + if (argc == 1) { + argv--; + argv[0] = argv[1]; + argv[1] = 0; + } + execl("/bin/px", "px", "/usr/lib/pxref", argv[0], argv[1], 0); + execl("/usr/bin/px", "pcx", "/usr/lib/pxref", argv[0], argv[1], 0); + write(2, "Can't find px\n", 14); + exit(1); +} diff --git a/pxref/pxref.p b/pxref/pxref.p new file mode 100644 index 0000000000..08c1696d28 --- /dev/null +++ b/pxref/pxref.p @@ -0,0 +1,344 @@ +program xref(input, output); +label + 99, 100; +const + p = 797; + nk = 36; + empty = ' '; +type + index = 0..p; + ref = ^item; + word = + record + key: alfa; + first, last: ref; + fol: index + end; + item = packed + record + lno: 0..9999; + next: ref + end; +var + i, top: index; + scr: alfa; + list: boolean; + k, k1: integer; + n: integer; + c1, c2: integer; + id: + record + case boolean of + false:( + a: alfa + ); + true:( + ord: integer + ) + end; + a: array [1..10] of char; + t: array [index] of word; + key: array [1..nk] of alfa; + + function letter(ch: char): Boolean; + begin + letter := (ch >= 'a') and (ch <= 'z') or (ch >= 'A') and (ch <= 'Z') + end { letter }; + + function digit(ch: char): Boolean; + begin + digit := (ch >= '0') and (ch <= '9') + end { digit }; + + function nokey(x: alfa): Boolean; + var + i, j, k: integer; + begin + i := 1; + j := nk; + repeat + k := (i + j) div 2; + if key[k] <= x then + i := k + 1; + if key[k] >= x then + j := k - 1 + until i > j; + nokey := key[k] <> x + end { nokey }; + + procedure newline; + begin + if n < 9999 then begin + n := n + 1; + if list then + write(n: 6, ' ') + end else begin + writeln(' text too long'); + goto 99 + end + end { newline }; + + procedure search; + var + h, d: index; + x: ref; + f: Boolean; + begin + h := id.ord div 4096 mod p; + f := false; + d := 1; + c2 := c2 + 1; + new(x); + x^.lno := n; + x^.next := nil; + repeat + if t[h].key = id.a then begin + f := true; + t[h].last^.next := x; + t[h].last := x + end else if t[h].key = empty then begin + f := true; + c1 := c1 + 1; + t[h].key := id.a; + t[h].first := x; + t[h].last := x; + t[h].fol := top; + top := h + end else begin + h := h + d; + d := d + 2; + if h >= p then + h := h - p; + if d = p then begin + writeln; + writeln(' **** table full'); + goto 99 + end + end + until f + end { search }; + + procedure printword(w: word); + var + l: integer; + x: ref; + begin + write(' ', w.key); + x := w.first; + l := 0; + repeat + if l = 20 then begin + l := 0; + writeln; + write(' ', empty) + end; + l := l + 1; + write(x^.lno: 6); + x := x^.next + until x = nil; + writeln + end { printword }; + + procedure printtable; + var + i, j, m: index; + begin + i := top; + while i <> p do begin + m := i; + j := t[i].fol; + while j <> p do begin + if t[j].key < t[m].key then + m := j; + j := t[j].fol + end; + printword(t[m]); + if m <> i then begin + t[m].key := t[i].key; + t[m].first := t[i].first; + t[m].last := t[i].last + end; + i := t[i].fol + end + end { printtable }; + + procedure openinput(i: integer); + var + filename: array [1..64] of char; + begin + argv(i, filename); + reset(input, filename) + end { openinput }; + + procedure lwriteln; + begin + if list then + writeln + end { lwriteln }; + + procedure lwrite(c: char); + begin + if list then + write(c) + end { lwrite }; + +begin { xref } + list := true; + if argc = 3 then begin + argv(1, scr); + if (scr[1] <> '-') or (scr[2] <> ' ') then begin + writeln('usage: pxref [ - ] file'); + goto 100 + end; + list := false + end; + if (argc < 2) or (argc > 3) then begin + writeln('usage: pxref [ - ] file'); + goto 100 + end; + if list then + openinput(1) + else + openinput(2); + for i := 0 to p - 1 do + t[i].key := empty; + c1 := 0; + c2 := 0; + key[1] := 'and'; + key[2] := 'array'; + key[3] := 'assert'; + key[4] := 'begin'; + key[5] := 'case'; + key[6] := 'const'; + key[7] := 'div'; + key[8] := 'do'; + key[9] := 'downto'; + key[10] := 'else'; + key[11] := 'end'; + key[12] := 'file'; + key[13] := 'for'; + key[14] := 'function'; + key[15] := 'hex'; + key[16] := 'if'; + key[17] := 'in'; + key[18] := 'mod'; + key[19] := 'nil'; + key[20] := 'not'; + key[21] := 'oct'; + key[22] := 'of'; + key[23] := 'or'; + key[24] := 'packed'; + key[25] := 'procedure'; + key[26] := 'program'; + key[27] := 'record'; + key[28] := 'repeat'; + key[29] := 'set'; + key[30] := 'then'; + key[31] := 'to'; + key[32] := 'type'; + key[33] := 'until'; + key[34] := 'var'; + key[35] := 'while'; + key[36] := 'with'; + n := 0; + top := p; + k1 := 10; + while not eof(input) do begin + if not eoln(input) then + newline + else + n := n + 1; + if input^ = '#' then begin + while not eoln(input) do begin + lwrite(input^); + get(input) + end; + id.a := '#include'; + search + end else + while not eoln(input) do begin + if (input^ = ' ') or (input^ = tab) then begin + lwrite(input^); + get(input) + end else if letter(input^) then begin + k := 0; + repeat + lwrite(input^); + if k < 10 then begin + k := k + 1; + a[k] := input^ + end; + get(input) + until not (letter(input^) or digit(input^)); + if k >= k1 then + k1 := k + else + repeat + a[k1] := ' '; + k1 := k1 - 1 + until k1 = k; + pack(a, 1, id.a); + if nokey(id.a) then + search + end else if digit(input^) then + repeat + lwrite(input^); + get(input) + until not digit(input^) + else if input^ = '''' then begin + repeat + lwrite(input^); + get(input) + until input^ = ''''; + lwrite(''''); + get(input) + end else if input^ = '{' then begin + repeat + lwrite(input^); + get(input); + while eoln(input) do begin + lwriteln; + get(input); + newline + end + until input^ = '}'; + lwrite('}'); + get(input) + end else if input^ = '(' then begin + lwrite('('); + get(input); + if input^ = '*' then begin + lwrite('*'); + get(input); + repeat + while input^ <> '*' do begin + if eoln(input) then begin + lwriteln; + newline + end else + lwrite(input^); + get(input) + end; + lwrite('*'); + get(input) + until input^ = ')'; + lwrite(')'); + get(input) + end + end else begin + lwrite(input^); + get(input) + end + end; + lwriteln; + get(input) + end; +99: + if list then + page(output); + printtable; + lwriteln; + writeln(c1, ' identifiers', c2, ' occurrences'); +100: + {nil} +end { xref }. -- 2.20.1