netnews@netcom.UUCP (USENET Administration) (12/12/90)
#!/bin/sh # This is part 02 of ksh-pd # ============= src/lex.h ============== if test ! -d 'src'; then echo 'x - creating directory src' mkdir 'src' fi if test -f 'src/lex.h' -a X"$1" != X"-c"; then echo 'x - skipping src/lex.h (File already exists)' else echo 'x - extracting src/lex.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/lex.h' && X/* X * Source input, lexer and parser X */ X X/* $Header: /tmp/egisin/src/RCS/lex.h,v 3.2 88/12/17 21:40:07 egisin Exp $ */ X X#define IDENT 64 X Xtypedef struct source Source; Xstruct source { X char *str; /* input pointer */ X int type; /* input type */ X union { X char **strv; /* string [] */ X FILE *file; /* file */ X struct tbl *tblp; /* alias */ X } u; X int line; /* line number */ X char *file; /* input file name */ X int echo; /* echo input to shlout */ X Source *next; /* stacked source */ X}; X X/* Source.type values */ X#define SEOF 0 /* input EOF */ X#define STTY 1 /* terminal input */ X#define SFILE 2 /* file input */ X#define SSTRING 4 /* string */ X#define SWSTR 3 /* string without \n */ X#define SWORDS 5 /* string[] */ X#define SWORDSEP 8 /* string[] seperator */ X#define SALIAS 6 /* alias expansion */ X#define SHIST 7 /* history expansion */ X XSource *pushs ARGS((int stype)); /* push Source */ Xstruct op *compile ARGS((Source *s)); /* compile tree */ X X/* X * states while lexing word X */ X#define SBASE 0 /* outside any lexical constructs */ X#define SWORD 6 /* implicit quoting for substitute() */ X#define SSQUOTE 1 /* inside '' */ X#define SDQUOTE 2 /* inside "" */ X#define SBRACE 3 /* inside ${} */ X#define SPAREN 4 /* inside $() */ X#define SBQUOTE 5 /* inside `` */ X XExtern int multiline; /* \n changed to ; */ X Xtypedef union { X int i; X char *cp; X char **wp; X struct op *o; X struct ioword *iop; X} YYSTYPE; X X#define LWORD 256 X#define LOGAND 257 X#define LOGOR 258 X#define BREAK 259 X#define IF 260 X#define THEN 261 X#define ELSE 262 X#define ELIF 263 X#define FI 264 X#define CASE 265 X#define ESAC 266 X#define FOR 267 X#define WHILE 268 X#define UNTIL 269 X#define DO 270 X#define DONE 271 X#define IN 272 X#define FUNCTION 273 X#define TIME 274 X#define REDIR 275 X#define MPAREN 276 /* () */ X#define YYERRCODE 300 X X/* flags to yylex */ X#define CONTIN BIT(0) /* skip new lines to complete command */ X#define ONEWORD BIT(1) /* single word for substitute() */ X#define ALIAS BIT(2) /* recognize alias */ X#define KEYWORD BIT(3) /* recognize keywords */ X X#define SYNTAXERR zzerr() X#define HERES 10 /* max << in line */ X XExtern char line [LINE+1]; /* input line */ XExtern Source *source; /* yyparse/yylex source */ XExtern YYSTYPE yylval; /* result from yylex */ XExtern int yynerrs; XExtern struct ioword *heres [HERES], **herep; XExtern char ident [IDENT+1]; X Xextern int yylex ARGS((int flags)); Xextern void yyerror ARGS((Const char *msg)); X X#define HISTORY 100 /* size of saved history */ X Xextern char *history [HISTORY]; /* saved commands */ Xextern char **histptr; /* last history item */ Xextern int histpush; /* number of pushed fc commands */ X SHAR_EOF true || echo 'restore of src/lex.h failed' fi # ============= src/tree.h ============== if test -f 'src/tree.h' -a X"$1" != X"-c"; then echo 'x - skipping src/tree.h (File already exists)' else echo 'x - extracting src/tree.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/tree.h' && X/* X * command trees for compile/execute X */ X X/* $Header: /tmp/egisin/src/RCS/tree.h,v 3.2 88/12/17 21:40:31 egisin Exp $ */ X X#define NOBLOCK ((struct op *)NULL) X#define NOWORD ((char *)NULL) X#define NOWORDS ((char **)NULL) X X/* X * Description of a command or an operation on commands. X */ Xstruct op { X int type; /* operation type, see below */ X char **args; /* arguments to a command */ X char **vars; /* variable assignments */ X struct ioword **ioact; /* IO actions (eg, < > >>) */ X struct op *left, *right; /* descendents */ X char *str; /* identifier for case and for (use vars[0]) */ X}; X X/* Tree.type values */ X#define TEOF 0 X#define TCOM 1 /* command */ X#define TPAREN 2 /* (c-list) */ X#define TPIPE 3 /* a | b */ X#define TLIST 4 /* a [&;] b */ X#define TOR 5 /* || */ X#define TAND 6 /* && */ X#define TFOR 7 X#define TCASE 9 X#define TIF 10 X#define TWHILE 11 X#define TUNTIL 12 X#define TELIF 13 X#define TPAT 14 /* pattern in case */ X#define TBRACE 15 /* {c-list} */ X#define TASYNC 16 /* c & */ X#define TFUNCT 17 /* function name { command; } */ X#define TTIME 18 /* time pipeline */ X#define TEXEC 19 /* fork/exec eval'd TCOM */ X X/* X * prefix codes for words in command tree X */ X#define EOS 0 /* end of string */ X#define CHAR 1 /* unquoted character */ X#define QCHAR 2 /* quoted character */ X#define COMSUB 3 /* $() substitution (0 terminated) */ X#define OQUOTE 4 /* opening " or ' */ X#define CQUOTE 5 /* closing " or ' */ X#define OSUBST 6 /* opening ${ substitution */ X#define CSUBST 7 /* closing } of above */ X X/* X * IO redirection X */ Xstruct ioword { X short unit; /* unit affected */ X short flag; /* action (below) */ X char *name; /* file name */ X}; X X/* ioword.flag - type of redirection */ X#define IOTYPE 0xF /* type: bits 0:3 */ X#define IOREAD 0x1 /* < */ X#define IOWRITE 0x2 /* > */ X#define IORDWR 0x3 /* <>: todo */ X#define IOHERE 0x4 /* << (here file) */ X#define IOCAT 0x5 /* >> */ X#define IODUP 0x6 /* <&/>& */ X#define IOEVAL BIT(4) /* expand in << */ X#define IOSKIP BIT(5) /* <<-, skip ^\t* */ X#define IOCLOB BIT(6) /* >!, override -o noclob */ X X/* values for E_LOOP longjmp */ X#define LBREAK 1 X#define LCONTIN 2 X X/* execute/exchild flags */ X#define XEXEC BIT(0) /* execute without forking */ X#define XFORK BIT(5) /* fork before executing */ X#define XBGND BIT(1) /* command & */ X#define XPIPEI BIT(2) /* input is pipe */ X#define XPIPEO BIT(3) /* output is pipe */ X#define XPIPE (XPIPEI|XPIPEO) /* member of pipe */ X#define XXCOM BIT(4) /* dup2 xcomfd to 1 */ X X/* X * flags to control expansion of words X */ X#define DOBLANK BIT(1) /* perform blank interpretation */ X#define DOGLOB BIT(2) /* expand [?* */ X#define DOPAT BIT(3) /* quote *?[ */ X#define DOTILDE BIT(5) /* expand ~ */ X X/* job.c: job control primatives */ Xint execute ARGS((struct op *, int flags)); /* execute tree */ Xint exchild ARGS((struct op *, int flags)); /* execute tree as child */ Xint waitfor ARGS((int job)); /* wait for job completion */ Xint waitlast ARGS((void)); /* wait for last job */ X X/* eval.c: word expansion */ Xchar **eval ARGS((char **wv, int flag)); /* expand words */ Xchar *evalstr ARGS((char *wp, int flags)); /* expand word */ Xchar *substitute ARGS((Const char *s, int flags)); /* compile and expand string */ X X/* tree.c: command trees */ Xvoid ptree ARGS((struct op *t, FILE *f)); /* print tree */ Xchar *wdscan ARGS((char *wp, int c)); /* scan word for prefix */ Xchar *wdcopy ARGS((char *wp, Area *)); /* copy word */ Xstruct op *tcopy ARGS((struct op *t, Area *)); /* copy tree */ Xvoid tfree ARGS((struct op *t, Area *)); /* free tree */ X SHAR_EOF true || echo 'restore of src/tree.h failed' fi # ============= src/tty.h ============== if test -f 'src/tty.h' -a X"$1" != X"-c"; then echo 'x - skipping src/tty.h (File already exists)' else echo 'x - extracting src/tty.h (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/tty.h' && X/* X tty.h -- centralized definitions for a variety of terminal interfaces X X created by DPK, Oct. 1986 X X last edit: 30-Jul-1987 D A Gwyn X*/ X X#if _BSD_SYSV /* BRL UNIX System V emulation */ X#include <termio.h> /* includes <sys/_ioctl.h> */ X#ifndef NTTYDISC X#define TIOCGETD _IOR( 't', 0, int ) X#define TIOCSETD _IOW( 't', 1, int ) X#define NTTYDISC 2 X#endif X#ifndef TIOCSTI X#define TIOCSTI _IOW( 't', 114, char ) X#endif X#ifndef TIOCSPGRP X#define TIOCSPGRP _IOW( 't', 118, int ) X#endif X#else /* !_BSD_SYSV */ X#if _BSD X#include <sys/ioctl.h> X#else X#include <termio.h> X#endif X#endif /* _BSD_SYSV */ SHAR_EOF true || echo 'restore of src/tty.h failed' fi # ============= src/version.c ============== if test -f 'src/version.c' -a X"$1" != X"-c"; then echo 'x - skipping src/version.c (File already exists)' else echo 'x - extracting src/version.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/version.c' && X/* X * value of $KSH_VERSION X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/version.c,v 3.2 88/12/14 20:10:41 egisin Exp $"; X X#include <stddef.h> X#include <setjmp.h> X#include "sh.h" X Xchar ksh_version [] = X "KSH_VERSION=@(#) PD alpha $Revision: 3.2 $ $Date: 88/12/14 20:10:41 $"; X X/*** X$Log: version.c,v $ XRevision 3.2 88/12/14 20:10:41 egisin Xmany fixes X XRevision 3.1 88/11/03 09:18:36 egisin Xalpha distribution X XRevision 1.3 88/10/20 17:34:03 egisin Xadded @(#) to ksh_version X XRevision 1.2 88/09/27 19:01:58 egisin Xfix version.c X XRevision 1.1 88/09/27 18:59:06 egisin XInitial revision X***/ X SHAR_EOF true || echo 'restore of src/version.c failed' fi # ============= src/main.c ============== if test -f 'src/main.c' -a X"$1" != X"-c"; then echo 'x - skipping src/main.c (File already exists)' else echo 'x - extracting src/main.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/main.c' && X/* X * startup, main loop, enviroments and error handling X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/main.c,v 3.2 88/12/17 19:56:54 egisin Exp $"; X X#define Extern /* define Externs in sh.h */ X X#include <stddef.h> X#include <stdlib.h> X#include <stdio.h> X#include <string.h> X#include <unistd.h> X#include <fcntl.h> X#include <signal.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X#include "lex.h" X#include "tree.h" X#include "table.h" X X/* X * global data X */ X XArea aperm; X Xstatic void reclaim ARGS((void)); X X/* X * shell initialization X */ X Xstatic char initifs [] = "IFS= \t\n"; /* must be R/W */ X Xstatic Const char initsubs [] = X "${SHELL:=/bin/sh} ${PATH:=/bin:/usr/bin:.} ${HOME:=/} ${PS1:=$ } ${PS2:=> }"; X Xstatic Const char *initcoms [] = { X "cd", ".", NULL, /* set up $PWD */ X "typeset", "-x", "SHELL", "PATH", "HOME", NULL, X "typeset", "-r", "PWD", "OLDPWD", NULL, X "typeset", "-i", "SECONDS=0", "OPTIND", NULL, X "alias", X "integer=typeset -i", "pwd=print -r \"$PWD\"", X "history=fc -l", "r=fc -s", "nohup=nohup ", X "login=exec login", "newgrp=exec newgrp", X "type=whence -v", "functions=typeset -f", X "echo=print", "true=:", "false=let", "[=\\[", NULL, X NULL X}; X Xmain(argc, argv, envp) X int argc; X register char **argv; X char **envp; X{ X register int i; X register char *arg; X int cflag = 0, qflag = 0; X char *name; X register Source *s; X register struct block *l = &globals; X register char **wp0, **wp; X extern char ksh_version []; X X ainit(&aperm); /* initialize permanent Area */ X X /* set up base enviroment */ X e.type = E_NONE; X ainit(&e.area); X e.loc = l; X e.savefd = NULL; X e.oenv = NULL; X X initctypes(); X X /* open file streams for fd's 0,1,2 */ X fopenshf(0); fopenshf(1); fopenshf(2); X X /* set up variable and command dictionaries */ X newblock(); /* set up global l->vars and l->funs */ X tinit(&commands, APERM); X tinit(&builtins, APERM); X tinit(&lexicals, APERM); X tinit(&homedirs, APERM); X X /* import enviroment */ X if (envp != NULL) X for (wp = envp; *wp != NULL; wp++) X import(*wp); X X typeset(initifs, 0, 0); /* for security */ X typeset(ksh_version, 0, 0); /* RDONLY */ X X /* define shell keywords */ X keywords(); X X /* define built-in commands */ X for (i = 0; shbuiltins[i].name != NULL; i++) X builtin(shbuiltins[i].name, shbuiltins[i].func); X for (i = 0; kshbuiltins[i].name != NULL; i++) X builtin(kshbuiltins[i].name, kshbuiltins[i].func); X X /* assign default shell variable values */ X substitute(initsubs, 0); X /* execute initialization statements */ X for (wp0 = (char**) initcoms; *wp0 != NULL; wp0 = wp+1) { X /* copy because the alias initializers are readonly */ X for (wp = wp0; *wp != NULL; wp++) X *wp = strsave(*wp, ATEMP); X shcomexec(wp0); X } X afreeall(ATEMP); X X if (geteuid() == 0) X setstr(global("PS1"), "# "); X X s = pushs(SFILE); X s->u.file = stdin; X cflag = 0; X name = *argv++; X X /* what a bloody mess */ X if (--argc >= 1) { X if (argv[0][0] == '-' && argv[0][1] != '\0') { X for (arg = argv[0]+1; *arg; arg++) X switch (*arg) { X case 'c': X cflag = 1; X if (--argc > 0) { X s->type = SSTRING; X s->str = *++argv; X } X break; X X case 'q': X qflag = 1; X break; X X default: X if (*arg>='a' && *arg<='z') X flag[FLAG(*arg)]++; X } X } else { X argv--; X argc++; X } X if (s->type == SFILE && --argc > 0) { X if ((s->u.file = fopen(*++argv, "r")) == NULL) X errorf("%s: cannot open\n", *argv); X s->file = *argv; X fileno(s->u.file) = savefd(fileno(s->u.file)); X setvbuf(s->u.file, (char *)NULL, _IOFBF, BUFSIZ); X } X } X X if (s->type == SFILE) { X if (fileno(s->u.file) == 0) X flag[FSTDIN] = 1; X if (isatty(0) && isatty(1) && !cflag) X flag[FTALKING] = 1; X if (flag[FTALKING] && flag[FSTDIN]) X s->type = STTY; X } X if (s->type == STTY) { X ttyfd = fcntl(0, F_DUPFD, FDBASE); X (void) fcntl(ttyfd, F_SETFD, FD_CLEXEC); X#if EDIT X x_init(); X#endif X } X X /* initialize job control */ X j_init(); X X if (!qflag) X ignoresig(SIGQUIT); X X l->argv = argv; X l->argc = argc; X l->argv[0] = name; X resetopts(); X X if (name[0] == '-') { X flag[FTALKING] = 1; X (void) include("/etc/profile"); X (void) include(".profile"); X } X X /* include $ENV */ X arg = substitute(strval(global("ENV")), DOTILDE); X if (*arg != '\0') X (void) include(arg); X X if (flag[FTALKING]) { X signal(SIGTERM, trapsig); X ignoresig(SIGINT); X } else X flag[FHASHALL] = 1; X X#if JOBS /* todo: could go before includes? */ X if (s->type == STTY) { X flag[FMONITOR] = 1; X j_change(); X } X#endif X X argc = shell(s); X leave(argc); X} X Xint Xinclude(name) X register char *name; X{ X register FILE *f; X register Source *s; X X if (strcmp(name, "-") != 0) { X f = fopen(name, "r"); X if (f == NULL) X return 0; X /* todo: the savefd doesn't get popped */ X fileno(f) = savefd(fileno(f)); /* questionable */ X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ); X } else X f = stdin; X s = pushs(SFILE); X s->u.file = f; X s->file = name; X /*return*/ shell(s); X if (f != stdin) X fclose(f); X return 1; X} X Xint Xcommand(comm) X register char *comm; X{ X register Source *s; X X s = pushs(SSTRING); X s->str = comm; X return shell(s); X} X X/* X * run the commands from the input source, returning status. X */ Xint Xshell(s) X Source *s; /* input source */ X{ X struct op *t; X Volatile int attempts = 13; X X newenv(E_PARSE); X e.interactive = 1; X exstat = 0; X if (setjmp(e.jbuf)) { X /*shellf("<unwind>");*/ X if (trap) /* pending SIGINT */ X shellf("\n"); X sigtraps[SIGINT].set = 0; X } X X while (1) { X if (trap) X runtraps(); X if (flag[FTALKING]) X signal(SIGINT, trapsig); X X if (s->next == NULL) X s->echo = flag[FVERBOSE]; X X j_notify(); X X if (s->type == STTY) X prompt = substitute(strval(global("PS1")), 0); X X t = compile(s); X if (t != NULL && t->type == TEOF) X if (s->type == STTY && flag[FIGNEOF] && --attempts > 0) X shellf("Use `exit'\n"); X else X break; X flushshf(2); /* flush -v output */ X X if (!flag[FNOEXEC] || s->type == STTY) X execute(t, 0); X X reclaim(); X } X Error: X quitenv(); X return exstat; X} X Xvoid Xleave(rv) X int rv; X{ X if (e.type == E_TCOM && e.oenv != NULL) /* exec'd command */ X unwind(); X runtrap(&sigtraps[0]); X j_exit(); X exit(rv); X /* NOTREACHED */ X} X Xerror() X{ X if (flag[FERREXIT] || !flag[FTALKING]) X leave(1); X unwind(); X} X X/* return to closest error handler or shell(), exit if none found */ Xunwind() X{ X while (1) X switch (e.type) { X case E_NONE: X leave(1); X /* NOTREACHED */ X case E_PARSE: X longjmp(e.jbuf, 1); X /* NOTREACHED */ X case E_ERRH: X longjmp(e.jbuf, 1); X /* NOTREACHED */ X default: X quitenv(); X break; X } X} X Xnewenv(type) X{ X register struct env *ep; X X ep = (struct env *) alloc(sizeof(*ep), ATEMP); X *ep = e; X ainit(&e.area); X e.type = type; X e.oenv = ep; X e.savefd = NULL; X e.temps = NULL; X} X Xquitenv() X{ X register struct env *ep; X register int fd; X X if ((ep = e.oenv) == NULL) X exit(exstat); /* exit child */ X if (e.loc != ep->loc) X popblock(); X if (e.savefd != NULL) X for (fd = 0; fd < NUFILE; fd++) X restfd(fd, e.savefd[fd]); X reclaim(); X e = *ep; X} X X/* remove temp files and free ATEMP Area */ Xstatic void Xreclaim() X{ X register struct temp *tp; X X for (tp = e.temps; tp != NULL; tp = tp->next) X remove(tp->name); X e.temps = NULL; X afreeall(&e.area); X} X Xvoid Xaerror(ap, msg) X Area *ap; X Const char *msg; X{ X errorf("alloc internal error: %s\n", msg); X} X SHAR_EOF true || echo 'restore of src/main.c failed' fi # ============= src/misc.c ============== if test -f 'src/misc.c' -a X"$1" != X"-c"; then echo 'x - skipping src/misc.c (File already exists)' else echo 'x - extracting src/misc.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/misc.c' && X/* X * Miscellaneous functions X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/misc.c,v 3.1 88/11/03 09:17:14 egisin Exp $"; X X#include <stddef.h> X#include <limits.h> X#include <string.h> X#include <signal.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X#include "expand.h" X Xchar ctypes [UCHAR_MAX]; /* type bits for unsigned char */ X X/* X * Fast character classes X */ Xvoid Xsetctypes(s, t) X register Const char *s; X register int t; X{ X register int i; X X if ((t&C_IFS)) { X for (i = 0; i < UCHAR_MAX; i++) X ctypes[i] &=~ C_IFS; X ctypes[0] |= C_IFS; /* include \0 in C_IFS */ X } X ctypes[(unsigned char) *s++] |= t; /* allow leading \0 in string */ X while (*s != 0) X ctypes[(unsigned char) *s++] |= t; X} X Xvoid Xinitctypes() X{ X register int c; X X for (c = 'a'; c <= 'z'; c++) X ctypes[c] |= C_ALPHA; X for (c = 'A'; c <= 'Z'; c++) X ctypes[c] |= C_ALPHA; X ctypes['_'] |= C_ALPHA; X setctypes("0123456789", C_DIGIT); X setctypes("\0 \t\n|&;<>()", C_LEX1); X setctypes("*@#!$-?", C_VAR1); X setctypes("=-+?#%", C_SUBOP); X} X X/* convert unsigned long to base N string */ X Xchar * Xulton(n, base) X register unsigned long n; X int base; X{ X register char *p; X static char buf [20]; X X p = &buf[sizeof(buf)]; X *--p = '\0'; X do { X *--p = "0123456789ABCDEF"[n%base]; X n /= base; X } while (n != 0); X return p; X} X Xchar * Xstrsave(s, ap) X register char *s; X Area *ap; X{ X return strcpy((char*) alloc((size_t)strlen(s)+1, ap), s); X} X Xstatic struct option { X char *name; X int flag; X} options[] = { X {"allexport", FEXPORT}, X {"bgnice", FBGNICE}, X#if EDIT X {"emacs", FEMACS}, X#endif X {"errexit", FERREXIT}, X {"hashall", FHASHALL}, X {"ignoreeof", FIGNEOF}, X {"interactive", FTALKING}, X {"keyword", FKEYWORD}, X {"markdirs", FMARKDIRS}, X {"monitor", FMONITOR}, X {"noexec", FNOEXEC}, X {"noglob", FNOGLOB}, X {"nounset", FNOUNSET}, X {"privileged", FPRIVILEGED}, X {"stdin", FSTDIN}, X {"trackall", FHASHALL}, X {"verbose", FVERBOSE}, X {"xtrace", FXTRACE}, X {NULL, 0} X}; X X/* X * translate -o option into F* constant X */ Xint Xoption(n) X Const char *n; X{ X register struct option *op; X X for (op = options; op->name != NULL; op++) X if (strcmp(op->name, n) == 0) X return op->flag; X return 0; X} X Xchar * Xgetoptions() X{ X register int c; X char m [26+1]; X register char *cp = m; X X for (c = 'a'; c <= 'z'; c++) X if (flag[FLAG(c)]) X *cp++ = (char) c; X *cp = 0; X return strsave(m, ATEMP); X} X Xvoid Xprintoptions() X{ X register struct option *op; X X for (op = options; op->name != NULL; op++) X if (flag[op->flag]) X shellf("%s ", op->name); X shellf("\n"); X} X X/* atoi with error detection */ X Xgetn(as) X char *as; X{ X register char *s; X register int n; X X s = as; X if (*s == '-') X s++; X for (n = 0; digit(*s); s++) X n = (n*10) + (*s-'0'); X if (*s) X errorf("%s: bad number\n", as); X return (*as == '-') ? -n : n; X} X X/* X * stripped down strerror for kill and exec X */ Xchar * Xstrerror(i) X int i; X{ X switch (i) { X case EINVAL: X return "Invalid argument"; X case EACCES: X return "Permission denied"; X case ESRCH: X return "No such process"; X case EPERM: X return "Not owner"; X case ENOENT: X return "No such file or directory"; X case ENOTDIR: X return "Not a directory"; X case ENOEXEC: X return "Exec format error"; X case ENOMEM: X return "Not enough memory"; X case E2BIG: X return "Argument list too long"; X default: X return "Unknown system error"; X } X} X Xxpexpand(xp) X register XPtrV *xp; X{ X int n = XPsize(*xp); X Void **vp; X register Void **dvp, **svp; X X vp = alloc(sizeofN(Void*, n*2), ATEMP); X for (svp = xp->beg, dvp = vp; svp < xp->cur; ) X *dvp++ = *svp++; X afree((Void*) xp->beg, ATEMP); X xp->beg = vp; X xp->cur = vp + n; X xp->end = vp + n*2; X} X X/* -------- gmatch.c -------- */ X X/* X * int gmatch(string, pattern) X * char *string, *pattern; X * X * Match a pattern as in sh(1). X * pattern character are prefixed with MAGIC by expand. X */ X X#define NOT '!' /* might use ^ */ X Xstatic char *cclass ARGS((char *, int c)); X Xint Xgmatch(s, p) X register char *s, *p; X{ X register int sc, pc; X X if (s == NULL || p == NULL) X return 0; X while ((pc = *p++) != 0) { X sc = *s++; X if (pc == MAGIC) X switch (*p++) { X case '[': X if ((p = cclass(p, sc)) == NULL) X return (0); X break; X X case '?': X if (sc == 0) X return (0); X break; X X case '*': X s--; X do { X if (*p == '\0' || gmatch(s, p)) X return (1); X } while (*s++ != '\0'); X return (0); X X } X else X if (sc != pc) X return 0; X } X return (*s == 0); X} X Xstatic char * Xcclass(p, sub) X register char *p; X register int sub; X{ X register int c, d, not, found = 0; X X if ((not = *p == NOT)) X p++; X do { X if (*p == '\0') X return NULL; X c = *p; X if (p[1] == '-' && p[2] != ']') { X d = p[2]; X p++; X } else X d = c; X if (c == sub || c <= sub && sub <= d) X found = 1; X } while (*++p != ']'); X X return (found != not) ? p+1 : NULL; X} X X/* -------- qsort.c -------- */ X X/* X * quick sort of array of generic pointers to objects. X */ X Xvoid Xqsortp(base, n, f) X Void **base; /* base address */ X size_t n; /* elements */ X int (*f)(); /* compare function */ X{ X qsort1(base, base + n, f); X} X X#define swap2(a, b) {\ X register Void *t; t = *(a); *(a) = *(b); *(b) = t;\ X} X#define swap3(a, b, c) {\ X register Void *t; t = *(a); *(a) = *(c); *(c) = *(b); *(b) = t;\ X} X Xqsort1(base, lim, f) X Void **base, **lim; X int (*f)(); X{ X register Void **i, **j; X register Void **lptr, **hptr; X size_t n; X int c; X X top: X n = (lim - base) / 2; X if (n == 0) X return; X hptr = lptr = base+n; X i = base; X j = lim - 1; X X for (;;) { X if (i < lptr) { X if ((c = (*f)(*i, *lptr)) == 0) { X lptr --; X swap2(i, lptr); X continue; X } X if (c < 0) { X i += 1; X continue; X } X } X X begin: X if (j > hptr) { X if ((c = (*f)(*hptr, *j)) == 0) { X hptr ++; X swap2(hptr, j); X goto begin; X } X if (c > 0) { X if (i == lptr) { X hptr ++; X swap3(i, hptr, j); X i = lptr += 1; X goto begin; X } X swap2(i, j); X j -= 1; X i += 1; X continue; X } X j -= 1; X goto begin; X } X X if (i == lptr) { X if (lptr-base >= lim-hptr) { X qsort1(hptr+1, lim, f); X lim = lptr; X } else { X qsort1(base, lptr, f); X base = hptr+1; X } X goto top; X } X X lptr -= 1; X swap3(j, lptr, i); X j = hptr -= 1; X } X} X Xint Xxstrcmp(p1, p2) X Void *p1, *p2; X{ X return (strcmp((char *)p1, (char *)p2)); X} X SHAR_EOF true || echo 'restore of src/misc.c failed' fi # ============= src/trap.c ============== if test -f 'src/trap.c' -a X"$1" != X"-c"; then echo 'x - skipping src/trap.c (File already exists)' else echo 'x - extracting src/trap.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/trap.c' && X/* X * signal handling X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/trap.c,v 3.1 88/11/03 09:18:00 egisin Exp $"; X X#include <stddef.h> X#include <string.h> X#include <errno.h> X#include <signal.h> X#include <setjmp.h> X#include "sh.h" X XTrap sigtraps [SIGNALS] = { X {0, "EXIT", "Signal 0"}, /* todo: belongs in e.loc->exit */ X {SIGHUP, "HUP", "Hangup"}, X {SIGINT, "INT", "Interrupt"}, X {SIGQUIT, "QUIT", "Quit"}, X {SIGILL, "ILL", "Illegal instruction"}, X {SIGTRAP, "TRAP", "Trace trap"}, X {SIGIOT, "IOT", "Abort"}, X {SIGEMT, "EMT", "EMT trap"}, X {SIGFPE, "FPE", "Floating exception"}, X {SIGKILL, "KILL", "Killed"}, X {SIGBUS, "BUS", "Bus error"}, X {SIGSEGV, "SEGV", "Memory fault"}, X {SIGSYS, "SYS", "Bad system call"}, X {SIGPIPE, "PIPE", "Broken pipe"}, X {SIGALRM, "ALRM", "Alarm clock"}, X {SIGTERM, "TERM", "Terminated"}, X#if JOBS /* todo: need to be more portable */ X {SIGURG, "URG", "Urgent condition"}, /* BSDism */ X {SIGSTOP, "STOP", "Stop (signal)"}, X {SIGTSTP, "TSTP", "Stop"}, X {SIGCONT, "CONT", "Continue"}, X {SIGCHLD, "CHLD", "Waiting children"}, X {SIGTTIN, "TTIN", "Stop (tty input)"}, X {SIGTTOU, "TTOU", "Stop (tty output)"}, X#endif X}; X XTrap * Xgettrap(name) X char *name; X{ X int i; X register Trap *p; X X if (digit(*name)) { X i = getn(name); X return (0 <= i && i < SIGNALS) ? &sigtraps[getn(name)] : NULL; X } X#if 0 X if (strcmp("ERR", name) == 0) X return &e.loc->err; X if (strcmp("EXIT", name) == 0) X return &e.loc->exit; X#endif X for (p = sigtraps, i = SIGNALS; --i >= 0; p++) X if (strcmp(p->name, name) == 0) X return p; X return NULL; X} X X/* X * trap signal handler X */ Xvoid Xtrapsig(i) X int i; X{ X trap = sigtraps[i].set = 1; X if (i == SIGINT && e.type == E_PARSE) X /* dangerous but necessary to deal with BSD silly signals */ X longjmp(e.jbuf, 1); X (void) signal(i, trapsig); /* todo: use sigact */ X} X X/* X * run any pending traps X */ Xruntraps() X{ X int i; X register Trap *p; X X for (p = sigtraps, i = SIGNALS; --i >= 0; p++) X if (p->set) X runtrap(p); X trap = 0; X} X Xruntrap(p) X Trap *p; X{ X char *trapstr; X X p->set = 0; X if ((trapstr = p->trap) == NULL) X if (p->signal == SIGINT) X unwind(); /* return to shell() */ X else X return; X if (p->signal == 0) /* ??? */ X p->trap = 0; X command(trapstr); X} X X/* restore signals for children */ Xcleartraps() X{ X int i; X register Trap *p; X X for (i = SIGNALS, p = sigtraps; --i >= 0; p++) { X p->set = 0; X if (p->ourtrap && signal(p->signal, SIG_IGN) != SIG_IGN) X (void) signal(p->signal, SIG_DFL); X } X} X Xignoresig(i) X int i; X{ X if (signal(i, SIG_IGN) != SIG_IGN) X sigtraps[i].sig_dfl = 1; X} X Xrestoresigs() X{ X int i; X register Trap *p; X X for (p = sigtraps, i = SIGNALS; --i >= 0; p++) X if (p->sig_dfl) { X p->sig_dfl = 0; X (void) signal(p->signal, SIG_DFL); X } X} X SHAR_EOF true || echo 'restore of src/trap.c failed' fi # ============= src/alloc.c ============== if test -f 'src/alloc.c' -a X"$1" != X"-c"; then echo 'x - skipping src/alloc.c (File already exists)' else echo 'x - extracting src/alloc.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/alloc.c' && X/* X * area-based allocation built on malloc/free X */ X Xstatic char *RCSid = "$Header"; X X#include <stddef.h> X#include <stdlib.h> X#include <setjmp.h> X#include "sh.h" X X#define ICELLS 100 /* number of Cells in small Block */ X Xtypedef union Cell Cell; Xtypedef struct Block Block; X X/* X * The Cells in a Block are organized as a set of objects. X * Each object (pointed to by dp) begins with a size in (dp-1)->size, X * followed with "size" data Cells. Free objects are X * linked together via dp->next. X */ X Xunion Cell { X size_t size; X Cell *next; X struct {int _;} junk; /* alignment */ X}; X Xstruct Block { X Block *next; /* list of Blocks in Area */ X Cell *free; /* object free list */ X Cell *last; /* &b.cell[size] */ X Cell cell [1]; /* [size] Cells for allocation */ X}; X XBlock aempty = {&aempty, aempty.cell, aempty.cell}; X X/* create empty Area */ XArea * Xainit(ap) X register Area *ap; X{ X ap->free = &aempty; X return ap; X} X X/* free all object in Area */ Xvoid Xafreeall(ap) X register Area *ap; X{ X register Block *bp; X X if (ap->free == NULL || ap->free == &aempty) X return; X for (bp = ap->free; ; bp = bp->next) { X free((Void*)bp); X if (bp->next == ap->free) X break; X } X ap->free = &aempty; X} X X/* allocate object from Area */ XVoid * Xalloc(size, ap) X size_t size; X register Area *ap; X{ X int cells, split; X register Block *bp; X register Cell *dp, *fp, *fpp; X X if (size <= 0) { X aerror(ap, "allocate bad size"); X return NULL; X } X cells = (unsigned)(size - 1) / sizeof(Cell) + 1; X X /* find Cell large enough */ X for (bp = ap->free; ; bp = bp->next) { X for (fpp = NULL, fp = bp->free; X fp != bp->last; fpp = fp, fp = fpp->next) X if ((fp-1)->size >= cells) X goto Found; X X /* wrapped around Block list, create new Block */ X if (bp == ap->free) { X bp = malloc(offsetof(Block, cell[ICELLS + cells])); X if (bp == NULL) { X aerror(ap, "cannot allocate"); X return NULL; X } X if (ap->free == &aempty) X bp->next = bp; X else { X bp->next = ap->free->next; X ap->free->next = bp; X } X bp->last = bp->cell + ICELLS + cells; X fp = bp->free = bp->cell + 1; /* initial free list */ X (fp-1)->size = ICELLS + cells - 1; X fp->next = bp->last; X fpp = NULL; X break; X } X } X Found: X ap->free = bp; X dp = fp; /* allocated object */ X split = (dp-1)->size - cells; X if (split < 0) X aerror(ap, "allocated object too small"); X if (--split <= 0) { /* allocate all */ X fp = fp->next; X } else { /* allocate head, free tail */ X (fp-1)->size = cells; X fp += cells + 1; X (fp-1)->size = split; X fp->next = dp->next; X } X if (fpp == NULL) X bp->free = fp; X else X fpp->next = fp; X return (Void*) dp; X} X X/* change size of object */ X/* todo: allow expansion */ XVoid * Xaresize(ptr, size, ap) X register Void *ptr; X size_t size; X register Area *ap; X{ X int cells, split; X register Cell *dp = (Cell*)ptr; X X if (size <= 0) { X aerror(ap, "allocate bad size"); X return NULL; X } X cells = (unsigned)(size - 1) / sizeof(Cell) + 1; X X split = (dp-1)->size - cells; X if (split < 0) X aerror(ap, "cannot resize larger"); X if (--split <= 0) /* cannot split */ X ; X else { /* shrink head, free tail */ X (dp-1)->size = cells; X dp += cells + 1; X (dp-1)->size = split; X afree((Void*)dp, ap); X } X X return (Void*) ptr; X} X Xvoid Xafree(ptr, ap) X Void *ptr; X register Area *ap; X{ X register Block *bp; X register Cell *fp, *fpp; X register Cell *dp = (Cell*)ptr; X X /* find Block containing Cell */ X for (bp = ap->free; ; bp = bp->next) { X if (bp->cell <= dp && dp < bp->last) X break; X if (bp->next == ap->free) { X aerror(ap, "freeing with invalid area"); X return; X } X } X X /* find position in free list */ X for (fpp = NULL, fp = bp->free; fp < dp; fpp = fp, fp = fpp->next) X ; X X if (fp == dp) { X aerror(ap, "freeing free object"); X return; X } X X /* join object with next */ X if (dp + (dp-1)->size == fp-1) { /* adjacent */ X (dp-1)->size += (fp-1)->size + 1; X dp->next = fp->next; X } else /* non-adjacent */ X dp->next = fp; X X /* join previous with object */ X if (fpp == NULL) X bp->free = dp; X else if (fpp + (fpp-1)->size == dp-1) { /* adjacent */ X (fpp-1)->size += (dp-1)->size + 1; X fpp->next = dp->next; X } else /* non-adjacent */ X fpp->next = dp; X} X X X#if TEST_ALLOC X XArea a; X Xmain(int argc, char **argv) { X int i; X char *p [9]; X X ainit(&a); X for (i = 0; i < 9; i++) { X p[i] = alloc(124, &a); X printf("alloc: %x\n", p[i]); X } X for (i = 1; i < argc; i++) X afree(p[atoi(argv[i])], &a); X afreeall(&a); X return 0; X} X Xvoid aerror(Area *ap, const char *msg) { X abort(); X} X X#endif X SHAR_EOF true || echo 'restore of src/alloc.c failed' fi # ============= src/io.c ============== if test -f 'src/io.c' -a X"$1" != X"-c"; then echo 'x - skipping src/io.c (File already exists)' else echo 'x - extracting src/io.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/io.c' && X/* X * shell buffered IO and formatted output X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/io.c,v 3.3 88/11/25 10:55:52 egisin Exp $"; X X#include <stddef.h> X#include <stdlib.h> X#include <stdio.h> X#include <errno.h> X#include <unistd.h> X#include <fcntl.h> X#include <signal.h> X#include <setjmp.h> X#if __STDC__ X#include <stdarg.h> X#else X#include <varargs.h> X#endif X#include "sh.h" X X#if 0 X/* fputc with ^ escaping */ Xstatic void Xfzotc(c, f) X register int c; X register FILE *f; X{ X if ((c&0x60) == 0) { /* C0|C1 */ X putc((c&0x80) ? '$' : '^', f); X putc((c&0x7F|0x40), f); X } else if ((c&0x7F) == 0x7F) { /* DEL */ X putc((c&0x80) ? '$' : '^', f); X putc('?', f); X } else X putc(c, f); X} X#endif X X/* X * formatted output functions X */ X X/* shellf(...); error() */ Xint X#if __STDC__ Xerrorf(Const char *fmt, ...) { X#else Xerrorf(va_alist) va_dcl X{ X char *fmt; X#endif X va_list va; X X#if __STDC__ X va_start(va, fmt); X#else X va_start(va); X fmt = va_arg(va, char *); X#endif X vfprintf(shlout, fmt, va); X va_end(va); X /*fflush(shlout);*/ X error(); X} X X/* printf to shlout (stderr) */ Xint X#if __STDC__ Xshellf(Const char *fmt, ...) { X#else Xshellf(va_alist) va_dcl X{ X char *fmt; X#endif X va_list va; X X#if __STDC__ X va_start(va, fmt); X#else X va_start(va); X fmt = va_arg(va, char *); X#endif X vfprintf(shlout, fmt, va); X va_end(va); X return 0; X} X X/* X * We have a stdio stream for any open shell file descriptors (0-9) X */ XFILE * shf [NUFILE]; /* map shell fd to FILE * */ X X/* open stream for shell fd */ Xvoid Xfopenshf(fd) X int fd; X{ X if (shf[fd] != NULL) X return; X if (fd <= 2) X _iob[fd]._flag = 0; /* re-use stdin, stdout, stderr */ X shf[fd] = fdopen(fd, "r+"); X if (shf[fd] == NULL) X return; X setvbuf(shf[fd], (char*)NULL, _IOFBF, (size_t)BUFSIZ); X} X X/* flush stream assoc with fd */ X/* this must invalidate input and output buffers */ Xvoid Xflushshf(fd) X int fd; X{ X if (shf[fd] != NULL) { X fseek(shf[fd], 0L, 1); /* V7 derived */ X fflush(shf[fd]); /* standard C */ X } X} X X/* X * move fd from user space (0<=fd<10) to shell space (fd>=10) X */ Xint Xsavefd(fd) X int fd; X{ X int nfd; X X if (fd < FDBASE) { X flushshf(fd); X nfd = fcntl(fd, F_DUPFD, FDBASE); X if (nfd < 0) X if (errno == EBADF) X return -1; X else X errorf("too many files open in shell\n"); X (void) fcntl(nfd, F_SETFD, FD_CLEXEC); X close(fd); X } else X nfd = fd; X return nfd; X} X Xvoid Xrestfd(fd, ofd) X int fd, ofd; X{ X if (ofd == 0) /* not saved (e.savefd) */ X return; X flushshf(fd); X close(fd); X if (ofd < 0) /* original fd closed */ X return; X (void) fcntl(ofd, F_DUPFD, fd); X close(ofd); X} X Xvoid Xopenpipe(pv) X register int *pv; X{ X if (pipe(pv) < 0) X errorf("can't create pipe - try again\n"); X pv[0] = savefd(pv[0]); X pv[1] = savefd(pv[1]); X} X Xvoid Xclosepipe(pv) X register int *pv; X{ X close(pv[0]); X close(pv[1]); X} X X/* X * temporary files X */ X Xstruct temp * Xmaketemp(ap) X Area *ap; X{ X register struct temp *tp; X static unsigned int inc = 0; X char path [PATH]; X X sprintf(path, "/tmp/sh%05u%02u", (unsigned)getpid(), inc++); X /* we could create the thing now with 600 mode */ X tp = (struct temp *) alloc(sizeof(struct temp), ap); X tp->next = NULL; X tp->name = strsave(path, ap); X return tp; X} SHAR_EOF true || echo 'restore of src/io.c failed' fi # ============= src/syn.c ============== if test -f 'src/syn.c' -a X"$1" != X"-c"; then echo 'x - skipping src/syn.c (File already exists)' else echo 'x - extracting src/syn.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'src/syn.c' && X/* X * shell parser (C version) X */ X Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/syn.c,v 3.2 88/12/17 21:18:59 egisin Exp $"; X X#include <stddef.h> X#include <stdio.h> X#include <string.h> X#include <errno.h> X#include <setjmp.h> X#include "sh.h" X#include "lex.h" X#include "tree.h" X#include "table.h" X#include "expand.h" X Xstatic void zzerr(); Xstatic struct op *block(), *newtp(); Xstatic struct op *pipeline(), *andor(), *command(); Xstatic struct op *nested(), *c_list(); Xstatic struct op *dogroup(), *thenpart(), *casepart(), *caselist(); Xstatic struct op *elsepart(); Xstatic char **wordlist(); Xstatic void musthave(); Xstatic struct ioword *synio(), *io(); X Xstatic struct op *outtree; /* yyparse output */ X Xstatic int reject; /* token(cf) gets symbol again */ Xstatic int symbol; /* yylex value */ X X#define REJECT (reject = 1) X#define ACCEPT (reject = 0) X#define token(cf) \ X ((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf))) X#define tpeek(cf) \ X ((reject) ? (symbol) : (REJECT, symbol = yylex(cf))) X Xint Xyyparse() X{ X ACCEPT; X yynerrs = 0; X if ((tpeek(KEYWORD|ALIAS)) == 0) { /* EOF */ X outtree = newtp(TEOF); X return 0; X } X outtree = c_list(); X musthave('\n', 0); X return (yynerrs != 0); X} X Xstatic struct op * Xpipeline(cf) X int cf; X{ X register struct op *t, *p, *tl = NULL; X register int c; X X t = command(cf); X if (t != NULL) { X while ((c = token(0)) == '|') { X if ((p = command(CONTIN)) == NULL) X SYNTAXERR; X if (tl == NULL) X t = tl = block(TPIPE, t, p, NOWORDS); X else X tl = tl->right = block(TPIPE, tl->right, p, NOWORDS); X /*t = block(TPIPE, t, p, NOWORDS);*/ X } X REJECT; X } X return (t); X} X Xstatic struct op * Xandor() X{ X register struct op *t, *p; X register int c; X X t = pipeline(0); X if (t != NULL) { X while ((c = token(0)) == LOGAND || c == LOGOR) { X if ((p = pipeline(CONTIN)) == NULL) X SYNTAXERR; X t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS); X } X REJECT; X } X return (t); X} X Xstatic struct op * Xc_list() X{ X register struct op *t, *p, *tl = NULL; X register int c; X X t = andor(); X if (t != NULL) { X while ((c = token(0)) == ';' || c == '&' || X multiline && c == '\n') { X if (c == '&') X t = block(TASYNC, t, NOBLOCK, NOWORDS); X if ((p = andor()) == NULL) X return (t); X if (tl == NULL) X t = tl = block(TLIST, t, p, NOWORDS); X else X tl = tl->right = block(TLIST, tl->right, p, NOWORDS); X } X REJECT; X } X return (t); X} X Xstatic struct ioword * Xsynio(cf) X int cf; X{ X register struct ioword *iop; X X if (tpeek(cf) != REDIR) X return NULL; X ACCEPT; X iop = yylval.iop; X musthave(LWORD, 0); X iop->name = yylval.cp; X if ((iop->flag&IOTYPE) == IOHERE) { X if (*ident != 0) /* unquoted */ X iop->flag |= IOEVAL; X if (herep >= &heres[HERES]) X errorf("too many <<'s\n"); X *herep++ = iop; X } X return iop; X} X Xstatic void Xmusthave(c, cf) X int c, cf; X{ X if ((token(cf)) != c) X SYNTAXERR; X} X Xstatic struct op * Xnested(type, mark) X int type, mark; X{ X register struct op *t; X X multiline++; X t = c_list(); X musthave(mark, KEYWORD); X multiline--; X return (block(type, t, NOBLOCK, NOWORDS)); X} X Xstatic struct op * Xcommand(cf) X int cf; X{ X register struct op *t; X register int c, iopn = 0; X struct ioword *iop, **iops; X XPtrV args, vars; X X iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1), ATEMP); X XPinit(args, 16); X XPinit(vars, 16); X X if (multiline) X cf = CONTIN; X cf |= KEYWORD|ALIAS; X X while ((iop = synio(cf)) != NULL) { X if (iopn >= NUFILE) X yyerror("too many redirections"); X iops[iopn++] = iop; X cf &=~ CONTIN; X } X X switch (c = token(cf)) { X case 0: X yyerror("unexpected EOF"); X return NULL; X X default: X REJECT; X if (iopn == 0) X return NULL; /* empty line */ X t = newtp(TCOM); X break; X X case LWORD: X REJECT; X t = newtp(TCOM); X while (1) X switch (tpeek(0)) { X case REDIR: X if (iopn >= NUFILE) X yyerror("too many redirections"); X iops[iopn++] = synio(0); X break; X X case LWORD: X ACCEPT; X if ((XPsize(args) == 0 || flag[FKEYWORD]) X && strchr(ident+1, '=')) X {XPput(vars, yylval.cp);} X else X {XPput(args, yylval.cp);} X break; X X case MPAREN: X ACCEPT; X if (XPsize(args) != 1) X SYNTAXERR; X if (*ident == 0) X yyerror("invalid function name\n"); X t = newtp(TFUNCT); X t->str = strsave(ident, ATEMP); X musthave('{', CONTIN|KEYWORD); X t->left = nested(TBRACE, '}'); X return t; X X default: X goto Leave; X } X Leave: X break; X X case '(': X t = nested(TPAREN, ')'); X break; X X case '{': X t = nested(TBRACE, '}'); X break; X X case FOR: X t = newtp(TFOR); X musthave(LWORD, 0); X t->str = strsave(ident, ATEMP); X multiline++; X t->vars = wordlist(); X t->left = dogroup(0); X multiline--; X break; X X case WHILE: X case UNTIL: X multiline++; X t = newtp((c == WHILE) ? TWHILE: TUNTIL); X t->left = c_list(); X t->right = dogroup(1); X multiline--; X break; X X case CASE: X t = newtp(TCASE); X musthave(LWORD, 0); X t->str = yylval.cp; X multiline++; X musthave(IN, KEYWORD|CONTIN); X t->left = caselist(); X musthave(ESAC, KEYWORD); X multiline--; X break; X X case IF: X multiline++; X t = newtp(TIF); X t->left = c_list(); X t->right = thenpart(); X musthave(FI, KEYWORD); X multiline--; X break; X X case TIME: X t = pipeline(CONTIN); X t = block(TTIME, t, NOBLOCK, NOWORDS); X break; X X case FUNCTION: X t = newtp(TFUNCT); X musthave(LWORD, 0); X t->str = strsave(ident, ATEMP); X musthave('{', CONTIN|KEYWORD); X t->left = nested(TBRACE, '}'); X break; X } X X while ((iop = synio(0)) != NULL) { X if (iopn >= NUFILE) X yyerror("too many redirections"); X iops[iopn++] = iop; X } X X if (iopn == 0) { X afree((Void*) iops, ATEMP); X t->ioact = NULL; X } else { X iops[iopn++] = NULL; X aresize((Void*) iops, sizeofN(struct ioword *, iopn), ATEMP); X t->ioact = iops; X } X X if (t->type == TCOM) { X XPput(args, NULL); X t->args = (char **) XPclose(args); X XPput(vars, NULL); X t->vars = (char **) XPclose(vars); X } else { X XPfree(args); X XPfree(vars); X } X X return t; X} X Xstatic struct op * Xdogroup(onlydone) X int onlydone; X{ X register int c; X register struct op *list; X X c = token(CONTIN|KEYWORD); X if (c == DONE && onlydone) X return NULL; X if (c != DO) X SYNTAXERR; X list = c_list(); X musthave(DONE, KEYWORD); X return list; X} X Xstatic struct op * Xthenpart() X{ X register int c; X register struct op *t; X X if ((c = token(0)) != THEN) { X REJECT; X return NULL; X } X t = newtp(0); X t->left = c_list(); X if (t->left == NULL) X SYNTAXERR; X t->right = elsepart(); X return (t); X} X Xstatic struct op * Xelsepart() X{ X register int c; X register struct op *t; X X switch (c = token(0)) { X case ELSE: X if ((t = c_list()) == NULL) X SYNTAXERR; X return (t); X X case ELIF: X t = newtp(TELIF); X t->left = c_list(); X t->right = thenpart(); X return (t); X X default: X REJECT; X return NULL; X } X} X Xstatic struct op * Xcaselist() X{ X register struct op *t, *tl; X X t = tl = NULL; X while ((tpeek(CONTIN|KEYWORD)) != ESAC) { X struct op *tc = casepart(); X if (tl == NULL) X t = tl = tc, tl->right = NULL; X else X tl->right = tc, tl = tc; X } X return (t); X} X Xstatic struct op * Xcasepart() X{ X register struct op *t; X register int c, cf; X XPtrV ptns; X X XPinit(ptns, 16); X t = newtp(TPAT); X cf = CONTIN|KEYWORD; X c = token(cf); X if (c != '(') X REJECT; X else X cf = 0; X do { X musthave(LWORD, cf); X XPput(ptns, yylval.cp); X cf = 0; X } while ((c = token(0)) == '|'); X REJECT; X XPput(ptns, NULL); X t->vars = (char **) XPclose(ptns); X musthave(')', 0); X X t->left = c_list(); X if ((tpeek(CONTIN|KEYWORD)) != ESAC) X musthave(BREAK, CONTIN|KEYWORD); X return (t); X} X Xstatic char ** Xwordlist() X{ X register int c; X XPtrV args; X X XPinit(args, 16); X if ((c = token(CONTIN|KEYWORD)) != IN) { X REJECT; X return NULL; X } X while ((c = token(0)) == LWORD) X XPput(args, yylval.cp); X if (c != '\n' && c != ';') X SYNTAXERR; X if (XPsize(args) == 0) { X XPfree(args); X return NULL; X } else { X XPput(args, NULL); X return (char **) XPclose(args); X } X} X X/* X * supporting functions X */ X Xstatic struct op * Xblock(type, t1, t2, wp) X struct op *t1, *t2; X char **wp; X{ X register struct op *t; X X t = newtp(type); X t->left = t1; X t->right = t2; X t->vars = wp; X return (t); X} X XConst struct res { X char *name; X int val; X} restab[] = { X "for", FOR, X "case", CASE, X "esac", ESAC, X "while", WHILE, X "do", DO, X "done", DONE, X "if", IF, X "in", IN, X "then", THEN, X "else", ELSE, X "elif", ELIF, X "until", UNTIL, X "fi", FI, X "function", FUNCTION, X "time", TIME, X "{", '{', X "}", '}', X 0 X}; X Xkeywords() X{ X register struct res Const *rp; X register struct tbl *p; X X for (rp = restab; rp->name; rp++) { X p = tenter(&lexicals, rp->name, hash(rp->name)); X p->flag |= DEFINED|ISSET; X p->type = CKEYWD; X p->val.i = rp->val; X } X} X Xstatic struct op * Xnewtp(type) X int type; X{ X register struct op *t; X X t = (struct op *) alloc(sizeof(*t), ATEMP); X t->type = type; X t->args = t->vars = NULL; X t->ioact = NULL; X t->left = t->right = NULL; X t->str = NULL; X return (t); X} X Xstatic void Xzzerr() X{ X yyerror("syntax error"); X} X Xstruct op * Xcompile(s) X Source *s; X{ X yynerrs = 0; X multiline = 0; X herep = heres; X source = s; X if (yyparse()) X unwind(); X if (s->type == STTY || s->type == SFILE) X s->str = null; /* line is not preserved */ X return outtree; X} X SHAR_EOF true || echo 'restore of src/syn.c failed' fi true || echo 'restore of src/lex.c failed' echo End of part 2, continue with part 3 exit 0