Public Domain Korn Shell - Part.04 of 7
USENET Administration
netnews at netcom.UUCP
Wed Dec 12 22:37:20 AEST 1990
#!/bin/sh
# This is part 04 of ksh-pd
# ============= src/tree.c ==============
if test ! -d 'src'; then
echo 'x - creating directory src'
mkdir 'src'
fi
if test -f 'src/tree.c' -a X"$1" != X"-c"; then
echo 'x - skipping src/tree.c (File already exists)'
else
echo 'x - extracting src/tree.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/tree.c' &&
X/*
X * command tree climbing
X */
X
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/tree.c,v 3.1 88/11/03 09:18:05 egisin Exp $";
X
X#include <stddef.h>
X#include <string.h>
X#include <stdio.h>
X#include <errno.h>
X#include <setjmp.h>
X#include <varargs.h>
X#include "sh.h"
X#include "tree.h"
X
X#define FSTRING (FILE*)NULL
X
Xstatic int tputc ARGS((int c, FILE *f));
Xstatic void tputC ARGS((int c, FILE *f));
Xstatic void tputS ARGS((char *wp, FILE *f));
X
X/*
X * print a command tree
X */
X
Xvoid
Xptree(t, f)
X register struct op *t;
X register FILE *f;
X{
X register char **w;
X struct ioword **ioact;
X struct op *t1;
X
X Chain:
X if (t == NULL)
X return;
X switch (t->type) {
X case TCOM:
X for (w = t->vars; *w != NULL; )
X fptreef(f, "%S ", *w++);
X for (w = t->args; *w != NULL; )
X fptreef(f, "%S ", *w++);
X break;
X case TEXEC:
X t = t->left;
X goto Chain;
X case TPAREN:
X fptreef(f, "(%T)", t->left);
X break;
X case TPIPE:
X fptreef(f, "%T | ", t->left);
X t = t->right;
X goto Chain;
X case TLIST:
X fptreef(f, "%T%;", t->left);
X t = t->right;
X goto Chain;
X case TOR:
X case TAND:
X fptreef(f, "%T %s %T",
X t->left, (t->type==TOR) ? "||" : "&&", t->right);
X break;
X case TFOR:
X fptreef(f, "for %s ", t->str);
X if (t->vars != NULL) {
X fptreef(f, "in ");
X for (w = t->vars; *w; )
X fptreef(f, "%S ", *w++);
X fptreef(f, "%;");
X }
X fptreef(f, "do %T%;done ", t->left);
X break;
X case TCASE:
X fptreef(f, "case %S in%;", t->str);
X for (t1 = t->left; t1 != NULL; t1 = t1->right) {
X fptreef(f, "(");
X for (w = t1->vars; *w != NULL; w++)
X fptreef(f, "%S%c", *w, (w[1] != NULL) ? '|' : ')');
X fptreef(f, " %T;;%;", t1->left);
X }
X fptreef(f, "esac ");
X break;
X case TIF:
X fptreef(f, "if %T%;", t->left);
X t = t->right;
X if (t->left != NULL)
X fptreef(f, "then %T%;", t->left);
X if (t->right != NULL)
X fptreef(f, "else %T%;", t->right);
X fptreef(f, "fi ");
X break;
X case TWHILE:
X case TUNTIL:
X fptreef(f, "%s %T%;do %T%;done ",
X (t->type==TWHILE) ? "while" : "until",
X t->left, t->right);
X break;
X case TBRACE:
X fptreef(f, "{%;%T%;} ", t->left);
X break;
X case TASYNC:
X fptreef(f, "%T &", t->left);
X break;
X case TFUNCT:
X fptreef(f, "function %s %T", t->str, t->left);
X break;
X case TTIME:
X fptreef(f, "time %T", t->left);
X break;
X default:
X fptreef(f, "<botch>");
X break;
X }
X if ((ioact = t->ioact) != NULL)
X while (*ioact != NULL)
X pioact(f, *ioact++);
X}
X
Xpioact(f, iop)
X register FILE *f;
X register struct ioword *iop;
X{
X fptreef(f, "%c><%S ", '0' + iop->unit, iop->name); /* todo: fix */
X}
X
X
X/*
X * variants of fputc, fputs for ptreef and snptreef
X */
X
Xstatic char *snpf_s; /* snptreef string */
Xstatic int snpf_n; /* snptreef length */
X
Xstatic int
Xtputc(c, f)
X int c;
X register FILE *f;
X{
X if (f != NULL)
X putc(c, f);
X else
X if (--snpf_n >= 0)
X *snpf_s++ = c;
X return c;
X}
X
Xstatic void
XtputC(c, f)
X register int c;
X register FILE *f;
X{
X if ((c&0x60) == 0) { /* C0|C1 */
X tputc((c&0x80) ? '$' : '^', f);
X tputc((c&0x7F|0x40), f);
X } else if ((c&0x7F) == 0x7F) { /* DEL */
X tputc((c&0x80) ? '$' : '^', f);
X tputc('?', f);
X } else
X tputc(c, f);
X}
X
Xstatic void
XtputS(wp, f)
X register char *wp;
X register FILE *f;
X{
X register int c;
X
X while (1)
X switch ((c = *wp++)) {
X case EOS:
X return;
X case CHAR:
X tputC(*wp++, f);
X break;
X case QCHAR:
X tputc('\\', f);
X tputC(*wp++, f);
X break;
X case OQUOTE:
X case CQUOTE:
X tputc('"', f);
X break;
X case OSUBST:
X tputc('$', f);
X tputc('{', f);
X while ((c = *wp++) != 0)
X tputc(c, f);
X if (*wp != CSUBST)
X tputC(*wp++, f);
X break;
X case CSUBST:
X tputc('}', f);
X break;
X case COMSUB:
X tputc('$', f);
X tputc('(', f);
X while (*wp != 0)
X tputC(*wp++, f);
X tputc(')', f);
X break;
X }
X}
X
X/* TODO: use varargs properly */
X
X/* VARARGS */ int
Xfptreef(f, va_alist) va_dcl
X register FILE *f;
X{
X va_list va;
X char *fmt;
X
X va_start(va);
X fmt = va_arg(va, char *);
X vfptreef(f, fmt, va);
X va_end(va);
X return 0;
X}
X
X/* VARARGS */ int
Xsnptreef(s, n, va_alist) va_dcl
X char *s;
X int n;
X{
X va_list va;
X char *fmt;
X
X snpf_s = s;
X snpf_n = n;
X va_start(va);
X fmt = va_arg(va, char *);
X vfptreef(FSTRING, fmt, va);
X tputc('\0', FSTRING);
X va_end(va);
X return 0;
X}
X
Xvfptreef(f, fmt, va)
X register FILE *f;
X register char *fmt;
X register va_list va;
X{
X register int c;
X
X while ((c = *fmt++))
X if (c == '%') {
X register long n;
X register char *p;
X int neg;
X
X switch ((c = *fmt++)) {
X case 'c':
X tputc(va_arg(va, int), f);
X break;
X case 's':
X p = va_arg(va, char *);
X while (*p)
X tputc(*p++, f);
X break;
X case 'S': /* word */
X p = va_arg(va, char *);
X tputS(p, f);
X break;
X case 'd': case 'u': /* decimal */
X n = (c == 'd') ? va_arg(va, int) : va_arg(va, unsigned int);
X neg = c=='d' && n<0;
X p = ulton((neg) ? -n : n, 10);
X if (neg)
X *--p = '-';
X while (*p)
X tputc(*p++, f);
X break;
X case 'T': /* format tree */
X ptree(va_arg(va, struct op *), f);
X break;
X case ';': /* newline or ; */
X p = (f == FSTRING) ? "; " : "\n";
X while (*p)
X tputc(*p++, f);
X break;
X default:
X tputc(c, f);
X break;
X }
X } else
X tputc(c, f);
X}
X
X/*
X * copy tree (for function definition)
X */
X
Xstatic struct ioword **iocopy();
X
Xstruct op *
Xtcopy(t, ap)
X register struct op *t;
X Area *ap;
X{
X register struct op *r;
X register char **tw, **rw;
X
X if (t == NULL)
X return NULL;
X
X r = (struct op *) alloc(sizeof(struct op), ap);
X
X r->type = t->type;
X
X /* this will copy function and for identifiers quite accidently */
X r->str = (t->str == NULL) ? NULL : wdcopy(t->str, ap);
X
X if (t->vars == NULL)
X r->vars = NULL;
X else {
X for (tw = t->vars; *tw++ != NULL; )
X ;
X rw = r->vars = (char **)
X alloc((int)(tw - t->vars) * sizeof(*tw), ap);
X for (tw = t->vars; *tw != NULL; )
X *rw++ = wdcopy(*tw++, ap);
X *rw = NULL;
X }
X
X if (t->args == NULL)
X r->args = NULL;
X else {
X for (tw = t->args; *tw++ != NULL; )
X ;
X rw = r->args = (char **)
X alloc((int)(tw - t->args) * sizeof(*tw), ap);
X for (tw = t->args; *tw != NULL; )
X *rw++ = wdcopy(*tw++, ap);
X *rw = NULL;
X }
X
X r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
X
X r->left = tcopy(t->left, ap);
X r->right = tcopy(t->right, ap);
X
X return r;
X}
X
Xchar *
Xwdcopy(wp, ap)
X char *wp;
X Area *ap;
X{
X size_t len = wdscan(wp, EOS) - wp;
X return memcpy(alloc(len, ap), wp, len);
X}
X
X/* return the position of prefix c in wp plus 1 */
Xchar *
Xwdscan(wp, c)
X register char *wp;
X register int c;
X{
X register int nest = 0;
X
X while (1)
X switch (*wp++) {
X case EOS:
X return wp;
X case CHAR:
X case QCHAR:
X wp++;
X break;
X case OQUOTE:
X case CQUOTE:
X break;
X case OSUBST:
X nest++;
X while (*wp++ != 0)
X ;
X if (*wp != CSUBST)
X wp++;
X break;
X case CSUBST:
X if (c == CSUBST && nest == 0)
X return wp;
X nest--;
X break;
X case COMSUB:
X while (*wp++ != 0)
X ;
X break;
X }
X}
X
Xstatic struct ioword **
Xiocopy(iow, ap)
X register struct ioword **iow;
X Area *ap;
X{
X register struct ioword **ior;
X register int i;
X
X for (ior = iow; *ior++ != NULL; )
X ;
X ior = (struct ioword **) alloc((int)(ior - iow) * sizeof(*ior), ap);
X
X for (i = 0; iow[i] != NULL; i++) {
X register struct ioword *p, *q;
X
X p = iow[i];
X q = (struct ioword *) alloc(sizeof(*p), ap);
X ior[i] = q;
X *q = *p;
X if (p->name != NULL)
X q->name = wdcopy(p->name, ap);
X }
X ior[i] = NULL;
X
X return ior;
X}
X
X/*
X * free tree (for function definition)
X */
X
Xstatic void iofree();
X
Xvoid
Xtfree(t, ap)
X register struct op *t;
X Area *ap;
X{
X register char **w;
X
X if (t == NULL)
X return;
X
X if (t->str != NULL)
X afree((Void*)t->str, ap);
X
X if (t->vars != NULL) {
X for (w = t->vars; *w != NULL; w++)
X afree((Void*)*w, ap);
X afree((Void*)t->vars, ap);
X }
X
X if (t->args != NULL) {
X for (w = t->args; *w != NULL; w++)
X afree((Void*)*w, ap);
X afree((Void*)t->args, ap);
X }
X
X if (t->ioact != NULL)
X iofree(t->ioact, ap);
X
X tfree(t->left, ap);
X tfree(t->right, ap);
X
X afree((Void*)t, ap);
X}
X
Xstatic void
Xiofree(iow, ap)
X struct ioword **iow;
X Area *ap;
X{
X register struct ioword **iop;
X register struct ioword *p;
X
X for (iop = iow; (p = *iop++) != NULL; ) {
X if (p->name != NULL)
X afree((Void*)p->name, ap);
X afree((Void*)p, ap);
X }
X}
X
SHAR_EOF
true || echo 'restore of src/tree.c failed'
fi
# ============= src/exec.c ==============
if test -f 'src/exec.c' -a X"$1" != X"-c"; then
echo 'x - skipping src/exec.c (File already exists)'
else
echo 'x - extracting src/exec.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/exec.c' &&
X/*
X * execute command tree
X */
X
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/exec.c,v 3.3 88/12/17 21:19:29 egisin Exp $";
X
X#include <stddef.h>
X#include <stdio.h>
X#include <string.h>
X#include <errno.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <unistd.h>
X#include <fcntl.h>
X#include "sh.h"
X#include "lex.h"
X#include "tree.h"
X#include "table.h"
X
Xstatic int comexec ARGS((struct op *t, char **vp, char **ap, int flags));
Xstatic void iosetup ARGS((struct ioword *iop));
Xstatic void echo ARGS((char **, char **));
Xstatic int herein ARGS((char *name, int sub));
X
X/*
X * execute command tree
X */
Xint
Xexecute(t, flags)
X register struct op *t;
X Volatile int flags; /* if XEXEC don't fork */
X{
X int i;
X int Volatile rv = 0;
X int pv[2];
X register char **ap;
X char *s, *cp;
X struct ioword **iowp;
X
X if (t == NULL)
X return 0;
X
X if ((flags&XFORK) && !(flags&XEXEC) && t->type != TPIPE)
X return exchild(t, flags); /* run in sub-process */
X
X newenv(E_EXEC);
X if (trap)
X runtraps();
X
X if (t->ioact != NULL || t->type == TPIPE) {
X e.savefd = alloc(sizeofN(short, NUFILE), ATEMP);
X for (i = 0; i < NUFILE; i++)
X e.savefd[i] = 0; /* not redirected */
X }
X
X /* do redirection, to be restored in quitenv() */
X if (t->ioact != NULL)
X for (iowp = t->ioact; *iowp != NULL; iowp++) {
X if ((flags&XPIPEI) && (*iowp)->unit == 0 ||
X (flags&XPIPEO) && (*iowp)->unit == 1)
X errorf("attempt to redirect fd 0/1 in pipe\n");
X iosetup(*iowp);
X }
X
X switch(t->type) {
X case TCOM:
X e.type = E_TCOM;
X rv = comexec(t, eval(t->vars, DOTILDE),
X eval(t->args, DOBLANK|DOGLOB|DOTILDE), flags);
X break;
X
X case TPAREN:
X rv = execute(t->left, flags|XFORK);
X break;
X
X case TPIPE:
X flags |= XFORK;
X e.savefd[0] = savefd(0);
X e.savefd[1] = savefd(1);
X flags |= XPIPEO;
X (void) dup2(e.savefd[0], 0); /* stdin of first */
X while (t->type == TPIPE) {
X openpipe(pv);
X (void) dup2(pv[1], 1); /* stdout of curr */
X exchild(t->left, flags);
X (void) dup2(pv[0], 0); /* stdin of next */
X closepipe(pv);
X flags |= XPIPEI;
X t = t->right;
X }
X flags &= ~ XPIPEO;
X (void) dup2(e.savefd[1], 1); /* stdout of last */
X exchild(t, flags);
X (void) dup2(e.savefd[0], 0); /* close pipe in */
X rv = waitlast();
X break;
X
X case TLIST:
X while (t->type == TLIST) {
X execute(t->left, 0);
X t = t->right;
X }
X rv = execute(t, 0);
X break;
X
X case TASYNC:
X rv = execute(t->left, flags|XBGND|XFORK);
X break;
X
X case TOR:
X case TAND:
X rv = execute(t->left, 0);
X if (t->right != NULL && (rv == 0) == (t->type == TAND))
X rv = execute(t->right, 0);
X break;
X
X case TFOR:
X e.type = E_LOOP;
X ap = (t->vars != NULL) ?
X eval(t->vars, DOBLANK|DOGLOB|DOTILDE) : e.loc->argv + 1;
X while ((i = setjmp(e.jbuf)))
X if (i == LBREAK)
X goto Break1;
X while (*ap != NULL) {
X setstr(global(t->str), *ap++);
X rv = execute(t->left, 0);
X }
X Break1:
X break;
X
X case TWHILE:
X case TUNTIL:
X e.type = E_LOOP;
X while ((i = setjmp(e.jbuf)))
X if (i == LBREAK)
X goto Break2;
X while ((execute(t->left, 0) == 0) == (t->type == TWHILE))
X rv = execute(t->right, 0);
X Break2:
X break;
X
X case TIF:
X case TELIF:
X if (t->right == NULL)
X break; /* should be error */
X rv = execute(t->left, 0) == 0 ?
X execute(t->right->left, 0) :
X execute(t->right->right, 0);
X break;
X
X case TCASE:
X cp = evalstr(t->str, 0);
X for (t = t->left; t != NULL && t->type == TPAT; t = t->right)
X for (ap = t->vars; *ap; ap++)
X if ((s = evalstr(*ap, DOPAT)) && gmatch(cp, s))
X goto Found;
X break;
X Found:
X rv = execute(t->left, 0);
X break;
X
X case TBRACE:
X rv = execute(t->left, 0);
X break;
X
X case TFUNCT:
X rv = define(t->str, t->left);
X break;
X
X case TTIME:
X rv = timex(t, flags);
X break;
X
X case TEXEC: /* an eval'd TCOM */
X s = t->args[0];
X ap = makenv();
X#if _MINIX /* no F_SETFD close-on-exec */
X for (i = 10; i < 20; i++)
X close(i);
X#endif
X execve(t->str, t->args, ap);
X if (errno == ENOEXEC) {
X *t->args-- = t->str;
X *t->args = s;
X execve(SHELL, t->args, ap);
X errorf("No shell\n");
X }
X errorf("%s: %s\n", s, strerror(errno));
X }
X
X quitenv(); /* restores IO */
X if (e.interactive) { /* flush stdout, shlout */
X fflush(shf[1]);
X fflush(shf[2]);
X }
X if ((flags&XEXEC))
X exit(rv); /* exit child */
X return rv;
X}
X
X/*
X * execute simple command
X */
X
Xstatic int
Xcomexec(t, vp, ap, flags)
X struct op *t;
X register char **ap, **vp;
X int flags;
X{
X int i;
X int rv = 0;
X register char *cp;
X register struct tbl *tp = NULL;
X register struct block *l;
X static struct op texec = {TEXEC};
X extern int c_exec(), c_builtin();
X
X if (flag[FXTRACE])
X echo(vp, ap);
X
X /* create new variable/function block */
X l = alloc(sizeof(struct block), ATEMP);
X l->next = e.loc; e.loc = l;
X newblock();
X
X Doexec:
X if ((cp = *ap) == NULL)
X cp = ":";
X tp = findcom(cp, 1);
X
X switch (tp->type) {
X case CSHELL: /* shell built-in */
X while (tp->val.f == c_builtin) {
X if ((cp = *++ap) == NULL)
X break;
X tp = tsearch(&builtins, cp, hash(cp));
X if (tp == NULL)
X errorf("%s: not builtin\n", cp);
X }
X if (tp->val.f == c_exec) {
X if (*++ap == NULL) {
X e.savefd = NULL; /* don't restore redirection */
X break;
X }
X flags |= XEXEC;
X goto Doexec;
X }
X if ((tp->flag&TRACE))
X e.loc = l->next; /* no local block */
X i = (tp->flag&TRACE) ? 0 : LOCAL;
X while (*vp != NULL)
X (void) typeset(*vp++, i, 0);
X rv = (*tp->val.f)(ap);
X break;
X
X case CFUNC: /* function call */
X if (!(tp->flag&ISSET))
X errorf("%s: undefined function", cp);
X l->argv = ap;
X for (i = 0; *ap++ != NULL; i++)
X ;
X l->argc = i - 1;
X resetopts();
X while (*vp != NULL)
X (void) typeset(*vp++, LOCAL, 0);
X e.type = E_FUNC;
X if (setjmp(e.jbuf))
X rv = exstat; /* return # */
X else
X rv = execute(tp->val.t, 0);
X break;
X
X case CEXEC: /* executable command */
X if (!(tp->flag&ISSET)) {
X shellf("%s: not found\n", cp);
X rv = 1;
X break;
X }
X
X /* set $_ to program's full path */
X setstr(typeset("_", LOCAL|EXPORT, 0), tp->val.s);
X while (*vp != NULL)
X (void) typeset(*vp++, LOCAL|EXPORT, 0);
X
X if ((flags&XEXEC)) {
X j_exit();
X if (flag[FMONITOR] || !(flags&XBGND)) {
X signal(SIGINT, SIG_DFL);
X signal(SIGQUIT, SIG_DFL);
X }
X }
X
X /* to fork we set up a TEXEC node and call execute */
X texec.left = t; /* for tprint */
X texec.str = tp->val.s;
X texec.args = ap;
X rv = exchild(&texec, flags);
X break;
X }
X if (rv != 0 && flag[FERREXIT])
X leave(rv);
X return (exstat = rv);
X}
X
Xint
Xshcomexec(wp)
X register char **wp;
X{
X register struct tbl *tp;
X
X tp = tsearch(&builtins, *wp, hash(*wp));
X if (tp == NULL)
X errorf("%s: shcomexec botch\n", *wp);
X return (*tp->val.f)(wp);
X}
X
X/*
X * define function
X */
Xint
Xdefine(name, t)
X char *name;
X struct op *t;
X{
X register struct block *l;
X register struct tbl *tp;
X
X for (l = e.loc; l != NULL; l = l->next) {
X lastarea = &l->area;
X tp = tsearch(&l->funs, name, hash(name));
X if (tp != NULL && (tp->flag&DEFINED))
X break;
X if (l->next == NULL) {
X tp = tenter(&l->funs, name, hash(name));
X tp->flag = DEFINED|FUNCT;
X tp->type = CFUNC;
X }
X }
X
X if ((tp->flag&ALLOC))
X tfree(tp->val.t, lastarea);
X tp->flag &= ~(ISSET|ALLOC);
X
X if (t == NULL) /* undefine */
X return 0;
X
X tp->val.t = tcopy(t, lastarea);
X tp->flag |= (ISSET|ALLOC);
X
X return 0;
X}
X
X/*
X * add builtin
X */
Xbuiltin(name, func)
X char *name;
X int (*func)();
X{
X register struct tbl *tp;
X int flag = DEFINED;
X
X if (*name == '=') { /* sets keyword variables */
X name++;
X flag |= TRACE; /* command does variable assignment */
X }
X
X tp = tenter(&builtins, name, hash(name));
X tp->flag |= flag;
X tp->type = CSHELL;
X tp->val.f = func;
X}
X
X/*
X * find command
X * either function, hashed command, or built-in (in that order)
X */
Xstruct tbl *
Xfindcom(name, insert)
X char *name;
X int insert; /* insert if not found */
X{
X register struct block *l = e.loc;
X unsigned int h = hash(name);
X register struct tbl *tp = NULL;
X static struct tbl temp;
X
X if (strchr(name, '/') != NULL) {
X tp = &temp;
X tp->type = CEXEC;
X tp->flag = 0; /* make ~ISSET */
X goto Search;
X }
X for (l = e.loc; l != NULL; l = l->next) {
X tp = tsearch(&l->funs, name, h);
X if (tp != NULL && (tp->flag&DEFINED))
X break;
X }
X if (tp == NULL)
X tp = tsearch(&commands, name, h);
X if (tp == NULL)
X tp = tsearch(&builtins, name, h);
X if (tp == NULL && insert) {
X tp = tenter(&commands, name, h);
X tp->type = CEXEC;
X tp->flag = DEFINED;
X }
X Search:
X if (tp->type == CEXEC && !(tp->flag&ISSET)) {
X if (!flag[FHASHALL]) {
X tp = &temp;
X tp->type = CEXEC;
X tp->flag = 0; /* make ~ISSET */
X }
X name = search(name, path, 1);
X if (name != NULL) {
X tp->val.s = strsave(name,
X (tp == &temp) ? ATEMP : APERM);
X tp->flag |= ISSET|ALLOC;
X }
X }
X return tp;
X}
X
X/*
X * flush executable commands with relative paths
X */
Xflushcom(all)
X int all; /* just relative or all */
X{
X register struct tbl *tp;
X
X for (twalk(&commands); (tp = tnext()) != NULL; )
X if ((tp->flag&ISSET) && (all || tp->val.s[0] != '/')) {
X if ((tp->flag&ALLOC))
X afree(tp->val.s, commands.areap);
X tp->flag = DEFINED; /* make ~ISSET */
X }
X}
X
X/*
X * search for command with PATH
X */
Xchar *
Xsearch(name, path, mode)
X char *name, *path;
X int mode; /* 0: readable; 1: executable */
X{
X register int i;
X register char *sp, *tp;
X
X if (strchr(name, '/'))
X return (eaccess(name, mode) == 0) ? name : NULL;
X
X sp = path;
X do {
X tp = line;
X for (; *sp != '\0'; tp++)
X if ((*tp = *sp++) == ':')
X break;
X if (tp != line)
X *tp++ = '/';
X for (i = 0; (*tp++ = name[i++]) != '\0';)
X ;
X i = eaccess(line, mode);
X if (i == 0)
X return line;
X /* what should we do about EACCES? */
X } while (*sp != '\0');
X return NULL;
X}
X
X/*
X * set up redirection, saving old fd's in e.savefd
X */
Xstatic void
Xiosetup(iop)
X register struct ioword *iop;
X{
X register int u = -1;
X char *cp = iop->name;
X extern long lseek();
X
X if (iop->unit == 0 || iop->unit == 1 || iop->unit == 2)
X e.interactive = 0;
X e.savefd[iop->unit] = savefd(iop->unit);
X
X if ((iop->flag&IOTYPE) != IOHERE)
X cp = evalstr(cp, DOTILDE);
X
X switch (iop->flag&IOTYPE) {
X case IOREAD:
X u = open(cp, 0);
X break;
X
X case IOCAT:
X if ((u = open(cp, 1)) >= 0) {
X (void) lseek(u, (long)0, 2);
X break;
X }
X /* FALLTHROUGH */
X case IOWRITE:
X u = creat(cp, 0666);
X break;
X
X case IORDWR:
X u = open(cp, 2);
X break;
X
X case IOHERE:
X u = herein(cp, iop->flag&IOEVAL);
X /* cp may have wrong name */
X break;
X
X case IODUP:
X if (*cp == '-')
X close(iop->unit);
X else
X if (digit(*cp))
X u = *cp - '0';
X else
X errorf("%s: illegal >& argument\n", cp);
X break;
X }
X if (u < 0)
X errorf("%s: cannot %s\n", cp,
X (iop->flag&IOTYPE) == IOWRITE ? "create" : "open");
X if (u != iop->unit) {
X (void) dup2(u, iop->unit);
X if (iop->flag != IODUP)
X close(u);
X }
X
X fopenshf(iop->unit);
X}
X
X/*
X * open here document temp file.
X * if unquoted here, expand here temp file into second temp file.
X */
Xstatic int
Xherein(hname, sub)
X char *hname;
X int sub;
X{
X int fd;
X FILE * Volatile f = NULL;
X
X f = fopen(hname, "r");
X if (f == NULL)
X return -1;
X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
X
X if (sub) {
X char *cp;
X struct source *s;
X struct temp *h;
X
X newenv(E_ERRH);
X if (setjmp(e.jbuf)) {
X if (f != NULL)
X fclose(f);
X quitenv();
X return -1; /* todo: error()? */
X }
X
X /* set up yylex input from here file */
X s = pushs(SFILE);
X s->u.file = f;
X source = s;
X if (yylex(ONEWORD) != LWORD)
X errorf("exec:herein error\n");
X cp = evalstr(yylval.cp, 0);
X
X /* write expanded input to another temp file */
X h = maketemp(ATEMP);
X h->next = e.temps; e.temps = h;
X if (h == NULL)
X error();
X f = fopen(h->name, "w+");
X if (f == NULL)
X error();
X setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
X fputs(cp, f);
X rewind(f);
X
X quitenv();
X }
X fd = dup(fileno(f));
X fclose(f);
X return fd;
X}
X
Xstatic void
Xecho(vp, ap)
X register char **vp, **ap;
X{
X shellf("+");
X while (*vp != NULL)
X shellf(" %s", *vp++);
X while (*ap != NULL)
X shellf(" %s", *ap++);
X shellf("\n");
X}
X
SHAR_EOF
true || echo 'restore of src/exec.c failed'
fi
# ============= src/jobs.c ==============
if test -f 'src/jobs.c' -a X"$1" != X"-c"; then
echo 'x - skipping src/jobs.c (File already exists)'
else
echo 'x - extracting src/jobs.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/jobs.c' &&
X/*
X * Process and job control
X */
X
Xstatic char *RCSid = "$Header: /tmp/egisin/src/RCS/jobs.c,v 3.4 88/12/14 19:49:17 egisin Exp $";
X
X/*
X * based on version by Ron Natalie, BRL
X *
X * TODO:
X * change Proc table to Job table, with array of pids.
X * make %+ be jobs, %- be jobs->next.
X * do not JFREE members of pipeline.
X * consider procs[] related critical sections.
X * signal(SIGCHLD, j_sigchld) should be
X * sigaction(SIGCHLD, sigchld, NULL),
X * with sigchld.sa_flags = SA_RESTART.
X * There is a simple work-around if there is no SA_RESTART.
X */
X
X#include <stddef.h>
X#include <string.h>
X#include <stdio.h>
X#include <errno.h>
X#include <unistd.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <sys/types.h>
X#include <sys/times.h>
X#include <sys/wait.h>
X#if JOBS
X#if _BSD
X#include <sys/ioctl.h>
X#else
X#include "termios.h"
X#endif
X#endif
X#include "sh.h"
X#include "tree.h"
X
X#ifndef WIFCORED
X#define WIFCORED(x) (!!((x)&0x80)) /* non-standard */
X#endif
X
X/* as of P1003.1 Draft 12.3:
X * pid_t getpgrp(void); // Get process group id
X * pid_t setsid(void); // Create session and Set process group id
X * int setpgid(pid_t pid, pid_t pgid); // Set process group id for job control
X */
X
X#if JOBS
X#if _BSD /* _BSD 4.* */
X#define setpgid(p, pg) setpgrp(p, pg)
X#define getpgid(p) getpgrp(p)
X#define tcsetpgrp(fd,p) ioctl(fd, TIOCSPGRP, &(p))
X#else /* POSIX-compatible */
X#define getpgid(p) getpgrp() /* 1003.1 stupidity */
X#define killpg(p, s) kill(-(p), s)
X#endif
X#endif
X
X#ifndef SIGCHLD
X#define SIGCHLD SIGCLD
X#endif
X
Xtypedef struct Proc Proc;
Xstruct Proc {
X Proc *next; /* `procs' list link */
X int job; /* job number: %n */
X short Volatile state; /* proc state */
X short Volatile notify; /* proc state has changed */
X Proc *prev; /* prev member of pipeline */
X pid_t proc; /* process id */
X pid_t pgrp; /* process group if flag[FMONITOR] */
X short flags; /* execute flags */
X int status; /* wait status */
X clock_t utime, stime; /* user/system time when JDONE */
X char com [48]; /* command */
X};
X
X/* proc states */
X#define JFREE 0 /* unused proc */
X#define JRUN 1 /* foreground */
X#define JEXIT 2 /* exit termination */
X#define JSIGNAL 3 /* signal termination */
X#define JSTOP 4 /* stopped */
X
Xstatic Proc *procs = NULL; /* job/process table */
X
Xclock_t j_utime, j_stime; /* user and system time for last job a-waited */
X#if JOBS
Xstatic int sm_default, sm_sigchld; /* signal masks */
Xstatic int our_pgrp; /* shell's pgrp */
X#endif
Xstatic Proc *j_lastj; /* last proc created by exchild */
Xstatic int j_lastjob = 0; /* last created job */
Xstatic int j_current = 0; /* current job */
Xstatic int j_previous = 0; /* previous job */
X
Xstatic int j_newjob ARGS((void));
Xstatic void j_print ARGS((Proc *j));
Xstatic Proc *j_search ARGS((int job));
Xstatic int j_waitj ARGS((Proc *j, int intr));
Xstatic void j_sigchld ARGS((int sig));
X
X/* initialize job control */
Xvoid
Xj_init()
X{
X#if JOBS
X#ifdef NTTYDISC
X int ldisc = NTTYDISC; /* BSD brain damage */
X
X if (ttyfd >= 0)
X ioctl(ttyfd, TIOCSETD, &ldisc);
X#endif
X our_pgrp = getpgid(0);
X sm_default = 0;
X sm_sigchld = sigmask(SIGCHLD);
X#endif
X}
X
X/* job cleanup before shell exit */
Xvoid
Xj_exit()
X{
X register Proc *j;
X int killed = 0;
X
X#if JOBS
X /* kill stopped jobs */
X for (j = procs; j != NULL; j = j->next)
X if (j->state == JSTOP) {
X killed ++;
X killpg(j->pgrp, SIGHUP);
X killpg(j->pgrp, SIGCONT);
X }
X if (killed)
X sleep(1);
X#endif
X j_notify();
X
X#if JOBS
X if (flag[FMONITOR]) {
X flag[FMONITOR] = 0;
X j_change();
X }
X#endif
X}
X
X#if JOBS
X/* turn job control on or off according to flag[FMONITOR] */
Xvoid
Xj_change()
X{
X static handler_t old_tstp, old_ttin, old_ttou;
X
X if (flag[FMONITOR]) {
X if (ttyfd < 0) {
X flag[FMONITOR] = 0;
X shellf("job control requires tty\n");
X return;
X }
X (void) signal(SIGCHLD, j_sigchld);
X sigtraps[SIGCHLD].sig_dfl = 1; /* restore on fork */
X old_tstp = signal(SIGTSTP, SIG_IGN);
X sigtraps[SIGTSTP].sig_dfl = 1;
X old_ttin = signal(SIGTTIN, SIG_IGN);
X sigtraps[SIGTTIN].sig_dfl = 1;
X old_ttou = signal(SIGTTOU, SIG_IGN);
X sigtraps[SIGTTOU].sig_dfl = 1;
X sigsetmask(sm_default);
X tcsetpgrp(ttyfd, our_pgrp);
X } else {
X (void) signal(SIGCHLD, SIG_DFL);
X (void) signal(SIGTSTP, old_tstp);
X sigtraps[SIGTSTP].sig_dfl = 0;
X (void) signal(SIGTTIN, old_ttin);
X sigtraps[SIGTTIN].sig_dfl = 0;
X (void) signal(SIGTTOU, old_ttou);
X sigtraps[SIGTTOU].sig_dfl = 0;
X }
X}
X#endif
X
X/* execute tree in child subprocess */
Xint
Xexchild(t, flags)
X struct op *t;
X int flags;
X{
X register int i;
X register Proc *j;
X int rv = 0;
X
X flags &= ~XFORK;
X if ((flags&XEXEC))
X return execute(t, flags);
X
X /* get free Proc entry */
X for (j = procs; j != NULL; j = j->next)
X if (j->state == JFREE)
X goto Found;
X j = alloc(sizeof(Proc), APERM);
X j->next = procs;
X j->state = JFREE;
X procs = j;
X Found:
X
X j->prev = ((flags&XPIPEI)) ? j_lastj : NULL;
X j->proc = j->pgrp = 0;
X j->flags = flags;
X j->job = (flags&XPIPEI) ? j_lastjob : j_newjob();
X snptreef(j->com, sizeof(j->com), "%T", t); /* save proc's command */
X j->com[sizeof(j->com)-1] = '\0';
X j->state = JRUN;
X
X /* stdio buffer must be flushed and invalidated */
X for (i = 0; i < NUFILE; i++)
X flushshf(i);
X
X /* create child process */
X if ((i = fork()) < 0) {
X /* todo: try a few times with exp-incr delay */
X j->state = JFREE;
X errorf("cannot fork - try again\n");
X }
X j->proc = (i != 0) ? i : getpid();
X
X#if JOBS
X /* job control set up */
X if (flag[FMONITOR] && !(flags&XXCOM)) {
X j->pgrp = !(flags&XPIPEI) ? j->proc : j_lastj->pgrp;
X /* do in both parent and child to avoid fork race condition */
X if (!(flags&XBGND))
X tcsetpgrp(ttyfd, j->pgrp); /* could be trouble */
X setpgid(j->proc, j->pgrp);
X }
X#endif
X j_lastj = j;
X
X if (i == 0) { /* child */
X e.oenv = NULL;
X if (flag[FTALKING])
X restoresigs();
X if ((flags&XBGND) && !flag[FMONITOR]) {
X signal(SIGINT, SIG_IGN);
X signal(SIGQUIT, SIG_IGN);
X if (flag[FTALKING])
X signal(SIGTERM, SIG_DFL);
X i = open("/dev/null", 0);
X (void) dup2(i, 0);
X close(i);
X }
X for (j = procs; j != NULL; j = j->next)
X j->state = JFREE;
X ttyfd = -1;
X flag[FMONITOR] = flag[FTALKING] = 0;
X cleartraps();
X execute(t, flags|XEXEC); /* no return */
X /* NOTREACHED */
X }
X
X /* shell (parent) stuff */
X if ((flags&XBGND)) { /* async statement */
X async = j->proc;
X j_previous = j_current;
X j_current = j->job;
X if (flag[FTALKING])
X j_print(j);
X } else { /* sync statement */
X if (!(flags&XPIPE))
X rv = j_waitj(j, 0);
X }
X
X return rv;
X}
X
X/* wait for last job: pipeline or $() sub-process */
Xint
Xwaitlast()
X{
X return j_waitj(j_lastj, 0);
X}
X
X/* wait for job to complete or change state */
Xstatic int
Xj_waitj(aj, intr)
X Proc *aj;
X int intr; /* interruptable */
X{
X register Proc *j;
X int rv = 1;
X int ttysig = 0;
X
X#if JOBS
X if (flag[FMONITOR])
X sigsetmask(sm_sigchld);
X#endif
X /* wait for all members of pipeline */
X for (j = aj; j != NULL; j = j->prev) {
X /* wait for job to finish, stop, or ^C of built-in wait */
X while (j->state == JRUN) {
X#if JOBS
X if (flag[FMONITOR])
X sigpause(sm_default);
X else
X#endif
X j_sigchld(SIGCHLD);
X if (sigtraps[SIGINT].set && intr)
X goto Break;
X }
X if (j->state == JEXIT) { /* exit termination */
X if (!(j->flags&XPIPEO))
X rv = WEXITSTATUS(j->status);
X j->notify = 0;
X } else
X if (j->state == JSIGNAL) { /* signalled to death */
X if (!(j->flags&XPIPEO))
X rv = 0x80 + WTERMSIG(j->status);
X if (WTERMSIG(j->status) == SIGINT ||
X WTERMSIG(j->status) == SIGPIPE && (j->flags&XPIPEO))
X j->notify = 0;
X if (WTERMSIG(j->status) == SIGINT ||
X WTERMSIG(j->status) == SIGQUIT)
X ttysig = 1;
X } else
X#if JOBS
X if (j->state == JSTOP)
X if (WSTOPSIG(j->status) == SIGTSTP)
X ttysig = 1;
X#else
X ;
X#endif
X }
X
X /* compute total child time for time statement */
X for (j = aj; j != NULL; j = j->prev)
X j_utime += j->utime, j_stime += j->stime;
X
X /* find new current job */
X#if JOBS
X if (aj->state == JSTOP) {
X j_previous = j_current;
X j_current = aj->job;
X } else {
X#else
X if (1) {
X#endif
X int hijob = 0;
X
X /* todo: this needs to be done in j_notify */
X /* todo: figure out what to do with j_previous */
X j_current = 0;
X for (j = procs; j != NULL; j = j->next)
X if ((j->state == JRUN || j->state == JSTOP)
X && j->job > hijob) {
X hijob = j->job;
X j_current = j->job;
X }
X }
X
X Break:
X#if JOBS
X if (flag[FMONITOR]) {
X /* reset shell job control state */
X sigsetmask(sm_default);
X tcsetpgrp(ttyfd, our_pgrp);
X }
X#endif
X if (ttysig)
X fputc('\n', shlout);
X j_notify();
X
X return rv;
X}
X
X/* SIGCHLD handler to reap children */
Xstatic void
Xj_sigchld(sig)
X int sig;
X{
X int errno_ = errno;
X struct tms t0, t1;
X
X (void) times(&t0);
X do {
X register Proc *j;
X int pid, status;
X#if JOBS
X if (flag[FMONITOR])
X pid = waitpid(-1, &status, (WNOHANG|WUNTRACED));
X else
X#endif
X pid = wait(&status);
X if (pid <= 0) /* return if would block (0) ... */
X break; /* ... or no children or interrupted (-1) */
X (void) times(&t1);
X
X for (j = procs; j != NULL; j = j->next)
X if (j->state != JFREE && pid == j->proc)
X goto Found;
X continue;
X
X Found:
X j->notify = 1;
X j->status = status;
X#if JOBS
X if (WIFSTOPPED(status))
X j->state = JSTOP;
X else
X#endif
X if (WIFEXITED(status))
X j->state = JEXIT;
X else
X if (WIFSIGNALED(status))
X j->state = JSIGNAL;
X
X /* compute child's time */
X /* todo: what does a stopped job do? */
X j->utime = t1.tms_cutime - t0.tms_cutime;
X j->stime = t1.tms_cstime - t0.tms_cstime;
X t0 = t1;
X#if JOBS
X } while (flag[FMONITOR]);
X#else
X } while (0); /* only once if wait()ing */
X#endif
X
X errno = errno_;
X}
X
X/* wait for child, interruptable */
Xint
Xwaitfor(job)
X int job;
X{
X register Proc *j;
X
X if (job == 0 && j_current == 0)
X errorf("no current job\n");
X j = j_search((job == 0) ? j_current : job);
X if (j == NULL)
X errorf("no such job: %d\n", job);
X if (flag[FTALKING])
X j_print(j);
X if (e.interactive) { /* flush stdout, shlout */
X fflush(shf[1]);
X fflush(shf[2]);
X }
X return j_waitj(j, 1);
X}
X
X/* kill (built-in) a job */
Xvoid
Xj_kill(job, sig)
X int job;
X int sig;
X{
X register Proc *j;
X
X j = j_search(job);
X if (j == NULL)
X errorf("cannot find job\n");
X if (j->pgrp == 0) { /* !flag[FMONITOR] */
X if (kill(j->proc, sig) < 0) /* todo: all member of pipeline */
X errorf("kill: %s\n", strerror(errno));
X#if JOBS
X } else {
X if (sig == SIGTERM || sig == SIGHUP)
X (void) killpg(j->pgrp, SIGCONT);
X if (killpg(j->pgrp, sig) < 0)
X errorf("killpg: %s\n", strerror(errno));
X#endif
X }
X}
X
X#if JOBS
X
X/* fg and bg built-ins */
Xint
Xj_resume(job, bg)
X int job;
X int bg;
X{
X register Proc *j;
X
X j = j_search((job == 0) ? j_current : job);
X if (j == NULL)
X errorf("cannot find job\n", job);
X if (j->pgrp == 0)
X errorf("job not job-controlled\n");
X
X j->state = JRUN;
X j_print(j);
X flushshf(2);
X
X if (!bg)
X tcsetpgrp(ttyfd, j->pgrp); /* attach shell to job */
X if (killpg(j->pgrp, SIGCONT) < 0)
X errorf("cannot continue job %%%d\n", job);
X if (!bg)
X return j_waitj(j, 0);
X return 0;
X}
X
X#endif
X
X/* list jobs for jobs built-in */
Xvoid
Xj_jobs()
X{
X register Proc *j;
X
X for (j = procs; j != NULL; j = j->next)
X if (j->state != JFREE)
X j_print(j);
X}
X
X/* list jobs for top-level notification */
Xvoid
Xj_notify()
X{
X register Proc *j;
X
X for (j = procs; j != NULL; j = j->next) {
X if (j->state == JEXIT && !flag[FTALKING])
X j->notify = 0;
X if (j->state != JFREE && j->notify)
X j_print(j);
X if (j->state == JEXIT || j->state == JSIGNAL)
X j->state = JFREE;
X j->notify = 0;
X }
X}
X
Xstatic void
Xj_print(j)
X register Proc *j;
X{
X char buf [64], *s = buf;
X
X switch (j->state) {
X case JRUN:
X s = "Running";
X break;
X
X#if JOBS
X case JSTOP:
X strcpy(buf, "Stopped ");
X s = strchr(sigtraps[WSTOPSIG(j->status)].mess, '(');
X if (s != NULL)
X strcat(buf, s);
X s = buf;
X break;
X#endif
X
X case JEXIT: {
X int rv;
X rv = WEXITSTATUS(j->status);
X sprintf(buf, "Done (%d)", rv);
X if (rv == 0)
X *strchr(buf, '(') = 0;
X j->state = JFREE;
X } break;
X
X case JSIGNAL: {
X int sig = WTERMSIG(j->status);
X char *n = sigtraps[sig].mess;
X if (n != NULL)
X sprintf(buf, "%s", n);
X else
X sprintf(buf, "Signal %d", sig);
X if (WIFCORED(j->status))
X strcat(buf, " - core dumped");
X j->state = JFREE;
X } break;
X
X default:
X s = "Hideous job state";
X j->state = JFREE;
X break;
X }
X shellf("%%%-2d%c %5d %-20s %s%s\n", j->job,
X (j_current==j->job) ? '+' : (j_previous==j->job) ? '-' : ' ',
X j->proc, s, j->com, (j->flags&XPIPEO) ? "|" : "");
X}
X
X/* convert % sequence to job number */
Xint
Xj_lookup(cp)
X char *cp;
X{
X register Proc *j;
X int len, job = 0;
X
X if (*cp == '%') /* leading % is optional */
X cp++;
X switch (*cp) {
X case '\0':
X case '+':
X job = j_current;
X break;
X
X case '-':
X job = j_previous;
X break;
X
X case '0': case '1': case '2': case '3': case '4':
X case '5': case '6': case '7': case '8': case '9':
X job = atoi(cp);
X break;
X
X case '?': /* %?string */
X for (j = procs; j != NULL; j = j->next)
X if (j->state != JFREE && strstr(j->com, cp+1) != NULL)
X job = j->job;
X break;
X
X default: /* %string */
X len = strlen(cp);
X for (j = procs; j != NULL; j = j->next)
X if (j->state != JFREE && strncmp(cp, j->com, len) == 0)
X job = j->job;
X break;
X }
X if (job == 0)
X errorf("%s: no such job\n", cp);
X return job;
X}
X
X/* are any stopped jobs ? */
X#if JOBS
Xint
Xj_stopped()
X{
X register Proc *j;
X
X for (j = procs; j != NULL; j = j->next)
X if (j->state == JSTOP)
X return 1;
X return 0;
X}
X#endif
X
X/* create new job number */
Xstatic int
Xj_newjob()
X{
X register Proc *j;
X register int max = 0;
X
X j_lastjob ++;
X for (j = procs; j != NULL; j = j->next)
X if (j->state != JFREE && j->job)
X if (j->job > max)
X max = j->job;
X if (j_lastjob > max)
X j_lastjob = max + 1;
X return j_lastjob;
X}
X
X/* search for job by job number */
Xstatic Proc *
Xj_search(job)
X int job;
X{
X register Proc *j;
X
X for (j = procs; j != NULL; j = j->next)
X if (j->state != JFREE && job == j->job && !(j->flags&XPIPEO))
X return j;
X return NULL;
X}
X
SHAR_EOF
true || echo 'restore of src/jobs.c failed'
fi
# ============= src/c_sh.c ==============
if test -f 'src/c_sh.c' -a X"$1" != X"-c"; then
echo 'x - skipping src/c_sh.c (File already exists)'
else
echo 'x - extracting src/c_sh.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'src/c_sh.c' &&
X/*
X * built-in Bourne commands
X */
X
Xstatic char *RCSid = "Id: /u/egisin/sh/src/RCS/c_sh.c,v 3.1 88/11/03 09:14:31 egisin Exp $";
X
X#include <stddef.h>
X#include <stdio.h>
X#include <string.h>
X#include <errno.h>
X#include <signal.h>
X#include <setjmp.h>
X#include <sys/times.h>
X#include <unistd.h> /* getcwd */
X#include "sh.h"
X#include "lex.h"
X#include "tree.h"
X#include "table.h"
X
Xstatic char *clocktos();
X
Xint
Xc_label(wp)
X char **wp;
X{
X return 0;
X}
X
X/* todo: add symlink hacks */
Xint
Xc_cd(wp)
X register char **wp;
X{
X char path [PATH];
X register char *cp;
X register struct tbl *vp;
X
X if ((cp = wp[1]) == NULL && (cp = strval(global("HOME"))) == NULL)
X errorf("no home directory");
X if (strcmp(cp, "-") == 0) {
X cp = strval(global("OLDPWD"));
X shellf("%s\n", cp);
X }
X if (chdir(cp) < 0)
X errorf("%s: bad directory\n", cp);
X flushcom(0);
X
X /* maintain $PWD and $OLDPWD */
X vp = global("PWD");
X cp = strval(vp);
X if (cp != null)
X setstr(global("OLDPWD"), cp);
X cp = getcwd(path, (size_t)PATH);
X if (cp == NULL)
X unset(vp);
X else
X setstr(vp, cp);
X
X return 0;
X}
X
Xint
Xc_shift(wp)
X register char **wp;
X{
X register struct block *l = e.loc;
X register int n;
X
X n = wp[1] ? evaluate(wp[1]) : 1;
X if (l->argc < n) {
X errorf("nothing to shift\n");
X return (1);
X }
X l->argv[n] = l->argv[0];
X l->argv += n;
X l->argc -= n;
X return 0;
X}
X
Xint
Xc_umask(wp)
X register char **wp;
X{
X register int i;
X register char *cp;
X
X if ((cp = wp[1]) == NULL) {
X i = umask(0);
X umask(i);
X printf("%#3.3o\n", i); /* should this be shell output? */
X } else {
X for (i = 0; *cp>='0' && *cp<='7'; cp++)
X i = i*8 + (*cp-'0');
X umask(i);
X }
X return 0;
X}
X
Xint
Xc_dot(wp)
X char **wp;
X{
X char *file, *cp;
X
X if ((cp = wp[1]) == NULL)
X return 0;
X file = search(cp, path, 0);
X if (file == NULL)
X errorf("%s: not found\n", cp);
X if (include(file))
X return exstat;
X return -1;
X}
X
Xint
Xc_wait(wp)
X char **wp;
X{
X register char *cp;
X
X wp++;
X cp = *wp;
X if (cp == NULL) cp = "%";
X /* todo: print status ? */
X return waitfor(j_lookup(cp));
X}
X
Xint
Xc_read(wp)
X register char **wp;
X{
X register int c = 0;
X FILE *f = stdin;
X int expand = 1;
X register char *cp;
X
X for (wp++; (cp = *wp) != NULL && *cp++ == '-'; wp++) {
X while (*cp) switch (*cp++) {
X case 'e':
X expand = 1;
X break;
X case 'r':
X expand = 0;
X break;
X case 'u':
X if (!digit(*cp) || (f = shf[*cp++-'0']) == NULL)
X errorf("bad -u argument\n");
X break;
X }
X }
X
X if (*wp == NULL)
X errorf("missing name\n");
X if ((cp = strchr(*wp, '?')) != NULL) {
X *cp = 0;
X if (flag[FTALKING]) {
X shellf("%s ", cp+1);
X fflush(shlout);
X }
X }
X
X for (; *wp != NULL; wp++) {
X for (cp = line; cp <= line+LINE; ) {
X if (c == '\n')
X break;
X c = getc(f);
X if (c == EOF)
X return 1;
X if (expand && c == '\\') {
X c = getc(f);
X if (c == '\n')
X c = 0;
X else
X *cp++ = c;
X continue;
X }
X if (c == '\n' || wp[1] && ctype(c, C_IFS))
X break;
X *cp++ = c;
X }
X *cp = 0;
X setstr(global(*wp), line);
X }
X return 0;
X}
X
Xint
Xc_eval(wp)
X register char **wp;
X{
X register struct source *s;
X
X s = pushs(SWORDS);
X s->u.strv = wp+1;
X return shell(s);
X}
X
Xvoid setsig ARGS((struct trap *p, handler_t f));
X
Xint
Xc_trap(wp)
X register char **wp;
X{
X int i;
X char *s;
X register struct trap *p;
X
X wp++;
X if (*wp == NULL) {
X for (p = sigtraps, i = SIGNALS; --i >= 0; p++) {
X if (p->trap != NULL)
X shellf("%s: %s\n", p->name, p->trap);
X }
X return 0;
X }
X
X s = (gettrap(*wp) == NULL) ? *wp++ : NULL; /* get command */
X if (s != NULL && s[0] == '-' && s[1] == '\0')
X s = NULL;
X
X /* set/clear traps */
X while (*wp != NULL) {
X p = gettrap(*wp++);
X if (p == NULL)
X errorf("trap: bad signal %s\n", wp[-1]);
X if (p->trap != NULL)
X afree((Void*)p->trap, APERM);
X p->trap = NULL;
X if (s != NULL) {
X if (strlen(s) != 0) {
X p->trap = strsave(s, APERM);
X setsig(p, trapsig);
X } else
X setsig(p, (handler_t)SIG_IGN);
X } else
X /* todo: restore to orginal value */
X setsig(p,
X (p->signal==SIGINT || p->signal==SIGQUIT) && flag[FTALKING]
X ? (handler_t)SIG_IGN : (handler_t)SIG_DFL);
X }
X return 0;
X}
X
Xvoid
Xsetsig(p, f)
X register struct trap *p;
X void (*f)();
X{
X if (p->signal == 0)
X return;
X if (signal(p->signal, SIG_IGN) != SIG_IGN || p->ourtrap) {
X p->ourtrap = 1;
X signal(p->signal, f);
X }
X}
X
Xint
Xc_return(wp)
X char **wp;
X{
X wp++;
X if (*wp != NULL)
X exstat = getn(*wp);
X quitenv(); /* pop E_TCOM */
X while (e.type == E_LOOP || e.type == E_EXEC)
X quitenv();
X if (e.type == E_FUNC)
X longjmp(e.jbuf, 1);
X leave(exstat);
X}
X
Xint
Xc_brkcont(wp)
X register char **wp;
X{
X int quit;
X
X quit = wp[1] == NULL ? 1 : getn(wp[1]);
X quitenv(); /* pop E_TCOM */
X while (e.type == E_LOOP || e.type == E_EXEC) {
X if (e.type == E_LOOP && --quit <= 0)
X longjmp(e.jbuf, (*wp[0] == 'b') ? LBREAK : LCONTIN);
X quitenv();
X }
X errorf("cannot %s\n", wp[0]);
X}
X
Xint
Xc_exit(wp)
X char **wp;
X{
X register char *cp;
X
X e.oenv = NULL;
X if ((cp = wp[1]) != NULL)
X exstat = getn(cp);
X#if JOBS
X if (flag[FMONITOR] && j_stopped()) /* todo: only once */
X errorf("There are stopped jobs\n");
X#endif
X leave(exstat);
X}
X
Xint
Xc_set(wp)
X register char **wp;
X{
X struct block *l = e.loc;
X register struct tbl *vp, **p;
X register char **owp = wp;
X register char *cp;
X int old_fmonitor = flag[FMONITOR];
X
X if ((cp = *++wp) == NULL) {
X static char * Const args [] = {"set", "-", NULL};
X extern int c_typeset ARGS((char **args));
X return c_typeset(args);
X }
X
X for (; (cp = *wp) != NULL && (*cp == '-' || *cp == '+');) {
X int i, n = *cp++ == '-'; /* set or clear flag */
X wp++;
X if (*cp == '\0') {
X if (n)
X flag[FXTRACE] = flag[FVERBOSE] = 0;
X break;
X }
X if (*cp == '-')
X goto setargs;
X for (; *cp != '\0'; cp++)
X if (*cp == 'o') {
X if (*wp == NULL) {
X printoptions();
X return 0;
X }
X i = option(*wp++);
X if (i == 0)
X shellf("%s: unknown option\n", *--wp);
X flag[i] = n;
X } else if (*cp>='a' && *cp<='z')
X flag[FLAG(*cp)] = n;
X else
X errorf("%c: bad flag\n", *cp);
X if (flag[FTALKING])
X flag[FERREXIT] = 0;
X }
X
X#if JOBS
X if (old_fmonitor != flag[FMONITOR])
X j_change();
X#endif
X
X /* set $# and $* */
X if (*wp != NULL) {
X setargs:
X owp = --wp;
X wp[0] = l->argv[0]; /* save $0 */
X while (*++wp != NULL)
X *wp = strsave(*wp, &l->area);
X l->argc = wp - owp - 1;
X l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
X for (wp = l->argv; (*wp++ = *owp++) != NULL; )
X ;
X resetopts();
X }
X return 0;
X}
X
Xint
Xc_unset(wp)
X register char **wp;
X{
X register char *id;
X int flagf = 0;
X
X for (wp++; (id = *wp) != NULL && *id == '-'; wp++)
X if (*++id == 'f')
X flagf++;
X for (; (id = *wp) != NULL; wp++)
X if (!flagf) { /* unset variable */
X unset(local(id));
X } else { /* unset function */
X register struct tbl *tp;
X tp = tsearch(&e.loc->funs, id, hash(id));
X if (tp != NULL)
X define(tp, (struct op *)NULL);
X }
X return 0;
X}
X
Xint
Xc_ulimit(wp)
X register char **wp;
X{
X extern int do_ulimit();
X
X return do_ulimit(wp[1], wp[2]);
X}
X
Xint
Xc_times(wp)
X char **wp;
X{
X struct tms all;
X
X (void) times(&all);
X printf("Shell: ");
X printf("%8s user ", clocktos(all.tms_utime));
X printf("%8s system\n", clocktos(all.tms_stime));
X printf("Kids: ");
X printf("%8s user ", clocktos(all.tms_cutime));
X printf("%8s system\n", clocktos(all.tms_cstime));
X
X return 0;
X}
X
X/*
X * time pipeline (really a statement, not a built-in comman)
X */
Xint
Xtimex(t, f)
X struct op *t;
X int f;
X{
X int rv;
X struct tms t0, t1;
X clock_t t0t, t1t;
X extern clock_t j_utime, j_stime; /* computed by j_wait */
X
X j_utime = j_stime = 0;
X t0t = times(&t0);
X rv = execute(t->left, f);
X t1t = times(&t1);
X
X shellf("%8s real ", clocktos(t1t - t0t));
X shellf("%8s user ",
X clocktos(t1.tms_utime - t0.tms_utime + j_utime));
X shellf("%8s system ",
X clocktos(t1.tms_stime - t0.tms_stime + j_stime));
X shellf("\n");
X
X return rv;
X}
X
Xstatic char *
Xclocktos(t)
X clock_t t;
X{
X static char temp[20];
X register int i;
X register char *cp = temp + sizeof(temp);
X
X#if CLK_TCK != 100 /* convert to 1/100'ths */
X t = (t < 1000000000/CLK_TCK) ?
X (t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
X#endif
X
X *--cp = '\0';
X *--cp = 's';
X for (i = -2; i <= 0 || t > 0; i++) {
X if (i == 0)
X *--cp = '.';
X *--cp = '0' + (char)(t%10);
X t /= 10;
X }
X return cp;
X}
X
X/* dummy function, special case in comexec() */
Xint
Xc_exec(wp)
X char ** wp;
X{
X return 0;
X}
X
X/* dummy function, special case in comexec() */
Xint
Xc_builtin(wp)
X char ** wp;
X{
X return 0;
X}
X
Xextern int c_test(); /* in test.c */
X
XConst struct builtin shbuiltins [] = {
X {"=:", c_label},
X {"=.", c_dot},
X {"[", c_test},
X {"=cd", c_cd},
X {"builtin", c_builtin},
X {"=exec", c_exec},
X {"=shift", c_shift},
X {"wait", c_wait},
X {"read", c_read},
X {"=eval", c_eval},
X {"trap", c_trap},
X {"break", c_brkcont},
X {"continue", c_brkcont},
X {"exit", c_exit},
X {"=return", c_return},
X {"=set", c_set},
X {"=unset", c_unset},
X {"umask", c_umask},
X {"test", c_test},
X {"times", c_times},
X {"ulimit", c_ulimit},
X {NULL, NULL}
X};
X
SHAR_EOF
true || echo 'restore of src/c_sh.c failed'
fi
true || echo 'restore of src/c_ksh.c failed'
echo End of part 4, continue with part 5
exit 0
More information about the Alt.sources
mailing list