home *** CD-ROM | disk | FTP | other *** search
- From: netnews@netcom.UUCP (USENET Administration)
- Newsgroups: alt.sources
- Subject: Public Domain Korn Shell - Part.04 of 7
- Message-ID: <18609@netcom.UUCP>
- Date: 12 Dec 90 11:37:20 GMT
-
- #!/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
-