Public Domain Korn Shell - Part.05 of 7

USENET Administration netnews at netcom.UUCP
Wed Dec 12 22:38:04 AEST 1990


#!/bin/sh
# This is part 05 of ksh-pd
# ============= src/c_ksh.c ==============
if test ! -d 'src'; then
    echo 'x - creating directory src'
    mkdir 'src'
fi
if test -f 'src/c_ksh.c' -a X"$1" != X"-c"; then
	echo 'x - skipping src/c_ksh.c (File already exists)'
else
echo 'x - extracting src/c_ksh.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/c_ksh.c' &&
X/*
X * built-in Korn commands: c_*
X */
X
Xstatic char *RCSid = "$Id: c_ksh.c,v 3.2 89/01/23 10:57:38 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_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
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, 1);
X		if (vflag)
X			switch ((tp == NULL) ? CNONE : tp->type) {
X			  case CNONE:
X				printf("%s is unknown\n", id);
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				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				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 : id);
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 0;
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#if 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
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 == '-') {
X			struct trap *p;
X			p = gettrap(cp+1);
X			if (p == NULL)
X				errorf("bad signal %s\n", cp+1);
X			sig = p->signal;
X		} else
X		if (digit(*cp)) {
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	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	{"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#if JOBS
X	{"fg", c_fgbg},
X	{"bg", c_fgbg},
X#endif
X#if EDIT
X	{"bind", c_bind},
X#endif
X	{NULL, NULL}
X};
X
SHAR_EOF
true || echo 'restore of src/c_ksh.c failed'
fi
# ============= src/c_test.c ==============
if test -f 'src/c_test.c' -a X"$1" != X"-c"; then
	echo 'x - skipping src/c_test.c (File already exists)'
else
echo 'x - extracting src/c_test.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/c_test.c' &&
X/*
X * test(1); version 7-like  --  author Erik Baalbergen
X * modified by Eric Gisin to be used as built-in.
X * modified by Arnold Robbins to add SVR3 compatibility
X * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
X */
X
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/c_test.c,v 3.2 88/12/17 21:39:26 egisin Exp $";
X
X#include <stddef.h>
X#include <string.h>
X#include <signal.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "sh.h"
X
X/* test(1) accepts the following grammar:
X	oexpr	::= aexpr | aexpr "-o" oexpr ;
X	aexpr	::= nexpr | nexpr "-a" aexpr ;
X	nexpr	::= primary ! "!" primary
X	primary	::= unary-operator operand
X		| operand binary-operator operand
X		| operand
X		| "(" oexpr ")"
X		;
X	unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
X		"-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
X
X	binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
X			"-nt"|"-ot"|"-ef";
X	operand ::= <any legal UNIX file name>
X*/
X
X#define EOI	0
X#define FILRD	1
X#define FILWR	2
X#define FILREG	3
X#define FILID	4
X#define FILGZ	5
X#define FILTT	6
X#define STZER	7
X#define STNZE	8
X#define STEQL	9
X#define STNEQ	10
X#define INTEQ	11
X#define INTNE	12
X#define INTGE	13
X#define INTGT	14
X#define INTLE	15
X#define INTLT	16
X#define UNOT	17
X#define BAND	18
X#define BOR	19
X#define LPAREN	20
X#define RPAREN	21
X#define OPERAND	22
X#define FILEX	23
X#define FILCDEV	24
X#define FILBDEV	25
X#define FILFIFO	26
X#define FILSETU	27
X#define FILSETG	28
X#define FILSTCK	29
X#define FILSYM	30
X#define FILNT	31
X#define FILOT	32
X#define FILEQ	33
X#define FILSOCK	34
X#define	FILUID	35
X#define	FILGID	36
X#define	OPTION	37
X
X#define UNOP	1
X#define BINOP	2
X#define BUNOP	3
X#define BBINOP	4
X#define PAREN	5
X
Xstruct t_op {
X	char *op_text;
X	short op_num, op_type;
X} Const ops [] = {
X	{"-r",	FILRD,	UNOP},
X	{"-w",	FILWR,	UNOP},
X	{"-x",	FILEX,	UNOP},
X	{"-f",	FILREG,	UNOP},
X	{"-d",	FILID,	UNOP},
X	{"-c",	FILCDEV,UNOP},
X	{"-b",	FILBDEV,UNOP},
X	{"-p",	FILFIFO,UNOP},
X	{"-u",	FILSETU,UNOP},
X	{"-g",	FILSETG,UNOP},
X	{"-k",	FILSTCK,UNOP},
X	{"-s",	FILGZ,	UNOP},
X	{"-t",	FILTT,	UNOP},
X	{"-z",	STZER,	UNOP},
X	{"-n",	STNZE,	UNOP},
X#if 0				/* conficts with binary -o */
X	{"-o",	OPTION,	UNOP},
X#endif
X	{"-U",	FILUID,	UNOP},
X	{"-G",	FILGID,	UNOP},
X	{"-L",	FILSYM,	UNOP},
X	{"-S",	FILSOCK,UNOP},
X	{"=",	STEQL,	BINOP},
X	{"!=",	STNEQ,	BINOP},
X	{"-eq",	INTEQ,	BINOP},
X	{"-ne",	INTNE,	BINOP},
X	{"-ge",	INTGE,	BINOP},
X	{"-gt",	INTGT,	BINOP},
X	{"-le",	INTLE,	BINOP},
X	{"-lt",	INTLT,	BINOP},
X	{"-nt",	FILNT,	BINOP},
X	{"-ot",	FILOT,	BINOP},
X	{"-ef",	FILEQ,	BINOP},
X	{"!",	UNOT,	BUNOP},
X	{"-a",	BAND,	BBINOP},
X	{"-o",	BOR,	BBINOP},
X	{"(",	LPAREN,	PAREN},
X	{")",	RPAREN,	PAREN},
X	{0,	0,	0}
X};
X
Xchar **t_wp;
Xstruct t_op Const *t_wp_op;
X
Xint
Xc_test(wp)
X	char **wp;
X{
X	t_wp = wp+1;
X	if (strcmp(wp[0], "[") == 0) {
X		while (*wp != NULL)
X			wp++;
X		if (strcmp(*--wp, "]") != 0)
X			errorf("[: missing ]\n");
X		*wp = NULL;
X	}
X	return *t_wp == NULL || !oexpr(t_lex(*t_wp));
X}
X
Xstatic
Xsyntax()
X{
X	errorf("test: syntax error\n");
X}
X
Xoexpr(n)
X{
X	int res;
X
X	res = aexpr(n);
X	if (t_lex(*++t_wp) == BOR)
X		return oexpr(t_lex(*++t_wp)) || res;
X	t_wp--;
X	return res;
X}
X
Xaexpr(n)
X{
X	int res;
X
X	res = nexpr(n);
X	if (t_lex(*++t_wp) == BAND)
X		return aexpr(t_lex(*++t_wp)) && res;
X	t_wp--;
X	return res;
X}
X
Xnexpr(n)
X	int n;			/* token */
X{
X	if (n == UNOT)
X		return !nexpr(t_lex(*++t_wp));
X	return primary(n);
X}
X
Xprimary(n)
X	int n;			/* token */
X{
X	register char *opnd1, *opnd2;
X	int res;
X
X	if (n == EOI)
X		syntax();
X	if (n == LPAREN) {
X		res = oexpr(t_lex(*++t_wp));
X		if (t_lex(*++t_wp) != RPAREN)
X			syntax();
X		return res;
X	}
X	if (n == OPERAND) {
X		opnd1 = *t_wp;
X		(void) t_lex(*++t_wp);
X		if (t_wp_op && t_wp_op->op_type == BINOP) {
X			struct t_op Const *op = t_wp_op;
X
X			if ((opnd2 = *++t_wp) == (char *)0)
X				syntax();
X			
X			switch (op->op_num) {
X			case STEQL:
X				return strcmp(opnd1, opnd2) == 0;
X			case STNEQ:
X				return strcmp(opnd1, opnd2) != 0;
X			case INTEQ:
X				return evaluate(opnd1) == evaluate(opnd2);
X			case INTNE:
X				return evaluate(opnd1) != evaluate(opnd2);
X			case INTGE:
X				return evaluate(opnd1) >= evaluate(opnd2);
X			case INTGT:
X				return evaluate(opnd1) > evaluate(opnd2);
X			case INTLE:
X				return evaluate(opnd1) <= evaluate(opnd2);
X			case INTLT:
X				return evaluate(opnd1) < evaluate(opnd2);
X			case FILNT:
X				return newerf (opnd1, opnd2);
X			case FILOT:
X				return olderf (opnd1, opnd2);
X			case FILEQ:
X				return equalf (opnd1, opnd2);
X			}
X		}
X		t_wp--;
X		return strlen(opnd1) > 0;
X	}
X	if (t_wp_op->op_type == UNOP) {
X		/* unary expression */
X		if (*++t_wp == NULL && n != FILTT)
X			syntax();
X		switch (n) {
X		  case OPTION:
X			return flag[option(*t_wp)];
X		  case STZER:
X			return strlen(*t_wp) == 0;
X		  case STNZE:
X			return strlen(*t_wp) != 0;
X		  case FILTT:
X			if (!digit(**t_wp))
X				return filstat("0", n);
X		  default:	/* all other FIL* */
X			return filstat(*t_wp, n);
X		}
X	}
X	syntax();
X}
X
Xfilstat(nm, mode)
X	char *nm;
X{
X	struct stat s;
X	
X	switch (mode) {
X	case FILRD:
X		return eaccess(nm, 4) == 0;
X	case FILWR:
X		return eaccess(nm, 2) == 0;
X	case FILEX:
X		return eaccess(nm, 1) == 0;
X	case FILREG:
X		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG;
X	case FILID:
X		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFDIR;
X	case FILCDEV:
X		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFCHR;
X	case FILBDEV:
X		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFBLK;
X	case FILFIFO:
X#ifdef S_IFIFO
X		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFIFO;
X#else
X		return 0;
X#endif
X	case FILSETU:
X		return stat(nm, &s) == 0 && (s.st_mode & S_ISUID) == S_ISUID;
X	case FILSETG:
X		return stat(nm, &s) == 0 && (s.st_mode & S_ISGID) == S_ISGID;
X	case FILSTCK:
X		return stat(nm, &s) == 0 && (s.st_mode & S_ISVTX) == S_ISVTX;
X	case FILGZ:
X		return stat(nm, &s) == 0 && s.st_size > 0L;
X	case FILTT:
X		return isatty(getn(nm));
X	  case FILUID:
X		return stat(nm, &s) == 0 && s.st_uid == geteuid();
X	  case FILGID:
X		return stat(nm, &s) == 0 && s.st_gid == getegid();
X#ifdef S_IFLNK
X	case FILSYM:
X		return lstat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFLNK;
X#endif
X#ifdef S_IFSOCK
X	case FILSOCK:
X		return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK;
X#endif
X	  default:
X		return 1;
X	}
X}
X
Xint
Xt_lex(s)
X	register char *s;
X{
X	register struct t_op Const *op = ops;
X
X	if (s == 0)
X		return EOI;
X	while (op->op_text) {
X		if (strcmp(s, op->op_text) == 0) {
X			t_wp_op = op;
X			return op->op_num;
X		}
X		op++;
X	}
X	t_wp_op = (struct t_op *)0;
X	return OPERAND;
X}
X
Xnewerf (f1, f2)
Xchar *f1, *f2;
X{
X	struct stat b1, b2;
X
X	return (stat (f1, &b1) == 0 &&
X		stat (f2, &b2) == 0 &&
X		b1.st_mtime > b2.st_mtime);
X}
X
Xolderf (f1, f2)
Xchar *f1, *f2;
X{
X	struct stat b1, b2;
X
X	return (stat (f1, &b1) == 0 &&
X		stat (f2, &b2) == 0 &&
X		b1.st_mtime < b2.st_mtime);
X}
X
Xequalf (f1, f2)
Xchar *f1, *f2;
X{
X	struct stat b1, b2;
X
X	return (stat (f1, &b1) == 0 &&
X		stat (f2, &b2) == 0 &&
X		b1.st_dev == b2.st_dev &&
X		b1.st_ino == b2.st_ino);
X}
X
SHAR_EOF
true || echo 'restore of src/c_test.c failed'
fi
# ============= src/getopts.c ==============
if test -f 'src/getopts.c' -a X"$1" != X"-c"; then
	echo 'x - skipping src/getopts.c (File already exists)'
else
echo 'x - extracting src/getopts.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/getopts.c' &&
X/*
X * Reimplementation of SysVr3 sh builtin command "getopts" for S5R2 shell.
X *
X * created by Arnold Robbins
X * modified by Doug Gwyn
X * modified for PD ksh by Eric Gisin
X */
X
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/getopts.c,v 3.2 89/01/14 13:29:26 egisin Exp $";
X
X#include <stddef.h>
X#include <string.h>
X#include <errno.h>
X#include <setjmp.h>
X#include "sh.h"
X#include "table.h"
X
X/*
X * The following is derived from getopt() source placed into the public
X * domain by AT&T (the only time they're known to have done that).
X *
X * It has been modified somewhat to fit into the context of the shell.
X *
X * -D"FASCIST" if you really want to strictly enforce ALL the
X * Command Syntax Standard rules (not recommended).
X */
X
X#define GETOPTEOF	(-1)
X#define ERR(S, C)	shellf("%s%c\n", (S), (C))
X
Xstatic	int	optind;
Xstatic char    *optarg;
Xstatic int	sp;
X
Xstatic int
Xgetopt(argc, argv, opts)
X	int argc;
X	register char **argv, *opts;
X{
X	register int c;
X	register char *cp;
X
X	if (sp == 1)
X		if (optind >= argc ||
X		   argv[optind][0] != '-' || argv[optind][1] == '\0')
X			return(GETOPTEOF);
X		else if (strcmp(argv[optind], "--") == 0) {
X			optind++;
X			return(GETOPTEOF);
X		}
X	c = argv[optind][sp];
X	if (c == ':' || (cp=strchr(opts, c)) == NULL) {
X		ERR("illegal option -- ", c);
X		if (argv[optind][++sp] == '\0') {
X			optind++;
X			sp = 1;
X		}
X		optarg = NULL;
X		return('?');
X	}
X	if (*++cp == ':') {
X#if FASCIST
X		if (sp != 1) {
X			ERR("option must not be grouped -- ", c );
X			optind++;
X			sp = 1;
X			optarg = NULL;
X			return('?');
X		} else
X#endif
X		if (argv[optind][sp+1] != '\0') {
X#if FASCIST
X			ERR("option must be followed by whitespace -- ", c );
X			optind++;
X			sp = 1;
X			optarg = NULL;
X			return('?');
X#else
X			optarg = &argv[optind++][sp+1];
X#endif
X		} else if (++optind >= argc) {
X			ERR("option requires an argument -- ", c);
X			sp = 1;
X			optarg = NULL;
X			return('?');
X		} else
X			optarg = argv[optind++];
X		sp = 1;
X	} else {
X		if (argv[optind][++sp] == '\0') {
X			sp = 1;
X			optind++;
X		}
X		optarg = NULL;
X	}
X	return(c);
X}
X
X/*
X * The following were created by Arnold Robbins.
X */
X
X/* resetopts --- magic code for when OPTIND is reset to 1 */
X
Xvoid
Xresetopts ()
X{
X	optind = 1;
X	sp = 1;
X}
X
Xint
Xc_getopts(wp)
X	char **wp;
X{
X	int ret;
X	register int argc;
X	char temp[2];
X	char *optstr;			/* list of options */
X	char *name;			/* variable to get flag val */
X
X	if ((optstr = *++wp) == NULL || (name = *++wp) == NULL)
X		errorf("missing arguments\n");
X
X	for (argc = 1; wp[argc] != NULL; argc++)
X		;
X
X	if (argc > 1)
X		ret = getopt(argc, wp, optstr);
X	else
X		ret = getopt(e.loc->argc+1, e.loc->argv, optstr);
X
X	/*
X	 * set the OPTIND variable in any case, to handle "--" skipping
X	 */
X
X	setint(global("OPTIND"), (long)optind);
X
X	if (ret == GETOPTEOF)		/* end of args */
X		return (1);
X
X	/*
X	 * else, got an arg, set the various shell variables
X	 */
X
X	if (optarg != NULL)
X		setstr(global("OPTARG"), optarg);
X
X	temp[0] = (char) ret;
X	temp[1] = '\0';
X	setstr(global(name), temp);
X
X	return (0);
X}
X
SHAR_EOF
true || echo 'restore of src/getopts.c failed'
fi
# ============= src/ulimit.c ==============
if test -f 'src/ulimit.c' -a X"$1" != X"-c"; then
	echo 'x - skipping src/ulimit.c (File already exists)'
else
echo 'x - extracting src/ulimit.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/ulimit.c' &&
X/*
X	ulimit -- handle "ulimit" builtin
X
X	Eric Gisin, September 1988
X	Adapted to PD KornShell. Removed AT&T code.
X
X	last edit:	06-Jun-1987	D A Gwyn
X
X	This started out as the BRL UNIX System V system call emulation
X	for 4.nBSD, and was later extended by Doug Kingston to handle
X	the extended 4.nBSD resource limits.  It now includes the code
X	that was originally under case SYSULIMIT in source file "xec.c".
X*/
X
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/ulimit.c,v 3.1 88/11/03 09:18:11 egisin Exp $";
X
X#include <stddef.h>
X#include <errno.h>
X#include <signal.h>
X#include <setjmp.h>
X#if defined(_BSD) || defined(_BSD_SYSV)
X#include <sys/time.h>
X#include <sys/resource.h>
X#else
X#define	RLIMIT_FSIZE	2
X#endif
X#include "sh.h"
X
Xextern	long ulimit();
X
Xint
Xdo_ulimit(a1, a2)
X	char	*a1, *a2;
X{
X	register int	c;
X	long		i;
X#if defined(_BSD) || defined(_BSD_SYSV)
X	struct rlimit	limit;		/* data being gotten/set */
X	int		softonly = 0;	/* set => soft limit, clear => hard limit */
X	int		factor = 1024;	/* unit scaling (1K or 1) */
X#endif
X	int	command = RLIMIT_FSIZE;
X
X	if (a1 && (*a1 == '-'))		/* DAG -- Gould added first test */
X	{	c = *++a1;		/* DAG */
X#if defined(_BSD) || defined(_BSD_SYSV)
X		if (c >= 'A' && c <= 'Z')
X		{
X			++softonly;
X			c += 'a' - 'A';	/* DAG -- map to lower-case */
X		}
X#endif
X		switch(c)
X		{
X#if defined(_BSD) || defined(_BSD_SYSV)
X			case 'c':
X				command = RLIMIT_CORE;
X				break;
X			case 'd':
X				command = RLIMIT_DATA;
X				break;
X			case 'm':
X				command = RLIMIT_RSS;
X				break;
X			case 's':
X				command = RLIMIT_STACK;
X				break;
X			case 't':
X				factor = 1;
X				command = RLIMIT_CPU;
X				break;
X#endif	/* _BSD || _BSD_SYSV */
X			case 'f':
X				command = RLIMIT_FSIZE;
X#if _BSD_SYSV
X				factor = 512;
X#endif
X				break;
X			default:
X#if _BSD
X				errorf("Usage: %s [-cdmstf] [limit]\n", "ulimit");
X#else
X				errorf("Usage: %s [-f] [limit]\n", "ulimit");
X#endif
X		}
X		a1 = a2;
X	}
X	if (a1)
X	{
X		i = 0;
X		while ((c = *a1++) >= '0' && c <= '9')
X		{
X			i = (i * 10) + (long)(c - '0');
X			if (i < 0)
X				goto Error;
X		}
X		if (c || i < 0)
X			goto Error;
X	}
X#if !(defined(_BSD) || defined(_BSD_SYSV))
X	else
X	{
X		i = -1;
X		command--;
X	}
X
X	if ((i = ulimit(command, i)) < 0L)
X		goto Error;
X
X	if (command != RLIMIT_FSIZE)
X		shellf("%ld\n", i);
X#else					/* DPK -- generalized for 4.nBSD: */
X	if (getrlimit(command, &limit))
X		goto Error;	/* errno is already set */
X
X	if (a1)
X	{
X		limit.rlim_cur = i * factor;
X
X		if (!softonly)
X			limit.rlim_max = limit.rlim_cur;
X
X		if (setrlimit(command, &limit))
X			goto Error;
X	}
X	else
X	{
X		i = softonly ? limit.rlim_cur : limit.rlim_max;
X#if _BSD			/* DAG -- System V always prints an integer */
X		if (i == RLIM_INFINITY)
X			shellf("unlimited\n");
X		else
X#endif
X			shellf("%ld\n", i/factor);
X	}
X#endif	/* _BSD || _BSD_SYSV */
X	return 0;
X
X  Error:
X	errorf("bad ulimit\n");
X}
X
SHAR_EOF
true || echo 'restore of src/ulimit.c failed'
fi
# ============= src/var.c ==============
if test -f 'src/var.c' -a X"$1" != X"-c"; then
	echo 'x - skipping src/var.c (File already exists)'
else
echo 'x - extracting src/var.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/var.c' &&
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/var.c,v 3.1 88/11/03 09:18:22 egisin Exp $";
X
X#include <stddef.h>
X#include <string.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <time.h>
X#include "sh.h"
X#include "table.h"
X#include "expand.h"
X
X/*
X * Variables
X *
X * WARNING: unreadable code, needs a rewrite
X *
X * if (flag&INTEGER), val.i contains integer value, and type contains base.
X * otherwise, (val.s + type) contains string value.
X * if (flag&EXPORT), val.s contains "name=value" for E-Z exporting.
X */
Xchar	null []	= "";
Xstatic	struct tbl vtemp;
Xstatic	void getspec(), setspec();
Xstatic	void export ARGS((struct tbl *, char *val));
Xstatic	int special ARGS ((char *name));
X
X/*
X * create a new block for function calls and simple commands
X * assume caller has allocated and set up e.loc
X */
Xvoid
Xnewblock()
X{
X	register struct block *l = e.loc;
X	static char *empty[] = {""};
X
X	ainit(&l->area);
X	l->argc = 0;
X	l->argv = empty;
X	l->exit = l->error = NULL;
X	tinit(&l->vars, &l->area);
X	tinit(&l->funs, &l->area);
X}
X
X/*
X * pop a block handling special variables
X */
Xvoid
Xpopblock()
X{
X	register struct block *l = e.loc;
X	register struct tbl *vp, **vpp = l->vars.tbls;
X	register int i;
X
X	e.loc = l->next;	/* pop block */
X	for (i = l->vars.size; --i >= 0; )
X		if ((vp = *vpp++) != NULL && (vp->flag&SPECIAL))
X			setspec(global(vp->name));
X	afreeall(&l->area);
X}
X
X/*
X * Search for variable, if not found create globally.
X */
Xstruct tbl *
Xglobal(n)
X	register char *n;
X{
X	register struct block *l = e.loc;
X	register struct tbl *vp;
X	register int c;
X	unsigned h = hash(n);
X
X	c = n[0];
X	if (digit(c)) {
X		vp = &vtemp;
X		lastarea = ATEMP;
X		vp->flag = (DEFINED|RDONLY);
X		vp->type = 0;
X		*vp->name = c;	/* should strncpy */
X		for (c = 0; digit(*n) && c < 1000; n++)
X			c = c*10 + *n-'0';
X		if (c <= l->argc)
X			setstr(vp, l->argv[c]);
X		return vp;
X	} else
X	if (!letter(c)) {
X		vp = &vtemp;
X		lastarea = ATEMP;
X		vp->flag = (DEFINED|RDONLY);
X		vp->type = 0;
X		*vp->name = c;
X		if (n[1] != '\0')
X			return vp;
X		vp->flag |= ISSET|INTEGER;
X		switch (c) {
X		  case '$':
X			vp->val.i = getpid();
X			break;
X		  case '!':
X			vp->val.i = async;
X			break;
X		  case '?':
X			vp->val.i = exstat;
X			break;
X		  case '#':
X			vp->val.i = l->argc;
X			break;
X		  case '-':
X			vp->flag &= ~ INTEGER;
X			vp->val.s = getoptions();
X			break;
X		  default:
X			vp->flag &= ~(ISSET|INTEGER);
X		}
X		return vp;
X	}
X	for (l = e.loc; l != NULL; l = l->next) {
X		vp = tsearch(&l->vars, n, h);
X		lastarea = &l->area;
X		if (vp != NULL)
X			return vp;
X		if (l->next == NULL)
X			break;
X	}
X	vp = tenter(&l->vars, n, h);
X	vp->flag |= DEFINED;
X	if (special(n))
X		vp->flag |= SPECIAL;
X	return vp;
X}
X
X/*
X * Search for local variable, if not found create locally.
X */
Xstruct tbl *
Xlocal(n)
X	register char *n;
X{
X	register struct block *l = e.loc;
X	register struct tbl *vp;
X	unsigned h = hash(n);
X
X	if (!letter(*n)) {
X		vp = &vtemp;
X		lastarea = ATEMP;
X		vp->flag = (DEFINED|RDONLY);
X		vp->type = 0;
X		return vp;
X	}
X	vp = tenter(&l->vars, n, h);
X	lastarea = &l->area;
X	vp->flag |= DEFINED;
X	if (special(n))
X		vp->flag |= SPECIAL;
X	return vp;
X}
X
X/* get variable string value */
Xchar *
Xstrval(vp)
X	register struct tbl *vp;
X{
X	register char *s;
X	static char strbuf[40];
X
X	if ((vp->flag&SPECIAL))
X		getspec(vp);
X	if (!(vp->flag&ISSET))
X		return null;	/* special to dollar() */
X	if (!(vp->flag&INTEGER))	/* string source */
X		s = vp->val.s + vp->type;
X	else {				/* integer source */
X		register unsigned long n;
X		register int base;
X
X		s = strbuf + sizeof(strbuf);
X		n = (vp->val.i < 0) ? -vp->val.i : vp->val.i;
X		base = (vp->type == 0) ? 10 : vp->type;
X
X		*--s = '\0';
X		do {
X			*--s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%base];
X			n /= base;
X		} while (n != 0);
X		/* todo: should we output base# ? */
X		if (vp->val.i < 0)
X			*--s = '-';
X	}
X	return s;
X}
X
X/* get variable integer value */
Xlong
Xintval(vp)
X	register struct tbl *vp;
X{
X	register struct tbl *vq;
X
X	if ((vp->flag&SPECIAL))
X		getspec(vp);
X	if ((vp->flag&INTEGER))
X		return vp->val.i;
X	vq = &vtemp;
X	vq->flag = (INTEGER);
X	vq->type = 0;
X	strint(vq, vp);
X	return vq->val.i;
X}
X
X/* set variable to string value */
Xvoid
Xsetstr(vq, s)
X	register struct tbl *vq;
X	char *s;
X{
X	if (!(vq->flag&INTEGER)) { /* string dest */
X		if ((vq->flag&ALLOC))
X			afree((Void*)vq->val.s, lastarea);
X		vq->flag &= ~ (ISSET|ALLOC);
X		vq->type = 0;
X		if ((vq->flag&EXPORT))
X			export(vq, s);
X		else
X			vq->val.s = strsave(s, lastarea);
X		vq->flag |= ALLOC;
X	} else {		/* integer dest */
X		register struct tbl *vp = &vtemp;	
X		vp->flag = (DEFINED|ISSET);
X		vp->type = 0;
X		vp->val.s = s;
X		strint(vq, vp);
X	}
X	vq->flag |= ISSET;
X	if ((vq->flag&SPECIAL))
X		setspec(vq);
X}
X	
X/* convert variable to integer variable */
Xstruct tbl *
Xstrint(vq, vp)
X	register struct tbl *vq, *vp;
X{
X	register char *s = vp->val.s + vp->type;
X	register int c;
X	int base, neg = 0;
X	
X	vq->flag |= INTEGER;
X	if ((vp->flag&INTEGER)) {
X		vq->val.i = vp->val.i;
X		return vq;
X	}
X	vq->val.i = 0;
X	base = 10;
X	for (c = *s++; c ; c = *s++)
X		if (c == '-') {
X			neg++;
X		} else if (c == '#') {
X			base = vq->type = vq->val.i;
X			vq->val.i = 0;
X		} else if (letnum(c)) {
X			if ('0' <= c && c <= '9')
X				c -= '0';
X			else if ('a' <= c && c <= 'z') /* fuck EBCDIC */
X				c -= 'a'-10;
X			else if ('A' <= c && c <= 'Z')
X				c -= 'A'-10;
X			vq->val.i = (vq->val.i*base) + c;
X		} else
X			break;
X	if (neg)
X		vq->val.i = -vq->val.i;
X	if (vq->type < 2 || vq->type > 36)
X		vq->type = 0;	/* default base (10) */
X	return vq;
X}
X
X/* set variable to integer */
Xvoid
Xsetint(vq, n)
X	register struct tbl *vq;
X	long n;
X{
X	if (!(vq->flag&INTEGER)) {
X		register struct tbl *vp = &vtemp;
X		vp->flag = (ISSET|INTEGER);
X		vp->type = 0;
X		vp->val.i = n;
X		setstr(vq, strval(vp));	/* ? */
X	} else
X		vq->val.i = n;
X	vq->flag |= ISSET;
X	if ((vq->flag&SPECIAL))
X		setspec(vq);
X}
X
X/* set variable from enviroment */
Ximport(thing)
X	char *thing;
X{
X	register struct tbl *vp;
X	register char *val;
X
X	val = strchr(thing, '=');
X	if (val == NULL)
X		return 0;
X	*val = '\0';
X	vp = local(thing);
X	*val++ = '=';
X	vp->flag |= DEFINED|ISSET|EXPORT;
X	vp->val.s = thing;
X	vp->type = val - thing;
X	if ((vp->flag&SPECIAL))
X		setspec(vp);
X	return 1;
X}
X
X/*
X * make vp->val.s be "name=value" for quick exporting.
X */
Xstatic void
Xexport(vp, val)
X	register struct tbl *vp;
X	char *val;
X{
X	register char *cp, *xp;
X	char *op = (vp->flag&ALLOC) ? vp->val.s : NULL;
X
X	xp = (char*)alloc(strlen(vp->name) + strlen(val) + 2, lastarea);
X	vp->flag |= ALLOC;
X	vp->val.s = xp;
X	for (cp = vp->name; (*xp = *cp++) != '\0'; xp++)
X		;
X	*xp++ = '=';
X	vp->type = xp - vp->val.s; /* offset to value */
X	for (cp = val; (*xp++ = *cp++) != '\0'; )
X		;
X	if (op != NULL)
X		afree((Void*)op, lastarea);
X}
X
X/*
X * lookup variable (according to (set&LOCAL)),
X * set its attributes (INTEGER, RDONLY, EXPORT, TRACE),
X * and optionally set its value if an assignment.
X */
Xstruct tbl *
Xtypeset(var, set, clr)
X	register char *var;
X	int clr, set;
X{
X	register struct tbl *vp;
X	register char *val;
X
X	/* check for valid variable name, search for value */
X	val = var;
X	if (!letter(*val))
X		return NULL;
X	for (val++; *val != '\0'; val++)
X		if (*val == '=')
X			break;
X		else if (letnum(*val))
X			;
X		else
X			return NULL;
X	if (*val == '=')
X		*val = '\0';
X	else
X		val = NULL;
X	vp = (set&LOCAL) ? local(var) : global(var);
X	set &= ~ LOCAL;
X	if (val != NULL)
X		*val++ = '=';
X
X	if (!(vp->flag&ISSET))
X		vp->flag = vp->flag & ~clr | set;
X	else
X	    if (!(vp->flag&INTEGER) && (set&INTEGER)) {
X		/* string to integer */
X		vtemp.flag = (ISSET);
X		vtemp.type = 0;
X		vtemp.val.s = vp->val.s + vp->type;
X		if ((vp->flag&ALLOC))
X			afree((Void*)vp->val.s, lastarea); /* dangerous, used later */
X		vp->flag &= ~ ALLOC;
X		vp->flag |= INTEGER;
X		vp->type = 0;
X		strint(vp, &vtemp);
X	    } else
X	    if ((clr&INTEGER) && (vp->flag&INTEGER)) {
X		/* integer to string */
X		vtemp.val.s = strval(vp);
X		vp->flag &= ~ INTEGER;
X		setstr(vp, vtemp.val.s);
X	    }
X
X	vp->flag = vp->flag & ~clr | set;
X
X	if (val != NULL) {
X		if ((vp->flag&RDONLY))
X			errorf("cannot set readonly %s\n", var);
X		if ((vp->flag&INTEGER))
X			/* setstr should be able to handle this */
X			(void)evaluate(var);
X		else
X			setstr(vp, val);
X	}
X
X	if ((vp->flag&EXPORT) && !(vp->flag&INTEGER) && vp->type == 0)
X		export(vp, (vp->flag&ISSET) ? vp->val.s : null);
X
X	return vp;
X}
X
Xvoid
Xunset(vp)
X	register struct tbl *vp;
X{
X	if ((vp->flag&ALLOC))
X		afree((Void*)vp->val.s, lastarea);
X	vp->flag &= ~ (ALLOC|ISSET);
X}
X
Xint
Xisassign(s)
X	register char *s;
X{
X	if (!letter(*s))
X		return (0);
X	for (s++; *s != '='; s++)
X		if (*s == 0 || !letnum(*s))
X			return (0);
X	return (1);
X}
X
X/*
X * Make the exported environment from the exported names in the dictionary.
X */
Xchar **
Xmakenv()
X{
X	struct block *l = e.loc;
X	XPtrV env;
X	register struct tbl *vp, **vpp;
X	register int i;
X
X	XPinit(env, 64);
X	for (l = e.loc; l != NULL; l = l->next)
X		for (vpp = l->vars.tbls, i = l->vars.size; --i >= 0; )
X			if ((vp = *vpp++) != NULL
X			    && (vp->flag&(ISSET|EXPORT)) == (ISSET|EXPORT)) {
X				register struct block *l2;
X				register struct tbl *vp2;
X				unsigned h = hash(vp->name);
X
X				lastarea = &l->area;
X
X				/* unexport any redefined instances */
X				for (l2 = l->next; l2 != NULL; l2 = l2->next) {
X					vp2 = tsearch(&l2->vars, vp->name, h);
X					if (vp2 != NULL)
X						vp2->flag &= ~ EXPORT;
X				}
X				if ((vp->flag&INTEGER)) {
X					/* integer to string */
X					char *val;
X					val = strval(vp);
X					vp->flag &= ~ INTEGER;
X					setstr(vp, val);
X				}
X				XPput(env, vp->val.s);
X			}
X	XPput(env, NULL);
X	return (char **) XPclose(env);
X}
X
X/*
X * handle special variables with side effects - PATH, SECONDS.
X */
X
Xstatic int
Xspecial(name)
X	register char * name;
X{
X	if (strcmp("PATH", name) == 0)
X		return V_PATH;
X	if (strcmp("IFS", name) == 0)
X		return V_IFS;
X	if (strcmp("SECONDS", name) == 0)
X		return V_SECONDS;
X	if (strcmp("OPTIND", name) == 0)
X		return V_OPTIND;
X	return V_NONE;
X}
X
Xextern	time_t time();
Xstatic	time_t	seconds;		/* time SECONDS last set */
X
Xstatic void
Xgetspec(vp)
X	register struct tbl *vp;
X{
X	switch (special(vp->name)) {
X	case V_SECONDS:
X		vp->flag &= ~ SPECIAL;
X		setint(vp, time((time_t *)0) - seconds);
X		vp->flag |= SPECIAL;
X		break;
X	}
X}
X
Xstatic void
Xsetspec(vp)
X	register struct tbl *vp;
X{
X	switch (special(vp->name)) {
X	  case V_PATH:
X		path = strval(vp);
X		flushcom(1);	/* clear tracked aliases */
X		break;
X	  case V_IFS:
X		setctypes(strval(vp), C_IFS);
X		break;
X	  case V_SECONDS:
X		seconds = time((time_t *)0);
X		break;
X	  case V_OPTIND:
X		if (intval(vp) == 1)
X			resetopts();
X		break;
X	}
X}
X
SHAR_EOF
true || echo 'restore of src/var.c failed'
fi
# ============= src/table.c ==============
if test -f 'src/table.c' -a X"$1" != X"-c"; then
	echo 'x - skipping src/table.c (File already exists)'
