byron@archone.tamu.edu (Byron Rakitzis) (05/22/91)
Submitted-by: Byron Rakitzis <byron@archone.tamu.edu> Posting-number: Volume 20, Issue 13 Archive-name: rc/part04 #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: COPYRIGHT Makefile builtins.h except.c except.h exec.c # exec.h footobar.h glob.h glom.h heredoc.h input.h lex.h list.c # list.h main.c match.c match.h mksignal nalloc.c nalloc.h node.h # open.c open.h parse.h rc.h redir.h status.c status.h stddef.h # stdlib.h string.h tree.h unistd.h utils.h version.c walk.h # Wrapped by kent@sparky on Wed May 22 01:21:49 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 4 (of 4)."' if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'COPYRIGHT'\" else echo shar: Extracting \"'COPYRIGHT'\" \(1106 characters\) sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE' X/* X * Copyright 1991 Byron Rakitzis. All rights reserved. X * X * This software is not subject to any license of the American Telephone X * and Telegraph Company or of the Regents of the University of California. X * X * Permission is granted to anyone to use this software for any purpose on X * any computer system, and to alter it and redistribute it freely, subject X * to the following restrictions: X * X * 1. The author is not responsible for the consequences of use of this X * software, no matter how awful, even if they arise from flaws in it. X * X * 2. The origin of this software must not be misrepresented, either by X * explicit claim or by omission. Since few users ever read sources, X * credits must appear in the documentation. X * X * 3. Altered versions must be plainly marked as such, and must not be X * misrepresented as being the original software. Since few users X * ever read sources, credits must appear in the documentation. X * X * 4. This notice may not be removed or altered. X * X * [this copyright notice is adapted from Henry Spencer's X * "awf" copyright notice.] X */ END_OF_FILE if test 1106 -ne `wc -c <'COPYRIGHT'`; then echo shar: \"'COPYRIGHT'\" unpacked with wrong size! fi # end of 'COPYRIGHT' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(1518 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' X# Makefile for rc. X# X# Define the macro NODIRENT if your system has <sys/dir.h> but not <dirent.h>. X# Define the macro NONMPIPES if your system does not support named pipes. X# Define the macro NOJOB if your system does not support job control. X# Define the macro NOLIMITS if your system does not support Berkeley limits. X# Define the macro READLINE if you want rc to call GNU readline instead of read(2). X X# Get rid of default CFLAGS on braindamaged make's. XCFLAGS= X X# Use an ANSI compiler (or at least one that groks prototypes and void *): XCC=gcc -g -O X X# On an sgi running IRIX 3.3.1 I used: X#CC=cc -g -O X# X# On the NeXT I used X#CC=cc -g -O -DNODIRENT X# X# On a VAX running BSD 4.2 X#CC=gcc -g -O -DNODIRENT X X# Use bison if you will, but yacc generates a smaller y.tab.c, and the speed X# of the parser is largely irrelevant in a shell. XYACC=yacc X XOBJS = builtins.o except.o exec.o fn.o footobar.o glob.o glom.o hash.o heredoc.o \ X input.o lex.o list.o main.o match.o nalloc.o open.o redir.o sigmsgs.o status.o \ X tree.o utils.o var.o version.o walk.o which.o y.tab.o X X# If rc is compiled with GNU readline, you must supply the correct arguments to X# ld on this line. Typically this would be something like: X# X# $(CC) -o rc $(OBJS) -lreadline -ltermcap X Xrc: $(OBJS) X $(CC) -o rc $(OBJS) X Xsigmsgs.c : mksignal X sh mksignal /usr/include/sys/signal.h X Xy.tab.c: parse.y X $(YACC) -d parse.y X Xclean: X rm -f *.o *.tab.[ch] sigmsgs.[ch] X X# dependencies: X Xsigmsgs.h : sigmsgs.c Xlex.o y.tab.o: y.tab.c Xfn.c status.c: sigmsgs.h END_OF_FILE if test 1518 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'builtins.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'builtins.h'\" else echo shar: Extracting \"'builtins.h'\" \(162 characters\) sed "s/^X//" >'builtins.h' <<'END_OF_FILE' Xtypedef void builtin_t(char **); X Xextern builtin_t *isbuiltin(char *); Xextern void b_exec(char **), funcall(char **), b_dot(char **); Xextern char *which(char *); END_OF_FILE if test 162 -ne `wc -c <'builtins.h'`; then echo shar: \"'builtins.h'\" unpacked with wrong size! fi # end of 'builtins.h' fi if test -f 'except.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'except.c'\" else echo shar: Extracting \"'except.c'\" \(2296 characters\) sed "s/^X//" >'except.c' <<'END_OF_FILE' X#include <setjmp.h> X#include <stdarg.h> X#include "rc.h" X#include "utils.h" X#include "except.h" X#include "status.h" X#include "hash.h" X#include "input.h" X#include "nalloc.h" X X/* X a return goes back stack frames to the last return. A break does not. A signal X goes to the last interactive level. X*/ X Xstatic Estack *estack; X X/* add an exception to the input stack. */ X Xvoid except(enum except e, jmp_buf jb, Estack *ex) { X ex->prev = estack; X estack = ex; X X switch (estack->e = e) { X case ARENA: X estack->b = newblock(); X break; X case ERROR: case BREAK: case RETURN: X estack->interactive = interactive; X estack->jb = (jmp_buf *) jb; X break; X case STAR: X break; X } X} X X/* remove an exception, restore last interactive value */ X Xvoid unexcept(void) { X if (estack->e == ERROR) X interactive = estack->interactive; X else if (estack->e == ARENA) X restoreblock(estack->b); X estack = estack->prev; X} X X/* X Raise an exception. The rules are pretty complicated: you can return from a loop inside a X function, but you can't break from a function inside of a loop. On errors, rc_raise() goes back X to the LAST INTERACTIVE stack frame. If no such frame exists, then rc_raise() exits the shell. X This is what happens, say, when there is a syntax error in a noninteractive shell script. While X traversing the exception stack backwards, rc_raise() also removes input sources (closing X file-descriptors, etc.) and pops instances of $* that have been pushed onto the variable stack X (e.g., for a function call). X*/ X Xvoid rc_raise(enum except e) { X if (e == ERROR && rc_pid != getpid()) X exit(1); /* child processes exit on an error/signal */ X X for (; estack != NULL; estack = estack->prev) X if (estack->e != e) { X if (e == BREAK && estack->e != ARENA) X rc_error("break outside of loop"); X else if (e == RETURN && estack->e == ERROR) /* can return from loops inside functions */ X rc_error("return outside of function"); X if (estack->e == STAR) X varrm("*", TRUE); X else if (estack->e == ARENA) X restoreblock(estack->b); X } else { X if (e == ERROR && !estack->interactive) { X popinput(); X } else { X jmp_buf *j = estack->jb; X X interactive = estack->interactive; X estack = estack->prev; X longjmp(*j, 1); X } X } X rc_exit(1); /* top of exception stack */ X} END_OF_FILE if test 2296 -ne `wc -c <'except.c'`; then echo shar: \"'except.c'\" unpacked with wrong size! fi # end of 'except.c' fi if test -f 'except.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'except.h'\" else echo shar: Extracting \"'except.h'\" \(295 characters\) sed "s/^X//" >'except.h' <<'END_OF_FILE' Xenum except { ERROR, BREAK, RETURN, STAR, ARENA }; Xtypedef struct Estack Estack; X Xstruct Estack { X enum except e; X boolean interactive; X jmp_buf *jb; X Block *b; X Estack *prev; X}; X Xextern void rc_raise(enum except); Xextern void except(enum except, jmp_buf, Estack *); Xextern void unexcept(void); END_OF_FILE if test 295 -ne `wc -c <'except.h'`; then echo shar: \"'except.h'\" unpacked with wrong size! fi # end of 'except.h' fi if test -f 'exec.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'exec.c'\" else echo shar: Extracting \"'exec.c'\" \(2186 characters\) sed "s/^X//" >'exec.c' <<'END_OF_FILE' X/* X exec.c: exec() takes an argument list and does the appropriate thing X (calls a builtin, calls a function, etc.) X*/ X X#include <setjmp.h> X#include <signal.h> X#include "rc.h" X#include "utils.h" X#include "exec.h" X#include "status.h" X#include "hash.h" X#include "builtins.h" X#include "footobar.h" X#include "except.h" X#include "redir.h" X Xvoid exec(List *s, boolean parent) { X char **av, **ev; X int pid, stat; X builtin_t *b; X char *path = NULL; X void (*handler)(int); X boolean forked; X X av = list2array(s, dashex); X ev = makeenv(); X Xagain: if (*av == NULL || isabsolute(*av)) /* null command or absolute pathname */ X b = NULL; X else if (fnlookup(*av) != NULL) X b = funcall; X else X b = isbuiltin(*av); X X if (b == b_exec) { X parent = FALSE; X b(av++); X if (*av == NULL) X return; /* return on null exec */ X goto again; /* go back and evaluate the type of command to be executed */ X } X X if (b == NULL) { X path = which(*av); X if (path == NULL && *av != NULL) { /* perform null commands for redirections */ X fprint(2,"%s not found\n",*av); X set(FALSE); X redirq = NULL; X empty_fifoq(); X if (parent) X return; X rc_exit(1); X } X } X X /* if parent & the redirq is nonnull, builtin or not it has to fork. */ X X if (parent && (b == NULL || redirq != NULL)) { X pid = fork(); X forked = TRUE; X } else { X pid = 0; X forked = FALSE; X } X X switch (pid) { X case -1: X uerror("fork"); X rc_error(NULL); X /* NOTREACHED */ X case 0: X if (forked) X setsigdefaults(); X doredirs(); X X /* null commands performed for redirections */ X if (*av == NULL || b != NULL) { X if (b != NULL) X b(av); X empty_fifoq(); X if (!forked && parent) X return; X rc_exit(getstatus()); X } X execve(path, (const char **) av, (const char **) ev); /* bogus, huh? */ X uerror(*av); X rc_exit(1); X /* NOTREACHED */ X default: X if ((handler = signal(SIGINT, SIG_IGN)) != sig) X signal(SIGINT, handler); /* don't ignore interrupts in noninteractive mode */ X while (pid != wait(&stat)) X if (pid < 0) X uerror("wait"); X signal(SIGINT, handler); X redirq = NULL; X empty_fifoq(); X setstatus(stat); X if (stat == SIGINT) /* interrupted? let the handler deal with it. */ X rc_raise(ERROR); X } X} END_OF_FILE if test 2186 -ne `wc -c <'exec.c'`; then echo shar: \"'exec.c'\" unpacked with wrong size! fi # end of 'exec.c' fi if test -f 'exec.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'exec.h'\" else echo shar: Extracting \"'exec.h'\" \(104 characters\) sed "s/^X//" >'exec.h' <<'END_OF_FILE' Xstruct Rq { X Node *r; X struct Rq *n; X}; X Xextern void exec(List *, boolean); Xextern void doredirs(void); END_OF_FILE if test 104 -ne `wc -c <'exec.h'`; then echo shar: \"'exec.h'\" unpacked with wrong size! fi # end of 'exec.h' fi if test -f 'footobar.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'footobar.h'\" else echo shar: Extracting \"'footobar.h'\" \(258 characters\) sed "s/^X//" >'footobar.h' <<'END_OF_FILE' Xextern char *fun2str(char *, Node *); Xextern char *ptree(Node *); Xextern char *list2str(char *, List *); Xextern char **list2array(List *, boolean); Xextern char *get_name(char *); Xextern List *parse_var(char *, char *); Xextern Node *parse_fn(char *, char *); END_OF_FILE if test 258 -ne `wc -c <'footobar.h'`; then echo shar: \"'footobar.h'\" unpacked with wrong size! fi # end of 'footobar.h' fi if test -f 'glob.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'glob.h'\" else echo shar: Extracting \"'glob.h'\" \(66 characters\) sed "s/^X//" >'glob.h' <<'END_OF_FILE' Xextern boolean lmatch(List *, List *); Xextern List *glob(List *); END_OF_FILE if test 66 -ne `wc -c <'glob.h'`; then echo shar: \"'glob.h'\" unpacked with wrong size! fi # end of 'glob.h' fi if test -f 'glom.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'glom.h'\" else echo shar: Extracting \"'glom.h'\" \(275 characters\) sed "s/^X//" >'glom.h' <<'END_OF_FILE' Xextern void assign(List *, List *, boolean); Xextern void qredir(Node *); Xextern List *append(List *, List*); Xextern List *flatten(List *); Xextern List *glom(Node *); Xextern List *concat(List *, List *); Xextern List *varsub(List *, List *); Xextern List *word(char *, char *); END_OF_FILE if test 275 -ne `wc -c <'glom.h'`; then echo shar: \"'glom.h'\" unpacked with wrong size! fi # end of 'glom.h' fi if test -f 'heredoc.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'heredoc.h'\" else echo shar: Extracting \"'heredoc.h'\" \(99 characters\) sed "s/^X//" >'heredoc.h' <<'END_OF_FILE' Xextern void heredoc(int); Xextern void qdoc(Node *, Node *); X Xtypedef struct Hq Hq; X Xextern Hq *hq; END_OF_FILE if test 99 -ne `wc -c <'heredoc.h'`; then echo shar: \"'heredoc.h'\" unpacked with wrong size! fi # end of 'heredoc.h' fi if test -f 'input.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'input.h'\" else echo shar: Extracting \"'input.h'\" \(373 characters\) sed "s/^X//" >'input.h' <<'END_OF_FILE' Xenum inputtype { FD, STRING }; X X#define EOF (-1) X Xextern void initinput(void); Xextern Node *parseline(char *); Xextern int gchar(void); Xextern void ugchar(int); Xextern Node *doit(boolean); Xextern void flushu(void); Xextern void pushinput(int /*enum inputtype*/,...); Xextern void popinput(void); Xextern int last; X Xextern boolean rcrc; Xextern char *histstr; Xextern int histfd; END_OF_FILE if test 373 -ne `wc -c <'input.h'`; then echo shar: \"'input.h'\" unpacked with wrong size! fi # end of 'input.h' fi if test -f 'lex.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'lex.h'\" else echo shar: Extracting \"'lex.h'\" \(502 characters\) sed "s/^X//" >'lex.h' <<'END_OF_FILE' Xenum redirtype { X FROM, CREATE, APPEND, HEREDOC, HERESTRING X}; X Xtypedef struct Pipe { X int left,right; X} Pipe; X Xtypedef struct Dup { X enum redirtype type; X int left,right; X} Dup; X Xtypedef struct Redir { X enum redirtype type; X int fd; X} Redir; X Xtypedef struct Word { X char *w; X char *m; X} Word; X Xextern int yylex(void); Xextern void inityy(void); Xextern void skipnl(void); Xextern void yyerror(const char *); Xextern void scanerror(char *); Xextern void print_prompt2(void); X Xextern const char nw[], dnw[]; END_OF_FILE if test 502 -ne `wc -c <'lex.h'`; then echo shar: \"'lex.h'\" unpacked with wrong size! fi # end of 'lex.h' fi if test -f 'list.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'list.c'\" else echo shar: Extracting \"'list.c'\" \(984 characters\) sed "s/^X//" >'list.c' <<'END_OF_FILE' X/* list.c: routines for manipulating the List type */ X X#include "rc.h" X#include "utils.h" X#include "list.h" X X/* X These list routines assign meta values of null to the resulting lists; X it is impossible to glob with the value of a variable unless this value X is rescanned with eval---therefore it is safe to throw away the meta-ness X of the list. X*/ X X/* free a list from malloc space */ X Xvoid listfree(List *p) { X if (p == NULL) X return; X listfree(p->n); X efree(p->w); X efree(p); X} X X/* copy of list in malloc space (for storing a variable) */ X XList *listcpy(List *s) { X List *r; X X if (s == NULL) X return NULL; X X r = enew(List); X r->w = ecpy(s->w); X r->m = NULL; X r->n = listcpy(s->n); X X return r; X} X X/* length of list */ X XSIZE_T listlen(List *s) { X SIZE_T size; X X for (size = 0; s != NULL; s = s->n) X size += strlen(s->w) + 1; X X return size; X} X X/* number of elements in list */ X Xint listnel(List *s) { X int nel; X X for (nel = 0; s != NULL; s = s->n) X nel++; X X return nel; X} END_OF_FILE if test 984 -ne `wc -c <'list.c'`; then echo shar: \"'list.c'\" unpacked with wrong size! fi # end of 'list.c' fi if test -f 'list.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'list.h'\" else echo shar: Extracting \"'list.h'\" \(119 characters\) sed "s/^X//" >'list.h' <<'END_OF_FILE' Xextern void listfree(List *); Xextern List *listcpy(List *); Xextern SIZE_T listlen(List *); Xextern int listnel(List *); END_OF_FILE if test 119 -ne `wc -c <'list.h'`; then echo shar: \"'list.h'\" unpacked with wrong size! fi # end of 'list.h' fi if test -f 'main.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'main.c'\" else echo shar: Extracting \"'main.c'\" \(2456 characters\) sed "s/^X//" >'main.c' <<'END_OF_FILE' X/* main.c: handles initialization of rc and command line options */ X X#include <stdarg.h> X#include "rc.h" X#include "utils.h" X#include "input.h" X#include "nalloc.h" X#include "hash.h" X#include "lex.h" X#include "open.h" X#include "tree.h" X#include "glom.h" X#include "builtins.h" X#include "parse.h" X Xboolean dashdee, dashee, dashvee, dashex, dashell, dasheye, interactive; Xint rc_pid; X X#define REALLYNULL ((void *) 0) /* used to terminate a vararg list with NULL */ X Xstatic void assigndefault(char *,...); X Xvoid main(int argc, char *argv[], char *envp[]) { X extern int getopt(int, char **, char *); X extern int optind; X extern char *optarg; X char *dashsee[2], pid[8], *dollarzero, *null[1]; X int c; X X dashee = dashell = dashvee = dashex = dashdee = FALSE; X dashsee[0] = dashsee[1] = NULL; X dollarzero = argv[0]; X X dashell = (*argv[0] == '-'); /* Unix tradition */ X X while ((c = getopt(argc, argv, "leivdxc:")) != -1) X switch (c) { X case 'l': X dashell = TRUE; X break; X case 'e': X dashee = TRUE; X break; X case 'i': X dasheye = interactive = TRUE; X break; X case 'v': X dashvee = TRUE; X break; X case 'x': X dashex = TRUE; X break; X case 'd': X dashdee = TRUE; X break; X case 'c': X dashsee[0] = optarg; X goto quitopts; X case '?': X exit(1); X } X Xquitopts: X argv += optind; X X /* use isatty() iff -i is not set, and iff the input is not from a script or -c flag */ X if (!dasheye && dashsee[0] == NULL && *argv == NULL) X interactive = isatty(0); X X inithandler(); X inithash(); X initparse(); X assigndefault("prompt", "; ", "", REALLYNULL); X assigndefault("path", ".", "/bin", "/usr/bin", "/usr/ucb", REALLYNULL); X assigndefault("ifs", " ", "\t", "\n", REALLYNULL); X assigndefault("pid", sprint(pid, "%d", rc_pid = getpid()), REALLYNULL); X initenv(envp); X initinput(); X null[0] = NULL; X starassign(dollarzero, null, FALSE); /* assign $0 to $* */ X X if (dashsee[0] != NULL) { /* input from the -c flag? */ X if (*argv != NULL) X starassign(dollarzero, argv, FALSE); X pushinput(STRING, dashsee); X } else if (*argv != NULL) { /* else from a file? */ X b_dot(--argv); X rc_exit(0); X } else { /* else stdin */ X pushinput(FD, 0); X } X X doit(TRUE); X rc_exit(0); X} X Xstatic void assigndefault(char *name,...) { X va_list ap; X List *l; X char *v; X X va_start(ap, name); X X for (l = NULL; (v = va_arg(ap, char *)) != NULL;) X l = append(l, word(v, NULL)); X X varassign(name, l, FALSE); X X if (streq(name,"path")) X alias(name, l, FALSE); X X va_end(ap); X} END_OF_FILE if test 2456 -ne `wc -c <'main.c'`; then echo shar: \"'main.c'\" unpacked with wrong size! fi # end of 'main.c' fi if test -f 'match.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'match.c'\" else echo shar: Extracting \"'match.c'\" \(1992 characters\) sed "s/^X//" >'match.c' <<'END_OF_FILE' X/* match.c: pattern matching routines */ X X#include "rc.h" X#include "utils.h" X#include "match.h" X Xstatic int rangematch(char *, char); X X/* X match() matches a single pattern against a single string. X*/ X Xboolean match(char *p, char *m, char *s) { X int i = 0; X int j; X X if (m == NULL) X return streq(p, s); X X while(1) { X if (p[i] == '\0') X return *s == '\0'; X else if (m[i]) { X switch (p[i++]) { X case '?': X if (*s++ == '\0') X return FALSE; X break; X case '*': X /* collapse multiple stars */ X while (p[i] == '*' && m[i] == 1) X i++; X X /* star at end of pattern? */ X if (p[i] == '\0') X return TRUE; X X while (*s != '\0') X if (match(p + i, m + i, s++)) X return TRUE; X return FALSE; X case '[': X if (*s == '\0' || ((j = rangematch(p + i, *s++)) < 0)) X return FALSE; X i += j; X break; X default: X fprint(2,"%c is not a metacharacter\n", p[i-1]); X return FALSE; X } X } else if (p[i++] != *s++) { X return FALSE; X } X } X} X X/* X From the ed(1) man pages (on ranges): X X The `-' is treated as an ordinary character if it occurs first X (or first after an initial ^) or last in the string. X X The right square bracket does not terminate the enclosed string X if it is the first character (after an initial `^', if any), in X the bracketed string. X X rangematch() matches a single character against a class, and returns X an integer offset to the end of the range on success, or -1 on X failure. X*/ X Xstatic int rangematch(char *p, char c) { X char *orig = p; X boolean neg = (*p == '~'); X boolean matched = FALSE; X X if (neg) X p++; X X if (*p == ']') { X p++; X matched = (c == ']'); X } X X for (; *p != ']'; p++) { X if (*p == '\0') X return -1; /* bad syntax */ X if (p[1] == '-' && p[2] != ']') { /* check for [..-..] but ignore [..-] */ X if (c >= *p) X matched |= (c <= p[2]); X p += 2; X } else { X matched |= (*p == c); X } X } X X if (matched ^ neg) X return p - orig + 1; /* skip the right-bracket */ X else X return -1; X} X END_OF_FILE if test 1992 -ne `wc -c <'match.c'`; then echo shar: \"'match.c'\" unpacked with wrong size! fi # end of 'match.c' fi if test -f 'match.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'match.h'\" else echo shar: Extracting \"'match.h'\" \(46 characters\) sed "s/^X//" >'match.h' <<'END_OF_FILE' Xextern boolean match(char *, char *, char *); END_OF_FILE if test 46 -ne `wc -c <'match.h'`; then echo shar: \"'match.h'\" unpacked with wrong size! fi # end of 'match.h' fi if test -f 'mksignal' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'mksignal'\" else echo shar: Extracting \"'mksignal'\" \(1683 characters\) sed "s/^X//" >'mksignal' <<'END_OF_FILE' X#!/bin/sh X# generate rc's internal signal table from signal.h X Xexec > sigmsgs.c X Xecho 'char *signals[][2] = {' X Xsed ' s/\/\*[ ]*// X s/[ ]*\*\/// X s/([@*+!]) // X s/[ ]*([a-zA-Z,->& ]*)[ ]*// X s/[ ]*signal$//' $1 | Xawk ' X BEGIN { X # assign to nomesg["SIGNAME"] to suppress a long message X nomesg["SIGINT"] = 1 X nomesg["SIGPIPE"] = 1 X # assign to mesg["SIGNAME"] to override a message X mesg["SIGHUP"] = "hangup" X mesg["SIGKILL"] = "killed" X mesg["SIGQUIT"] = "quit" X mesg["SIGTERM"] = "terminated" X mesg["SIGURG"] = "urgent condition on i/o channel" X mesg["SIGSTOP"] = "stop signal not from tty" X mesg["SIGTSTP"] = "stopped" X mesg["SIGCONT"] = "continue" X mesg["SIGCHLD"] = "child stop or exit" X mesg["SIGTTIN"] = "background tty read" X mesg["SIGTTOU"] = "background tty write" X # assign to ignore["SIGNAME"] to explicitly ignore a named signal X ignore["SIGMAX"] = 1 X } X $1 == "#define" && $2 == "NSIG" && $3 ~ /^[0-9]+$/ { nsig = $3 } X $1 == "#define" && $2 ~ /^SIG/ && $3 ~ /^[0-9]+$/ && sig[$3] == "" && ignore[$2] == 0 { X sig[$3] = $2 X if ($3 > max) X max = $3 X if (mesg[$2] == "" && nomesg[$2] == 0) { X str = $4 X for (i = 5; i <= NF; i++) X str = str " " $i X mesg[$2] = str X } X } X END { X if (nsig == 0) X nsig = max + 1 X printf " !!, !!,\n" X for (i = 1; i < nsig; i++) { X if (sig[i] == "") X printf " !!, !!,\n" X else X printf " !%s!, !%s!,\n", sig[i], mesg[sig[i]] X } X } X' | Xtr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!' 'abcdefghijklmnopqrstuvwxyz"' X Xecho '};' X Xexec > sigmsgs.h X Xecho 'extern char *signals[][2];' X Xgrep '^ ' sigmsgs.c | # the thing in quotes is ^<tab> Xawk ' X { sum = sum + 1; } X END { print "#define NUMOFSIGNALS", sum } X' END_OF_FILE if test 1683 -ne `wc -c <'mksignal'`; then echo shar: \"'mksignal'\" unpacked with wrong size! fi # end of 'mksignal' fi if test -f 'nalloc.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'nalloc.c'\" else echo shar: Extracting \"'nalloc.c'\" \(2218 characters\) sed "s/^X//" >'nalloc.c' <<'END_OF_FILE' X/* nalloc.c: a simple single-arena allocator for command-line-lifetime allocation */ X X#include "rc.h" X#include "utils.h" X#include "nalloc.h" X Xstatic struct Block { X SIZE_T used; X SIZE_T size; X char *mem; X Block *n; X} *fl, *ul; X X/* alignto() works only with power of 2 blocks and assumes 2's complement arithmetic */ X#define alignto(m, n) ((m + n - 1) & ~(n - 1)) X#define BLOCKSIZE 4096 X X/* gets a block from malloc space and places it at the head of the used-list */ X Xstatic void getblock(SIZE_T n) { X Block *r, *p; X X for (r = fl, p = NULL; r != NULL; p = r, r = r->n) X if (n <= r->size) X break; X X if (r != NULL) { X if (p != NULL) X p->n = r->n; X else X fl = r->n; X } else { X r = enew(Block); X r->mem = ealloc(alignto(n, BLOCKSIZE)); X r->size = alignto(n, BLOCKSIZE); X } X X r->used = 0; X r->n = ul; X ul = r; X} X X/* X A fast single-arena allocator. Looks at the current block, and if there is not enough room, X it goes to getblock() for more. "ul" stands for "used list", and the head of the list is the X current block. X*/ X Xvoid *nalloc(SIZE_T n) { X char *ret; X X n = alignto(n, sizeof (ALIGN_T)); X X if (ul == NULL || n + ul->used >= ul->size) X getblock(n); X X ret = ul->mem + ul->used; X ul->used += n; X return ret; X} X X/* X Frees memory from nalloc space by putting it on the freelist. Returns free blocks to the X system, retaining at least MAXMEM bytes worth of blocks for nalloc. X*/ X X#define MAXMEM 500000 X Xvoid nfree() { X Block *r; X SIZE_T count; X X if (ul == NULL) X return; X X for (r = ul; r->n != NULL; r = r->n) X ; X X r->n = fl; X fl = ul; X ul = NULL; X X for (r = fl, count = r->size; r->n != NULL; r = r->n, count += r->size) { X if (count >= MAXMEM) { X Block *tmp = r; X X r = r->n; X tmp->n = NULL; /* terminate the freelist */ X X while (r != NULL) { /* free memory off the tail of the freelist */ X tmp = r->n; X efree(r->mem); X efree(r); X r = tmp; X } X return; X } X } X} X X/* X "allocates" a new arena by zeroing out the old one. Up to the calling routine to keep X the old value of the block around. X*/ X XBlock *newblock() { X Block *ret = ul; X X ul = NULL; X return ret; X} X X/* "restores" an arena to its saved value. */ X Xvoid restoreblock(Block *b) { X nfree(); X ul = b; X} END_OF_FILE if test 2218 -ne `wc -c <'nalloc.c'`; then echo shar: \"'nalloc.c'\" unpacked with wrong size! fi # end of 'nalloc.c' fi if test -f 'nalloc.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'nalloc.h'\" else echo shar: Extracting \"'nalloc.h'\" \(323 characters\) sed "s/^X//" >'nalloc.h' <<'END_OF_FILE' Xextern Block *newblock(void); Xextern void *nalloc(SIZE_T); Xextern void nfree(void); Xextern void restoreblock(Block *); X X#undef offsetof X#define offsetof(t, m) ((SIZE_T) &((t *)0)->m) X X/* memory allocation abbreviation */ X#define nnew(x) ((x *) nalloc(sizeof(x))) X#define ncpy(x) (strcpy((char *) nalloc(strlen(x) + 1), x)) END_OF_FILE if test 323 -ne `wc -c <'nalloc.h'`; then echo shar: \"'nalloc.h'\" unpacked with wrong size! fi # end of 'nalloc.h' fi if test -f 'node.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'node.h'\" else echo shar: Extracting \"'node.h'\" \(356 characters\) sed "s/^X//" >'node.h' <<'END_OF_FILE' Xenum nodetype { X rANDAND, ASSIGN, BACKQ, rBANG, BODY, NOWAIT, BRACE, CONCAT, X rCOUNT, rELSE, rFLAT, rDUP, EPILOG, NEWFN, FORIN, rIF, X rOROR, rPIPE, PRE, rREDIR, RMFN, ARGS, rSUBSHELL, X rSWITCH, MATCH, VAR, VARSUB, rWHILE, rWORD, LAPPEND, NMPIPE X}; X Xtypedef struct Node Node; X Xstruct Node { X enum nodetype type; X union { char *s; int i; Node *p; } u[3]; X}; END_OF_FILE if test 356 -ne `wc -c <'node.h'`; then echo shar: \"'node.h'\" unpacked with wrong size! fi # end of 'node.h' fi if test -f 'open.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'open.c'\" else echo shar: Extracting \"'open.c'\" \(772 characters\) sed "s/^X//" >'open.c' <<'END_OF_FILE' X/* open.c: to insulate <fcntl.h> from the rest of rc. */ X X#include <fcntl.h> X#include "lex.h" X#include "open.h" X X/* prototype for open() follows. comment out if necessary */ X X/*extern int open(const char *, int,...);*/ Xextern void rc_error(const char *); X X/* X Opens a file with the necessary flags. Assumes the following X declaration for enum redirtype: X X enum redirtype { X FROM, CREATE, APPEND, HEREDOC, HERESTRING X }; X*/ X Xstatic const int mode_masks[] = { X /* read */ O_RDONLY, X /* create */ O_TRUNC | O_CREAT | O_WRONLY, X /* append */ O_APPEND | O_CREAT | O_WRONLY X}; X Xint rc_open(const char *name, enum redirtype m) { X if ((unsigned int) m >= (sizeof(mode_masks)/sizeof(int))) X rc_error("bad mode passed to rc_open"); X X return open(name, mode_masks[m], 0644); X} END_OF_FILE if test 772 -ne `wc -c <'open.c'`; then echo shar: \"'open.c'\" unpacked with wrong size! fi # end of 'open.c' fi if test -f 'open.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'open.h'\" else echo shar: Extracting \"'open.h'\" \(50 characters\) sed "s/^X//" >'open.h' <<'END_OF_FILE' Xextern int rc_open(const char *, enum redirtype); END_OF_FILE if test 50 -ne `wc -c <'open.h'`; then echo shar: \"'open.h'\" unpacked with wrong size! fi # end of 'open.h' fi if test -f 'parse.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'parse.h'\" else echo shar: Extracting \"'parse.h'\" \(79 characters\) sed "s/^X//" >'parse.h' <<'END_OF_FILE' Xextern Node *parsetree; Xextern int yyparse(void); Xextern void initparse(void); END_OF_FILE if test 79 -ne `wc -c <'parse.h'`; then echo shar: \"'parse.h'\" unpacked with wrong size! fi # end of 'parse.h' fi if test -f 'rc.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rc.h'\" else echo shar: Extracting \"'rc.h'\" \(603 characters\) sed "s/^X//" >'rc.h' <<'END_OF_FILE' X#include "stddef.h" X#include "stdlib.h" X#include "string.h" X#include "unistd.h" X X#include "node.h" X X/* braindamaged IBM header files #define true and false */ X#undef FALSE X#undef TRUE X Xenum bool { FALSE, TRUE }; X Xtypedef enum bool boolean; Xtypedef struct Rq Rq; Xtypedef struct Block Block; Xtypedef struct List List; X Xstruct List { X char *w; X char *m; X List *n; X}; X Xextern char *prompt, *prompt2; Xextern Rq *redirq; Xextern boolean dashdee, dashee, dashvee, dashex, dashell, dasheye, interactive; Xextern int rc_pid; Xextern int lineno; Xextern List *fifoq; X X#define arraysize(a) ((int)sizeof(a)/sizeof(*a)) END_OF_FILE if test 603 -ne `wc -c <'rc.h'`; then echo shar: \"'rc.h'\" unpacked with wrong size! fi # end of 'rc.h' fi if test -f 'redir.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'redir.h'\" else echo shar: Extracting \"'redir.h'\" \(28 characters\) sed "s/^X//" >'redir.h' <<'END_OF_FILE' Xextern void doredirs(void); END_OF_FILE if test 28 -ne `wc -c <'redir.h'`; then echo shar: \"'redir.h'\" unpacked with wrong size! fi # end of 'redir.h' fi if test -f 'status.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'status.c'\" else echo shar: Extracting \"'status.c'\" \(2375 characters\) sed "s/^X//" >'status.c' <<'END_OF_FILE' X/* status.c: functions for printing fancy status messages in rc */ X X#include "rc.h" X#include "utils.h" X#include "status.h" X#include "nalloc.h" X#include "walk.h" X#include "sigmsgs.h" X X/* status == the wait() value of the last command in the pipeline, or the last command */ X Xstatic int statuses[512]; Xstatic int pipelength = 1; X X/* X Test to see if rc's status is true. According to td, status is true if and only if every X pipe-member has an exit status of zero. X*/ X Xint istrue(void) { X int i; X X for (i = 0; i < pipelength; i++) X if (statuses[i] != 0) X return FALSE; X return TRUE; X} X X/* X Return the status as an integer. A status which has low-bits set is a signal number, X whereas a status with high bits set is a value set from exit(). X*/ X Xint getstatus(void) { X int s = statuses[0]; X X return s & 0xff ? s & 0x7f : (s >> 8) & 0xff; X} X Xvoid set(boolean code) { X setstatus((!code) << 8); /* exit status 1 == 0x100 */ X} X X/* take a pipeline and store the exit statuses. Check to see whether any of the children dumped core */ X Xvoid setpipestatus(int stats[], int num) { X int i; X X for (i = 0; i < (pipelength = num); i++) { X statprint(stats[i]); X statuses[i] = stats[i]; X } X} X X/* set a simple status, as opposed to a pipeline */ X Xvoid setstatus(int i) { X pipelength = 1; X statuses[0] = i; X statprint(i); X} X X/* print a message if termination was with a signal, and if the child dumped core. exit on error if -e is set */ X Xvoid statprint(int i) { X if (i & 0xff) { X char *msg = ((i & 0x7f) < NUMOFSIGNALS ? signals[i & 0x7f][1] : ""); X X if (i & 0x80) { X if (*msg == '\0') X fprint(2,"core dumped\n"); X else X fprint(2,"%s--core dumped\n",msg); X } else if (*msg != '\0') X fprint(2,"%s\n",msg); X } X X if (i != 0 && dashee && !cond) X rc_exit(getstatus()); X} X X/* prepare a list to be passed back. Used whenever $status is dereferenced */ X XList *sgetstatus(void) { X List *r; X int i; X X for (r = NULL, i = 0; i < pipelength; i++) { X char buf[16]; X List *q = nnew(List); X int s = statuses[i]; X int t; X X q->n = r; X r = q; X X if ((t = s & 0x7f) != 0) { X if (t < NUMOFSIGNALS && *signals[t][0] != '\0') X sprint(buf, "%s", signals[t][0]); X else X sprint(buf,"-%d", t); /* unknown signals are negated */ X if (s & 0x80) X strcat(buf, "+core"); X } else { X sprint(buf, "%d", (s >> 8) & 0xff); X } X X r->w = ncpy(buf); X r->m = NULL; X } X X return r; X} END_OF_FILE if test 2375 -ne `wc -c <'status.c'`; then echo shar: \"'status.c'\" unpacked with wrong size! fi # end of 'status.c' fi if test -f 'status.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'status.h'\" else echo shar: Extracting \"'status.h'\" \(206 characters\) sed "s/^X//" >'status.h' <<'END_OF_FILE' Xextern int istrue(void); Xextern int getstatus(void); Xextern void set(boolean); Xextern void setstatus(int); Xextern List *sgetstatus(void); Xextern void setpipestatus(int [], int); Xextern void statprint(int); END_OF_FILE if test 206 -ne `wc -c <'status.h'`; then echo shar: \"'status.h'\" unpacked with wrong size! fi # end of 'status.h' fi if test -f 'stddef.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stddef.h'\" else echo shar: Extracting \"'stddef.h'\" \(758 characters\) sed "s/^X//" >'stddef.h' <<'END_OF_FILE' X/* stddef.h X This file provides a definition for size_t and align_t that X should work for your system. If it does not, it is up to you to X make it the right thing. The problem is that I cannot rely upon X <sys/params.h> to do the right thing on machines which don't X yet have ansi header files. Note that on many RISC machines, X align_t must be at least 32 bits wide, and sparc doubles are X aligned on 64 bit boundaries, but of course, rc does not use X doubles in its code, so the "typedef long ALIGN_T" is good X enough in the sparc's case. Also for performance reasons on a X VAX one would probably want align_t to be 32 bits wide. X*/ Xtypedef long ALIGN_T; Xtypedef unsigned int SIZE_T; Xtypedef short int MODE_T; Xtypedef int PID_T; X X#undef NULL X#define NULL 0 END_OF_FILE if test 758 -ne `wc -c <'stddef.h'`; then echo shar: \"'stddef.h'\" unpacked with wrong size! fi # end of 'stddef.h' fi if test -f 'stdlib.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stdlib.h'\" else echo shar: Extracting \"'stdlib.h'\" \(462 characters\) sed "s/^X//" >'stdlib.h' <<'END_OF_FILE' X/* X stdlib.h function prototypes as taken from Appendix B of K&R 2. X Unused functions are: X atof(), atoi(), atol(), strtod(), strtol(), strtoul(), rand(), X srand(), calloc(), abort(), atexit(), system(), getenv(), bsearch(), X abs(), labs(), div() and ldiv() X*/ X Xextern void *malloc(SIZE_T); Xextern void *realloc(void *, SIZE_T); Xextern void free(void *); Xextern void exit(int); Xextern void qsort(void *, SIZE_T, SIZE_T, int (*)(const void *, const void *)); END_OF_FILE if test 462 -ne `wc -c <'stdlib.h'`; then echo shar: \"'stdlib.h'\" unpacked with wrong size! fi # end of 'stdlib.h' fi if test -f 'string.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'string.h'\" else echo shar: Extracting \"'string.h'\" \(475 characters\) sed "s/^X//" >'string.h' <<'END_OF_FILE' Xextern int strncmp(const char *, const char *, SIZE_T); Xextern int strcmp(const char *, const char *); Xextern SIZE_T strlen(const char *); Xextern char *strchr(const char *, int); Xextern char *strcpy(char *, const char *); Xextern char *strncpy(char *, const char *, SIZE_T); Xextern char *strcat(char *, const char *); Xextern char *strncat(char *, const char *, SIZE_T); Xextern void *memcpy(void *, const void *, SIZE_T); X X#define streq(x,y) (*(x) == *(y) && strcmp(x,y) == 0) END_OF_FILE if test 475 -ne `wc -c <'string.h'`; then echo shar: \"'string.h'\" unpacked with wrong size! fi # end of 'string.h' fi if test -f 'tree.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tree.h'\" else echo shar: Extracting \"'tree.h'\" \(132 characters\) sed "s/^X//" >'tree.h' <<'END_OF_FILE' Xextern Node *newnode(int /*enum nodetype*/ t,...); Xextern Node *treecpy(Node *s, void *(*)(SIZE_T)); Xextern void treefree(Node *s); END_OF_FILE if test 132 -ne `wc -c <'tree.h'`; then echo shar: \"'tree.h'\" unpacked with wrong size! fi # end of 'tree.h' fi if test -f 'unistd.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'unistd.h'\" else echo shar: Extracting \"'unistd.h'\" \(490 characters\) sed "s/^X//" >'unistd.h' <<'END_OF_FILE' Xextern PID_T fork(void); Xextern PID_T getpid(void); Xextern int chdir(const char *); Xextern int close(int); Xextern int dup2(int, int); Xextern int execve(const char *, const char **, const char **); Xextern int isatty(int); Xextern int mknod(const char *, int, int); Xextern int pipe(int *); Xextern int read(int, void *, unsigned int); Xextern int setpgrp(int, PID_T); Xextern int unlink(const char *); Xextern int write(int, const void *, unsigned int); Xextern int wait(int *); X Xextern int errno; END_OF_FILE if test 490 -ne `wc -c <'unistd.h'`; then echo shar: \"'unistd.h'\" unpacked with wrong size! fi # end of 'unistd.h' fi if test -f 'utils.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'utils.h'\" else echo shar: Extracting \"'utils.h'\" \(854 characters\) sed "s/^X//" >'utils.h' <<'END_OF_FILE' Xextern char *strprint(char *, int, int); Xextern char *sprint(char *, char *,...); Xextern int isabsolute(char *); /* not boolean because y.tab.c includes utils.h */ Xextern int a2u(char *); Xextern int o2u(char *); Xextern int starstrcmp(const void *, const void *); Xextern void *ealloc(SIZE_T); Xextern void *erealloc(void *, SIZE_T); Xextern void efree(void *); Xextern void fprint(int, char *,...); Xextern void empty_fifoq(void); Xextern void rc_error(char *); Xextern void rc_exit(int); /* prototyped here, but defined in fn.c */ Xextern void sig(int); Xextern void clear(char *, SIZE_T); Xextern void uerror(char *); Xextern void writeall(int, char *, SIZE_T); Xextern SIZE_T strarraylen(char **); X X/* memory allocation abbreviations */ X#define enew(x) ((x *) ealloc(sizeof(x))) X#define ecpy(x) strcpy((char *) ealloc(strlen(x) + 1),x) X X#define FPRINT_SIZE 16384 END_OF_FILE if test 854 -ne `wc -c <'utils.h'`; then echo shar: \"'utils.h'\" unpacked with wrong size! fi # end of 'utils.h' fi if test -f 'version.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'version.c'\" else echo shar: Extracting \"'version.c'\" \(63 characters\) sed "s/^X//" >'version.c' <<'END_OF_FILE' Xstatic volatile const char *id = "rc version 1.0, 5/20/91.\n"; END_OF_FILE if test 63 -ne `wc -c <'version.c'`; then echo shar: \"'version.c'\" unpacked with wrong size! fi # end of 'version.c' fi if test -f 'walk.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'walk.h'\" else echo shar: Extracting \"'walk.h'\" \(59 characters\) sed "s/^X//" >'walk.h' <<'END_OF_FILE' Xextern boolean walk(Node *, boolean); Xextern boolean cond; END_OF_FILE if test 59 -ne `wc -c <'walk.h'`; then echo shar: \"'walk.h'\" unpacked with wrong size! fi # end of 'walk.h' fi echo shar: End of archive 4 \(of 4\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 4 archives. rm -f ark[1-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.