Subject: v12i007: Cake, a make replacement, Part01/09 Newsgroups: comp.sources.unix Sender: sources Approved: rs@uunet.UU.NET Submitted-by: Zoltan Somogyi Posting-number: Volume 12, Issue 7 Archive-name: cake/part01 Cake is a rewrite of make from the ground up. The main difference is one of attitude: cake is considerably more general and flexible, and can be extended and customized by the user to a much greater extent. It is applicable to a wide range of domains, not just program development: for example, standard cakefiles exist to handle documents and VLSI designs. The main differences between make and cake: - Cake dependencies may be dynamic, and their applicability may be conditional upon a test. - Cake rules have the same syntax and semantics as ordinary dependencies, and may more than one target. - There are no restrictions on the forms of either the targets or the sources. This enables cake to handle files in more than one directory and to interface with SCCS, RCS and archivers, among others, without any special arrangements. - Cake has a more general search algorithm than make. When seeking a target it considers all rules which could update it even if the corresponding intermediate files do not exist; it recreates them if (and only if) it is necessary to do so. - Cakefiles are passed through the C preprocessor. They may therefore #include other cakefiles (including standard ones) and use #if and #ifdef to customize themselves. - Cake allows the user to choose his own shell, and to include shell scripts in actions. - Cake can check to see if a newly 'updated' file has actually been changed via a byte-by-byte comparison, which works even if the modify date has been touched. If there is no change, cake avoids recomputing the file's dependents. - Cake has a lot more options (whether one considers these an improvement of course depends on whether one needs them). Cake is not backwards-compatible with make. The copyright on cake is derived from GNU Emacs. The following files are shar files. To extract their contents, give them to /bin/sh as input. Some of them should be put in different directories, according to the map below: Part01 . Part02 . Part03 . Part04 ./Aux Part05 ./Lex Part06 ./Lib Part07 ./Man Part08 ./Man Part09 ./Script Some of the programs in Aux and some of the scripts in Script are also usable independently of cake. For example, the program Aux/subcmd solves the consistent renaming problem (e.g. how to move x to .x, y to .y z to .z etc in one command), and the script Script/ol is an outline generator for -me documents. Zoltan Somogyi Department of Computer Science University of Melbourne Parkville, 3052 Victoria, Australia UUCP: {uunet,mcvax,ukc}!munnari.oz!zs ARPA: zs%munnari.oz@uunet.uu.net CSNET: zs%munnari.oz@australia #! /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: # README # COPYING # Makefile # cake.h # cake_g.y # cake_s.l # conf.h # extern.h # list.h # macro.h # port.h # std.h # table.h # wait.h # This archive created: Wed Oct 14 21:07:46 1987 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'README'" '(5454 characters)' if test -f 'README' then echo shar: "will not over-write existing file 'README'" else sed 's/^X//' << \SHAR_EOF > 'README' XThis is the root directory of the cake distribution. X XThis directory contains the sources for the cake command itself. XIts subdirectories contain sources for commands used by the standard Xcakefiles (Aux), diffs for a modified version of the lex driver (Lex), X"standard" cakefiles (Lib), manuals and a paper on cake (Man), and Xcommands implemented by scripts (Script). Each subdirectory contains Xits own README file; you should have a look at them. The rest of this Xfile is just for the cake source. X XCake was developed on a 3240 under 4.2BSD Unix, with an early version Xon a Pyramid 90x (in the Berkeley universe). It has been tested on a XVAX-11/780 under 4.3BSD, on a Sun under SunOS 3.4, and on an ELXSI 6400 Xunder both 4.2BSD and System V. It should also be portable to other Xconfigurations. Its parameters are concentrated in the Makefile and Xin conf.h, but you should have a look at Lex/README *before* you run X"make install". X XMakefile: X XThe four make variables you should have a look at and maybe change Xare DEST, COPTS, CFLAGS, and LDFLAGS. DEST and CFLAGS should be Xself-explanatory. LDFLAGS as it is just sets the max stack size Xon the 3240 (a segmented non-paged machine) - on other machines Xan empy LDFLAGS should do just fine. The macros you can choose from Xfor COPTS are: X XATT is for AT&T variants of Unix. Cake has not been tested extensively Xfor these, but it has been in use for a while now on an Elxsi 6400 Xrunning Enix, a System V port. Defining ATT shortens variable names Xto ensure that all are unique in the first six characters (see port.h) Xand that no two variable names differ only in case. This effect depends Xon the C preprocessor being able to handle long case-sensitive variable Xnames, even if the compiler/loader can't handle them. Defining ATT makes Xcake call System V system calls instead of Berkeley ones, and does a few Xother things as well. It may or may not work for System III. X XCAKEDEBUG, when defined, enables cake to output debugging information Xof various kinds, either on abnormal termination or in response to Xdebugging options (see main.c). The option -Y requires YYDEBUG Xto debug the parser actions. X XCAREFUL is a safety feature. It prevents cake from removing user files, Xeven when its semantics call for it (see the -G option). It moves files Xto /tmp instead. This can slow cake down, so if you think it is not Xnecessary (e.g. because you have used cake long enough to be confident Xthat it will not delete files it should not delete or because you do Xfrequent backups) you should not define CAREFUL. X XEXTRACHECK is another safety feature - it enables extra internal Xconsistency checks. These are fairly cheap, so you may keep them Xunless you are hurting for CPU time. The one specific instance you Xmay want to delete is the one in mem.c which checks the aligment Xof malloc returns. X XIf you are concerned about memory usage, you may want to define MEMUSED, Xwithout which cake never free()s space. However, the opportunities for Xsavings are minimal (really!); and you should also keep in mind that Xcake has never been tested with MEMUSED. X Xconf.h: X XCast should be a type to which all kinds of pointers can be converted Xforward and back without loss. On most machines int will do. X XSLIB is the directory containing the "standard" systemwide library X(which is in the Lib subdirectory in the distribution), while ULIB Xis the suffix (after $HOME) of people's own cake library. X XCPP is the command to invoke the C preprocessor. X XSTATS_FILE is the name of the file in which each invocation of cake Xputs statistics. If you don't define STATS_FILE, cake does not keep Xany stats. If you do, the stats are reported (nicely formatted) Xby Script/{cs,ccs}. X XCake parses and execs normal (non-script) actions by itself if they Xdon't contain any chars from the macro METACHARS. If they do, cake Xcalls SYSTEM_CMD, while it calls SCRIPT_CMD for scripts. The arg Xto SYSTEM_CMD is the command itself, while the arg to SCRIPT_CMD Xis the name of a file (in /tmp) which contains the script. To convert Xto the Bourne shell, change csh to sh and delete the -f flags. XFor other shells, you will have to find out how to get equivalent Xbehaviour, but keep in mind that Unix restricts you to zero or one Xarguments. X XFor ATT systems, TIMERES is the resulotion of the times() system call, Xbut this is used only for stats. X XGENESIS is just a time() value used internally for time when there is Xnone applicable. It doesn't really matter what it is, as long as it Xprecedes all valid values. X XCHASEROOT is also a name used only internally - it too could be anything Xas long as it does not conflict with real filenames. X XThe other macros in conf.h define the (maximum) sizes of various kinds Xof things. You need to check only CHARSETSIZE, which should be 512 for X9-bit byte systems. You should enlarge the others when somebody gets Xa bounds exceeded message. X XConditions: X XThe copying conditions for the cake distribution are in the file XCOPYING. It is patterned after the copying conditions of GNU, Xin particular GNU Emacs. Basically, you can do anything with it Xexcept prevent other people from getting access to it. This Xmeans that you can't sell it. For the reasons for these conditions, Xread Stallman's GNU manifesto. X XAuthor: X XZoltan Somogyi X XDepartment of Computer Science XUniversity of Melbourne XParkville, 3052 Victoria, Australia X XUUCP: {uunet,mcvax,ukc}!munnari.oz!zs XARPA: zs%munnari.oz@uunet.uu.net XCSNET: zs%munnari.oz@australia SHAR_EOF if test 5454 -ne "`wc -c < 'README'`" then echo shar: "error transmitting 'README'" '(should have been 5454 characters)' fi fi echo shar: "extracting 'COPYING'" '(2204 characters)' if test -f 'COPYING' then echo shar: "will not over-write existing file 'COPYING'" else sed 's/^X//' << \SHAR_EOF > 'COPYING' XCake copying permission notice Copyright (C) 1987 Zoltan Somogyi X XCake is distributed in the hope that it will be useful, but without any Xwarranty. No author or distributor accepts responsibility to anyone for Xthe consequences of using it or for whether it serves any particular purpose Xor works at all, unless he/she says so in writing. X XEveryone is granted permission to copy, modify and redistribute Cake Xunder the following conditions: X X Permission is granted to anyone to make or distribute verbatim copies X of Cake source code as received, in any medium, provided that all X copyright notices and permission and nonwarranty notices are preserved, X and that the distributor grants the recipient permission for further X redistribution as permitted by this document, and gives him/her and X points out to him/her an exact copy of this document to inform him/her X of his/her rights. X X Permission is granted to distribute modified versions of Cake source X code, or of portions of it, under the above conditions, provided also X that all changed files carry prominent notices stating who last changed X them and that all the Cake-derived material, including everything X packaged together with it and not independently usable, is distributed X under the conditions stated in this document. X X Permission is granted to distribute Cake in compiled or executable form X under the same conditions applying for source code, provided that either X X A it is accompanied by the corresponding machine-readable source X code, or X B it is accompanied by a written offer, with no time limit, to X give anyone a machine-readable copy of the corresponding source X code in return for reimbursement of the cost of distribution. X This written offer must permit verbatim duplication by anyone. X C it is distributed by someone who received only the executable X form, and is accompanied by a copy of the written offer of X source code which he/she received along with it. X XIn other words, you are welcome to use, share and improve Cake. XYou are forbidden to forbid anyone else to use, share and improve Xwhat you give them. Help stamp out software-hoarding! X XThis copyright notice was adapted from the one supplied with GNU Emacs. SHAR_EOF if test 2204 -ne "`wc -c < 'COPYING'`" then echo shar: "error transmitting 'COPYING'" '(should have been 2204 characters)' fi fi echo shar: "extracting 'Makefile'" '(1943 characters)' if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else sed 's/^X//' << \SHAR_EOF > 'Makefile' X# Makefile for Cake X# X# $Header: /mip/zs/src/sys/cake/RCS/Makefile,v 1.15 87/10/05 20:13:19 zs Exp $ X XHDR = cake.h conf.h port.h XSRC = act.c chase.c entry.c error.c expand.c file.c \ X list.c main.c make.c mem.c pat.c print.c proc.c \ X sym.c sys.c table.c test.c trail.c XOBJ = act.o chase.o entry.o error.o expand.o file.o \ X list.o main.o make.o mem.o pat.o print.o proc.o \ X sym.o sys.o table.o test.o trail.o XGEN = cake_g.y cake_s.l XGHDR = cake_g.h XGSRC = cake_g.c cake_s.c XGOBJ = cake_g.o cake_s.o XDEST = /mip/usr/bin XCOPTS = -DCAKEDEBUG -DYYDEBUG -DCAREFUL XCFLAGS= $(COPTS) XLDFLAGS=-k 64k X Xcake: $(OBJ) $(GOBJ) X $(CC) $(LDFLAGS) $(CFLAGS) -o cake $(OBJ) $(GOBJ) X -/bin/rm fake X ln cake fake X Xall: cake lint tags defs X Xinstall: cake X mv $(DEST)/cake /tmp/Oldcake X cp cake $(DEST)/cake X strip $(DEST)/cake X X$(OBJ): $(HDR) X$(GOBJ): $(HDR) X Xcake_g.c: cake_g.y X yacc -dv cake_g.y X @mv y.tab.h cake_g.h X @mv y.tab.c cake_g.c X @mv y.output cake_g.t X Xcake_s.c: cake_s.l X lex cake_s.l X @mv lex.yy.c cake_s.c X Xvar: $(SRC) $(GSRC) X var -DATT $(COPTS) $(SRC) $(GSRC) > Var X Xplint: $(SRC) $(GSRC) X lint -acpx $(COPTS) $(SRC) $(GSRC) > Lint_errs X Xulint: $(SRC) $(GSRC) X lint -v $(COPTS) $(SRC) $(GSRC) > Lint_errs X Xlint: $(SRC) $(GSRC) X lint -v $(COPTS) $(SRC) $(GSRC) > Lint_errs X @gred yy Lint_errs X @gred malloc Lint_errs X @gred strcpy Lint_errs X @gred strcat Lint_errs X @gred printf Lint_errs X @gred flsbuf Lint_errs X @gred setbuf Lint_errs X @gred rcs_id Lint_errs X @gred longjmp Lint_errs X @gred sbrk Lint_errs X Xcchk: $(SRC) X cchk $(SRC) > Cchk_errs X Xtags: $(SRC) $(GSRC) X ctags $(SRC) $(GSRC) X Xdefs: $(SRC) $(GSRC) X defn $(SRC) $(GSRC) > defs X Xcxref: $(SRC) X cxref -C $(SRC) > Cxref X Xssize: X ssize $(SRC) $(GEN) X Xasize: X ssize $(SRC) $(GEN) $(GSRC) X Xclean: X /bin/rm cake_g.h cake_g.t \ X Make_errs Lint_errs Cchk_errs core \ X $(OBJ) $(GOBJ) $(GSRC) X Xgclean: X /bin/rm $(GSRC) $(GHDR) SHAR_EOF if test 1943 -ne "`wc -c < 'Makefile'`" then echo shar: "error transmitting 'Makefile'" '(should have been 1943 characters)' fi fi echo shar: "extracting 'cake.h'" '(2721 characters)' if test -f 'cake.h' then echo shar: "will not over-write existing file 'cake.h'" else sed 's/^X//' << \SHAR_EOF > 'cake.h' X/* X** Cake definitions. X** X** $Header: /mip/zs/src/sys/cake/RCS/cake.h,v 1.15 87/10/05 20:13:40 zs Exp $ X*/ X X#include X#include X#include "std.h" X#include "conf.h" X#include "wait.h" X#include "list.h" X#include "table.h" X X#define nf_NONVOL 0x0001 X#define nf_PRECIOUS 0x0002 X#define nf_PSEUDO 0x0004 X#define nf_REDUNDANT 0x0008 X#define nf_WHEN 0x0010 X#define nf_DEPNONVOL 0x0020 X#define nf_NODELETE 0x0040 X#define nf_NEWFILE 0x0080 X#define nf_EXIST 0x0100 X#define nf_BUSY 0x0200 X#define nf_ERR 0x0400 X#define nf_TRACED 0x0800 X#define nf_WARNED 0x1000 X#define nf_ORIG 0x2000 X X#define af_SILENT 0x0001 X#define af_IGNORE 0x0002 X#define af_MINUSN 0x0004 X#define af_SYSTEM 0x0008 X#define af_SCRIPT 0x0010 X X/* type of internal patterns */ Xtypedef struct s_pat X{ X char *p_str; X short p_flag; X short p_cmd; X} Pat; X X/* type of internal actions */ Xtypedef struct s_act X{ X char *a_str; X short a_flag; X} Act; X X/* kinds of actions */ Xtypedef enum X{ X Exec, System, Script X} A_kind; X X/* kinds of tests */ Xtypedef enum X{ X t_TRUE, t_FALSE, t_AND, t_OR, t_NOT, X t_CMD, t_MATCH, t_LIST, t_EXIST, t_CANDO, t_OK X} T_kind; X X/* type of tests */ Xtypedef struct s_test X{ X T_kind t_kind; X Pat *t_pat; X List *t_list; /* of Pat(L), char(M) */ X char *t_cmd; X struct s_test *t_left; X struct s_test *t_right; X} Test; X X/* type of substitution variables */ Xtypedef struct s_var X{ X char *v_val; X bool v_bound; X} Var; X X#define NOVAR 10 X#define MAXVAR 11 X X/* type of substitution environments */ Xtypedef Var Env[MAXVAR]; X X/* type of entries */ Xtypedef struct s_entry X{ X char *e_file; X List *e_new; /* of Pat */ X List *e_old; /* of Pat */ X List *e_when; /* of Pat */ X List *e_act; /* of Act */ X Test *e_cond; X bool e_dblc; X} Entry; X Xtypedef enum X{ X n_OK, n_CANDO, n_NOWAY X} N_kind; X X/* type of nodes in the dependency graph */ Xtypedef struct s_node X{ X char *n_name; /* name of the node */ X N_kind n_kind; /* current status of the chase */ X int n_flag; /* the applicable nf_[A-Z]* */ X time_t n_rtime; /* Real modify time if exist */ X time_t n_stime; /* Saved copy of n_rtime */ X time_t n_utime; /* last ancestor Update time */ X List *n_new; /* left side or rule, of Node */ X List *n_old; /* right side of rule, of Node */ X List *n_when; /* starred right side, of Pat */ X List *n_act; /* the actions, of Act */ X#if 0 /* N must be 1 for the time being */ X int n_pid; /* current update process */ X char *n_file; /* name of output file */ X#endif X char *n_msg; /* error message, if nf_ERR */ X List *n_badguys; /* error causes, if nf_ERR */ X} Node; X Xtypedef struct s_proc X{ X int pr_pid; X bool pr_run; X Wait pr_stat; X int (*pr_func)(); X List *pr_args; X Node *pr_node; X} Proc; X X#include "extern.h" X#include "macro.h" SHAR_EOF if test 2721 -ne "`wc -c < 'cake.h'`" then echo shar: "error transmitting 'cake.h'" '(should have been 2721 characters)' fi fi echo shar: "extracting 'cake_g.y'" '(3523 characters)' if test -f 'cake_g.y' then echo shar: "will not over-write existing file 'cake_g.y'" else sed 's/^X//' << \SHAR_EOF > 'cake_g.y' X%{ X/* X** Grammar for Cakefiles X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/cake_g.y,v 1.15 87/10/05 20:13:45 zs Exp $"; X X#include "cake.h" X#include X Xextern List *set_flag(); Xextern int yylineno; Xextern char *yyfile; X%} X X%start file X X%union X{ X int Uint; X char *Ustr; X List *Ulist; X Entry *Uent; X Test *Utest; X Act *Uact; X Pat *Upat; X} X X%token NL EMPTYLINE X%token NONVOL PRECIOUS REDUNDANT PSEUDO WHEN X%token IF IN MATCH EXIST CANDO OK X%token LPAREN RPAREN X%token COLON PAT PATCMD TESTCMD X%token BEGIN_ACT ACT END_ACT X%token GARBAGE X%left OR X%left AND X%left NOT X X%type rule X%type cond test X%type basepat X%type act X%type flag flag_el X%type pat X%type rule_l ACT_el act_el pat_el pat_l X X%% X X/**********************************************************************/ X/* Entries */ X Xfile : empty_el ent_esl empty_el X ; X Xentry : rule_l act_el X { new_entry($1, $2); } X ; X Xrule : pat_l COLON pat_el cond NL X { $$ = make_dep($1, $3, $4, new_name(yyfile), $2); } X ; X Xcond : IF test X { $$ = $2; } X | /* empty */ X { $$ = (Test *) NULL; } X ; X Xtest : basepat IN pat_l X { $$ = make_test_l($1, $3); } X | basepat MATCH basepat X { $$ = make_test_m($1, (Pat *) NULL, $3);} X | basepat MATCH basepat basepat X { $$ = make_test_m($1, $3, $4); } X | EXIST basepat X { $$ = make_test_s(t_EXIST, $2); } X | CANDO basepat X { $$ = make_test_s(t_CANDO, $2); } X | OK basepat X { $$ = make_test_s(t_OK, $2); } X | TESTCMD X { $$ = make_test_c($1); } X | test AND test X { $$ = make_test_b(t_AND, $1, $3);} X | test OR test X { $$ = make_test_b(t_OR, $1, $3); } X | NOT test X { $$ = make_test_u(t_NOT, $2); } X | LPAREN test RPAREN X { $$ = $2; } X ; X Xact : ACT X { $$ = $1; } X | BEGIN_ACT ACT_el END_ACT X { $$ = prep_script($1, $2, $3); } X ; X Xbasepat : PAT X { $$ = make_pat($1, FALSE, 0); } X | PATCMD X { $$ = make_pat($1, TRUE, 0); } X ; X Xpat : basepat flag_el X { $$ = set_flag(makelist($1), $2);} X | LPAREN pat_l RPAREN flag_el X { $$ = set_flag($2, $4); } X ; X Xflag : NONVOL X { $$ = nf_NONVOL; } X | PRECIOUS X { $$ = nf_PRECIOUS; } X | REDUNDANT X { $$ = nf_REDUNDANT; } X | PSEUDO X { $$ = nf_PSEUDO; } X | WHEN X { $$ = nf_WHEN; } X ; X X/* From here on, the grammar is JUNK */ X/**********************************************************************/ X/* Lists */ X Xent_esl : entry X | ent_esl empty_l entry X ; X Xrule_l : rule X { $$ = makelist($1); } X | rule_l rule X { $$ = addtail($1, $2); } X ; X XACT_el : /* empty */ X { $$ = makelist0(); } X | ACT_el ACT X { $$ = addtail($1, $2); } X ; X Xact_el : /* empty */ X { $$ = makelist0(); } X | act_el act X { $$ = addtail($1, $2); } X ; X Xpat_el : /* empty */ X { $$ = makelist0(); } X | pat_l X { $$ = $1; } X ; X Xpat_l : pat X { $$ = $1; } X | pat_l pat X { $$ = addlist($1, $2); } X ; X Xflag_el : /* empty */ X { $$ = 0; } X | flag_el flag X { $$ = $1 | $2; } X ; X Xempty_el: /* empty */ X | empty_l X ; X Xempty_l : EMPTYLINE X | empty_l EMPTYLINE X ; X X%% X Xyyerror(s) Xchar *s; X{ X extern int yyleng; X extern char yytext[]; X char buf[80]; X X if (yychar <= 0) X { X sprintf(buf, "premature EOF"); X yylineno--; X } X or (yytext[0] == '\n' || yytext[0] == '\f') X sprintf(buf, "%s at end of line", s); X or (isprint(yytext[0])) X sprintf(buf, "%s at symbol %s", s, yytext); X else X sprintf(buf, "%s at \\%o", s, yytext[0]); X X if (cakedebug) X printf("%s, %d: %s, token %d\n", yyfile, yylineno, buf, yychar); X else X printf("%s, %d: %s\n", yyfile, yylineno, buf); X} SHAR_EOF if test 3523 -ne "`wc -c < 'cake_g.y'`" then echo shar: "error transmitting 'cake_g.y'" '(should have been 3523 characters)' fi fi echo shar: "extracting 'cake_s.l'" '(6441 characters)' if test -f 'cake_s.l' then echo shar: "will not over-write existing file 'cake_s.l'" else sed 's/^X//' << \SHAR_EOF > 'cake_s.l' X%{ X/* X** Scanner for Cake X*/ X Xstatic char Xrcs_id[] = "$Header: /mip/zs/src/sys/cake/RCS/cake_s.l,v 1.15 87/10/05 20:13:49 zs Exp $"; X X#include "cake.h" X#include "cake_g.h" X#include X X#ifdef CAKEDEBUG X#define ret(x) if (lexdebug) printf("lex: x\n"); return x X#else X#define ret(x) return x X#endif X X/* YYLMAX must be defined here; it can't be defined in conf.h */ X#undef YYLMAX X#define YYLMAX MAXLEXBUF X X#define LATE_CATCH X#define LATE_RECOVERY printf("cake: token '%s' is too long\n", yytext); \ X exit(1); X X#define LBRACE '{' X#define RBRACE '}' X Xextern char *yysquare(); Xextern char *yycurly(); X Xextern int lexdebug; Xchar *yyfile = "no input file"; Xbool afterifdef = FALSE; X%} X X%a 2500 X%o 5000 X X%start edge middle X Xpat [a-zA-Z_0-9/%+-.,] Xsp [ \t] Xnl [\n\f] Xnonl [^\n\f] Xenonl ({nonl}|\\{nl}) X X%% X X"if" { BEGIN middle; ret(IF); } X"and" { BEGIN middle; ret(AND); } X"or" { BEGIN middle; ret(OR); } X"not" { BEGIN middle; ret(NOT); } X"in" { BEGIN middle; ret(IN); } X"match" { BEGIN middle; ret(MATCH); } X"exist" { BEGIN middle; ret(EXIST); } X"cando" { BEGIN middle; ret(CANDO); } X"ok" { BEGIN middle; ret(OK); } X X"(" { BEGIN middle; ret(LPAREN); } X")" { BEGIN middle; ret(RPAREN); } X X"@" { BEGIN middle; ret(NONVOL); } X"!" { BEGIN middle; ret(PRECIOUS); } X"&" { BEGIN middle; ret(PSEUDO); } X"^" { BEGIN middle; ret(REDUNDANT); } X"*" { BEGIN middle; ret(WHEN); } X X":" | X"::" { X BEGIN middle; X yylval.Ustr = new_name(yytext); X ret(COLON); X } X X({pat}|\\{nonl})+ { X BEGIN middle; X yylval.Ustr = new_name(yytext); X ret(PAT); X } X X\"([^"]|\\\")*\" { X BEGIN middle; X /* strip off quotes */ X yytext[yyleng-1] = '\0'; X yylval.Ustr = new_name(yytext+1); X ret(PAT); X } X X"[[" { X BEGIN middle; X yylval.Ustr = yysquare(); X ret(PATCMD); X } X X"{{" { X BEGIN middle; X yylval.Ustr = yycurly(); X ret(TESTCMD); X } X X({sp}|\\{nl})* { BEGIN middle; } X X[@!+-]*"{"{enonl}*{nl} | X[@!+-]*"}"{enonl}*{nl} | X{sp}+{enonl}+{nl} { X BEGIN edge; X afterifdef = FALSE; X yylval.Uact = prep_act(yytext); X X /* comment out check_actlen if */ X /* have a lex driver with CATCH */ X check_actlen(); X X /* braces around ret ARE needed */ X /* as ret expands to an if stmt */ X if (yylval.Uact->a_str[0] == LBRACE) X { X ret(BEGIN_ACT); X } X or (yylval.Uact->a_str[0] == RBRACE) X { X ret(END_ACT); X } X else X { X ret(ACT); X } X } X X"set"{nonl}*{nl} { X BEGIN edge; X if (lexdebug) X printf("set line\n"); X yyset(yytext); X } X X#{nonl}*{nl} { X BEGIN edge; X if (lexdebug) X printf("hash line\n"); X yyhash(yytext); X if (! afterifdef) X ret(EMPTYLINE); X } X X{sp}*{nl} { X BEGIN edge; X if (lexdebug) X printf("empty line\n"); X if (! afterifdef) X ret(EMPTYLINE); X } X X{nl} { X BEGIN edge; X afterifdef = FALSE; X ret(NL); X } X X{nonl} { BEGIN middle; ret(GARBAGE); } X X"$"{nonl}*{nl} { BEGIN edge; } X X%% X Xyyinit() X{ X BEGIN edge; X} X Xyywrap() X{ X return 1; X} X Xyyset(text) Xreg char text[]; X{ X reg char *s; X int setc; X char *setv[MAXARGS]; X X for (s = text+4; *s != '\0' && isspace(*s); s++) X ; X X setc = parse_args(s, setv); X process_args(setv, &setc, 0); X if (setc > 0) X printf("cake: non-options on parameter line ignored\n"); X} X Xyyhash(text) Xreg char text[]; X{ X reg char *oldfile = yyfile; X reg char *s, *t; X X afterifdef = TRUE; /* assume so until proven otherwise */ X if (sscanf(text+1, "%d", &yylineno) != 1) X return; X X text[strlen(text)-1] = '\0'; /* clobber the newline */ X for (s = text; *s != '\0' && *s != '"' && !isalpha(*s); s++) X ; X X if (*s == '\0') X return; X X if (*s != '"') X yyfile = new_name(s); X else X { X for (t = s+strlen(s)-1; t != s && *t != '"'; t--) X ; X X if (t != s) X *t = '\0'; X X yyfile = new_name(s+1); X } X X if (yyfile != oldfile) X { X afterifdef = FALSE; X return; X } X} X X/* X** Read in a PATCMD, which is [[.*PATCMD?.*]] X** (or a matched set of double brackets with other stuff. X** Note that PATCMD cannot be described by a REAL regular X** expression; the one above cheats by using recursion. X** yysquare returns the PATCMD brackets and all. X*/ X Xchar * Xyysquare() X{ X char buf[MAXSIZE]; X reg int c, c1; X reg int i; X reg int n; /* number of outstanding levels */ X X n = 1; X i = 0; X buf[i++] = '['; X buf[i++] = '['; X for (c = input(); c != '\0' && c != '\n' && c != '\f'; c = input()) X { X buf[i++] = c; X if (c == ']') X { X if ((c1 = input()) != ']') X { X /* for the next iteration */ X unput(c1); X continue; X } X X buf[i++] = c1; X if (--n > 0) X continue; X X buf[i] = '\0'; X if (strlen(buf) >= MAXSIZE) X { X fprintf(stderr, "cake internal error: buffer overflow in yysquare\n"); X exit_cake(FALSE); X } X X if (lexdebug) X printf("yysquare: %s\n", buf); X X fflush(stdout); X return new_name(buf); X } X or (c == '[') X { X if ((c1 = input()) != '[') X { X /* for the next iteration */ X unput(c1); X continue; X } X X buf[i++] = c1; X n++; X } X or (c == '\\') X { X /* don't check next char */ X if ((c1 = input()) != '\0') X buf[i++] = c1; X } X } X X if (c == '\0') X fprintf(stderr, "%s, %d: premature EOF\n", yyfile, yylineno); X else X fprintf(stderr, "%s, %d: unescaped newline inside a command\n", yyfile, yylineno); X X exit_cake(FALSE); X} X X/* X** Read in a TESTCMD, which is {{.*}}. Strip the brackets. X*/ X Xchar * Xyycurly() X{ X char buf[MAXSIZE]; X reg int c, c1; X reg int i; X X i = 0; X for (c = input(); c != '\0' && c != '\n' && c != '\f'; c = input()) X { X buf[i++] = c; X if (c == RBRACE) X { X if ((c1 = input()) != RBRACE) X { X /* for the next iteration */ X unput(c1); X continue; X } X X /* overwrite first RBRACE */ X buf[--i] = '\0'; X if (strlen(buf) >= MAXSIZE) X { X fprintf(stderr, "cake internal error: buffer overflow in yycurly\n"); X exit_cake(FALSE); X } X X if (lexdebug) X printf("yycurly: %s\n", buf); X X fflush(stdout); X return new_name(buf); X } X or (c == '\\') X { X /* don't check next char */ X if ((c1 = input()) != '\0') X buf[i++] = c1; X } X } X X if (c == '\0') X fprintf(stderr, "%s, %d: premature EOF\n", yyfile, yylineno); X else X fprintf(stderr, "%s, %d: unescaped newline inside a command\n", yyfile, yylineno); X X exit_cake(FALSE); X} X Xcheck_actlen() X{ X if (strlen(yytext) >= YYLMAX) X { X printf("cake: action '%s' too long\n", yytext); X exit_cake(FALSE); X } X} SHAR_EOF if test 6441 -ne "`wc -c < 'cake_s.l'`" then echo shar: "error transmitting 'cake_s.l'" '(should have been 6441 characters)' fi fi echo shar: "extracting 'conf.h'" '(1401 characters)' if test -f 'conf.h' then echo shar: "will not over-write existing file 'conf.h'" else sed 's/^X//' << \SHAR_EOF > 'conf.h' X/* X** Cake configuration parameters. X** X** $Header: /mip/zs/src/sys/cake/RCS/conf.h,v 1.15 87/10/05 20:14:08 zs Exp $ X*/ X X/* type used when type is not known */ Xtypedef int Cast; X X/* location of the systemwide cake library */ X#define SLIB "/u/pgrad/zs/lib/cake" X X/* suffix (after $HOME) of personal libraries */ X#define ULIB "/lib/cake" X X/* command to invoke the C preprocessor */ X#define CPP "/lib/cpp" X X/* location of the statistics file - if not defined, no stats kept */ X#define STATS_FILE "/u/pgrad/zs/lib/cake_stats" X X/* characters always requiring shell attention */ X#define METACHARS "*?!&|;<>()[]{}'`\"%$~#" X X/* default command to execute non-script shell actions */ X#define SYSTEM_CMD "/bin/csh -cf" X X/* default command to execute shell scripts */ X#define SCRIPT_CMD "/bin/csh -f" X X/* System V compatibility */ X#ifdef ATT X/* the resolution of the times(2) system call */ X#ifdef exlsi X#define TIMERES 100 X#else X#define TIMERES 60 X#endif X X#include "port.h" X X#define vfork() fork() X#define index(s, c) strchr(s, c) X#define rindex(s, c) strrchr(s, c) X#endif X X#define MAXARGS 64 X#define MAXGSTACK 128 X#define MAXARGSIZE 128 X#define MAXPATSIZE 512 X#define MAXLEXBUF 2048 X#define MAXSIZE 2048 X#define MAXSCRIPT 16384 X#define MAXNEST 8 X#define SIZE 97 /* size of tables */ X#define CHARSETSIZE 256 X#define GENESIS (time_t) 42 /* something distinctive */ X#define CHASEROOT "!MAINCAKE!" SHAR_EOF if test 1401 -ne "`wc -c < 'conf.h'`" then echo shar: "error transmitting 'conf.h'" '(should have been 1401 characters)' fi fi echo shar: "extracting 'extern.h'" '(1540 characters)' if test -f 'extern.h' then echo shar: "will not over-write existing file 'extern.h'" else sed 's/^X//' << \SHAR_EOF > 'extern.h' X/* X** External definitions for Cake. X** X** $Header: /mip/zs/src/sys/cake/RCS/extern.h,v 1.15 87/10/05 20:14:30 zs Exp $ X*/ X X/* library functions */ Xextern char *malloc(); X#ifdef ATT Xextern char *strchr(); Xextern char *strrchr(); X#else Xextern char *index(); Xextern char *rindex(); X#endif X X/* memory management */ Xextern Cast newmem(); Xextern oldmem(); X X/* make routines */ Xextern Node *make_node(); Xextern Entry *make_dep(); Xextern Test *make_test_mm(); Xextern Test *make_test_m(); Xextern Test *make_test_c(); Xextern Test *make_test_s(); Xextern Test *make_test_l(); Xextern Test *make_test_b(); Xextern Test *make_test_u(); Xextern Pat *make_pat(); Xextern Act *make_act(); X Xextern Act *prep_act(); Xextern Act *prep_script(); X X/* table handling routines */ Xextern init_sym(); Xextern char *new_name(); X X/* printout routines */ Xextern char scratchbuf[]; Xextern print_pat(); Xextern print_test(); Xextern print_entry(); Xextern print_node(); X X/* flags */ Xextern int Gflag; Xextern int Lflag; Xextern int Rflag; Xextern int Xflag; Xextern int bflag; Xextern int cflag; Xextern int dflag; Xextern int gflag; Xextern int iflag; Xextern int kflag; Xextern int nflag; Xextern int qflag; Xextern int rflag; Xextern int sflag; Xextern int tflag; Xextern int vflag; Xextern int wflag; Xextern int xflag; Xextern int zflag; X Xextern int cakedebug; Xextern int entrydebug; Xextern int patdebug; Xextern int lexdebug; X X/* misc global vars */ Xextern char *cakefile; Xextern int maxprocs; X X/* misc functions */ Xextern char *get_newname(); Xextern put_trail(); Xextern get_trail(); SHAR_EOF if test 1540 -ne "`wc -c < 'extern.h'`" then echo shar: "error transmitting 'extern.h'" '(should have been 1540 characters)' fi fi echo shar: "extracting 'list.h'" '(1206 characters)' if test -f 'list.h' then echo shar: "will not over-write existing file 'list.h'" else sed 's/^X//' << \SHAR_EOF > 'list.h' X/* X** Definitions for the list module. X** X** $Header: /mip/zs/src/sys/cake/RCS/list.h,v 1.15 87/10/05 20:14:45 zs Exp $ X*/ X Xtypedef struct s_list X{ X Cast l_data; X struct s_list *l_prev; X struct s_list *l_next; X} List; X X#define next(ptr) (ptr)->l_next X#define prev(ptr) (ptr)->l_prev X#define ldata(ptr) (ptr)->l_data X#define first_ptr(list) ((list)->l_next) X#define last_ptr(list) ((list)->l_prev) X#define first(list) ((list)->l_next->l_data) X#define last(list) ((list)->l_prev->l_data) X X#define for_list(p, l) for (p = (l? next(l): NULL); p != l && p != NULL; p = next(p)) X#define for_2list(p1, p2, l1, l2) for \ X (p1 = (l1? next(l1): NULL), p2 = (l2? next(l2): NULL); \ X p1 != l1 && p1 != NULL && p2 != l2 && p2 != NULL; \ X p1 = next(p1), p2 = next(p2)) X#define end_list(p, l) (p == l || p == NULL) X X#define makelist(d) _makelist((Cast) d) X#define addhead(l, d) _addhead(l, (Cast) d) X#define addtail(l, d) _addtail(l, (Cast) d) X#define insert_before(l, w, d) _insert_before(l, w, (Cast) d) X#define insert_after(l, w, d) _insert_after(l, w, (Cast) d) X Xextern List *makelist0(); Xextern List *_makelist(); Xextern List *_addhead(); Xextern List *_addtail(); Xextern List *addlist(); Xextern delete(); SHAR_EOF if test 1206 -ne "`wc -c < 'list.h'`" then echo shar: "error transmitting 'list.h'" '(should have been 1206 characters)' fi fi echo shar: "extracting 'macro.h'" '(1029 characters)' if test -f 'macro.h' then echo shar: "will not over-write existing file 'macro.h'" else sed 's/^X//' << \SHAR_EOF > 'macro.h' X/* X** Common macros for Cake X** X** $Header: /mip/zs/src/sys/cake/RCS/macro.h,v 1.15 87/10/05 20:14:48 zs Exp $ X*/ X X#define checkpatlen(p) if (strlen(p) > MAXPATSIZE) \ X printf("Pattern %s too long\n", p), exit_cake(FALSE) X#define cdebug if (cakedebug) printf X X#ifndef CAKEDEBUG X#define put_trail(func, event) X#define get_trail(fp) X#endif X X/* Flag handling */ X X#define on_node(n, f) ((n)->n_flag & (f)) X#define off_node(n, f) (!((n)->n_flag & (f))) X#define set_node(n, f) (n)->n_flag |= (f) X#define reset_node(n, f) (n)->n_flag &= ~(f) X X#define on_pat(p, f) ((p)->p_flag & (f)) X#define off_pat(p, f) (!((p)->p_flag & (f))) X#define set_pat(p, f) (p)->p_flag |= (f) X#define reset_pat(p, f) (p)->p_flag &= ~(f) X X#define on_act(a, f) ((a)->a_flag & (f)) X#define off_act(a, f) (!((a)->a_flag & (f))) X#define set_act(a, f) (a)->a_flag |= (f) X#define reset_act(a, f) (a)->a_flag &= ~(f) X X#define is_ok(n) ((n)->n_kind == n_OK) X#define is_cando(n) ((n)->n_kind == n_CANDO) X#define is_noway(n) ((n)->n_kind == n_NOWAY) SHAR_EOF if test 1029 -ne "`wc -c < 'macro.h'`" then echo shar: "error transmitting 'macro.h'" '(should have been 1029 characters)' fi fi echo shar: "extracting 'port.h'" '(2793 characters)' if test -f 'port.h' then echo shar: "will not over-write existing file 'port.h'" else sed 's/^X//' << \SHAR_EOF > 'port.h' X/* X** Cake portability aids. X** X** $Header: /mip/zs/src/sys/cake/RCS/port.h,v 1.15 87/10/05 20:15:28 zs Exp $ X*/ X X/* too long names */ X#define cake_abort c_abort X#define cake_error c_error X#define cake_exec c_exec X#define cake_finish c_finish X#define cake_gettime c_gettime X#define cake_pclose c_pclose X#define cake_popen c_popen X#define cake_remove c_remove X#define cake_script c_script X#define cake_system c_system X#define cake_utimes c_utimes X#define cake_wait c_wait X#define chase chs X#define chase_node chs_node X#define cppargc cppcarg X#define cppargv cppvarg X#define deref drf X#define deref_entry drf_entry X#define dir_finish dr_finish X#define dir_setup dr_setup X#define dir_start dr_start X#define entry_anay en_nay X#define entry_ayea en_yea X#define expand_cmds ex_cmds X#define find_path fd_path X#define find_process fd_proc X#define found_incl fnd_incl X#define found_main fnd_main X#define get_allnodes g_allnodes X#define get_cmd_result gc_result X#define get_cmd_status gc_status X#define get_newname g_newname X#define get_output g_output X#define get_savename g_savename X#define get_utime g_utime X#define get_youngest g_youngest X#define goal_stackp gs_p X#define ground gr X#define ground_entry gr_entry X#define ground_test gr_test X#define init_chase i_chase X#define init_entry i_entry X#define init_sym i_sym X#define make_act m_act X#define make_cmd m_cmd X#define make_dep m_dep X#define make_node m_node X#define make_pat m_pat X#define make_test_b m_btest X#define make_test_c m_ctest X#define make_test_l m_ltest X#define make_test_m m_mtest X#define make_test_mm m_mmtest X#define make_test_s m_stest X#define make_test_u m_utest X#define makelist0 m_0list X#define miss_anay ms_nay X#define miss_ayea ms_yea X#define mutex_lock mx_lock X#define mutex_unlock mx_unlock X#define name_equal nm_equal X#define name_key nm_key X#define new_cmd nw_cmd X#define new_name nw_name X#define node_resetstat nd_resetstat X#define node_setstat nd_setstat X#define node_stat nd_stats X#define picked_time pck_time X#define prep_act pp_act X#define prep_entries pp_entries X#define prep_script pp_script X#define print_act pr_act X#define print_entry pr_entry X#define print_node pr_node X#define print_pat pr_pat X#define print_test pr_test X#define print_time pr_time X#define script_filename scr_fn X#define set_buddies st_buddies X#define set_flag st_flag X#define shell_cmd sh_cmd X#define shell_opt sh_opt X#define shell_path sh_path X#define signalint sg_int X#define signalquit sg_quit X#define spawn_finish sp_finish X#define spawn_start sp_start X#define stat_tried st_tried X#define str_aflag s_aflag X#define str_nkind s_nkind X#define str_pflag s_pflag X#define warn_equal w_equal X#define warn_key w_key X X/* case sensitive variable names */ X#define Gflag ggflag X#define Lflag llflag X#define Rflag rrflag X#define Xflag xxflag SHAR_EOF if test 2793 -ne "`wc -c < 'port.h'`" then echo shar: "error transmitting 'port.h'" '(should have been 2793 characters)' fi fi echo shar: "extracting 'std.h'" '(942 characters)' if test -f 'std.h' then echo shar: "will not over-write existing file 'std.h'" else sed 's/^X//' << \SHAR_EOF > 'std.h' X/* X** Standard definitions for C X** X** $Header: /mip/zs/src/sys/cake/RCS/std.h,v 1.15 87/10/05 20:16:04 zs Exp $ X*/ X X#define or else if X#define when break;case X#define otherwise break;default X#define loop for(;;) X#define until(expr) while(!(expr)) X#ifndef reg X#define reg register X#endif X#ifndef bool X#define bool char X#endif X X#define max(a, b) ((a) > (b) ? (a) : (b)) X#define min(a, b) ((a) < (b) ? (a) : (b)) X X#define streq(s1, s2) (strcmp(s1, s2) == 0) X#define strdiff(s1, s2) (strcmp(s1, s2) != 0) X#define strneq(s1, s2, n) (strncmp(s1, s2, n) == 0) X#define strndiff(s1, s2, n) (strncmp(s1, s2, n) != 0) X X#define ungetchar(c) ungetc(c, stdin) X#define make(type) ((type *) newmem(sizeof(type))) X#define make_many(type, count) ((type *) newmem(count * sizeof(type))) X X#ifndef TRUE X#define TRUE 1 X#endif X#ifndef FALSE X#define FALSE 0 X#endif X#ifndef NULL X#define NULL 0 X#endif X X#define CNULL (char *) 0 X#define LNULL (List *) 0 SHAR_EOF if test 942 -ne "`wc -c < 'std.h'`" then echo shar: "error transmitting 'std.h'" '(should have been 942 characters)' fi fi echo shar: "extracting 'table.h'" '(837 characters)' if test -f 'table.h' then echo shar: "will not over-write existing file 'table.h'" else sed 's/^X//' << \SHAR_EOF > 'table.h' X/* X** Definitions for the table module. X** X** $Header: /mip/zs/src/sys/cake/RCS/table.h,v 1.14 86/07/19 12:24:13 zs Exp $ X*/ X Xtypedef struct s_table X{ X int ta_size; /* the size of the store */ X List **ta_store; /* the store, an array of lists */ X Cast (*ta_key)(); /* applied to entries */ X int (*ta_hash)(); /* applied to keys */ X bool (*ta_equal)(); /* applied to two keys */ X} Table; X X#define init_table(t) _init_table(&t) X#define lookup_table(t, k) _lookup_table(&t, (Cast) k) X#define insert_table(t, e) _insert_table(&t, (Cast) e) X#define contents_table(t) _contents_table(&t) X X#define tablekey(table) (*(table->ta_key)) X#define tablehash(table) (*(table->ta_hash)) X#define tableequal(table) (*(table->ta_equal)) X Xextern _init_table(); Xextern Cast _lookup_table(); Xextern bool _insert_table(); Xextern List *_contents_table(); SHAR_EOF if test 837 -ne "`wc -c < 'table.h'`" then echo shar: "error transmitting 'table.h'" '(should have been 837 characters)' fi fi echo shar: "extracting 'wait.h'" '(2707 characters)' if test -f 'wait.h' then echo shar: "will not over-write existing file 'wait.h'" else sed 's/^X//' << \SHAR_EOF > 'wait.h' X/* X** Compatibility for ATT versions of Unix X** with Berkeley's wait system calls. X** X** $Header: /mip/zs/src/sys/cake/RCS/wait.h,v 1.14 86/07/19 12:24:22 zs Exp $ X*/ X X#ifdef ATT X/* X * Copyright (c) 1982 Regents of the University of California. X * All rights reserved. The Berkeley software License Agreement X * specifies the terms and conditions for redistribution. X * X * @(#)wait.h 6.2 (Berkeley) 6/8/85 X */ X X/* X * This file holds definitions relevent to the wait system call. X * Some of the options here are available only through the ``wait3'' X * entry point; the old entry point with one argument has more fixed X * semantics, never returning status of unstopped children, hanging until X * a process terminates if any are outstanding, and never returns X * detailed information about process resource utilization (). X */ X X/* X * Structure of the information in the first word returned by both X * wait and wait3. If w_stopval==WSTOPPED, then the second structure X * describes the information returned, else the first. See WUNTRACED below. X */ Xunion wait { X int w_status; /* used in syscall */ X /* X * Terminated process status. X */ X struct { X unsigned short w_Termsig:7; /* termination signal */ X unsigned short w_Coredump:1; /* core dump indicator */ X unsigned short w_Retcode:8; /* exit code if w_termsig==0 */ X } w_T; X /* X * Stopped process status. Returned X * only for traced children unless requested X * with the WUNTRACED option bit. X */ X struct { X unsigned short w_Stopval:8; /* == W_STOPPED if stopped */ X unsigned short w_Stopsig:8; /* signal that stopped us */ X } w_S; X}; X#define w_termsig w_T.w_Termsig X#define w_coredump w_T.w_Coredump X#define w_retcode w_T.w_Retcode X#define w_stopval w_S.w_Stopval X#define w_stopsig w_S.w_Stopsig X X X#define WSTOPPED 0177 /* value of s.stopval if process is stopped */ X X/* X * Option bits for the second argument of wait3. WNOHANG causes the X * wait to not hang if there are no stopped or terminated processes, rather X * returning an error indication in this case (pid==0). WUNTRACED X * indicates that the caller should receive status about untraced children X * which stop due to signals. If children are stopped and a wait without X * this option is done, it is as though they were still running... nothing X * about them is returned. X */ X#define WNOHANG 1 /* dont hang in wait */ X#define WUNTRACED 2 /* tell about stopped, untraced children */ X X#define WIFSTOPPED(x) ((x).w_stopval == WSTOPPED) X#define WIFSIGNALED(x) ((x).w_stopval != WSTOPPED && (x).w_termsig != 0) X#define WIFEXITED(x) ((x).w_stopval != WSTOPPED && (x).w_termsig == 0) X#else X#include X X#define mask(s) (1 << ((s)-1)) X#endif X Xtypedef union wait Wait; SHAR_EOF if test 2707 -ne "`wc -c < 'wait.h'`" then echo shar: "error transmitting 'wait.h'" '(should have been 2707 characters)' fi fi exit 0 # End of shell archive