else
echo 'x - extracting src/table.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/table.c' &&
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/table.c,v 3.1 88/11/03 09:17:53 egisin Exp $";
X
X/*
X * dynamic hashed associative table for commands and variables
X */
X
X#include <stddef.h>
X#include <errno.h>
X#include <setjmp.h>
X#include "sh.h"
X#include "table.h"
X
X#define	INIT_TBLS	8	/* initial table size (power of 2) */
X
Xstatic struct tstate {
X	int left;
X	struct tbl **next;
X} tstate;
X
Xstatic void texpand();
X
Xunsigned int
Xhash(n)
X	register char * n;
X{
X	register unsigned int h = 0;
X
X	while (*n != '\0')
X		h = 2*h + *n++;
X	return h * 32821;	/* scatter bits */
X}
X
X#if 0
Xphash(s) char *s; {
X	printf("%2d: %s\n", hash(s)%32, s);
X}
X#endif
X
Xvoid
Xtinit(tp, ap)
X	register struct table *tp;
X	register Area *ap;
X{
X	tp->areap = ap;
X	tp->size = tp->free = 0;
X	tp->tbls = NULL;
X}
X
Xstatic void
Xtexpand(tp, nsize)
X	register struct table *tp;
X	int nsize;
X{
X	register int i;
X	register struct tbl *tblp, **p;
X	register struct tbl **ntblp, **otblp = tp->tbls;
X	int osize = tp->size;
X
X	ntblp = alloc(sizeofN(struct tbl *, nsize), tp->areap);
X	for (i = 0; i < nsize; i++)
X		ntblp[i] = NULL;
X	tp->size = nsize;
X	tp->free = 8*nsize/10;	/* table can get 80% full */
X	tp->tbls = ntblp;
X	if (otblp == NULL)
X		return;
X	for (i = 0; i < osize; i++)
X		if ((tblp = otblp[i]) != NULL)
X			if ((tblp->flag&DEFINED)) {
X				for (p = &ntblp[hash(tblp->name) & tp->size-1];
X				     *p != NULL; p--)
X					if (p == ntblp) /* wrap */
X						p += tp->size;
X				*p = tblp;
X				tp->free--;
X			} else {
X				afree((Void*)tblp, tp->areap);
X			}
X	afree((Void*)otblp, tp->areap);
X}
X
Xstruct tbl *
Xtsearch(tp, n, h)
X	register struct table *tp;	/* table */
X	register char *n;		/* name to enter */
X	unsigned int h;			/* hash(n) */
X{
X	register struct tbl **pp, *p;
X
X	if (tp->size == 0)
X		return NULL;
X
X	/* search for name in hashed table */
X	for (pp = &tp->tbls[h & tp->size-1]; (p = *pp) != NULL; pp--) {
X		if (*p->name == *n && strcmp(p->name, n) == 0
X		    && (p->flag&DEFINED))
X			return p;
X		if (pp == tp->tbls) /* wrap */
X			pp += tp->size;
X	}
X
X	return NULL;
X}
X
Xstruct tbl *
Xtenter(tp, n, h)
X	register struct table *tp;	/* table */
X	register char *n;		/* name to enter */
X	unsigned int h;			/* hash(n) */
X{
X	register struct tbl **pp, *p;
X	register char *cp;
X
X	if (tp->size == 0)
X		texpand(tp, INIT_TBLS);
X  Search:
X	/* search for name in hashed table */
X	for (pp = &tp->tbls[h & tp->size-1]; (p = *pp) != NULL; pp--) {
X		if (*p->name == *n && strcmp(p->name, n) == 0)
X			return p; 	/* found */
X		if (pp == tp->tbls) /* wrap */
X			pp += tp->size;
X	}
X
X	if (tp->free <= 0) {	/* too full */
X		texpand(tp, 2*tp->size);
X		goto Search;
X	}
X
X	/* create new tbl entry */
X	for (cp = n; *cp != '\0'; cp++)
X		;
X	p = (struct tbl *) alloc(offsetof(struct tbl, name[(cp-n)+1]), tp->areap);
X	p->flag = 0;
X	p->type = 0;
X	for (cp = p->name; *n != '\0';)
X		*cp++ = *n++;
X	*cp = '\0';
X
X	/* enter in tp->tbls */
X	tp->free--;
X	*pp = p;
X	return p;
X}
X
Xvoid
Xtdelete(p)
X	register struct tbl *p;
X{
X	p->flag = 0;
X}
X
Xvoid
Xtwalk(tp)
X	register struct table *tp;
X{
X	tstate.left = tp->size;
X	tstate.next = tp->tbls;
X}
X
Xstruct tbl *
Xtnext()
X{
X	while (--tstate.left >= 0) {
X		struct tbl *p = *tstate.next++;
X		if (p != NULL && (p->flag&DEFINED))
X			return p;
X	}
X	return NULL;
X}
X
Xstatic int
Xtnamecmp(p1, p2)
X	Void *p1, *p2;
X{
X	return strcmp(((struct tbl *)p1)->name, ((struct tbl *)p2)->name);
X}
X
Xstruct tbl **
Xtsort(tp)
X	register struct table *tp;
X{
X	register int i;
X	register struct tbl **p, **sp, **dp;
X
X	p = (struct tbl **)alloc(sizeofN(struct tbl *, tp->size+1), ATEMP);
X	sp = tp->tbls;		/* source */
X	dp = p;			/* dest */
X	for (i = 0; i < tp->size; i++)
X		if ((*dp = *sp++) != NULL && ((*dp)->flag&DEFINED))
X			dp++;
X	i = dp - p;
X	qsortp((Void**)p, (size_t)i, tnamecmp);
X	p[i] = NULL;
X	return p;
X}
X
SHAR_EOF
true || echo 'restore of src/table.c failed'
fi
true || echo 'restore of src/eval.c failed'
echo End of part 5, continue with part 6
exit 0



More information about the Alt.sources mailing list