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