rsalz@uunet.UU.NET (Rich Salz) (10/16/87)
Submitted-by: Zoltan Somogyi <zs@munnari.oz> Posting-number: Volume 12, Issue 9 Archive-name: cake/part03 #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # list.c # main.c # make.c # mem.c # pat.c # print.c # proc.c # sym.c # sys.c # table.c # test.c # trail.c # This archive created: Wed Oct 14 21:10:02 1987 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'list.c'" '(2669 characters)' if test -f 'list.c' then echo shar: "will not over-write existing file 'list.c'" else sed 's/^X//' << \SHAR_EOF > 'list.c' X/* X** Linked list module. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/list.c,v 1.14 86/07/19 12:23:15 zs Exp $"; X X#include "cake.h" X X/* X** Make an empty list. X*/ X XList * Xmakelist0() X{ X reg List *list; X X list = make(List); X ldata(list) = (Cast) 0; X next(list) = list; X prev(list) = list; X X return list; X} X X/* X** Make a list with the argument is its only element. X*/ X XList * X_makelist(data) Xreg Cast data; X{ X return addhead(makelist0(), data); X} X X/* X** Add some data to the head of a list. X*/ X XList * X_addhead(list, data) Xreg List *list; Xreg Cast data; X{ X reg List *item; X X if (list == NULL) X list = makelist0(); X X item = make(List); X ldata(item) = data; X ldata(list) = (Cast) ((int) ldata(list) + 1); X X /* item's pointers */ X next(item) = next(list); X prev(item) = list; X /* neighbours' pointers */ X next(prev(item)) = item; X prev(next(item)) = item; X X return list; X} X X/* X** Add some data to the tail of a list. X*/ X XList * X_addtail(list, data) Xreg List *list; Xreg Cast data; X{ X reg List *item; X X if (list == NULL) X list = makelist0(); X X item = make(List); X ldata(item) = data; X ldata(list) = (Cast) ((int) ldata(list) + 1); X X /* item's pointers */ X next(item) = list; X prev(item) = prev(list); X /* neighbours' pointers */ X next(prev(item)) = item; X prev(next(item)) = item; X X return list; X} X X/* X** Destructively append list2 to list1. Since the header of X** list2 is not meaningful after the operation, it is freed. X*/ X XList * Xaddlist(list1, list2) Xreg List *list1; Xreg List *list2; X{ X if (list1 == NULL) X list1 = makelist0(); X X if (list2 == NULL) X list2 = makelist0(); X X if (length(list2) > 0) X { X if (length(list1) == 0) X { X ldata(list1) = ldata(list2); X /* pointers from header */ X next(list1) = next(list2); X prev(list1) = prev(list2); X /* pointers to header */ X prev(next(list1)) = list1; X next(prev(list1)) = list1; X } X else X { X ldata(list1) = (Cast) ((int) ldata(list1) + (int) ldata(list2)); X /* end of list 1 to start of list 2 */ X next(prev(list1)) = next(list2); X prev(next(list2)) = prev(list1); X /* end of list 2 to start of list 1 */ X next(prev(list2)) = list1; X prev(list1) = prev(list2); X } X } X X oldmem((Cast) list2); X return list1; X} X X/* X** Return the length of a given list. X*/ X Xint Xlength(list) Xreg List *list; X{ X if (list == NULL) X return 0; X X return (int) ldata(list); X} X X/* X** Delete an item from its linked list, and free the node. X*/ X Xdelete(list, item) Xreg List *list; Xreg List *item; X{ X if (list == NULL) X return; X X if (item == NULL) X return; X X ldata(list) = (Cast) ((int) ldata(list) - 1); X next(prev(item)) = next(item); X prev(next(item)) = prev(item); X X oldmem((Cast) item); X} SHAR_EOF if test 2669 -ne "`wc -c < 'list.c'`" then echo shar: "error transmitting 'list.c'" '(should have been 2669 characters)' fi fi echo shar: "extracting 'main.c'" '(9780 characters)' if test -f 'main.c' then echo shar: "will not over-write existing file 'main.c'" else sed 's/^X//' << \SHAR_EOF > 'main.c' X/* X** Cake main file. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/main.c,v 1.15 87/10/05 20:14:53 zs Exp $"; X X#include "cake.h" X#include <pwd.h> X#include <signal.h> X#include <sys/stat.h> X Xtypedef struct passwd Pwent; Xtypedef struct stat Stat; X Xint Gflag = FALSE; Xint Lflag = FALSE; Xint Rflag = FALSE; Xint Xflag = FALSE; Xint Zflag = FALSE; Xint bflag = FALSE; Xint cflag = FALSE; Xint dflag = FALSE; Xint gflag = FALSE; Xint iflag = FALSE; Xint kflag = TRUE; Xint nflag = FALSE; Xint qflag = FALSE; Xint rflag = FALSE; Xint sflag = FALSE; Xint tflag = FALSE; Xint vflag = FALSE; Xint wflag = FALSE; Xint xflag = FALSE; Xint zflag = FALSE; X Xchar *cakefile = NULL; Xchar *shellfile[2] = { SYSTEM_CMD, SCRIPT_CMD }; Xchar *metachars = METACHARS; Xint maxprocs = 1; XList *active_procs; Xchar scratchbuf[128]; X Xint cakedebug = FALSE; Xint entrydebug = FALSE; Xint patdebug = FALSE; Xint lexdebug = FALSE; X Xchar cakeflagbuf[MAXSIZE]; Xchar *cppargv[MAXARGS]; Xint cppargc = 0; X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X extern cake_abort(), cake_finish(); X extern int parse_args(), process_args(); X extern Node *chase(); X extern char *getenv(); X extern char *dir_setup(); X extern Pwent *getpwuid(); X extern int geteuid(); X extern FILE *cake_popen(); X extern FILE *yyin; X extern int yydebug; X Stat statbuf; X int envc; X char *envv[MAXARGS]; X reg Pwent *pwent; X reg char *envstr; X reg int status; X reg Node *rootnode; X X signal(SIGINT, cake_finish); X signal(SIGQUIT, cake_finish); X signal(SIGILL, cake_abort); X signal(SIGTRAP, cake_abort); X signal(SIGIOT, cake_abort); X signal(SIGEMT, cake_abort); X signal(SIGFPE, cake_abort); X signal(SIGBUS, cake_abort); X signal(SIGSEGV, cake_abort); X signal(SIGSYS, cake_abort); X signal(SIGPIPE, cake_abort); X signal(SIGALRM, cake_abort); X X yydebug = FALSE; X active_procs = makelist0(); X X if (rindex(argv[0], 'f') != NULL X && streq(rindex(argv[0], 'f'), "fake")) X cakedebug = TRUE; X X init_sym(); X cppargv[cppargc++] = new_name(CPP); X strcpy(cakeflagbuf, "-DCAKEFLAGS="); X X if ((envstr = getenv("CAKE")) != NULL) X { X envc = parse_args(envstr, envv); X process_args(envv, &envc, 0); X if (envc > 0) X fprintf(stderr, "cake: non-options in environment ignored\n"); X } X X argv += process_args(argv, &argc, 1); X X#ifdef CAKEDEBUG X if (cakedebug || entrydebug || patdebug || lexdebug) X setlinebuf(stdout); X#endif X X if (cakefile == NULL) X { X if (stat("cakefile", &statbuf) == 0) X cakefile = "cakefile"; X or (stat("Cakefile", &statbuf) == 0) X cakefile = "Cakefile"; X or (stat("recipe", &statbuf) == 0) X cakefile = "recipe"; X or (stat("Recipe", &statbuf) == 0) X cakefile = "Recipe"; X else X { X fprintf(stderr, "cake: cannot locate a cakefile\n"); X exit(1); X } X } X X if (gflag) X cakefile = dir_setup(cakefile); X X pwent = getpwuid(geteuid()); X strcpy(scratchbuf, "-I"); X strcat(scratchbuf, pwent->pw_dir); X strcat(scratchbuf, ULIB); X cppargv[cppargc++] = new_name(scratchbuf); X strcpy(scratchbuf, "-I"); X strcat(scratchbuf, SLIB); X cppargv[cppargc++] = new_name(scratchbuf); X cppargv[cppargc++] = cakeflagbuf; X cppargv[cppargc++] = cakefile; X cppargv[cppargc] = NULL; X X if (cakedebug) X { X reg int i; X X for (i = 0; i < cppargc; i++) X printf("%s\n", cppargv[i]); X } X X if ((yyin = cake_popen(cppargv, "r")) == NULL) X { X fprintf(stderr, "cake: cannot open cpp filter\n"); X exit(1); X } X X if (Zflag) X { X reg int c; X X while ((c = getc(yyin)) != EOF) X putchar(c); X X cake_pclose(yyin); X exit(0); X } X X yyinit(); X init_entry(); X if (yyparse()) X { X fprintf(stderr, "cake: cannot parse %s\n", cakefile); X exit(1); X } X X shell_setup(shellfile[0], 0); X shell_setup(shellfile[1], 1); X meta_setup(metachars); X X cake_pclose(yyin); X dir_start(); X prep_entries(); X final_entry(argc, argv); X X rootnode = chase(CHASEROOT, 0, (Entry *) NULL); X X if (! qflag) X execute(rootnode); X X dir_finish(); X cleanup(); X#ifdef STATS_FILE X statistics(); X#endif X X status = (off_node(rootnode, nf_ERR) && is_ok(rootnode))? 0: 1; X cdebug("exit status %d\n", status); X exit(status); X} X Xint Xprocess_args(vector, count, base) Xreg char **vector; Xreg int *count; Xreg int base; X{ X reg int i, j; X X j = 0; X cdebug("process args:"); X while (*count > base && vector[base][0] == '-') X { X putflag(base, vector[base]); X X for (i = 1; vector[base][i] != '\0'; i++) X { X switch (vector[base][i]) X { X X#ifdef CAKEDEBUG X when 'C': cdebug(" -C"); X cakedebug = ! cakedebug; X X when 'E': cdebug(" -E"); X entrydebug = ! entrydebug; X X when 'P': cdebug(" -P"); X patdebug = ! patdebug; X X when 'W': cdebug(" -W"); X lexdebug = TRUE; X X when 'Y': cdebug(" -Y"); X yydebug = TRUE; X#endif X when 'G': cdebug(" -G"); X Gflag = TRUE; X X when 'L': cdebug(" -L"); X Lflag = TRUE; X X when 'R': cdebug(" -R"); X Rflag = TRUE; X X when 'X': cdebug(" -X"); X Xflag = TRUE; X X when 'Z': cdebug(" -Z"); X Zflag = TRUE; X X when 'a': cdebug(" -a"); X kflag = FALSE; X X when 'b': cdebug(" -b"); X bflag = TRUE; X X when 'c': cdebug(" -c"); X cflag = TRUE; X X when 'd': cdebug(" -d"); X dflag = TRUE; X X when 'g': cdebug(" -g"); X gflag = TRUE; X X when 'i': cdebug(" -i"); X iflag = TRUE; X X when 'k': cdebug(" -k"); X kflag = TRUE; X X when 'n': cdebug(" -n"); X nflag = TRUE; X tflag = FALSE; X qflag = FALSE; X X when 'q': cdebug(" -q"); X qflag = TRUE; X nflag = FALSE; X tflag = FALSE; X X when 'r': cdebug(" -r"); X rflag = TRUE; X X when 's': cdebug(" -s"); X sflag = TRUE; X X when 't': cdebug(" -t"); X tflag = TRUE; X nflag = FALSE; X qflag = FALSE; X X when 'v': cdebug(" -v"); X vflag = TRUE; X X when 'w': cdebug(" -w"); X wflag = TRUE; X X when 'x': cdebug(" -x"); X xflag = TRUE; X X when 'z': cdebug(" -z"); X zflag = TRUE; X X when 'D': X case 'I': X case 'U': if (i != 1) X usage(); X X cdebug(" %s", vector[base]); X cppargv[cppargc++] = new_name(vector[base]); X goto nextword; X X when 'N': putflag(base, vector[base+1]); X sscanf(vector[base+1], "%d", &maxprocs); X if (vector[base][i+1] != '\0') X usage(); X X cdebug(" -N %d", maxprocs); X (*count)--; X vector++, j++; X goto nextword; X X when 'S': putflag(base, vector[base+1]); X if (vector[base][i+1] == '1') X shellfile[0] = new_name(vector[base+1]); X or (vector[base][i+1] == '2') X shellfile[1] = new_name(vector[base+1]); X else X usage(); X X if (vector[base][i+2] != '\0') X usage(); X X cdebug(" -S%c %s", vector[base][i+1], vector[base+1]); X (*count)--; X vector++, j++; X goto nextword; X X when 'T': putflag(base, vector[base+1]); X metachars = new_name(vector[base+1]); X if (vector[base][i+1] != '\0') X usage(); X X cdebug(" -T %s", metachars); X (*count)--; X vector++, j++; X goto nextword; X X when 'f': putflag(base, vector[base+1]); X cakefile = new_name(vector[base+1]); X if (vector[base][i+1] != '\0') X usage(); X X cdebug(" -f %s", cakefile); X (*count)--; X vector++, j++; X goto nextword; X X otherwise: usage(); X } X } X Xnextword: X (*count)--; X vector++, j++; X } X X cdebug(" \n%return %d\n", j); X return j; X} X X/* X** Put a flag into the CAKEFLAGS definition. X*/ X Xputflag(base, flag) Xreg int base; Xreg char *flag; X{ X if (base == 1) X { X strcat(cakeflagbuf, " "); X strcat(cakeflagbuf, flag); X if (strlen(cakeflagbuf) >= MAXSIZE) X { X fprintf(stderr, "cake: CAKEFLAGS too long\n"); X exit(1); X } X } X} X X/* X** Tell the unfortunate user how to use cake. X*/ X Xusage() X{ X fprintf(stderr, "Usage: cake [-abcdgiknqrstvwxzGLRXZ] [-ffile]\n"); X fprintf(stderr, " [-Ddefn] [-Idir] [-Uname] [-S shell] [-T metachars] [file ...]\n"); X exit(1); X} X Xexit_cake(needtrail) Xreg int needtrail; X{ X if (cakedebug && needtrail) X get_trail(stdout); X else X dir_finish(); X X exit(1); X} X X/* X** Handle bus errors and segmentation violations. X*/ X Xcake_abort() X{ X X signal(SIGINT, SIG_IGN); X signal(SIGQUIT, SIG_IGN); X X printf("Abort on signal\n"); X if (cakedebug) X get_trail(stdout); X X signal(SIGQUIT, SIG_DFL); X kill(getpid(), SIGQUIT); X} X X/* X** Handle user interrupts. X*/ X Xcake_finish() X{ X reg List *ptr; X reg Proc *proc; X X signal(SIGINT, SIG_IGN); X signal(SIGQUIT, SIG_IGN); X X printf("*** Interrupt\n"); X fflush(stdout); X for_list (ptr, active_procs) X { X proc = (Proc *) ldata(ptr); X if (proc->pr_node != NULL) X cake_error(proc->pr_node); X } X X exit_cake(FALSE); X} X X#ifdef STATS_FILE X#ifdef ATT X#include <sys/times.h> X Xtypedef struct tms Tms; X#else X#include <sys/time.h> X#include <sys/resource.h> X Xtypedef struct rusage Rusage; X#endif X Xstatistics() X{ X extern char *getlogin(); X extern getpw(); X extern int out_tried, out_found; X extern int stat_tried, stat_found; X FILE *sfp; X X if ((sfp = fopen(STATS_FILE, "a")) != NULL) X { X#ifdef ATT X Tms tbuf; X#else X Rusage s, c; X#endif X long su, ss, cu, cs; X char *usr; X X if ((usr = getlogin()) == NULL) X { X char buf[256]; X char *usr_end; X X if (getpw(getuid(), buf) != 0) X usr = "NULL"; X else X { X usr = buf; X if ((usr_end = index(usr, ':')) != NULL) X *usr_end = '\0'; X else X usr = "NULL"; X } X X usr = new_name(usr); X } X X#ifdef ATT X if (times(&tbuf) == -1) X { X fclose(sfp); X return; X } X X su = tbuf.tms_utime*100/TIMERES; X ss = tbuf.tms_stime*100/TIMERES; X cu = tbuf.tms_cutime*100/TIMERES; X cs = tbuf.tms_cstime*100/TIMERES; X#else X getrusage(RUSAGE_SELF, &s); X getrusage(RUSAGE_CHILDREN, &c); X X su = s.ru_utime.tv_sec*100 + s.ru_utime.tv_usec/10000; X ss = s.ru_stime.tv_sec*100 + s.ru_stime.tv_usec/10000; X cu = c.ru_utime.tv_sec*100 + c.ru_utime.tv_usec/10000; X cs = c.ru_stime.tv_sec*100 + c.ru_stime.tv_usec/10000; X#endif X fprintf(sfp, "%s %ld %ld %ld %ld ", usr, su, ss, cu, cs); X fprintf(sfp, "%d %d %d %d %d\n", sbrk(0), X out_tried, out_found, stat_tried, stat_found); X X fclose(sfp); X } X} X#endif SHAR_EOF if test 9780 -ne "`wc -c < 'main.c'`" then echo shar: "error transmitting 'main.c'" '(should have been 9780 characters)' fi fi echo shar: "extracting 'make.c'" '(2967 characters)' if test -f 'make.c' then echo shar: "will not over-write existing file 'make.c'" else sed 's/^X//' << \SHAR_EOF > 'make.c' X/* X** Module to make Cake data structures. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/make.c,v 1.15 87/10/05 20:15:02 zs Exp $"; X X#include "cake.h" X XNode * Xmake_node(name) Xreg char *name; X{ X reg Node *node; X X node = make(Node); X node->n_name = name; X X if (name == NULL) X return node; X X node->n_kind = n_NOWAY; /* not yet */ X node->n_flag = 0; X node->n_old = makelist0(); X node->n_when = NULL; X node->n_act = NULL; X node->n_new = makelist(node); X#if 0 /* N must be 1 for the time being */ X node->n_pid = 0; X node->n_file = NULL; X#endif X node_stat(node); X node->n_utime = 0; X node->n_stime = node->n_rtime; X node->n_badguys = NULL; X node->n_msg = NULL; X X return node; X} X XEntry * Xmake_dep(new, old, cond, file, colon) Xreg List *new; /* of Pat */ Xreg List *old; /* of Pat */ Xreg Test *cond; Xreg char *file; Xreg char *colon; X{ X reg Entry *entry; X X entry = make(Entry); X entry->e_new = new; X entry->e_old = old; X entry->e_cond = cond; X entry->e_file = file; X entry->e_dblc = streq(colon, "::"); X entry->e_when = makelist0(); X X return entry; X} X XTest * Xmake_test_mm(name) Xreg Pat *name; X{ X reg Test *test; X X test = make(Test); X test->t_kind = t_MATCH; X test->t_pat = name; X test->t_list = makelist0(); X X return test; X} X XTest * Xmake_test_m(name, varpat, pattern) Xreg Pat *name; Xreg Pat *varpat; Xreg Pat *pattern; X{ X reg Test *test; X X test = make(Test); X test->t_kind = t_MATCH; X test->t_pat = name; X test->t_list = makelist0(); X X if (varpat == NULL) X addtail(test->t_list, make_pat("-vX", FALSE, 0)); X else X addtail(test->t_list, varpat); /* no assignment */ X X addtail(test->t_list, pattern); /* no assignment */ X return test; X} X XTest * Xmake_test_c(cmd) Xreg char *cmd; X{ X reg Test *test; X X test = make(Test); X test->t_kind = t_CMD; X test->t_cmd = cmd; X X return test; X} X XTest * Xmake_test_s(tkind, pat) Xreg T_kind tkind; Xreg Pat *pat; X{ X reg Test *test; X X test = make(Test); X test->t_kind = tkind; X test->t_pat = pat; X X return test; X} X XTest * Xmake_test_l(pat, list) Xreg Pat *pat; Xreg List *list; /* of Pat */ X{ X reg Test *test; X X test = make(Test); X test->t_kind = t_LIST; X test->t_pat = pat; X test->t_list = list; X X return test; X} X XTest * Xmake_test_b(tkind, left, right) Xreg T_kind tkind; Xreg Test *left; Xreg Test *right; X{ X reg Test *test; X X test = make(Test); X test->t_kind = tkind; X test->t_left = left; X test->t_right = right; X X return test; X} X XTest * Xmake_test_u(tkind, left) Xreg T_kind tkind; Xreg Test *left; X{ X reg Test *test; X X test = make(Test); X test->t_kind = tkind; X test->t_left = left; X test->t_right = (Test *) NULL; X X return test; X} X XPat * Xmake_pat(text, iscmd, flags) Xreg char *text; Xreg bool iscmd; Xreg int flags; X{ X reg Pat *pat; X X pat = make(Pat); X pat->p_str = text; X pat->p_cmd = iscmd; X pat->p_flag = flags; X X checkpatlen(text); X return pat; X} X XAct * Xmake_act(str, flag) Xreg char *str; Xreg int flag; X{ X reg Act *act; X X act = make(Act); X act->a_str = str; X act->a_flag = flag; X X return act; X} SHAR_EOF if test 2967 -ne "`wc -c < 'make.c'`" then echo shar: "error transmitting 'make.c'" '(should have been 2967 characters)' fi fi echo shar: "extracting 'mem.c'" '(822 characters)' if test -f 'mem.c' then echo shar: "will not over-write existing file 'mem.c'" else sed 's/^X//' << \SHAR_EOF > 'mem.c' X/* X** Memory management module. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/mem.c,v 1.15 87/10/05 20:15:10 zs Exp $"; X X#include "cake.h" X X/* X** Allocate space if possible. In the future it may record X** all pointers returned, so that old can do some checks. X*/ X XCast Xnewmem(size) Xint size; X{ X reg char *space; X X if ((space = malloc((unsigned) size)) == NULL) X { X fprintf(stderr, "cake system error: no more malloc\n"); X exit_cake(FALSE); X } X X#ifdef EXTRACHECK X if (((int) space & 03) != 0) X { X fprintf(stderr, "cake system error: malloc not aligned\n"); X exit_cake(FALSE); X } X#endif X X return (Cast) space; X} X X/* X** Return some storage to the free list. This storage must X** have been obtained from new and malloc. X*/ X X/*ARGSUSED*/ Xoldmem(ptr) XCast ptr; X{ X#ifdef MEMUSED X free((char *) ptr); X#endif X} SHAR_EOF if test 822 -ne "`wc -c < 'mem.c'`" then echo shar: "error transmitting 'mem.c'" '(should have been 822 characters)' fi fi echo shar: "extracting 'pat.c'" '(6360 characters)' if test -f 'pat.c' then echo shar: "will not over-write existing file 'pat.c'" else sed 's/^X//' << \SHAR_EOF > 'pat.c' X/* X** Module to manipulate Cake patterns. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/pat.c,v 1.15 87/10/05 20:15:15 zs Exp $"; X X#include "cake.h" X#include <ctype.h> X X/* X** This function serves as an interface to the rest of the system X** for domatch, looking after its environment. X*/ X Xbool Xmatch(env, str, pat) XEnv env; Xreg char *str; Xreg Pat *pat; X{ X extern bool domatch(); X reg bool result; X reg int i; X reg char *s, *p; X X if (patdebug) X printf("Match %s vs %s\n", str, pat->p_str); X X if (pat->p_cmd) X { X fprintf(stderr, "cake internal error: undereferenced pattern %s in match\n", X pat->p_str); X exit_cake(TRUE); X } X X if (streq(str, CHASEROOT)) X result = streq(pat->p_str, CHASEROOT); X else X { X result = TRUE; /* assume so for the moment */ X p = pat->p_str+strlen(pat->p_str)-1; X if (*p != '%' && !isdigit(*p)) /* not part of a var */ X { X s = str+strlen(str)-1; X if (*s != *p) /* last chars differ */ X result = FALSE; X } X X if (result) /* if last-char test inconclusive */ X { X for (i = 0; i < MAXVAR; i++) X env[i].v_bound = FALSE; X X result = domatch(env, str, pat->p_str); X } X } X X if (patdebug) X { X if (result == FALSE) X printf("Match failed\n"); X else X { X printf("Match succeeded\n"); X for (i = 0; i < MAXVAR; i++) X if (env[i].v_bound) X printf("X%d: %s\n", i, env[i].v_val); X } X } X X return result; X} X X/* X** Match a string against a pattern. X** The pattern is expected to have been dereferenced. X** To handle nondeterminism, a brute force recursion approach X** is taken. X*/ X Xbool Xdomatch(env, str, patstr) XEnv env; Xreg char *str; Xreg char *patstr; X{ X char buf[MAXPATSIZE]; X reg char *follow; X reg char *s, *t; X reg int varno; X reg int i; X reg bool more; X X put_trail("domatch", "start"); X if (patstr[0] == '%') X { X if (isdigit(patstr[1])) X { X varno = patstr[1] - '0'; X follow = patstr + 2; X } X else X { X varno = NOVAR; X follow = patstr + 1; X } X X if (env[varno].v_bound) X { X /* lifetime of buf is local */ X strcpy(buf, env[varno].v_val); X strcat(buf, follow); X checkpatlen(buf); X put_trail("domatch", "recurse"); X return domatch(env, str, buf); X } X X i = 0; X buf[0] = '\0'; X env[varno].v_bound = TRUE; X env[varno].v_val = buf; X X /* keep invariant: buf = tentative value of var */ X /* the value of a variable may never contain a % */ X /* must consider *s == \0, but do not overshoot */ X for (s = str, more = TRUE; more && *s != '%'; s++) X { X if (patdebug) X printf("trying X%d = '%s'\n", varno, buf); X X if (domatch(env, s, follow)) X { X checkpatlen(buf); X env[varno].v_val = new_name(buf); X /* lifetime of buf is now global */ X put_trail("domatch", "finish"); X return TRUE; X } X X /* maintain invariant */ X buf[i++] = *s; X buf[i] = '\0'; X X more = (*s != '\0'); X } X X /* no luck, match failed */ X env[varno].v_bound = FALSE; X put_trail("domatch", "finish"); X return FALSE; X } X X /* here we have something other than a variable first off */ X for (s = str, t = patstr; *t != '\0' && *t != '%'; s++, t++) X { X if (*t == '\\') X t++; /* the new *t is not checked for % */ X X if (*s != *t) X { X put_trail("domatch", "finish"); X return FALSE; X } X } X X /* see if we have come to the end of the pattern */ X if (*t == '\0') X { X put_trail("domatch", "finish"); X return *s == '\0'; X } X X /* if not, recurse on the next variable */ X put_trail("domatch", "recurse"); X return domatch(env, s, t); X} X X/* X** Ground the argument string, i.e. replace all occurrences X** of variables in it. It is fatal error for the string to X** contain a variable which has no value. X*/ X Xchar * Xground(env, str) XEnv env; Xreg char *str; X{ X reg char *s, *t; X reg int i, var; X char buf[MAXSIZE]; X X put_trail("ground", "start"); X i = 0; X for (s = str; *s != '\0'; s++) X { X if (*s == '%') X { X if (isdigit(s[1])) X var = *++s - '0'; X else X var = NOVAR; X X if (! env[var].v_bound) X { X if (var == NOVAR) X fprintf(stderr, "cake: %s is undefined in %s\n", "%", str); X else X fprintf(stderr, "cake: %s%1d is undefined in %s\n", "%", var, str); X exit_cake(FALSE); X } X X for (t = env[var].v_val; *t != '\0'; t++) X buf[i++] = *t; X } X or (*s == '\\') X { X if (s[1] != '\0') X buf[i++] = *++s; X } X else X buf[i++] = *s; X } X X buf[i] = '\0'; X if (i >= MAXSIZE) X { X fprintf(stderr, "cake internal error: pattern buffer overflow for %s\n", buf); X exit_cake(FALSE); X } X X put_trail("ground", "new_name finish"); X return new_name(buf); X} X X/* X** See if the argument contains any variebles. X*/ X Xbool Xhasvars(str) Xreg char *str; X{ X reg char *s; X X for (s = str; *s != '\0'; s++) X { X if (*s == '%') X return TRUE; X or (*s == '\\') X { X if (s[1] != '\0') X s++; X } X } X X return FALSE; X} X X/* X** Dereference the pattern; i.e. if it a command pattern X** replace it with the output of the command. It is the task X** of the caller to break this up if necessary. X** Note that the pattern will never have to be dereferenced again. X** X** The second arg says whether the pattern is to be broken after X** dereferencing: this is needed purely for debugging purposes. X*/ X Xderef(pat, broken) Xreg Pat *pat; Xreg bool broken; X{ X extern char *expand_cmds(); X X if (! pat->p_cmd) X return; X X pat->p_cmd = FALSE; X pat->p_str = expand_cmds(pat->p_str); X X if (! broken) X checkpatlen(pat->p_str); X} X X/* X** Break the given pattern up into a (possibly empty) list X** of smaller patterns at white space positions. X*/ X XList * Xbreak_pat(pat) Xreg Pat *pat; X{ X reg Pat *newpat; X reg List *list; X reg char *s; X X put_trail("break_pat", "start"); X if (pat->p_cmd) X { X fprintf(stderr, "cake internal error: trying to break command pattern %s\n", pat->p_str); X exit_cake(TRUE); X } X X list = makelist0(); X s = pat->p_str; X while (*s != '\0') X { X char buf[MAXSIZE]; X reg int i; X X for (; *s != '\0' && isspace(*s); s++) X ; X X i = 0; X for (; *s != '\0' && !isspace(*s); s++) X buf[i++] = *s; X X buf[i] = '\0'; X if (i > 0) X { X newpat = make_pat(new_name(buf), FALSE, pat->p_flag); X addtail(list, newpat); /* no assignment */ X } X } X X put_trail("break_pat", "finish"); X return list; X} X X/* X** Add flags to a list of patterns. X*/ X XList * Xset_flag(patlist, flags) Xreg List *patlist; Xreg int flags; X{ X reg List *ptr; X reg Pat *pat; X X for_list (ptr, patlist) X { X pat = (Pat *) ldata(ptr); X pat->p_flag |= flags; X } X X return patlist; X} SHAR_EOF if test 6360 -ne "`wc -c < 'pat.c'`" then echo shar: "error transmitting 'pat.c'" '(should have been 6360 characters)' fi fi echo shar: "extracting 'print.c'" '(4954 characters)' if test -f 'print.c' then echo shar: "will not over-write existing file 'print.c'" else sed 's/^X//' << \SHAR_EOF > 'print.c' X/* X** Printout routines for Cake data structures. X*/ X X#ifdef CAKEDEBUG X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/print.c,v 1.15 87/10/05 20:15:33 zs Exp $"; X X#include "cake.h" X Xchar * Xstr_pflag(flag) Xreg int flag; X{ X char buf[256]; X X strcpy(buf, "["); X if (flag & nf_NONVOL) X strcat(buf, "nonvol "); X if (flag & nf_PRECIOUS) X strcat(buf, "precious "); X if (flag & nf_PSEUDO) X strcat(buf, "pseudo "); X if (flag & nf_REDUNDANT) X strcat(buf, "redundant "); X if (flag & nf_WHEN) X strcat(buf, "when "); X if (flag & nf_DEPNONVOL) X strcat(buf, "depnonvol "); X if (flag & nf_NODELETE) X strcat(buf, "nodelete "); X if (flag & nf_NEWFILE) X strcat(buf, "newfile "); X if (flag & nf_EXIST) X strcat(buf, "exist "); X if (flag & nf_BUSY) X strcat(buf, "busy "); X if (flag & nf_ERR) X strcat(buf, "err "); X if (flag & nf_TRACED) X strcat(buf, "traced "); X if (flag & nf_WARNED) X strcat(buf, "warned "); X if (flag & nf_ORIG) X strcat(buf, "orig "); X X if (strlen(buf) > 1) X buf[strlen(buf)-1] = '\0'; X X strcat(buf, "]"); X return new_name(buf); X} X Xchar * Xstr_aflag(flag) Xreg int flag; X{ X char buf[128]; X X strcpy(buf, "["); X if (flag & af_SILENT) X strcat(buf, "silent "); X if (flag & af_IGNORE) X strcat(buf, "ignore "); X if (flag & af_MINUSN) X strcat(buf, "minusn "); X if (flag & af_SYSTEM) X strcat(buf, "system "); X if (flag & af_SCRIPT) X strcat(buf, "script "); X X if (strlen(buf) > 1) X buf[strlen(buf)-1] = '\0'; X X strcat(buf, "]"); X return new_name(buf); X} X Xprint_pat(pat) Xreg Pat *pat; X{ X if (pat->p_cmd) X printf("`%s`", pat->p_str); X else X printf("%s", pat->p_str); X X printf(str_pflag(pat->p_flag)); X} X Xprint_act(act) Xreg Act *act; X{ X printf(str_aflag(act->a_flag)); X printf("%s", act->a_str); X} X Xprint_test(test) Xreg Test *test; X{ X reg List *ptr; X reg char *pre; X reg Pat *pat; X X if (test == NULL) X { X printf("null"); X return; X } X X switch (test->t_kind) X { X Xwhen t_TRUE: printf("true"); Xwhen t_FALSE: printf("false"); X Xwhen t_AND: print_test(test->t_left); X printf(" and "); X print_test(test->t_right); X Xwhen t_OR: print_test(test->t_left); X printf(" or "); X print_test(test->t_right); X Xwhen t_NOT: printf("not "); X print_test(test->t_left); X Xwhen t_CMD: printf("cmd `%s`", test->t_cmd); X Xwhen t_MATCH: printf("match "); X print_pat(test->t_pat); X printf(" against"); X printf(" ("); X print_pat((Pat *) first(test->t_list)); X printf(") "); X print_pat((Pat *) last(test->t_list)); X Xwhen t_LIST: printf("list "); X print_pat(test->t_pat); X X printf(" in ("); X pre = ""; X for_list (ptr, test->t_list) X { X pat = (Pat *) ldata(ptr); X printf(pre); X print_pat(pat); X pre = ", "; X } X X printf(")"); X Xwhen t_EXIST: printf("exist "); X print_pat(test->t_pat); X Xwhen t_CANDO: printf("cando "); X print_pat(test->t_pat); X Xwhen t_OK: printf("ok "); X print_pat(test->t_pat); X Xotherwise: printf("Bad type kind %d in print_test\n", test->t_kind); X X } X} X Xprint_entry(entry) Xreg Entry *entry; X{ X reg List *ptr; X reg Pat *pat; X reg Act *act; X reg char *pre; X X printf("ENTRY\nnew: "); X pre = ""; X for_list (ptr, entry->e_new) X { X pat = (Pat *) ldata(ptr); X printf(pre); X print_pat(pat); X pre = ", "; X } X X printf("\nold: "); X pre = ""; X for_list (ptr, entry->e_old) X { X pat = (Pat *) ldata(ptr); X printf(pre); X print_pat(pat); X pre = ", "; X } X X printf("\nwhen: "); X pre = ""; X for_list (ptr, entry->e_when) X { X pat = (Pat *) ldata(ptr); X printf(pre); X print_pat(pat); X pre = ", "; X } X X printf("\ntest: "); X print_test(entry->e_cond); X X printf("\nactions:\n"); X for_list (ptr, entry->e_act) X { X act = (Act *) ldata(ptr); X print_act(act); X } X X printf("\n"); X} X Xchar * Xstr_nkind(nkind) Xreg N_kind nkind; X{ X switch (nkind) X { Xwhen n_OK: return "ok"; Xwhen n_NOWAY: return "noway"; Xwhen n_CANDO: return "cando"; X } X X return "bizarre"; X} X Xprint_time(str, ntime) Xreg char *str; Xtime_t ntime; X{ X extern char *ctime(); X X printf("%s time: %d, %s", str, ntime, ctime(&ntime)); X} X Xprint_node(node) Xreg Node *node; X{ X reg List *ptr; X reg char *pre; X reg Node *bnode; X reg Act *act; X X printf("\nNODE\n%s: kind %s flag %s\n", node->n_name, X str_nkind(node->n_kind), str_pflag(node->n_flag)); X print_time("real", node->n_rtime); X print_time("used", node->n_utime); X print_time("saved", node->n_stime); X X printf("new: "); X pre = ""; X for_list (ptr, node->n_new) X { X bnode = (Node *) ldata(ptr); X printf(pre); X printf(bnode->n_name); X pre = ", "; X } X X printf("\nold: "); X pre = ""; X for_list (ptr, node->n_old) X { X bnode = (Node *) ldata(ptr); X printf(pre); X printf(bnode->n_name); X pre = ", "; X } X X printf("\naction:\n"); X for_list (ptr, node->n_act) X { X act = (Act *) ldata(ptr); X print_act(act); X } X X if (node->n_badguys != (List *) NULL) X { X printf("bad guys: "); X pre = ""; X for_list (ptr, node->n_badguys) X { X bnode = (Node *) ldata(ptr); X printf(pre); X printf(bnode->n_name); X pre = ", "; X } X X printf("\n"); X } X X if (node->n_msg != NULL) X printf("msg: %s", node->n_msg); X X printf("\n"); X} X X#endif SHAR_EOF if test 4954 -ne "`wc -c < 'print.c'`" then echo shar: "error transmitting 'print.c'" '(should have been 4954 characters)' fi fi echo shar: "extracting 'proc.c'" '(8939 characters)' if test -f 'proc.c' then echo shar: "will not over-write existing file 'proc.c'" else sed 's/^X//' << \SHAR_EOF > 'proc.c' X/* X** Cake interface to the other processes. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/proc.c,v 1.15 87/10/05 20:15:45 zs Exp $"; X X#include "cake.h" X#include <ctype.h> X#include <errno.h> X#include <signal.h> X#include <fcntl.h> X#include <sys/param.h> X Xextern List *active_procs; /* of Proc */ X X/* X** Process the given command in the manner described by the args. X*/ X Xint Xcake_proc(cmd, type, file, node, func, args) Xreg char *cmd; Xreg A_kind type; Xreg char *file; Xreg Node *node; Xreg int (*func)(); Xreg List *args; X{ X extern bool has_meta(); X extern char *strip_backslash(); X extern char *shell_path[2]; X extern char *shell_cmd[2]; X extern char *shell_opt[2]; X char *argv[MAXARGS]; X reg Proc *proc; X reg int pid; X reg char *script_filename; X X cmd = strip_backslash(cmd); X X#ifdef CAKEDEBUG X if (file != NULL) X cdebug("file is %s\n", file); X else X cdebug("file is NULL\n"); X#endif X X if (type == Exec && has_meta(cmd, TRUE)) X type = System; X X cdebug("cake_proc, type %d: %s\n", type, cmd); X fflush(stdout); X X if (type == Exec) X parse_args(cmd, argv); X or (type == Script) X { X reg FILE *script_fp; X X script_filename = get_newname(); X if ((script_fp = fopen(script_filename, "w")) == NULL) X { X sprintf(scratchbuf, "cake system error, fopen %s", script_filename); X perror(scratchbuf); X exit_cake(FALSE); X } X X fprintf(script_fp, "%s", cmd); X fclose(script_fp); X } X X mutex_lock(); X if ((pid = vfork()) == 0) X { X reg int fd; X X#ifdef CLOSE_ALL X for (fd = 3; fd < NOFILE; fd++) X close(fd); X#endif X X if (file != NULL) X { X if (close(1) != 0) X { X perror("cake system error, close stdout"); X _exit(127); X } X X if ((fd = open(file, O_WRONLY|O_CREAT, 0600)) < 0) X { X perror("cake system error, reopen stdout"); X _exit(127); X } X X if (fd != 1) X { X fprintf(stderr, "cake system error: reopen stdout gives fd %d\n", fd); X _exit(127); X } X } X X switch (type) X { X X when Script: if (shell_opt[1] != NULL) X execl(shell_path[1], shell_cmd[1], shell_opt[1], script_filename, 0); X else X execl(shell_path[1], shell_cmd[1], script_filename, 0); X X perror("cake system error, shell script exec"); X _exit(127); X X when System: if (shell_opt[0] != NULL) X execl(shell_path[0], shell_cmd[0], shell_opt[0], cmd, 0); X else X execl(shell_path[0], shell_cmd[0], cmd, 0); X X perror("cake system error, shell exec"); X _exit(127); X X when Exec: execvp(argv[0], argv); X sprintf(scratchbuf, "cake system error, %s exec", argv[0]); X perror(scratchbuf); X _exit(127); X X otherwise: fprintf(stderr, "cake internal error: type = %x in cake_proc\n", type); X _exit(127); X } X } X or (pid == -1) X { X perror("cake system error, fork"); X exit_cake(FALSE); X } X X proc = make(Proc); X proc->pr_pid = pid; X proc->pr_node = node; X proc->pr_func = func; X proc->pr_args = args; X proc->pr_run = TRUE; X addtail(active_procs, proc); X cdebug("cake_proc pid = %d\n", pid); X X mutex_unlock(); X if (type == Script && ! cakedebug) X { X cdebug("cake_proc unlink script_filename %s\n", script_filename); X if (unlink(script_filename) != 0) X { X sprintf(scratchbuf, "cake system error, unlink %s", script_filename); X perror(scratchbuf); X exit_cake(FALSE); X } X } X X return pid; X} X X/* X** The cake code allows many child processes to be running X** at any given time. Cake waits for these processes X** when their results are required. However, there is no X** necessary relationship between between when a process exits X** and when its product is needed. X** X** The list of active processes contains all running processes X** and all exited processes that haven't been waited for yet. X** Cake_wait maintains this list. Whenever cake_wait gets X** an exit report from wait, it invokes the function (if any) X** associated with the exited process. If the exited process X** is the one cake_wait is looking for, it returns; otherwise X** it calls wait again and again until it finds that process. X*/ X XWait Xcake_wait(pid) Xreg int pid; X{ X extern List *find_process(); X reg int exitpid; X reg List *ptr; X reg Proc *proc; X Wait status; X X mutex_lock(); X ptr = find_process(pid); X proc = (Proc *) ldata(ptr); X if (! proc->pr_run) X { X status = proc->pr_stat; X delete(active_procs, ptr); X mutex_unlock(); X return status; X } X X while ((exitpid = wait(&status)) != -1) X { X mutex_lock(); X ptr = find_process(exitpid); X proc = (Proc *) ldata(ptr); X proc->pr_run = FALSE; X proc->pr_stat = status; X cdebug("cake_wait pid = %d, status = %d\n", exitpid, status.w_status); X fflush(stdout); X X if (proc->pr_func != NULL) X { X cdebug("cake_wait calling function at %x\n", proc->pr_func); X fflush(stdout); X (*proc->pr_func)(status, proc->pr_args); X } X X if (exitpid == pid) X { X delete(active_procs, ptr); X mutex_unlock(); X return status; /* normal return */ X } X X mutex_unlock(); X } X X fprintf(stderr, "cake internal error: waiting for nonactive process %s\n", pid); X exit_cake(TRUE); X return status; /* to shut up lint */ X} X X/* X** Find an active process in the active process list. X*/ X XList * Xfind_process(pid) Xreg int pid; X{ X reg List *ptr; X reg Proc *proc; X reg bool found; X X found = FALSE; X for_list (ptr, active_procs) X { X proc = (Proc *) ldata(ptr); X if (proc->pr_pid == pid) X { X found = TRUE; X break; X } X } X X if (! found) X { X fprintf(stderr, "cake internal error: cannot find active process %d\n", pid); X exit_cake(TRUE); X } X X return ptr; X} X X/* X** Open a filter the cake way, with an execv instead of an execl. X*/ X X#define READSIDE 0 X#define WRITESIDE 1 X Xstatic int popen_pid[NOFILE]; X XFILE * Xcake_popen(argv, mode) Xreg char *argv[MAXARGS]; Xreg char *mode; X{ X int pdesc[2]; X reg int parent_end, child_end; X reg int replaced, pid; X reg Proc *proc; X X if (pipe(pdesc) < 0) X return NULL; X X if (mode[0] == 'r') X { X parent_end = pdesc[READSIDE]; X child_end = pdesc[WRITESIDE]; X replaced = 1; X } X else X { X parent_end = pdesc[WRITESIDE]; X child_end = pdesc[READSIDE]; X replaced = 0; X } X X fflush(stdout); X mutex_lock(); X if ((pid = vfork()) == 0) X { X close(parent_end); X close(replaced); X if (dup(child_end) != replaced) X _exit(127); X X close(child_end); X execv(argv[0], argv); X sprintf(scratchbuf, "cake system error, %s exec", argv[0]); X perror(scratchbuf); X _exit(127); X } X or (pid == -1) X { X close(parent_end); X close(child_end); X perror("cake system error, fork"); X exit_cake(FALSE); X } X X proc = make(Proc); X proc->pr_pid = pid; X proc->pr_func = NULL; X proc->pr_args = NULL; X proc->pr_run = TRUE; X addtail(active_procs, proc); X X close(child_end); X popen_pid[parent_end] = pid; X mutex_unlock(); X X return fdopen(parent_end, mode); X} X Xint Xcake_pclose(fp) Xreg FILE *fp; X{ X Wait code; X reg int f; X X f = fileno(fp); X fclose(fp); X code = cake_wait(popen_pid[f]); X return code.w_status; X} X X/* X** Parse the given command into argv, argc. X*/ X Xint Xparse_args(cmd, vector) Xreg char *cmd; Xreg char **vector; X{ X char buf[MAXARGSIZE]; X reg int i, count; X reg char *s; X reg bool instring; X X cdebug("parse_args: "); X X s = cmd; X for (count = 0; *s != '\0'; count++) X { X while (*s != '\0' && isspace(*s)) X s++; X X instring = FALSE; X for (i = 0; *s != '\0' && (! isspace(*s) || instring); s++) X { X if (*s == '\\') X { X if (s[1] != '\0') X buf[i++] = *++s; X } X or (*s == '"') X instring = ! instring; X else X buf[i++] = *s; X } X X buf[i] = '\0'; X if (i >= MAXARGSIZE) X { X fprintf(stderr, "cake: argument '%s' too long\n", buf); X exit_cake(FALSE); X } X X if (count >= MAXARGS) X { X fprintf(stderr, "cake: '%s' has too many arguments\n", cmd); X exit_cake(FALSE); X } X X if (i == 0) X count--; X else X { X cdebug("<%s>", buf); X vector[count] = new_name(buf); X } X } X X vector[count] = NULL; X cdebug("/%d\n", count); X return count; X} X X/* X** Strip one level of backslashes from the given string. X*/ X Xchar * Xstrip_backslash(str) Xreg char *str; X{ X char buf[MAXSIZE]; X reg char *s; X reg int i; X X if (index(str, '\\') == NULL) X return str; X X for (i = 0, s = str; *s != '\0'; s++) X { X if (*s != '\\') X buf[i++] = *s; X or (s[1] != '\0') X buf[i++] = *++s; X } X X buf[i] = '\0'; X if (i >= MAXSIZE) X { X fprintf(stderr, "cake: command '%s' too long.\n", str); X exit_cake(FALSE); X } X X return new_name(buf); X} X X/* X** These functions implement mutual exclusion. X** They prevent cake from being interrupted X** between calls to lock and unlock. X** This is used to preserve the consistency X** of the active_procs data structure in the presence X** of multiple executing children. X*/ X X#if 0 /* mutual exclusion is not necessary & has bug */ X#ifdef ATT Xint (*signalint)(); Xint (*signalquit)(); X#else Xint signalmask; X#endif X#endif X Xmutex_lock() X{ X#if 0 X#ifdef ATT X signalint = signal(SIGINT, SIG_IGN); X signalquit = signal(SIGQUIT, SIG_IGN); X#else X signalmask = sigblock(mask(SIGINT)|mask(SIGQUIT)); X#endif X#endif X} X Xmutex_unlock() X{ X#if 0 X#ifdef ATT X signal(SIGINT, signalint); X signal(SIGQUIT, signalquit); X#else X sigsetmask(signalmask); X#endif X#endif X} SHAR_EOF if test 8939 -ne "`wc -c < 'proc.c'`" then echo shar: "error transmitting 'proc.c'" '(should have been 8939 characters)' fi fi echo shar: "extracting 'sym.c'" '(4553 characters)' if test -f 'sym.c' then echo shar: "will not over-write existing file 'sym.c'" else sed 's/^X//' << \SHAR_EOF > 'sym.c' X/* X** Symbol table module X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/sym.c,v 1.15 87/10/05 20:16:08 zs Exp $"; X X#include "cake.h" X Xtypedef struct s_out X{ X char *o_cmd; X char *o_out; X} Out; X Xtypedef struct s_stat X{ X char *s_cmd; X int s_stat; X} Stat; X Xextern int hash(); Xextern Cast name_key(); extern bool name_equal(); Xextern Cast node_key(); extern bool node_equal(); Xextern Cast out_key(); extern bool out_equal(); Xextern Cast stat_key(); extern bool stat_equal(); XTable name_tab = { SIZE, NULL, name_key, hash, name_equal }; XTable node_tab = { SIZE, NULL, node_key, hash, node_equal }; XTable out_tab = { SIZE, NULL, out_key, hash, out_equal }; XTable stat_tab = { SIZE, NULL, stat_key, hash, stat_equal }; X X/* X** Initialize the name and the command tables. X*/ X Xinit_sym() X{ X init_table(name_tab); X init_table(node_tab); X init_table(out_tab); X init_table(stat_tab); X} X X/**********************************************************************/ X/* Name table */ X X/* X** Save the given string in the name table if not already there; X** return its new address. This address is unique, so comparing X** two identifiers for equality can be done by comparing their X** addresses. X*/ X Xchar * Xnew_name(str) Xreg char *str; X{ X reg Cast old; X reg char *copy; X X if ((old = lookup_table(name_tab, str)) != NULL) X return (char *) old; X X copy = (char *) newmem(strlen(str) + 1); X strcpy(copy, str); X insert_table(name_tab, copy); X X return copy; X} X XCast Xname_key(entry) Xreg Cast entry; X{ X return entry; X} X Xbool Xname_equal(key1, key2) Xreg Cast key1, key2; X{ X return streq((char *) key1, (char *) key2); X} X X/**********************************************************************/ X/* Node table */ X X/* X** Th insertion function for the node table is chase(), X** which is in chase.c with the rest of the chase stuff. X*/ X X/* X** This function merely reports on the results X** of past calls to chase. X*/ X XNode * Xchase_node(name) Xreg char *name; X{ X return (Node *) lookup_table(node_tab, name); X} X X/* X** Return a list of all the nodes of this run. X*/ X XList * Xget_allnodes() X{ X return contents_table(node_tab); X} X XCast Xnode_key(entry) Xreg Cast entry; X{ X return (Cast) ((Node *) entry)->n_name; X} X Xbool Xnode_equal(key1, key2) Xreg Cast key1, key2; X{ X#ifdef EXTRACHECK X if (key1 != key2 && streq((char *) key1, (char *) key2)) X { X fprintf(stderr, "cake internal error: inconsistency in node_equal\n"); X exit_cake(TRUE); X } X#endif X X return key1 == key2; X} X X/**********************************************************************/ X/* Command output table */ X X#ifdef STATS_FILE Xint out_tried = 0; Xint out_found = 0; X#endif X X/* X** Save a command and its output. X*/ X Xnew_out(cmd, output) Xreg char *cmd; Xreg char *output; X{ X reg Out *out; X X out = make(Out); X out->o_cmd = cmd; X out->o_out = output; X insert_table(out_tab, out); X} X X/* X** Return the output if any associated with a given command. X*/ X Xchar * Xget_out(cmd) Xreg char *cmd; X{ X reg Out *out; X X#ifdef STATS_FILE X out_tried++; X#endif X X if ((out = (Out *) lookup_table(out_tab, cmd)) == NULL) X return NULL; X X#ifdef STATS_FILE X out_found++; X#endif X X return out->o_out; X} X XCast Xout_key(entry) Xreg Cast entry; X{ X return (Cast) ((Out *) entry)->o_cmd; X} X Xbool Xout_equal(key1, key2) Xreg Cast key1, key2; X{ X#ifdef EXTRACHECK X if (key1 != key2 && streq((char *) key1, (char *) key2)) X { X fprintf(stderr, "cake internal error: inconsistency in out_equal\n"); X exit_cake(TRUE); X } X#endif X X return key1 == key2; X} X X/**********************************************************************/ X/* Command status table */ X X#ifdef STATS_FILE Xint stat_tried = 0; Xint stat_found = 0; X#endif X X/* X** Save a command and its status. X*/ X Xnew_stat(cmd, status) Xreg char *cmd; Xreg int status; X{ X reg Stat *stat; X X stat = make(Stat); X stat->s_cmd = cmd; X stat->s_stat = status; X insert_table(stat_tab, stat); X} X X/* X** Return the status if any associated with a given command. X*/ X Xbool Xget_stat(cmd, code) Xreg char *cmd; Xreg int *code; X{ X reg Stat *stat; X X#ifdef STATS_FILE X stat_tried++; X#endif X X if ((stat = (Stat *) lookup_table(stat_tab, cmd)) == NULL) X return FALSE; X X#ifdef STATS_FILE X stat_found++; X#endif X X *code = stat->s_stat; X return TRUE; X} X XCast Xstat_key(entry) Xreg Cast entry; X{ X return (Cast) ((Stat *) entry)->s_cmd; X} X Xbool Xstat_equal(key1, key2) Xreg Cast key1, key2; X{ X#ifdef EXTRACHECK X if (key1 != key2 && streq((char *) key1, (char *) key2)) X { X fprintf(stderr, "cake internal error: inconsistency in stat_equal\n"); X exit_cake(TRUE); X } X#endif X X return key1 == key2; X} SHAR_EOF if test 4553 -ne "`wc -c < 'sym.c'`" then echo shar: "error transmitting 'sym.c'" '(should have been 4553 characters)' fi fi echo shar: "extracting 'sys.c'" '(2672 characters)' if test -f 'sys.c' then echo shar: "will not over-write existing file 'sys.c'" else sed 's/^X//' << \SHAR_EOF > 'sys.c' X/* X** Cake system interface. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/sys.c,v 1.15 87/10/05 20:16:20 zs Exp $"; X X#include "cake.h" X X/* X** Change to the directory of the cakefile. X** Return the shortened name of the cakefile. X*/ X Xchar * Xdir_setup(name) Xreg char *name; X{ X char buf[MAXSIZE]; X reg int i, l; /* l is the subscript of the last / */ X X l = -1; X for (i = 0; name[i] != '\0'; i++) X if (name[i] == '/') X l = i; X X if (l < 0) X return name; X else X { X for (i = 0; i < l; i++) X buf[i] = name[i]; X X if (i == 0) X buf[i++] = '/'; X X buf[i] = '\0'; X if (chdir(buf) != 0) X { X sprintf(scratchbuf, "cake system error, chdir %s", buf); X perror(scratchbuf); X exit(1); X } X X return name+l+1; X } X} X X/* X** Set up the arguments to shell exec's. X** pattern: execl("/bin/sh", "sh", "-c", s, 0); X** pattern: execl("/bin/csh", "csh", "-cf", s, 0); X*/ X Xchar *shell_path[2]; Xchar *shell_cmd[2]; Xchar *shell_opt[2]; X Xshell_setup(shell, which) Xreg char *shell; Xreg int which; X{ X char buf[MAXSIZE]; X reg char *s; X reg int i, l; X X /* find the shell path */ X i = 0; X for (s = shell; *s != '\0' && *s != ' ' && *s != '\t'; s++) X buf[i++] = *s; X X buf[i] = '\0'; X shell_path[which] = new_name(buf); X X for (; *s != '\0' && *s != '-'; s++) X ; X X /* find the options */ X i = 0; X for (; *s != '\0' && *s != ' ' && *s != '\t'; s++) X buf[i++] = *s; X X buf[i] = '\0'; X if (i != 0) X shell_opt[which] = new_name(buf); X else X shell_opt[which] = NULL; X X if (*s != NULL) X { X fprintf(stderr, "cake: cannot parse shell command '%s'\n", shell); X exit_cake(FALSE); X } X X /* find the shell command itself */ X s = shell_path[which]; X l = -1; X for (i = 0; s[i] != '\0'; i++) X if (s[i] == '/') X l = i; X X shell_cmd[which] = new_name(s+l+1); X X if (cakedebug) X { X printf("shell path%d: %s\n", which, shell_path[which]); X printf("shell cmd%d: %s\n", which, shell_cmd[which]); X if (shell_opt[which] != NULL) X printf("shell opt%d: %s\n", which, shell_opt[which]); X else X printf("shell opt%d: NULL\n", which); X } X} X Xbool metatab[CHARSETSIZE]; X X/* X** Set up the metacharacter table. X*/ X Xmeta_setup(metachars) Xreg char *metachars; X{ X reg int i; X reg char *s; X X for (i = 0; i < CHARSETSIZE; i++) X metatab[i] = FALSE; X X for (s = metachars; *s != '\0'; s++) X metatab[*s] = TRUE; X} X X/* X** Decide whether the given string has metacharacters or not. X** The second arg tells whether to honour backslash escapes. X*/ X Xbool Xhas_meta(str, allow_esc) Xreg char *str; Xreg bool allow_esc; X{ X reg char *s; X X for (s = str; *s != '\0'; s++) X if (metatab[(unsigned) *s]) X return TRUE; X or (allow_esc && (*s == '\\')) X { X if (s[1] != '\0') X s++; X } X X return FALSE; X} SHAR_EOF if test 2672 -ne "`wc -c < 'sys.c'`" then echo shar: "error transmitting 'sys.c'" '(should have been 2672 characters)' fi fi echo shar: "extracting 'table.c'" '(2269 characters)' if test -f 'table.c' then echo shar: "will not over-write existing file 'table.c'" else sed 's/^X//' << \SHAR_EOF > 'table.c' X/* X** Table handling module. X** X** This file supplies data manipulation routines to other modules; X** it does not store any data itself. Its routines are generic, X** applicable to the storage of any kind of data structure with X** primary key and a hash function on it. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/table.c,v 1.15 87/10/05 20:16:28 zs Exp $"; X X#include "cake.h" X X/* X** Initialize a table. X*/ X X_init_table(table) Xreg Table *table; X{ X reg int i; X X table->ta_store = make_many(List *, table->ta_size); X for (i = 0; i < table->ta_size; i++) X table->ta_store[i] = NULL; X} X X/* X** Look up and return the entry corresponding to the key X** in a table. X*/ X XCast X_lookup_table(table, key) Xreg Table *table; Xreg Cast key; X{ X reg List *ptr; X reg int h; X X put_trail("lookup_table", "start"); X h = tablehash(table)(key); X for_list (ptr, table->ta_store[h]) X { X if (tableequal(table)(key, tablekey(table)(ldata(ptr)))) X { X#ifdef EXTRACHECK X if (ldata(ptr) == NULL) X { X fprintf(stderr, "cake internal error: returning null in lookup_table\n"); X exit_cake(TRUE); X } X#endif X put_trail("lookup_table", "finish"); X return ldata(ptr); X } X } X X put_trail("lookup_table", "finish"); X return NULL; X} X X/* X** Insert a new entry into the table. X** Return whether it was there before. X*/ X Xbool X_insert_table(table, entry) Xreg Table *table; Xreg Cast entry; X{ X reg List *ptr; X reg Cast key; X reg int h; X X put_trail("insert_table", "start"); X key = tablekey(table)(entry); X h = tablehash(table)(key); X for_list (ptr, table->ta_store[h]) X if (tableequal(table)(key, tablekey(table)(ldata(ptr)))) X { X put_trail("insert_table", "finish"); X return TRUE; X } X X table->ta_store[h] = addhead(table->ta_store[h], entry); X put_trail("insert_table", "finish"); X return FALSE; X} X X/* X** Hash str into the range 0 to SIZE-1. X*/ X Xint Xhash(s) Xreg char *s; X{ X reg int h; X X for (h = 0; *s != '\0'; s++) X h = (h << 1) + *s; X X return (h >= 0? h: -h) % SIZE; X} X X/* X** Return a list of all the entries in a table. X*/ X XList * X_contents_table(table) Xreg Table *table; X{ X reg List *all; X reg List *ptr; X reg int i; X X all = makelist0(); X for (i = 0; i < table->ta_size; i++) X for_list (ptr, table->ta_store[i]) X addtail(all, ldata(ptr)); /* na */ X X return all; X} SHAR_EOF if test 2269 -ne "`wc -c < 'table.c'`" then echo shar: "error transmitting 'table.c'" '(should have been 2269 characters)' fi fi echo shar: "extracting 'test.c'" '(3874 characters)' if test -f 'test.c' then echo shar: "will not over-write existing file 'test.c'" else sed 's/^X//' << \SHAR_EOF > 'test.c' X/* X** Module to handle Cake's tests. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/test.c,v 1.15 87/10/05 20:16:34 zs Exp $"; X X#include "cake.h" X Xbool Xeval(node, test, env) Xreg Node *node; Xreg Test *test; XEnv env; X{ X extern char *expand_cmds(); X extern int cake_proc(); X extern Wait cake_wait(); X extern Node *chase(); X extern bool get_stat(); X extern bool exist(); X extern char *ground(); X char buf[256]; X Wait status; X reg List *ptr; X reg Pat *pat; X reg char *text1, *text2; X reg char *cmd; X reg Node *chasenode; X reg int result; X reg int pid; X X if (test == (Test *) NULL) X return TRUE; X X#ifdef CAKEDEBUG X if (cakedebug) X { X printf("testing "); X print_test(test); X printf("\n"); X } X#endif X X switch (test->t_kind) X { X Xwhen t_TRUE: return TRUE; Xwhen t_FALSE: return FALSE; Xwhen t_AND: return eval(node, test->t_left, env) && eval(node, test->t_right, env); Xwhen t_OR: return eval(node, test->t_left, env) || eval(node, test->t_right, env); Xwhen t_NOT: return ! eval(node, test->t_left, env); X Xwhen t_CMD: if (get_stat(test->t_cmd, &status.w_status)) X { X test->t_kind = (status.w_status == 0)? t_TRUE: t_FALSE; X cdebug("test cmd cache %s: %s\n", test->t_cmd, X (status.w_status == 0)? "True": "False"); X return (status.w_status == 0)? TRUE: FALSE; X } X X cmd = expand_cmds(ground(env, test->t_cmd)); X pid = cake_proc(cmd, Exec, "/dev/null", (Node *) NULL, X (int (*)()) NULL, (List *) NULL); X status = cake_wait(pid); X new_stat(test->t_cmd, status.w_status); X test->t_kind = (status.w_status == 0)? t_TRUE: t_FALSE; X cdebug("test cmd %s: %s\n", test->t_cmd, X (status.w_status == 0)? "True": "False"); X return (status.w_status == 0)? TRUE: FALSE; X Xwhen t_MATCH: text1 = (char *) first(test->t_list); /* -vX */ X text2 = (char *) last(test->t_list); /* file */ X /* e.g. sub -vX X.c NULL file.c */ X sprintf(buf, "sub %s %s NULL %s > /dev/null", X text1, text2, test->t_pat->p_str); X X cmd = new_name(buf); X cdebug("matching command: %s\n", cmd); X if (get_stat(cmd, &status.w_status)) X { X test->t_kind = (status.w_status == 0)? t_TRUE: t_FALSE; X cdebug("test cmd cache %s: %s\n", test->t_cmd, X (status.w_status == 0)? "True": "False"); X return (status.w_status == 0)? TRUE: FALSE; X } X X pid = cake_proc(cmd, Exec, "/dev/null", (Node *) NULL, X (int (*)()) NULL, (List *) NULL); X status = cake_wait(pid); X new_stat(test->t_cmd, status.w_status); X test->t_kind = (status.w_status == 0)? t_TRUE: t_FALSE; X cdebug("test cmd %s: %s\n", test->t_cmd, X (status.w_status == 0)? "True": "False"); X return (status.w_status == 0)? TRUE: FALSE; X Xwhen t_LIST: for_list (ptr, test->t_list) X { X pat = (Pat *) ldata(ptr); X if (streq(test->t_pat->p_str, pat->p_str)) X return TRUE; X } X X return FALSE; X Xwhen t_EXIST: result = exist(test->t_pat->p_str); X cdebug("test exist %s: %s\n", test->t_pat->p_str, X result? "True": "False"); X return result; X Xwhen t_CANDO: chasenode = chase(test->t_pat->p_str, 0, (Entry *) NULL); X if (on_node(chasenode, nf_ERR)) X { X sprintf(scratchbuf, "cannot evaluate 'cando %s' test for %s", X chasenode->n_name, node->n_name); X add_error(node, new_name(scratchbuf), LNULL, TRUE); X } X X result = is_ok(chasenode) || is_cando(chasenode); X cdebug("test cando %s: %s\n", test->t_pat->p_str, X result? "True": "False"); X return result; X Xwhen t_OK: chasenode = chase(test->t_pat->p_str, 0, (Entry *) NULL); X if (on_node(chasenode, nf_ERR)) X { X sprintf(scratchbuf, "cannot evaluate 'ok %s' test for %s", X chasenode->n_name, node->n_name); X add_error(node, new_name(scratchbuf), LNULL, TRUE); X } X X result = is_ok(chasenode); X cdebug("test ok %s: %s\n", test->t_pat->p_str, X result? "True": "False"); X return result; X Xotherwise: fprintf(stderr, "cake internal error: invalid test type %x in eval\n", X test->t_kind); X exit_cake(TRUE); X } X X /*NOTREACHED*/ X return FALSE; X} SHAR_EOF if test 3874 -ne "`wc -c < 'test.c'`" then echo shar: "error transmitting 'test.c'" '(should have been 3874 characters)' fi fi echo shar: "extracting 'trail.c'" '(1045 characters)' if test -f 'trail.c' then echo shar: "will not over-write existing file 'trail.c'" else sed 's/^X//' << \SHAR_EOF > 'trail.c' X/* X** Trail module. X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/trail.c,v 1.14 86/07/19 12:24:19 zs Exp $"; X X#ifdef CAKEDEBUG X#include "cake.h" X X#define TRAILSIZE 100 X Xstatic int trail_entries = 0; /* no. of calls to put_tr */ Xstatic int slot = 0; /* next slot */ Xstatic char *trailfunc[TRAILSIZE]; /* functions and events */ Xstatic char *trailevent[TRAILSIZE]; /* init to NULL by C */ X X/* X** Register this function on the trail. X*/ X Xput_trail(func, event) Xreg char *func; Xreg char *event; X{ X trailfunc[slot] = func; X trailevent[slot] = event; X X trail_entries++; X if (++slot == TRAILSIZE) X slot = 0; X} X X/* X** Print the trail on the given file. X*/ X Xget_trail(fp) Xreg FILE *fp; X{ X reg int maxent; X X fprintf(fp, "^^^^^^^^^^^^^^^^^^^ TRAIL ^^^^^^^^^^^^^^^^^^^\n"); X fprintf(fp, "%d entries\n", trail_entries); X X maxent = (trail_entries < TRAILSIZE)? trail_entries: TRAILSIZE; X while (maxent-- > 0) X { X if (--slot == -1) X slot = TRAILSIZE - 1; X X fprintf(fp, "%s %s\n", trailfunc[slot], trailevent[slot]); X } X} X#endif SHAR_EOF if test 1045 -ne "`wc -c < 'trail.c'`" then echo shar: "error transmitting 'trail.c'" '(should have been 1045 characters)' fi fi exit 0 # End of shell archive