[comp.sources.unix] v12i009: Cake, a make replacement, Part03/09

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