home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-11-12 | 54.5 KB | 2,637 lines |
- Newsgroups: comp.sources.misc
- From: sjg@zen.void.oz.au (Simon J. Gerraty)
- Subject: v25i050: pdksh - Public Domain Korn Shell, v4, Part04/09
- Message-ID: <1991Nov13.031114.15918@sparky.imd.sterling.com>
- X-Md4-Signature: 39dc3d95402c3f04617242cea892a466
- Date: Wed, 13 Nov 1991 03:11:14 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: sjg@zen.void.oz.au (Simon J. Gerraty)
- Posting-number: Volume 25, Issue 50
- Archive-name: pdksh/part04
- Environment: UNIX
-
- #! /bin/sh
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # The tool that generated this appeared in the comp.sources.unix newsgroup;
- # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
- # Contents: Changes.mlj sh/c_ksh.c sh/eval.c sh/lex.c sh/syn.c
- # Wrapped by kent@sparky on Tue Nov 12 20:44:32 1991
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 4 (of 9)."'
- if test -f 'Changes.mlj' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Changes.mlj'\"
- else
- echo shar: Extracting \"'Changes.mlj'\" \(1777 characters\)
- sed "s/^X//" >'Changes.mlj' <<'END_OF_FILE'
- XI got the pd-ksh from John MacMillan after he indicated that he
- Xhad a version of it that had vi editing (I'd seen various versions
- Xwith emacs-editing, but none with vi).
- X
- XIt had a few bugs and areas which were not quite complete. I fixed
- X(or at least tried) to fix several; there are still some things
- Xwhich I plan on doing (or at least looking into).
- X
- XBugs fixed (or at least abated):
- X
- X vi-mode changes:
- X - Changed memcpy() to memmove(), which fixed the trashing of
- X the end of the edit buffer while inserting in the middle
- X of a line or with use of '#'
- X - using 'r' replacing the current character with ^@
- X - typing ctrl-c resulting in next command being garbled
- X - lack of support for '-' and '+' (pretty trivial)
- X - finish adding support for '*' (not entirely sure I'm freeing
- X malloc'ed memory correctly here, but I haven't had any problems)
- X - treats '_' as end of a word
- X
- X general changes:
- X - reporting "not found" when a file actually doesn't have
- X the appropriate execute bit set (now says "cannot execute"
- X or "not found", as appropriate)
- X
- X
- XStill to do:
- X
- X vi changes:
- X - fix ctrl-r (I've come up with a hack, but it involves
- X redrawing the screen a lot when it isn't necessary; I
- X really wouldn't consider this a fix)
- X - add support for 'v'
- X
- X general changes:
- X - seems to be a memory leak when executing shells in the
- X current shell; repeatedly executing ". /etc/profile"
- X increased the size of the program as reported in the
- X "SZ" field of "ps -l"
- X - don't give a file its complete pathname in argv[0]; only
- X its filename (religious issue?)
- X - history recall should start at the previous command, not
- X the current one (typing "r r" causes an infinite loop)
- END_OF_FILE
- if test 1777 -ne `wc -c <'Changes.mlj'`; then
- echo shar: \"'Changes.mlj'\" unpacked with wrong size!
- fi
- # end of 'Changes.mlj'
- fi
- if test -f 'sh/c_ksh.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sh/c_ksh.c'\"
- else
- echo shar: Extracting \"'sh/c_ksh.c'\" \(11631 characters\)
- sed "s/^X//" >'sh/c_ksh.c' <<'END_OF_FILE'
- X/*
- X * built-in Korn commands: c_*
- X */
- X
- Xstatic char *RCSid = "$Id: c_ksh.c,v 3.4 89/03/27 15:47:16 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 "table.h"
- X
- Xint
- Xc_hash(wp)
- X register char **wp;
- X{
- X register int i;
- X register struct tbl *tp, **p;
- X
- X wp++;
- X if (*wp == NULL) {
- X for (p = tsort(&commands); (tp = *p++) != NULL; )
- X if ((tp->flag&ISSET))
- X printf("%s\n", tp->val.s);
- X return 0;
- X }
- X
- X if (strcmp(*wp, "-r") == 0)
- X flushcom(1);
- X while (*wp != NULL)
- X findcom(*wp++, 1);
- X return 0;
- X}
- X
- Xint
- Xc_cd(wp)
- X register char **wp;
- X{
- X char path [PATH];
- X char newd [PATH];
- X register char *cp;
- X register char *dir;
- X register char *cdpath;
- X register char *rep;
- X register char *pwd = NULL, *oldpwd = NULL;
- X register int done = 0;
- X register int prt = 0;
- X register struct tbl *v_pwd = NULL, *v_oldpwd = NULL;
- X extern Void cleanpath();
- X
- X if ((dir = wp[1]) == NULL && (dir = strval(global("HOME"))) == NULL)
- X errorf("no home directory");
- X
- X v_pwd = global("PWD");
- X if ((pwd = strval(v_pwd)) == null) {
- X setstr(v_pwd, getcwd(path, (size_t)PATH));
- X pwd = strval(v_pwd);
- X }
- X
- X if (wp[1] != NULL && (rep = wp[2]) != NULL) {
- X /*
- X * Two arg version: cd pat rep
- X */
- X if (strlen(pwd) - strlen(dir) + strlen(rep) >= PATH)
- X errorf("substitution too long\n");
- X cp = strstr(pwd, dir);
- X if (cp == NULL)
- X errorf("substitution failed\n");
- X strncpy(path, pwd, cp - pwd); /* first part */
- X strcpy(path + (cp - pwd), rep); /* replacement */
- X strcat(path, cp + strlen(dir)); /* last part */
- X dir = strsave(path, ATEMP);
- X prt = 1;
- X } else if (dir[0] == '-' && dir[1] == '\0') {
- X /*
- X * Change to previous dir: cd -
- X */
- X dir = strval(v_oldpwd = global("OLDPWD"));
- X prt = 1;
- X }
- X if (dir[0] == '/' || (dir[0] == '.' && (dir[1] == '/' ||
- X (dir[1] == '.' && dir[2] == '/')))) {
- X /*
- X * dir is an explicitly named path, so no CDPATH search
- X */
- X cleanpath(pwd, dir, newd);
- X if (chdir(newd) < 0)
- X errorf("%s: bad directory\n", newd);
- X else if (prt)
- X shellf("%s\n", newd);
- X flushcom(0);
- X } else {
- X /*
- X * search CDPATH for dir
- X */
- X cdpath = strval(global("CDPATH"));
- X while ( !done && cdpath != NULL ) {
- X cp = path;
- X while (*cdpath && *cdpath != ':')
- X *cp++ = *cdpath++;
- X if (*cdpath == '\0')
- X cdpath = NULL;
- X else
- X cdpath++;
- X if (prt = (cp > path)) {
- X *cp++ = '/';
- X (void) strcpy( cp, dir );
- X cp = path;
- X } else
- X cp = dir;
- X
- X cleanpath(pwd, cp, newd);
- X if (chdir(newd) == 0)
- X done = 1;
- X } while (!done && cdpath != NULL);
- X if (!done)
- X errorf("%s: bad directory\n", dir);
- X if (prt)
- X shellf("%s\n", newd);
- X flushcom(0);
- X }
- X
- X /*
- X * Keep track of OLDPWD and PWD
- X */
- X oldpwd = pwd;
- X pwd = newd;
- X if (!v_oldpwd)
- X v_oldpwd = global("OLDPWD");
- X if (oldpwd && *oldpwd)
- X setstr(v_oldpwd, oldpwd);
- X else
- X unset(v_oldpwd);
- X if (*pwd)
- X setstr(v_pwd, pwd);
- X else
- X unset(v_pwd);
- X
- X return 0;
- X}
- X
- Xint
- Xc_print(wp)
- X register char **wp;
- X{
- X int nl = 1;
- X int expand = 1;
- X FILE *f = stdout;
- X
- X for (wp++; *wp != NULL && **wp == '-'; wp++) {
- X register char *s = *wp + 1;
- X if (*s == '\0') {
- X wp++;
- X break;
- X }
- X while (*s) switch (*s++) {
- X case 'n':
- X nl = 0;
- X break;
- X case 'e':
- X expand = 1;
- X break;
- X case 'r':
- X expand = 0;
- X break;
- X case 'u':
- X if (!digit(*s) || (f = shf[*s++-'0']) == NULL)
- X errorf("bad -u argument\n");
- X break;
- X }
- X }
- X
- X while (*wp != NULL) {
- X register char *s = *wp;
- X register int c;
- X while ((c = *s++) != '\0')
- X if (expand && c == '\\') {
- X switch ((c = *s++)) {
- X case 'b': c = '\b'; break;
- X case 'c': nl = 0; continue; /* AT&T brain damage */
- X case 'f': c = '\f'; break;
- X case 'n': c = '\n'; break;
- X case 'r': c = '\r'; break;
- X case 't': c = '\t'; break;
- X case 'v': c = 0x0B; break;
- X case '0': case '1': case '2': case '3':
- X case '4': case '5': case '6': case '7':
- X c = c - '0';
- X if (*s >= '0' && *s <= '7')
- X c = 8*c + *s++ - '0';
- X if (*s >= '0' && *s <= '7')
- X c = 8*c + *s++ - '0';
- X break;
- X case '\\': break;
- X default:
- X putc('\\', f);
- X }
- X putc(c, f);
- X } else
- X putc(c, f);
- X if (*++wp != NULL)
- X putc(' ', f);
- X }
- X if (nl)
- X putc('\n', f);
- X return 0;
- X}
- X
- X/* todo: handle case where id is both lexical and command */
- Xint
- Xc_whence(wp)
- X register char **wp;
- X{
- X register struct tbl *tp;
- X char *id;
- X int vflag = 0;
- X int ret = 0;
- X
- X for (wp++; (id = *wp) != NULL && *id == '-'; wp++)
- X if (id[1] == 'v')
- X vflag = 1;
- X
- X while ((id = *wp++) != NULL) {
- X tp = tsearch(&lexicals, id, hash(id));
- X if (tp == NULL)
- X tp = findcom(id, 0);
- X if (vflag)
- X switch ((tp == NULL) ? CNONE : tp->type) {
- X case CNONE:
- X printf("%s is unknown\n", id);
- X ret = 1;
- X break;
- X case CSHELL:
- X printf("%s is a shell builtin\n", id);
- X break;
- X case CFUNC:
- X printf("%s is a function\n", id);
- X fptreef(stdout, "function %s %T\n", id, tp->val.t);
- X break;
- X case CEXEC:
- X printf("%s is %s\n", id,
- X (tp->flag&ISSET) ? tp->val.s : "unknown");
- X if (!(tp->flag&ISSET))
- X ret = 1;
- X break;
- X case CALIAS:
- X printf("%s is the alias '%s'\n", id, tp->val.s);
- X break;
- X case CKEYWD:
- X printf("%s is a shell keyword\n", id);
- X break;
- X default:
- X printf("%s is *GOK*\n", id);
- X break;
- X }
- X else
- X switch ((tp == NULL) ? CNONE : tp->type) {
- X case CNONE:
- X printf("\n");
- X ret = 1;
- X break;
- X case CSHELL:
- X printf("builtin %s\n", id);
- X break;
- X case CFUNC:
- X printf("%s\n", id);
- X break;
- X case CEXEC:
- X printf("%s\n", (tp->flag&ISSET) ? tp->val.s : "");
- X if (!(tp->flag&ISSET))
- X ret = 1;
- X break;
- X case CALIAS:
- X printf("%s\n", tp->val.s);
- X break;
- X case CKEYWD:
- X printf("%s\n", id);
- X break;
- X default:
- X printf("*GOK*\n");
- X break;
- X }
- X }
- X return ret;
- X}
- X
- X/* typeset, export, and readonly */
- Xint
- Xc_typeset(wp)
- X register char **wp;
- X{
- X register char *id;
- X struct block *l = e.loc;
- X register struct tbl *vp, **p;
- X int fset = 0, fclr = 0;
- X int thing = 0, func = 0, local = 0;
- X
- X switch (**wp) {
- X case 'e': /* export */
- X fset |= EXPORT;
- X break;
- X case 'r': /* readonly */
- X fset |= RDONLY;
- X break;
- X case 't': /* typeset */
- X local = 1;
- X break;
- X }
- X
- X for (wp++; (id = *wp) != NULL && (*id == '-' || *id == '+'); wp++) {
- X int flag = 0;
- X thing = *id;
- X while (*++id != '\0') switch (*id) {
- X case 'f':
- X flag |= FUNCT;
- X func = 1;
- X break;
- X case 'i':
- X flag |= INTEGER;
- X break;
- X case 'r':
- X flag |= RDONLY;
- X break;
- X case 'x':
- X flag |= EXPORT;
- X break;
- X case 't':
- X flag |= TRACE;
- X break;
- X default:
- X errorf("unknown flag -%c\n", *id);
- X }
- X if (flag != 0) { /* + or - with options */
- X if (thing == '-')
- X fset |= flag;
- X else
- X fclr |= flag;
- X thing = 0;
- X }
- X }
- X
- X /* list variables and attributes */
- X if (*wp == NULL) {
- X for (l = e.loc; l != NULL; l = l->next) {
- X for (p = tsort((func==0) ? &l->vars : &l->funs);
- X (vp = *p++) != NULL; )
- X if ((vp->flag&ISSET))
- X if (thing == 0 && fclr == 0 && fset == 0) {
- X printf("typeset ");
- X if ((vp->flag&INTEGER))
- X printf("-i ");
- X if ((vp->flag&EXPORT))
- X printf("-x ");
- X if ((vp->flag&RDONLY))
- X printf("-r ");
- X if ((vp->flag&TRACE))
- X printf("-t ");
- X printf("%s\n", vp->name);
- X } else
- X if (thing == '+' ||
- X fclr && (vp->flag&fclr) == fclr) {
- X printf("%s\n", vp->name);
- X } else
- X if (thing == '-' ||
- X fset && (vp->flag&fset) == fset) {
- X if (fset&FUNCT)
- X printf("function %s\n", vp->name);
- X else
- X printf("%s=%s\n", vp->name, strval(vp));
- X }
- X }
- X return (0);
- X }
- X
- X if (local)
- X fset |= LOCAL;
- X for (; *wp != NULL; wp++)
- X#if 0
- X if (func) {
- X } else
- X#endif
- X if (typeset(*wp, fset, fclr) == NULL)
- X errorf("%s: not identifier\n", *wp);
- X return 0;
- X}
- X
- Xint
- Xc_alias(wp)
- X register char **wp;
- X{
- X register struct table *t = &lexicals;
- X register struct tbl *ap, **p;
- X register int i;
- X int rv = 0;
- X
- X if (*++wp != NULL && strcmp(*wp, "-d") == 0) {
- X t = &homedirs;
- X wp++;
- X }
- X
- X if (*wp == NULL)
- X for (p = tsort(t); (ap = *p++) != NULL; )
- X if (ap->type == CALIAS && (ap->flag&DEFINED))
- X printf("%s='%s'\n", ap->name, ap->val.s);
- X
- X for (; *wp != NULL; wp++) {
- X register char *id = *wp;
- X register char *val = strchr(id, '=');
- X
- X if (val == NULL) {
- X ap = tsearch(t, id, hash(id));
- X if (ap != NULL && ap->type == CALIAS && (ap->flag&DEFINED))
- X printf("%s='%s'\n", ap->name, ap->val.s);
- X else
- X rv = 1;
- X } else {
- X *val++ = '\0';
- X ap = tenter(t, id, hash(id));
- X if (ap->type == CKEYWD)
- X errorf("cannot alias keyword\n");
- X if ((ap->flag&ALLOC)) {
- X afree((Void*)ap->val.s, APERM);
- X ap->flag &= ~(ALLOC|ISSET);
- X }
- X ap->type = CALIAS;
- X ap->val.s = strsave(val, APERM);
- X ap->flag |= DEFINED|ALLOC|ISSET;
- X }
- X }
- X return rv;
- X}
- X
- Xint
- Xc_unalias(wp)
- X register char **wp;
- X{
- X register struct table *t = &lexicals;
- X register struct tbl *ap;
- X
- X if (*++wp != NULL && strcmp(*wp, "-d") == 0) {
- X t = &homedirs;
- X wp++;
- X }
- X
- X for (; *wp != NULL; wp++) {
- X ap = tsearch(t, *wp, hash(*wp));
- X if (ap == NULL || ap->type != CALIAS)
- X continue;
- X if ((ap->flag&ALLOC))
- X afree((Void*)ap->val.s, APERM);
- X ap->flag &= ~(DEFINED|ISSET|ALLOC);
- X }
- X return 0;
- X}
- X
- Xint
- Xc_let(wp)
- X char **wp;
- X{
- X int rv = 1;
- X
- X for (wp++; *wp; wp++)
- X rv = evaluate(*wp) == 0;
- X return rv;
- X}
- X
- Xint
- Xc_jobs(wp)
- X char **wp;
- X{
- X j_jobs();
- X return 0;
- X}
- X
- X#ifdef JOBS
- Xint
- Xc_fgbg(wp)
- X register char **wp;
- X{
- X int bg = strcmp(*wp, "bg") == 0;
- X
- X if (!flag[FMONITOR])
- X errorf("Job control not enabled\n");
- X wp++;
- X j_resume(j_lookup((*wp == NULL) ? "%" : *wp), bg);
- X return 0;
- X}
- X#endif
- X
- Xint
- Xc_kill(wp)
- X register char **wp;
- X{
- X register char *cp;
- X int sig = 15; /* SIGTERM */
- X int rv = 0;
- X int n;
- X int gotsig = FALSE;
- X
- X if (*++wp == NULL)
- X errorf("Usage: kill [-l] [-signal] {pid|job} ...\n");
- X if (strcmp(*wp, "-l") == 0) {
- X register struct trap *p = sigtraps;
- X for (sig = 0; sig < SIGNALS; sig++, p++)
- X if (p->signal)
- X printf("%2d %8s %s\n", p->signal, p->name, p->mess);
- X return 0;
- X }
- X
- X for (; (cp = *wp) != NULL; wp++)
- X if (*cp == '-' && gotsig == FALSE && *(wp+1) != NULL) {
- X struct trap *p;
- X gotsig = FALSE;
- X if (digit(*(cp+1))) {
- X if ((n = atoi(cp+1)) < SIGNALS) {
- X sig = n;
- X gotsig = TRUE;
- X } else if (kill(n, sig) < 0) {
- X shellf("%s: %s\n", cp, strerror(errno));
- X rv++;
- X }
- X } else {
- X p = gettrap(cp+1);
- X if (p == NULL)
- X errorf("bad signal %s\n", cp+1);
- X sig = p->signal;
- X gotsig = TRUE;
- X }
- X } else {
- X gotsig = FALSE;
- X if (digit(*cp) || (*cp == '-' && digit(*(cp+1)))) {
- X if (kill(atoi(cp), sig) < 0) {
- X shellf("%s: %s\n", cp, strerror(errno));
- X rv++;
- X }
- X } else
- X if (*cp == '%')
- X j_kill(j_lookup(cp), sig);
- X else
- X errorf("invalid argument\n");
- X }
- X return rv;
- X}
- X
- Xint
- Xc_bind(wp)
- X register char **wp;
- X{
- X int macro = 0;
- X register char *cp;
- X
- X for (wp++; (cp = *wp) != NULL && *cp == '-'; wp++)
- X if (cp[1] == 'm')
- X macro = 1;
- X
- X if (*wp == NULL) /* list all */
- X x_bind((char*)NULL, (char*)NULL, 0);
- X
- X for (; *wp != NULL; wp++) {
- X cp = strchr(*wp, '=');
- X if (cp != NULL)
- X *cp++ = 0;
- X x_bind(*wp, cp, macro);
- X }
- X
- X return 0;
- X}
- X
- Xextern c_fc();
- Xextern c_getopts();
- X
- XConst struct builtin kshbuiltins [] = {
- X {"cd", c_cd},
- X {"print", c_print},
- X {"getopts", c_getopts},
- X {"=typeset", c_typeset},
- X {"=export", c_typeset},
- X {"=readonly", c_typeset},
- X {"whence", c_whence},
- X {"=alias", c_alias},
- X {"unalias", c_unalias},
- X {"hash", c_hash},
- X {"let", c_let},
- X {"fc", c_fc},
- X {"jobs", c_jobs},
- X {"kill", c_kill},
- X#ifdef JOBS
- X {"fg", c_fgbg},
- X {"bg", c_fgbg},
- X#endif
- X#ifdef EMACS
- X {"bind", c_bind},
- X#endif
- X {NULL, NULL}
- X};
- X
- END_OF_FILE
- if test 11631 -ne `wc -c <'sh/c_ksh.c'`; then
- echo shar: \"'sh/c_ksh.c'\" unpacked with wrong size!
- fi
- # end of 'sh/c_ksh.c'
- fi
- if test -f 'sh/eval.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sh/eval.c'\"
- else
- echo shar: Extracting \"'sh/eval.c'\" \(14245 characters\)
- sed "s/^X//" >'sh/eval.c' <<'END_OF_FILE'
- X/*
- X * Expansion - quoting, separation, substitution, globbing
- X */
- X
- Xstatic char *RCSid = "$Id: eval.c,v 3.4 89/03/27 15:49:55 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 <unistd.h>
- X#include <sys/types.h>
- X#include <dirent.h>
- X#include <pwd.h>
- X#include "sh.h"
- X#include "lex.h"
- X#include "tree.h"
- X#include "table.h"
- X#include "expand.h"
- X
- X/*
- X * string expansion
- X *
- X * first pass: quoting, IFS separation, ${} and $() substitution.
- X * second pass: filename expansion (*?[]~).
- X */
- X
- X/* expansion generator state */
- Xtypedef struct Expand {
- X /* int type; */ /* see expand() */
- X char *str; /* string */
- X union {
- X char **strv; /* string[] */
- X FILE *file; /* file */
- X } u; /* source */
- X short split; /* split "$@"*/
- X} Expand;
- X
- X#define XBASE 0 /* scanning original */
- X#define XSUB 1 /* expanding ${} string */
- X#define XARGSEP 2 /* ifs0 between "$@" */
- X#define XARG 3 /* expanding $*, $@ */
- X#define XCOM 4 /* expanding $() */
- X
- Xstatic void expand ARGS((char *, XPtrV *, int));
- Xstatic int comsub ARGS((Expand *, char *comm));
- Xstatic int varsub ARGS((Expand *, char *name, int stype));
- Xstatic void glob ARGS((char *cp, XPtrV *wp));
- Xstatic void globit ARGS((char *ds, char *dp, char *sp, XPtrV *wp, int check));
- Xstatic char *tilde ARGS((char *wp));
- Xstatic char *trimsub ARGS((char *str, char *pat, int how));
- X
- Xint ifs0 = ' '; /* todo: first char of $IFS */
- X
- X/* compile and expand word */
- Xchar *
- Xsubstitute(cp, f)
- X char Const *cp;
- X int f;
- X{
- X struct source *s, *sold;
- X
- X sold = source;
- X s = pushs(SWSTR);
- X s->str = (char *) cp;
- X source = s;
- X if (yylex(ONEWORD) != LWORD)
- X errorf("eval:substitute error\n");
- X source = sold;
- X return evalstr(yylval.cp, f);
- X}
- X
- X/*
- X * expand arg-list
- X */
- Xchar **
- Xeval(ap, f)
- X register char **ap;
- X{
- X XPtrV w;
- X
- X if (*ap == NULL)
- X return ap;
- X XPinit(w, 32);
- X XPput(w, NULL); /* space for shell name */
- X#ifdef SHARPBANG
- X XPput(w, NULL); /* and space for one arg */
- X#endif
- X while (*ap != NULL)
- X expand(*ap++, &w, f);
- X XPput(w, NULL);
- X#ifdef SHARPBANG
- X return (char **) XPclose(w) + 2;
- X#else
- X return (char **) XPclose(w) + 1;
- X#endif
- X}
- X
- X/*
- X * expand string
- X */
- Xchar *
- Xevalstr(cp, f)
- X register char *cp;
- X int f;
- X{
- X XPtrV w;
- X
- X XPinit(w, 1);
- X expand(cp, &w, f);
- X cp = (XPsize(w) == 0) ? "" : (char*) *XPptrv(w);
- X XPfree(w);
- X return cp;
- X}
- X
- X/* for nested substitution: ${var:=$var2} */
- Xtypedef struct SubType {
- X short type; /* [=+-?%#] action after expanded word */
- X short base; /* begin position of expanded word */
- X char *name; /* name for ${var=word} */
- X} SubType;
- X
- Xstatic void
- Xexpand(cp, wp, f)
- X char *cp; /* input word */
- X register XPtrV *wp; /* output words */
- X int f; /* DO* flags */
- X{
- X register int c;
- X register int type = XBASE; /* expansion type */
- X register int quote = 0; /* quoted */
- X int quotestack[11]; /* Keep this bigger than the subtype stack */
- X register int *qst = quotestack + 11; /* This too, of course */
- X XString ds; /* destination string */
- X register char *dp, *sp; /* dest., source */
- X int fdo, word, combase; /* second pass flags; have word */
- X Expand x; /* expansion variables */
- X SubType subtype [10]; /* substitution type stack */
- X register SubType *st = subtype + 10;
- X int newlines; /* For trailing newlines in COMSUB */
- X
- X if (cp == NULL)
- X errorf("eval:expand(NULL)\n");
- X if (flag[FNOGLOB])
- X f &= ~ DOGLOB;
- X
- X Xinit(ds, dp, 128); /* init dest. string */
- X type = XBASE;
- X sp = cp;
- X fdo = 0;
- X word = !(f&DOBLANK);
- X
- X while (1) {
- X Xcheck(ds, dp);
- X
- X switch (type) {
- X case XBASE: /* original prefixed string */
- X c = *sp++;
- X switch (c) {
- X case EOS:
- X c = 0;
- X break;
- X case CHAR:
- X c = *sp++;
- X break;
- X case QCHAR:
- X quote |= 2; /* temporary quote */
- X c = *sp++;
- X break;
- X case OQUOTE:
- X word = quote = 1;
- X continue;
- X case CQUOTE:
- X quote = 0;
- X continue;
- X case COMSUB:
- X type = comsub(&x, sp);
- X sp = strchr(sp, 0) + 1;
- X combase = Xsavepos(ds, dp);
- X newlines = 0;
- X continue;
- X case OSUBST: /* ${var{:}[=+-?]word} */
- X cp = sp; /* variable */
- X sp = strchr(sp, 0) + 1; /* skip variable */
- X c = (*sp == CSUBST) ? 0 : *sp++;
- X if ((c&0x7F) == '#' || (c&0x7F) == '%') {
- X if (flag[FNOUNSET] &&
- X strval(global(cp)) == null)
- X errorf("%s: unset variable\n", cp);
- X f |= DOPAT;
- X type = XBASE;
- X *--qst = quote;
- X quote = 0;
- X } else
- X type = varsub(&x, cp, c);
- X if (type == XBASE) { /* expand? */
- X if (st == subtype)
- X errorf("ridiculous ${} nesting\n");
- X --st;
- X st->type = c;
- X st->base = Xsavepos(ds, dp);
- X st->name = cp;
- X } else
- X sp = wdscan(sp, CSUBST); /* skip word */
- X continue;
- X case CSUBST: /* only get here if expanding word */
- X *dp = 0;
- X if (f&DOGLOB)
- X f &= ~DOPAT;
- X switch (st->type&0x7F) {
- X case '#':
- X case '%':
- X *dp = 0;
- X dp = Xrestpos(ds, dp, st->base);
- X quote = *qst++;
- X x.str = trimsub(strval(global(st->name)),
- X dp, st->type);
- X type = XSUB;
- X continue;
- X case '=':
- X#if 0
- X if ((x.u.vp->flag&RDONLY))
- X errorf("cannot set readonly %s\n", cp);
- X#endif
- X setstr(global(st->name), Xrestpos(ds, dp, st->base));
- X break;
- X case '?':
- X if (dp == Xrestpos(ds, dp, st->base))
- X errorf("missing value for %s\n", cp);
- X else
- X errorf("%s\n", Xrestpos(ds, dp, st->base));
- X }
- X st++;
- X type = XBASE;
- X continue;
- X }
- X break;
- X
- X case XSUB:
- X if ((c = *x.str++) == 0) {
- X type = XBASE;
- X continue;
- X }
- X break;
- X
- X case XARGSEP:
- X type = XARG;
- X quote = 1;
- X case XARG:
- X if ((c = *x.str++) == 0) {
- X if ((x.str = *x.u.strv++) == NULL) {
- X type = XBASE;
- X continue;
- X } else if (quote && x.split) {
- X /* terminate word for "$@" */
- X type = XARGSEP;
- X quote = 0;
- X }
- X c = ifs0;
- X }
- X break;
- X
- X case XCOM:
- X if (newlines) { /* Spit out saved nl's */
- X c = '\n';
- X --newlines;
- X } else {
- X while ((c = getc(x.u.file)) == '\n')
- X newlines++; /* Save newlines */
- X if (newlines && c != EOF) {
- X ungetc(c, x.u.file);
- X c = '\n';
- X --newlines;
- X }
- X }
- X if (c == EOF) {
- X cp = Xrestpos(ds, sp, combase);
- X newlines = 0;
- X fclose(x.u.file);
- X if (x.split)
- X waitlast();
- X type = XBASE;
- X continue;
- X }
- X break;
- X }
- X
- X /* check for end of word or IFS separation */
- X if (c == 0 || !quote && (f&DOBLANK) && ctype(c, C_IFS)) {
- X if (word) {
- X *dp++ = 0;
- X cp = Xclose(ds, dp);
- X if (fdo&DOTILDE)
- X cp = tilde(cp);
- X if (fdo&DOGLOB)
- X glob(cp, wp);
- X else
- X {XPput(*wp, cp);}
- X fdo = word = 0;
- X if (c != 0)
- X Xinit(ds, dp, 128);
- X } else
- X ; /* ignore IFS */
- X if (c == 0)
- X return;
- X } else {
- X /* mark any special second pass chars */
- X if (!quote)
- X switch (c) {
- X case '*':
- X case '?':
- X case '[':
- X if (f&(DOPAT|DOGLOB)) {
- X fdo |= (f&DOGLOB);
- X *dp++ = MAGIC;
- X }
- X break;
- X case NOT:
- X if ((f&(DOPAT|DOGLOB)) &&
- X dp[-1] == '[' && dp[-2] == MAGIC) {
- X *dp++ = MAGIC;
- X }
- X break;
- X case '~':
- X if ((f&DOTILDE) && dp == Xstring(ds, dp) ||
- X !(f&DOBLANK) &&
- X (dp[-1] == '=' || dp[-1] == ':')) {
- X fdo |= DOTILDE;
- X *dp++ = MAGIC;
- X }
- X break;
- X }
- X else
- X quote &= ~2; /* undo temporary */
- X
- X word = 1;
- X *dp++ = c; /* save output char */
- X }
- X }
- X}
- X
- X/*
- X * Prepare to generate the string returned by ${} substitution.
- X */
- Xstatic int
- Xvarsub(xp, sp, stype)
- X register Expand *xp;
- X register char *sp;
- X int stype;
- X{
- X register int c;
- X int type;
- X
- X /* ${#var}, string length or argc */
- X if (sp[0] == '#' && (c = sp[1]) != 0) {
- X c = (c == '*' || c == '@') ? e.loc->argc :
- X strlen(strval(global(sp+1)));
- X xp->str = strsave(ulton((unsigned long)c, 10), ATEMP);
- X return XSUB;
- X }
- X
- X c = sp[0];
- X if (c == '*' || c == '@') {
- X if (e.loc->argc == 0) {
- X xp->str = null;
- X type = XSUB;
- X } else {
- X xp->u.strv = e.loc->argv + 1;
- X xp->str = *xp->u.strv++;
- X xp->split = c == '@'; /* $@ */
- X type = XARG;
- X }
- X } else {
- X xp->str = strval(global(sp));
- X type = XSUB;
- X }
- X
- X c = stype&0x7F;
- X /* test the compiler's code generator */
- X if (c == '%' || c == '#' ||
- X (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */
- X c == '=' || c == '-' || c == '?' : c == '+'))
- X type = XBASE; /* expand word instead of variable value */
- X if (type != XBASE && flag[FNOUNSET] && xp->str == null && c != '+')
- X errorf("%s: unset variable\n", sp);
- X return type;
- X}
- X
- X/*
- X * Run the command in $(...) and read its output.
- X */
- Xstatic int
- Xcomsub(xp, cp)
- X register Expand *xp;
- X char *cp;
- X{
- X Source *s;
- X register struct op *t;
- X FILE *fi;
- X
- X s = pushs(SSTRING);
- X s->str = cp;
- X t = compile(s);
- X
- X if (t != NULL && t->type == TCOM && /* $(<file) */
- X *t->args == NULL && *t->vars == NULL && t->ioact != NULL) {
- X register struct ioword *io = *t->ioact;
- X
- X if ((io->flag&IOTYPE) != IOREAD)
- X errorf("funny $() command\n");
- X fi = fopen(evalstr(io->name, DOTILDE), "r");
- X if (fi != NULL)
- X fileno(fi) = savefd(fileno(fi));
- X xp->split = 0; /* no waitlast() */
- X } else {
- X int ofd1, pv[2];
- X openpipe(pv);
- X fi = fdopen(pv[0], "r");
- X ofd1 = savefd(1);
- X dup2(pv[1], 1);
- X close(pv[1]);
- X#if 0
- X exchild(t, XXCOM|XPIPEO);
- X#else
- X execute(t, XFORK|XXCOM|XPIPEO);
- X#endif
- X dup2(ofd1, 1);
- X close(ofd1);
- X xp->split = 1; /* waitlast() */
- X }
- X
- X if (fi == NULL)
- X errorf("cannot open $() input\n");
- X setvbuf(fi, (char *)NULL, _IOFBF, BUFSIZ);
- X xp->u.file = fi;
- X return XCOM;
- X}
- X
- X/*
- X * perform #pattern and %pattern substitution in ${}
- X */
- X
- Xstatic char *
- Xtrimsub(str, pat, how)
- X register char *str;
- X char *pat;
- X int how;
- X{
- X register char *end = strchr(str, 0);
- X register char *p, c, *match;
- X
- X switch (how&0xff) { /* UCHAR_MAX maybe? */
- X case '#': /* shortest at begin */
- X for (p = str; p <= end; p++) {
- X c = *p; *p = '\0';
- X if (gmatch(str, pat)) {
- X *p = c;
- X return p;
- X }
- X *p = c;
- X }
- X break;
- X case '#'|0x80: /* longest match at begin */
- X for (p = end; p >= str; p--) {
- X c = *p; *p = '\0';
- X if (gmatch(str, pat)) {
- X *p = c;
- X return p;
- X }
- X *p = c;
- X }
- X break;
- X case '%': /* shortest match at end */
- X for (p = end; p >= str; p--) {
- X if (gmatch(p, pat)) {
- X c = *p; *p = '\0';
- X match = strsave( str, APERM ); /* APERM? */
- X *p = c;
- X return match;
- X }
- X }
- X break;
- X case '%'|0x80: /* longest match at end */
- X for (p = str; p <= end; p++) {
- X if (gmatch(p, pat)) {
- X c = *p; *p = '\0';
- X match = strsave( str, ATEMP ); /* APERM? */
- X *p = c;
- X return match;
- X }
- X }
- X break;
- X }
- X
- X return str; /* no match, return string */
- X}
- X
- X/*
- X * glob
- X * Name derived from V6's /etc/glob, the program that expanded filenames.
- X */
- X
- Xstatic char *debunk();
- X
- Xstatic void
- Xglob(cp, wp)
- X char *cp;
- X register XPtrV *wp;
- X{
- X char path [PATH];
- X register char *sp = cp;
- X int oldsize;
- X
- X oldsize = XPsize(*wp);
- X globit(path, path, sp, wp, 0);
- X
- X if (XPsize(*wp) == oldsize)
- X {XPput(*wp, debunk(cp));}
- X else
- X qsortp(XPptrv(*wp) + oldsize, (size_t)(XPsize(*wp) - oldsize), xstrcmp);
- X}
- X
- Xstatic void
- Xglobit(ds, dp, sp, wp, check)
- X char *ds; /* dest path */
- X char *dp; /* dest end */
- X char *sp; /* source path */
- X register XPtrV *wp; /* output list */
- X int check; /* check dest existence */
- X{
- X register char *np; /* next source component */
- X register char *tsp, *tdp;
- X
- X if (sp == NULL) { /* end of source path */
- X if (check && eaccess(ds, 0) < 0)
- X return;
- X XPput(*wp, strsave(ds, ATEMP));
- X return;
- X }
- X
- X if (dp > ds)
- X *dp++ = '/';
- X while (*sp == '/')
- X *dp++ = *sp++;
- X np = strchr(sp, '/');
- X if (np != NULL)
- X *np++ = 0;
- X
- X *dp = 0;
- X if (strchr(sp, MAGIC) == NULL) { /* contains no pattern? */
- X tdp = dp; tsp = sp;
- X while ((*tdp++ = *tsp++) != 0)
- X ;
- X --tdp;
- X globit(ds, tdp, np, wp, check);
- X } else {
- X DIR *dirp;
- X struct dirent *d;
- X
- X /* ToDo:
- X * should not attemp to open() special files: /dev/ttyd0/*
- X * opendir should do this check, but Doug Gwyn's does not.
- X */
- X dirp = opendir((*ds == 0) ? "." : ds);
- X if (dirp == NULL)
- X goto Nodir;
- X while ((d = readdir(dirp)) != NULL) {
- X tsp = d->d_name;
- X if (tsp[0] == '.' &&
- X (tsp[1] == 0 || tsp[1] == '.' && tsp[2] == 0))
- X continue; /* always ignore . and .. */
- X if (*tsp == '.' && *sp != '.' || !gmatch(tsp, sp))
- X continue;
- X
- X tdp = dp;
- X while ((*tdp++ = *tsp++) != 0)
- X ;
- X --tdp;
- X globit(ds, tdp, np, wp, np != NULL);
- X }
- X closedir(dirp);
- X Nodir:;
- X }
- X
- X if (np != NULL)
- X *--np = '/';
- X}
- X
- X/* remove MAGIC from string */
- Xstatic char *
- Xdebunk(cp)
- X char *cp;
- X{
- X register char *dp, *sp;
- X
- X for (dp = sp = cp; *sp != 0; sp++)
- X if (*sp != MAGIC)
- X *dp++ = *sp;
- X *dp = 0;
- X return cp;
- X}
- X
- X/*
- X * tilde expansion
- X *
- X * based on a version by Arnold Robbins
- X */
- X
- Xstatic char *homedir();
- X
- Xstatic char *
- Xtilde(acp)
- X char *acp;
- X{
- X register int c;
- X char path [PATH+1];
- X register char *cp = acp, *wp = path, *dp;
- X char userid [16+1];
- X
- X Again:
- X while (1) {
- X if ((c = *cp++) == 0) {
- X *wp = 0;
- X afree((Void*)acp, ATEMP);
- X return strsave(path, ATEMP);
- X } else if (c == MAGIC && *cp == '~')
- X break;
- X else
- X *wp++ = c;
- X }
- X
- X dp = NULL; /* no output substitution */
- X if (cp[1] == 0 || cp[1] == '/' || cp[1] == ':') /* ~ or ~/ */
- X dp = strval(global("HOME")), cp += 1;
- X else if (cp[1] == '+' && (cp[2] == '/' || cp[2] == ':' || cp[2] == 0))
- X dp = strval(global("PWD")), cp += 2;
- X else if (cp[1] == '-' && (cp[2] == '/' || cp[2] == ':' || cp[2] == 0))
- X dp = strval(global("OLDPWD")), cp += 2;
- X else if (letter(cp[1])) {
- X char *save = cp;
- X for (dp = userid, cp++; letnum(*cp) && dp < userid+16; )
- X *dp++ = *cp++;
- X *dp = 0;
- X dp = homedir(userid);
- X if (dp == NULL)
- X cp = save;
- X }
- X /* substitute */
- X if (dp != NULL)
- X while (*dp != 0)
- X *wp++ = *dp++;
- X goto Again;
- X}
- X
- X/*
- X * map userid to user's home directory.
- X * todo: implement a cache with the "homedirs" table.
- X * note that 4.3's getpw adds more than 6K to the shell,
- X * and the YP version probably adds much more.
- X * we might consider our own version of getpwnam() to keep the size down.
- X */
- X
- Xstatic char *
- Xhomedir(name)
- X char *name;
- X{
- X register struct tbl *ap;
- X register struct passwd *pw;
- X extern struct passwd *getpwnam();
- X
- X ap = tsearch(&homedirs, name, hash(name));
- X if ((ap != NULL && (ap->flag&ISSET)))
- X return ap->val.s;
- X pw = getpwnam(name);
- X if (pw == NULL)
- X return NULL;
- X return pw->pw_dir;
- X}
- END_OF_FILE
- if test 14245 -ne `wc -c <'sh/eval.c'`; then
- echo shar: \"'sh/eval.c'\" unpacked with wrong size!
- fi
- # end of 'sh/eval.c'
- fi
- if test -f 'sh/lex.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sh/lex.c'\"
- else
- echo shar: Extracting \"'sh/lex.c'\" \(12416 characters\)
- sed "s/^X//" >'sh/lex.c' <<'END_OF_FILE'
- X/*
- X * lexical analysis and source input
- X */
- X
- X#ifndef lint
- Xstatic char *RCSid = "$Id: lex.c,v 3.6 89/03/27 15:51:20 egisin Exp $";
- Xstatic char *sccs_id = "@(#)lex.c 1.3 91/11/09 15:35:19 (sjg)";
- X#endif
- X
- X#include <stddef.h>
- X#include <stdio.h>
- X#include <string.h>
- X#include <errno.h>
- X#include <setjmp.h>
- X#include <unistd.h>
- X#include <assert.h>
- X#include "sh.h"
- X#include "lex.h"
- X#include "tree.h"
- X#include "table.h"
- X#include "expand.h"
- X
- X int ttyfd = -1; /* tty fd for edit and jobs */
- X char *history[HISTORY]; /* saved commands */
- X char **histptr = history - 1; /* last history item */
- X int histpush; /* number of pushed fc commands */
- X
- X/* we set s->str to NULLSTR instead of "", so that ungetsc() works */
- Xstatic char nullstr [] = {0, 0};
- X#define NULLSTR (nullstr + 1)
- X
- Xstatic int expanding_alias;
- Xstatic int alias;
- Xstatic int getsc_ ARGS((void));
- X
- X/* optimized getsc_() */
- X#define getsc() ((*source->str != 0) ? *source->str++ : getsc_())
- X#define ungetsc() (source->str--)
- X
- X/*
- X * Lexical analyzer
- X *
- X * tokens are not regular expressions, they are LL(1).
- X * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
- X * hence the state stack.
- X */
- X
- Xint
- Xyylex(cf)
- X int cf;
- X{
- X register int c, state;
- X char states [64], *statep = states;
- X XString ws; /* expandable output word */
- X register char *wp; /* output word pointer */
- X register char *sp, *dp;
- X int istate;
- X int c2;
- X static int rec_alias_cnt = 0;
- X static struct tbl *rec_alias_table[20];
- X
- X
- X if (expanding_alias) {
- X expanding_alias = 0;
- X while (rec_alias_cnt-- > 0)
- X rec_alias_table[rec_alias_cnt]->flag &= ~EXPALIAS;
- X rec_alias_cnt = 0;
- X }
- X Again:
- X Xinit(ws, wp, 64);
- X
- X if (cf&ONEWORD)
- X istate = SWORD;
- X else if (cf&LETEXPR)
- X istate = SDPAREN;
- X else { /* normal lexing */
- X istate = SBASE;
- X while ((c = getsc()) == ' ' || c == '\t')
- X ;
- X if (c == '#')
- X while ((c = getsc()) != 0 && c != '\n')
- X ;
- X ungetsc();
- X }
- X if (alias) { /* trailing ' ' in alias definition */
- X alias = 0;
- X cf |= ALIAS;
- X }
- X
- X /* collect non-special or quoted characters to form word */
- X for (*statep = state = istate;
- X !((c = getsc()) == 0 || state == SBASE && ctype(c, C_LEX1)); ) {
- X Xcheck(ws, wp);
- X switch (state) {
- X case SBASE:
- X Sbase:
- X switch (c) {
- X case '\\':
- X c = getsc();
- X if (c != '\n')
- X *wp++ = QCHAR, *wp++ = c;
- X else
- X if (wp == Xstring(ws, wp))
- X goto Again;
- X break;
- X case '\'':
- X *++statep = state = SSQUOTE;
- X *wp++ = OQUOTE;
- X break;
- X case '"':
- X *++statep = state = SDQUOTE;
- X *wp++ = OQUOTE;
- X break;
- X default:
- X goto Subst;
- X }
- X break;
- X
- X Subst:
- X switch (c) {
- X case '\\':
- X c = getsc();
- X switch (c) {
- X case '\n':
- X break;
- X case '"': case '\\':
- X case '$': case '`':
- X *wp++ = QCHAR, *wp++ = c;
- X break;
- X default:
- X Xcheck(ws, wp);
- X *wp++ = CHAR, *wp++ = '\\';
- X *wp++ = CHAR, *wp++ = c;
- X break;
- X }
- X break;
- X case '$':
- X c = getsc();
- X if (c == '(') {
- X *++statep = state = SPAREN;
- X *wp++ = COMSUB;
- X } else
- X if (c == '{') {
- X *++statep = state = SBRACE;
- X *wp++ = OSUBST;
- X c = getsc();
- X do {
- X Xcheck(ws, wp);
- X *wp++ = c;
- X c = getsc();
- X } while (ctype(c, C_ALPHA|C_DIGIT));
- X *wp++ = 0;
- X /* todo: more compile-time checking */
- X if (c == '}')
- X ungetsc();
- X else if (c == '#' || c == '%') {
- X /* Korn pattern trimming */
- X if (getsc() == c)
- X c |= 0x80;
- X else
- X ungetsc();
- X *wp++ = c;
- X } else if (c == ':')
- X *wp++ = 0x80|getsc();
- X else
- X *wp++ = c;
- X } else if (ctype(c, C_ALPHA)) {
- X *wp++ = OSUBST;
- X do {
- X Xcheck(ws, wp);
- X *wp++ = c;
- X c = getsc();
- X } while (ctype(c, C_ALPHA|C_DIGIT));
- X *wp++ = 0;
- X *wp++ = CSUBST;
- X ungetsc();
- X } else if (ctype(c, C_DIGIT|C_VAR1)) {
- X Xcheck(ws, wp);
- X *wp++ = OSUBST;
- X *wp++ = c;
- X *wp++ = 0;
- X *wp++ = CSUBST;
- X } else {
- X *wp++ = CHAR, *wp++ = '$';
- X ungetsc();
- X }
- X break;
- X case '`':
- X *++statep = state = SBQUOTE;
- X *wp++ = COMSUB;
- X break;
- X default:
- X *wp++ = CHAR, *wp++ = c;
- X }
- X break;
- X
- X case SSQUOTE:
- X if (c == '\'') {
- X state = *--statep;
- X *wp++ = CQUOTE;
- X } else
- X *wp++ = QCHAR, *wp++ = c;
- X break;
- X
- X case SDQUOTE:
- X if (c == '"') {
- X state = *--statep;
- X *wp++ = CQUOTE;
- X } else
- X goto Subst;
- X break;
- X
- X case SPAREN:
- X if (c == '(')
- X *++statep = state;
- X else if (c == ')')
- X state = *--statep;
- X if (state == SPAREN)
- X *wp++ = c;
- X else
- X *wp++ = 0; /* end of COMSUB */
- X break;
- X
- X case SBRACE:
- X if (c == '}') {
- X state = *--statep;
- X *wp++ = CSUBST;
- X } else
- X goto Sbase;
- X break;
- X
- X case SBQUOTE:
- X if (c == '`') {
- X *wp++ = 0;
- X state = *--statep;
- X } else if (c == '\\') {
- X switch (c = getsc()) {
- X case '\n':
- X break;
- X case '\\':
- X case '$': case '`':
- X *wp++ = c;
- X break;
- X default:
- X *wp++ = '\\';
- X *wp++ = c;
- X break;
- X }
- X } else
- X *wp++ = c;
- X break;
- X
- X case SWORD: /* ONEWORD */
- X goto Subst;
- X
- X case SDPAREN: /* LETEXPR */
- X if (c == ')') {
- X if (getsc() == ')') {
- X c = 0;
- X goto Done;
- X } else
- X ungetsc();
- X }
- X goto Subst;
- X }
- X }
- XDone:
- X Xcheck(ws, wp);
- X if (state != istate)
- X yyerror("no closing quote");
- X
- X if (c == '<' || c == '>') {
- X char *cp = Xstring(ws, wp);
- X if (wp > cp && cp[0] == CHAR && digit(cp[1])) {
- X wp = cp; /* throw away word */
- X c2/*unit*/ = cp[1] - '0';
- X } else
- X c2/*unit*/ = c == '>'; /* 0 for <, 1 for > */
- X }
- X
- X if (wp == Xstring(ws, wp) && state == SBASE) {
- X Xfree(ws, sp); /* free word */
- X /* no word, process LEX1 character */
- X switch (c) {
- X default:
- X return c;
- X
- X case '|':
- X case '&':
- X case ';':
- X if (getsc() == c)
- X c = (c == ';') ? BREAK :
- X (c == '|') ? LOGOR :
- X (c == '&') ? LOGAND :
- X YYERRCODE;
- X else
- X ungetsc();
- X return c;
- X
- X case '>':
- X case '<': {
- X register struct ioword *iop;
- X
- X iop = (struct ioword *) alloc(sizeof(*iop), ATEMP);
- X iop->unit = c2/*unit*/;
- X
- X c2 = getsc();
- X if (c2 == '>' || c2 == '<') {
- X iop->flag = c != c2 ? IORDWR : c == '>' ? IOCAT : IOHERE;
- X c2 = getsc();
- X } else
- X iop->flag = c == '>' ? IOWRITE : IOREAD;
- X
- X if (iop->flag == IOHERE)
- X if (c2 == '-')
- X iop->flag |= IOSKIP;
- X else
- X ungetsc();
- X else
- X if (c2 == '&')
- X iop->flag = IODUP;
- X else if (c2 == '!' && iop->flag == IOWRITE)
- X iop->flag |= IOCLOB;
- X else
- X ungetsc();
- X yylval.iop = iop;
- X return REDIR;
- X }
- X case '\n':
- X gethere();
- X if (cf & CONTIN)
- X goto Again;
- X return c;
- X
- X case '(':
- X c2 = getsc();
- X if (c2 == ')')
- X c = MPAREN;
- X else if (c2 == '(')
- X c = MDPAREN;
- X else
- X ungetsc();
- X case ')':
- X return c;
- X }
- X }
- X
- X *wp++ = EOS; /* terminate word */
- X yylval.cp = Xclose(ws, wp);
- X if (state == SWORD || state == SDPAREN) /* ONEWORD? */
- X return LWORD;
- X ungetsc(); /* unget terminator */
- X
- X /* copy word to unprefixed string ident */
- X for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
- X *dp++ = *sp++;
- X /* Make sure the ident array stays '\0' padded */
- X while (dp <= ident+IDENT)
- X *dp++ = '\0';
- X#if 0
- X if (*ident == '~' || (dp = strchr(ident, '=')) != NULL && dp[1] == '~')
- X "Tilde expansion";
- X#endif
- X if (c != EOS)
- X *ident = 0; /* word is not unquoted */
- X
- X if (*ident != 0 && (cf&(KEYWORD|ALIAS))) {
- X register struct tbl *p;
- X
- X p = tsearch(&lexicals, ident, hash(ident));
- X if (p != NULL && (p->flag&ISSET))
- X if (p->type == CKEYWD && (cf&KEYWORD)) {
- X afree(yylval.cp, ATEMP);
- X return p->val.i;
- X } else if (p->type == CALIAS && (cf&ALIAS) &&
- X !(p->flag&EXPALIAS)) {
- X register Source *s;
- X
- X if (rec_alias_cnt == sizeof(rec_alias_table)/sizeof(rec_alias_table[0]))
- X yyerror("excessive recusrsive aliasing");
- X else
- X rec_alias_table[rec_alias_cnt++] = p;
- X p->flag |= EXPALIAS;
- X /* check for recursive aliasing */
- X for (s = source; s->type == SALIAS; s = s->next)
- X if (s->u.tblp == p)
- X return LWORD;
- X afree(yylval.cp, ATEMP);
- X
- X /* push alias expansion */
- X s = pushs(SALIAS);
- X s->str = p->val.s;
- X s->u.tblp = p;
- X s->next = source;
- X source = s;
- X goto Again;
- X }
- X }
- X
- X return LWORD;
- X}
- X
- Xstatic void readhere();
- X
- Xgethere()
- X{
- X register struct ioword **p;
- X
- X for (p = heres; p < herep; p++)
- X readhere(*p);
- X herep = heres;
- X}
- X
- X/*
- X * read "<<word" text into temp file
- X * todo: set up E_ERR to fclose(f) on unwind
- X */
- X
- Xstatic void
- Xreadhere(iop)
- X register struct ioword *iop;
- X{
- X register FILE *f;
- X struct temp *h;
- X register int c;
- X char *eof;
- X register char *cp;
- X char line [LINE+1];
- X
- X eof = evalstr(iop->name, 0);
- X
- X h = maketemp(ATEMP);
- X h->next = e.temps; e.temps = h;
- X iop->name = h->name;
- X f = fopen(h->name, "w");
- X if (f == NULL)
- X errorf("Cannot create temporary file\n");
- X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
- X
- X for (;;) {
- X cp = line;
- X while ((c = getsc()) != '\n') {
- X if (c == 0)
- X errorf("here document `%s' unclosed\n", eof);
- X if (cp >= line+LINE)
- X break;
- X *cp++ = c;
- X }
- X ungetsc();
- X *cp = 0;
- X for (cp = line; iop->flag&IOSKIP && *cp == '\t'; cp++)
- X ;
- X if (strcmp(eof, cp) == 0 || c == 0)
- X break;
- X while ((c = *cp++) != '\0')
- X putc(c, f);
- X while ((c = getsc()) != '\n') {
- X if (c == 0)
- X errorf("here document `%s' unclosed\n", eof);
- X putc(c, f);
- X }
- X putc(c, f);
- X }
- X fclose(f);
- X}
- X
- Xvoid
- Xyyerror(msg)
- X Const char *msg;
- X{
- X yynerrs++;
- X while (source->type == SALIAS) /* pop aliases */
- X source = source->next;
- X if (source->file != NULL)
- X shellf("%s[%d]: ", source->file, source->line);
- X source->str = NULLSTR; /* zap pending input */
- X errorf("%s\n", msg);
- X}
- X
- X/*
- X * input for yylex with alias expansion
- X */
- X
- XSource *
- Xpushs(type)
- X int type;
- X{
- X register Source *s;
- X
- X s = (Source *) alloc(sizeof(Source), ATEMP);
- X s->type = type;
- X s->str = NULLSTR;
- X s->line = 0;
- X s->file = NULL;
- X s->echo = 0;
- X s->next = NULL;
- X return s;
- X}
- X
- Xstatic int
- Xgetsc_()
- X{
- X register Source *s = source;
- X register int c;
- X extern void mprint();
- X
- X while ((c = *s->str++) == 0) {
- X s->str = NULL; /* return 0 for EOF by default */
- X switch (s->type) {
- X case SEOF:
- X s->str = NULLSTR;
- X return 0;
- X
- X case STTY:
- X if (histpush < 0) { /* commands pushed by dofc */
- X s->type = SHIST;
- X s->str = NULLSTR;
- X continue;
- X }
- X s->line++;
- X s->str = line;
- X line[0] = '\0';
- X mprint();
- X pprompt(prompt);
- X flushshf(1); flushshf(2);
- X#ifdef EDIT
- X#ifdef EMACS
- X if (flag[FEMACS])
- X c = x_read(ttyfd, line, LINE);
- X else
- X#endif
- X#ifdef VI
- X if (flag[FVI])
- X c = x_read(ttyfd, line, LINE);
- X else
- X#endif
- X#endif
- X c = read(ttyfd, line, LINE);
- X if (c < 0) /* read error */
- X c = 0;
- X line[c] = '\0';
- X prompt = strval(global("PS2"));
- X if (c == 0) { /* EOF */
- X s->str = NULL;
- X s->line--;
- X } else {
- X c = 0;
- X while(line[c] && ctype(line[c], C_IFS))
- X c++;
- X if (!line[c]) {
- X s->str = &line[c - 1];
- X s->line--;
- X } else {
- X s->str = &line[c];
- X histsave(s->str);
- X }
- X }
- X break;
- X
- X case SHIST:
- X if (histpush == 0) {
- X s->type = STTY;
- X s->str = NULLSTR;
- X continue;
- X }
- X s->line++;
- X s->str = histptr[++histpush];
- X#if 0
- X pprompt("!< "); /* todo: PS9 */
- X#endif
- X shellf("%s\n", s->str);
- X strcpy(line, s->str);
- X s->str = strchr(line, 0);
- X *s->str++ = '\n';
- X *s->str = 0;
- X s->str = line;
- X break;
- X
- X case SFILE:
- X s->line++;
- X s->str = fgets(line, LINE, s->u.file);
- X if (s->str == NULL)
- X if (s->u.file != stdin)
- X fclose(s->u.file);
- X break;
- X
- X case SWSTR:
- X break;
- X
- X case SSTRING:
- X s->str = "\n";
- X s->type = SEOF;
- X break;
- X
- X case SWORDS:
- X s->str = *s->u.strv++;
- X s->type = SWORDSEP;
- X break;
- X
- X case SWORDSEP:
- X if (*s->u.strv == NULL) {
- X s->str = "\n";
- X s->type = SEOF;
- X } else {
- X s->str = " ";
- X s->type = SWORDS;
- X }
- X break;
- X
- X case SALIAS:
- X s->str = s->u.tblp->val.s;
- X if (s->str[0] != 0) {
- X c = strchr(s->str, 0)[-1];
- X if (c == ' ' || c == '\t')
- X alias = 1; /* trailing ' ' */
- X }
- X source = s = s->next;
- X expanding_alias = 1;
- X continue;
- X }
- X if (s->str == NULL) {
- X s->type = SEOF;
- X s->str = NULLSTR;
- X return 0;
- X }
- X if (s->echo)
- X fputs(s->str, shlout);
- X }
- X return c;
- X}
- X
- Xpprompt(cp)
- X register char *cp;
- X{
- X while (*cp != 0)
- X if (*cp != '!')
- X putc(*cp++, shlout);
- X else
- X if (*++cp == '!')
- X putc(*cp++, shlout);
- X else
- X shellf("%d", source->line);
- X fflush(shlout);
- X}
- END_OF_FILE
- if test 12416 -ne `wc -c <'sh/lex.c'`; then
- echo shar: \"'sh/lex.c'\" unpacked with wrong size!
- fi
- # end of 'sh/lex.c'
- fi
- if test -f 'sh/syn.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'sh/syn.c'\"
- else
- echo shar: Extracting \"'sh/syn.c'\" \(9735 characters\)
- sed "s/^X//" >'sh/syn.c' <<'END_OF_FILE'
- X/*
- X * shell parser (C version)
- X */
- X
- Xstatic char *RCSid = "$Id: syn.c,v 3.3 89/03/27 15:51:51 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 || source->type == SSTRING
- X || source->type == SALIAS) && c == '\n') {
- X if (c == '&') {
- X if (tl)
- X tl->right = block(TASYNC, tl->right, NOBLOCK, NOWORDS);
- X else
- X t = block(TASYNC, t, NOBLOCK, NOWORDS);
- X }
- 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 case MDPAREN:
- X REJECT;
- X t = newtp(TCOM);
- X if (c == MDPAREN) {
- X ACCEPT;
- X XPput(args,"let");
- X musthave(LWORD,LETEXPR);
- X XPput(args,yylval.cp);
- X }
- 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#if 0
- X case MDPAREN:
- X t = newtp(TCOM);
- X XPput(args, "let");
- X musthave(LWORD, LETEXPR);
- X XPput(args, yylval.cp);
- X while (tpeek(0) == REDIR) {
- X if (iopn >= NUFILE)
- X yyerror("too many redirections");
- X iops[iopn++] = synio(0);
- X }
- X break;
- X#endif
- 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 || s->type == SHIST)
- X s->str = null; /* line is not preserved */
- X return outtree;
- X}
- X
- END_OF_FILE
- if test 9735 -ne `wc -c <'sh/syn.c'`; then
- echo shar: \"'sh/syn.c'\" unpacked with wrong size!
- fi
- # end of 'sh/syn.c'
- fi
- echo shar: End of archive 4 \(of 9\).
- cp /dev/null ark4isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 9 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-