Public Domain Korn Shell - Part.02 of 7
USENET Administration
netnews at netcom.UUCP
Wed Dec 12 22:35:35 AEST 1990
#!/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
More information about the Alt.sources
mailing list