1*b30d1939SAndy Fiddaman /***********************************************************************
2*b30d1939SAndy Fiddaman *                                                                      *
3*b30d1939SAndy Fiddaman *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1990-2011 AT&T Intellectual Property          *
5*b30d1939SAndy Fiddaman *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
7*b30d1939SAndy Fiddaman *                    by AT&T Intellectual Property                     *
8*b30d1939SAndy Fiddaman *                                                                      *
9*b30d1939SAndy Fiddaman *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*b30d1939SAndy Fiddaman *                                                                      *
13*b30d1939SAndy Fiddaman *              Information and Software Systems Research               *
14*b30d1939SAndy Fiddaman *                            AT&T Research                             *
15*b30d1939SAndy Fiddaman *                           Florham Park NJ                            *
16*b30d1939SAndy Fiddaman *                                                                      *
17*b30d1939SAndy Fiddaman *                 Glenn Fowler <gsf@research.att.com>                  *
18*b30d1939SAndy Fiddaman *                                                                      *
19*b30d1939SAndy Fiddaman ***********************************************************************/
20*b30d1939SAndy Fiddaman #pragma prototyped
21*b30d1939SAndy Fiddaman 
22*b30d1939SAndy Fiddaman /*
23*b30d1939SAndy Fiddaman  * mamake -- MAM make
24*b30d1939SAndy Fiddaman  *
25*b30d1939SAndy Fiddaman  * coded for portability
26*b30d1939SAndy Fiddaman  */
27*b30d1939SAndy Fiddaman 
28*b30d1939SAndy Fiddaman static char id[] = "\n@(#)$Id: mamake (AT&T Research) 2011-08-31 $\0\n";
29*b30d1939SAndy Fiddaman 
30*b30d1939SAndy Fiddaman #if _PACKAGE_ast
31*b30d1939SAndy Fiddaman 
32*b30d1939SAndy Fiddaman #include <ast.h>
33*b30d1939SAndy Fiddaman #include <error.h>
34*b30d1939SAndy Fiddaman 
35*b30d1939SAndy Fiddaman static const char usage[] =
36*b30d1939SAndy Fiddaman "[-?\n@(#)$Id: mamake (AT&T Research) 2011-08-31 $\n]"
37*b30d1939SAndy Fiddaman USAGE_LICENSE
38*b30d1939SAndy Fiddaman "[+NAME?mamake - make abstract machine make]"
39*b30d1939SAndy Fiddaman "[+DESCRIPTION?\bmamake\b reads \amake abstract machine\a target and"
40*b30d1939SAndy Fiddaman "	prerequisite file descriptions from a mamfile (see \b-f\b) and executes"
41*b30d1939SAndy Fiddaman "	actions to update targets that are older than their prerequisites."
42*b30d1939SAndy Fiddaman "	Mamfiles are generated by the \b--mam\b option of \bnmake\b(1) and"
43*b30d1939SAndy Fiddaman "	\bgmake\b(1) and are portable to environments that only have"
44*b30d1939SAndy Fiddaman "	\bsh\b(1) and \bcc\b(1).]"
45*b30d1939SAndy Fiddaman "[+?In practice \bmamake\b is used to bootstrap build \bnmake\b(1) and"
46*b30d1939SAndy Fiddaman "	\bksh\b(1) in new environments. Mamfiles are used rather than"
47*b30d1939SAndy Fiddaman "	old-\bmake\b makefiles because some features are not reliably supported"
48*b30d1939SAndy Fiddaman "	across all \bmake\b variants:]{"
49*b30d1939SAndy Fiddaman "		[+action execution?Multi-line actions are executed as a"
50*b30d1939SAndy Fiddaman "			unit by \b$SHELL\b. There are some shell constructs"
51*b30d1939SAndy Fiddaman "			that cannot be expressed in an old-\bmake\b makefile.]"
52*b30d1939SAndy Fiddaman "		[+viewpathing?\bVPATH\b is properly interpreted. This allows"
53*b30d1939SAndy Fiddaman "			source to be separate from generated files.]"
54*b30d1939SAndy Fiddaman "		[+recursion?Ordered subdirectory recursion over unrelated"
55*b30d1939SAndy Fiddaman "			makefiles.]"
56*b30d1939SAndy Fiddaman "	}"
57*b30d1939SAndy Fiddaman "[+?\bmamprobe\b(1) is called to probe and generate system specific variable"
58*b30d1939SAndy Fiddaman "	definitions. The probe information is regenerated when it is older"
59*b30d1939SAndy Fiddaman "	than the \bmamprobe\b command.]"
60*b30d1939SAndy Fiddaman "[+?For compatibility with \bnmake\b(1) the \b-K\b option and the"
61*b30d1939SAndy Fiddaman "	\brecurse\b and \bcc-*\b command line targets are ignored.]"
62*b30d1939SAndy Fiddaman "[e:?Explain reason for triggering action. Ignored if -F is on.]"
63*b30d1939SAndy Fiddaman "[f:?Read \afile\a instead of the default.]:[file:=Mamfile]"
64*b30d1939SAndy Fiddaman "[i:?Ignore action errors.]"
65*b30d1939SAndy Fiddaman "[k:?Continue after error with sibling prerequisites.]"
66*b30d1939SAndy Fiddaman "[n:?Print actions but do not execute. Recursion actions (see \b-r\b) are still"
67*b30d1939SAndy Fiddaman "	executed. Use \b-N\b to disable recursion actions too.]"
68*b30d1939SAndy Fiddaman "[r:?Recursively make leaf directories matching \apattern\a. Only leaf"
69*b30d1939SAndy Fiddaman "	directories containing a makefile named \bNmakefile\b, \bnmakefile\b,"
70*b30d1939SAndy Fiddaman "	\bMakefile\b or \bmakefile\b are considered. The first makefile"
71*b30d1939SAndy Fiddaman "	found in each leaf directory is scanned for leaf directory"
72*b30d1939SAndy Fiddaman "	prerequisites; the recusion order is determined by a topological sort"
73*b30d1939SAndy Fiddaman "	of these prerequisites.]:[pattern]"
74*b30d1939SAndy Fiddaman "[C:?Do all work in \adirectory\a. All messages will mention"
75*b30d1939SAndy Fiddaman "	\adirectory\a.]:[directory]"
76*b30d1939SAndy Fiddaman "[D:?Set the debug trace level to \alevel\a. Higher levels produce more"
77*b30d1939SAndy Fiddaman "	output.]#[level]"
78*b30d1939SAndy Fiddaman "[F:?Force all targets to be out of date.]"
79*b30d1939SAndy Fiddaman "[K:?Ignored.]"
80*b30d1939SAndy Fiddaman "[N:?Like \b-n\b but recursion actions (see \b-r\b) are also disabled.]"
81*b30d1939SAndy Fiddaman "[V:?Print the program version and exit.]"
82*b30d1939SAndy Fiddaman "[G:debug-symbols?Compile and link with debugging symbol options enabled.]"
83*b30d1939SAndy Fiddaman "[S:strip-symbols?Strip link-time static symbols from executables.]"
84*b30d1939SAndy Fiddaman 
85*b30d1939SAndy Fiddaman "\n"
86*b30d1939SAndy Fiddaman "\n[ target ... ] [ name=value ... ]\n"
87*b30d1939SAndy Fiddaman "\n"
88*b30d1939SAndy Fiddaman 
89*b30d1939SAndy Fiddaman "[+SEE ALSO?\bgmake\b(1), \bmake\b(1), \bmamprobe\b(1),"
90*b30d1939SAndy Fiddaman "	\bnmake\b(1), \bsh\b(1)]"
91*b30d1939SAndy Fiddaman ;
92*b30d1939SAndy Fiddaman 
93*b30d1939SAndy Fiddaman #else
94*b30d1939SAndy Fiddaman 
95*b30d1939SAndy Fiddaman #define elementsof(x)	(sizeof(x)/sizeof(x[0]))
96*b30d1939SAndy Fiddaman #define newof(p,t,n,x)	((p)?(t*)realloc((char*)(p),sizeof(t)*(n)+(x)):(t*)calloc(1,sizeof(t)*(n)+(x)))
97*b30d1939SAndy Fiddaman 
98*b30d1939SAndy Fiddaman #define NiL		((char*)0)
99*b30d1939SAndy Fiddaman 
100*b30d1939SAndy Fiddaman #endif
101*b30d1939SAndy Fiddaman 
102*b30d1939SAndy Fiddaman #include <stdio.h>
103*b30d1939SAndy Fiddaman #include <unistd.h>
104*b30d1939SAndy Fiddaman #include <ctype.h>
105*b30d1939SAndy Fiddaman #include <sys/types.h>
106*b30d1939SAndy Fiddaman #include <sys/stat.h>
107*b30d1939SAndy Fiddaman #include <time.h>
108*b30d1939SAndy Fiddaman 
109*b30d1939SAndy Fiddaman #if !_PACKAGE_ast && defined(__STDC__)
110*b30d1939SAndy Fiddaman #include <stdlib.h>
111*b30d1939SAndy Fiddaman #include <string.h>
112*b30d1939SAndy Fiddaman #endif
113*b30d1939SAndy Fiddaman 
114*b30d1939SAndy Fiddaman #define delimiter(c)	((c)==' '||(c)=='\t'||(c)=='\n'||(c)==';'||(c)=='('||(c)==')'||(c)=='`'||(c)=='|'||(c)=='&'||(c)=='=')
115*b30d1939SAndy Fiddaman 
116*b30d1939SAndy Fiddaman #define add(b,c)	(((b)->nxt >= (b)->end) ? append(b, "") : NiL, *(b)->nxt++ = (c))
117*b30d1939SAndy Fiddaman #define get(b)		((b)->nxt-(b)->buf)
118*b30d1939SAndy Fiddaman #define set(b,o)	((b)->nxt=(b)->buf+(o))
119*b30d1939SAndy Fiddaman #define use(b)		(*(b)->nxt=0,(b)->nxt=(b)->buf)
120*b30d1939SAndy Fiddaman 
121*b30d1939SAndy Fiddaman #define CHUNK		1024
122*b30d1939SAndy Fiddaman #define KEY(a,b,c,d)	((((unsigned long)(a))<<15)|(((unsigned long)(b))<<10)|(((unsigned long)(c))<<5)|(((unsigned long)(d))))
123*b30d1939SAndy Fiddaman #define NOW		((unsigned long)time((time_t*)0))
124*b30d1939SAndy Fiddaman #define ROTATE(p,l,r,t)	((t)=(p)->l,(p)->l=(t)->r,(t)->r=(p),(p)=(t))
125*b30d1939SAndy Fiddaman 
126*b30d1939SAndy Fiddaman #define RULE_active	0x0001		/* active target		*/
127*b30d1939SAndy Fiddaman #define RULE_dontcare	0x0002		/* ok if not found		*/
128*b30d1939SAndy Fiddaman #define RULE_error	0x0004		/* not found or not generated	*/
129*b30d1939SAndy Fiddaman #define RULE_exists	0x0008		/* target file exists		*/
130*b30d1939SAndy Fiddaman #define RULE_generated	0x0010		/* generated target		*/
131*b30d1939SAndy Fiddaman #define RULE_ignore	0x0020		/* ignore time			*/
132*b30d1939SAndy Fiddaman #define RULE_implicit	0x0040		/* implicit prerequisite	*/
133*b30d1939SAndy Fiddaman #define RULE_made	0x0080		/* already made			*/
134*b30d1939SAndy Fiddaman #define RULE_virtual	0x0100		/* not a file			*/
135*b30d1939SAndy Fiddaman 
136*b30d1939SAndy Fiddaman #define STREAM_KEEP	0x0001		/* don't fclose() on pop()	*/
137*b30d1939SAndy Fiddaman #define STREAM_MUST	0x0002		/* push() file must exist	*/
138*b30d1939SAndy Fiddaman #define STREAM_PIPE	0x0004		/* pclose() on pop()		*/
139*b30d1939SAndy Fiddaman 
140*b30d1939SAndy Fiddaman #ifndef S_IXUSR
141*b30d1939SAndy Fiddaman #define S_IXUSR		0100		/* owner execute permission	*/
142*b30d1939SAndy Fiddaman #endif
143*b30d1939SAndy Fiddaman #ifndef S_IXGRP
144*b30d1939SAndy Fiddaman #define S_IXGRP		0010		/* group execute permission	*/
145*b30d1939SAndy Fiddaman #endif
146*b30d1939SAndy Fiddaman #ifndef S_IXOTH
147*b30d1939SAndy Fiddaman #define S_IXOTH		0001		/* other execute permission	*/
148*b30d1939SAndy Fiddaman #endif
149*b30d1939SAndy Fiddaman 
150*b30d1939SAndy Fiddaman struct Rule_s;
151*b30d1939SAndy Fiddaman 
152*b30d1939SAndy Fiddaman typedef struct stat Stat_t;
153*b30d1939SAndy Fiddaman typedef FILE Stdio_t;
154*b30d1939SAndy Fiddaman 
155*b30d1939SAndy Fiddaman typedef struct Buf_s			/* buffer stream		*/
156*b30d1939SAndy Fiddaman {
157*b30d1939SAndy Fiddaman 	struct Buf_s*	old;		/* next dropped buffer		*/
158*b30d1939SAndy Fiddaman 	char*		end;		/* 1 past end of buffer		*/
159*b30d1939SAndy Fiddaman 	char*		nxt;		/* next char to add		*/
160*b30d1939SAndy Fiddaman 	char*		buf;		/* buffer space			*/
161*b30d1939SAndy Fiddaman } Buf_t;
162*b30d1939SAndy Fiddaman 
163*b30d1939SAndy Fiddaman typedef struct Dict_item_s		/* dictionary item		*/
164*b30d1939SAndy Fiddaman {
165*b30d1939SAndy Fiddaman 	struct Dict_item_s*	left;	/* left child			*/
166*b30d1939SAndy Fiddaman 	struct Dict_item_s*	right;	/* right child			*/
167*b30d1939SAndy Fiddaman 	void*			value;	/* user defined value		*/
168*b30d1939SAndy Fiddaman 	char			name[1];/* 0 terminated name		*/
169*b30d1939SAndy Fiddaman } Dict_item_t;
170*b30d1939SAndy Fiddaman 
171*b30d1939SAndy Fiddaman typedef struct Dict_s			/* dictionary handle		*/
172*b30d1939SAndy Fiddaman {
173*b30d1939SAndy Fiddaman 	Dict_item_t*	root;		/* root item			*/
174*b30d1939SAndy Fiddaman } Dict_t;
175*b30d1939SAndy Fiddaman 
176*b30d1939SAndy Fiddaman typedef struct List_s			/* Rule_t list			*/
177*b30d1939SAndy Fiddaman {
178*b30d1939SAndy Fiddaman 	struct List_s*	next;		/* next in list			*/
179*b30d1939SAndy Fiddaman 	struct Rule_s*	rule;		/* list item			*/
180*b30d1939SAndy Fiddaman } List_t;
181*b30d1939SAndy Fiddaman 
182*b30d1939SAndy Fiddaman typedef struct Rule_s			/* rule item			*/
183*b30d1939SAndy Fiddaman {
184*b30d1939SAndy Fiddaman 	char*		name;		/* unbound name			*/
185*b30d1939SAndy Fiddaman 	char*		path;		/* bound path			*/
186*b30d1939SAndy Fiddaman 	List_t*		prereqs;	/* prerequisites		*/
187*b30d1939SAndy Fiddaman 	struct Rule_s*	leaf;		/* recursion leaf alias		*/
188*b30d1939SAndy Fiddaman 	int		flags;		/* RULE_* flags			*/
189*b30d1939SAndy Fiddaman 	int		making;		/* currently make()ing		*/
190*b30d1939SAndy Fiddaman 	unsigned long	time;		/* modification time		*/
191*b30d1939SAndy Fiddaman } Rule_t;
192*b30d1939SAndy Fiddaman 
193*b30d1939SAndy Fiddaman typedef struct Stream_s			/* input file stream stack	*/
194*b30d1939SAndy Fiddaman {
195*b30d1939SAndy Fiddaman 	Stdio_t*	fp;		/* read stream			*/
196*b30d1939SAndy Fiddaman 	char*		file;		/* stream path			*/
197*b30d1939SAndy Fiddaman 	unsigned long	line;		/* stream line			*/
198*b30d1939SAndy Fiddaman 	int		flags;		/* stream flags			*/
199*b30d1939SAndy Fiddaman } Stream_t;
200*b30d1939SAndy Fiddaman 
201*b30d1939SAndy Fiddaman typedef struct View_s			/* viewpath level		*/
202*b30d1939SAndy Fiddaman {
203*b30d1939SAndy Fiddaman 	struct View_s*	next;		/* next level in viewpath	*/
204*b30d1939SAndy Fiddaman 	int		node;		/* viewpath node path length	*/
205*b30d1939SAndy Fiddaman 	char		dir[1];		/* viewpath level dir prefix	*/
206*b30d1939SAndy Fiddaman } View_t;
207*b30d1939SAndy Fiddaman 
208*b30d1939SAndy Fiddaman static struct				/* program state		*/
209*b30d1939SAndy Fiddaman {
210*b30d1939SAndy Fiddaman 	Buf_t*		buf;		/* work buffer			*/
211*b30d1939SAndy Fiddaman 	Buf_t*		old;		/* dropped buffers		*/
212*b30d1939SAndy Fiddaman 	Buf_t*		opt;		/* option buffer		*/
213*b30d1939SAndy Fiddaman 
214*b30d1939SAndy Fiddaman 	Dict_t*		leaf;		/* recursion leaf dictionary	*/
215*b30d1939SAndy Fiddaman 	Dict_t*		libs;		/* library dictionary		*/
216*b30d1939SAndy Fiddaman 	Dict_t*		rules;		/* rule dictionary		*/
217*b30d1939SAndy Fiddaman 	Dict_t*		vars;		/* variable dictionary		*/
218*b30d1939SAndy Fiddaman 
219*b30d1939SAndy Fiddaman 	View_t*		view;		/* viewpath levels		*/
220*b30d1939SAndy Fiddaman 
221*b30d1939SAndy Fiddaman 	char*		directory;	/* work in this directory	*/
222*b30d1939SAndy Fiddaman 	char*		id;		/* command name			*/
223*b30d1939SAndy Fiddaman 	char*		file;		/* first input file		*/
224*b30d1939SAndy Fiddaman 	char*		pwd;		/* current directory		*/
225*b30d1939SAndy Fiddaman 	char*		recurse;	/* recursion pattern		*/
226*b30d1939SAndy Fiddaman 	char*		shell;		/* ${SHELL}			*/
227*b30d1939SAndy Fiddaman 
228*b30d1939SAndy Fiddaman 	int		active;		/* targets currently active	*/
229*b30d1939SAndy Fiddaman 	int		debug;		/* negative of debug level	*/
230*b30d1939SAndy Fiddaman 	int		errors;		/* some error(s) occurred	*/
231*b30d1939SAndy Fiddaman 	int		exec;		/* execute actions		*/
232*b30d1939SAndy Fiddaman 	int		explain;	/* explain actions		*/
233*b30d1939SAndy Fiddaman 	int		force;		/* all targets out of date	*/
234*b30d1939SAndy Fiddaman 	int		ignore;		/* ignore command errors	*/
235*b30d1939SAndy Fiddaman 	int		indent;		/* debug indent			*/
236*b30d1939SAndy Fiddaman 	int		keepgoing;	/* do siblings on error		*/
237*b30d1939SAndy Fiddaman 	int		never;		/* never execute		*/
238*b30d1939SAndy Fiddaman 	int		peek;		/* next line already in input	*/
239*b30d1939SAndy Fiddaman 	int		probed;		/* probe already done		*/
240*b30d1939SAndy Fiddaman 	int		verified;	/* don't bother with verify()	*/
241*b30d1939SAndy Fiddaman 
242*b30d1939SAndy Fiddaman 	Stream_t	streams[4];	/* input file stream stack	*/
243*b30d1939SAndy Fiddaman 	Stream_t*	sp;		/* input stream stack pointer	*/
244*b30d1939SAndy Fiddaman 
245*b30d1939SAndy Fiddaman 	char		input[8*CHUNK];	/* input buffer			*/
246*b30d1939SAndy Fiddaman } state;
247*b30d1939SAndy Fiddaman 
248*b30d1939SAndy Fiddaman static unsigned long	make(Rule_t*);
249*b30d1939SAndy Fiddaman 
250*b30d1939SAndy Fiddaman static char		mamfile[] = "Mamfile";
251*b30d1939SAndy Fiddaman static char		sh[] = "/bin/sh";
252*b30d1939SAndy Fiddaman 
253*b30d1939SAndy Fiddaman extern char**		environ;
254*b30d1939SAndy Fiddaman 
255*b30d1939SAndy Fiddaman #if !_PACKAGE_ast
256*b30d1939SAndy Fiddaman 
257*b30d1939SAndy Fiddaman #if defined(NeXT) || defined(__NeXT)
258*b30d1939SAndy Fiddaman #define getcwd(a,b)	getwd(a)
259*b30d1939SAndy Fiddaman #endif
260*b30d1939SAndy Fiddaman 
261*b30d1939SAndy Fiddaman /*
262*b30d1939SAndy Fiddaman  * emit usage message and exit
263*b30d1939SAndy Fiddaman  */
264*b30d1939SAndy Fiddaman 
265*b30d1939SAndy Fiddaman static void
usage()266*b30d1939SAndy Fiddaman usage()
267*b30d1939SAndy Fiddaman {
268*b30d1939SAndy Fiddaman 	fprintf(stderr, "Usage: %s [-iknFKNV] [-f mamfile] [-r pattern] [-C directory] [-D level] [target ...] [name=value ...]\n", state.id);
269*b30d1939SAndy Fiddaman 	exit(2);
270*b30d1939SAndy Fiddaman }
271*b30d1939SAndy Fiddaman 
272*b30d1939SAndy Fiddaman #endif
273*b30d1939SAndy Fiddaman 
274*b30d1939SAndy Fiddaman /*
275*b30d1939SAndy Fiddaman  * output error message identification
276*b30d1939SAndy Fiddaman  */
277*b30d1939SAndy Fiddaman 
278*b30d1939SAndy Fiddaman static void
identify(Stdio_t * sp)279*b30d1939SAndy Fiddaman identify(Stdio_t* sp)
280*b30d1939SAndy Fiddaman {
281*b30d1939SAndy Fiddaman 	if (state.directory)
282*b30d1939SAndy Fiddaman 		fprintf(sp, "%s [%s]: ", state.id, state.directory);
283*b30d1939SAndy Fiddaman 	else
284*b30d1939SAndy Fiddaman 		fprintf(sp, "%s: ", state.id);
285*b30d1939SAndy Fiddaman }
286*b30d1939SAndy Fiddaman 
287*b30d1939SAndy Fiddaman /*
288*b30d1939SAndy Fiddaman  * emit error message
289*b30d1939SAndy Fiddaman  * level:
290*b30d1939SAndy Fiddaman  *	<0	debug
291*b30d1939SAndy Fiddaman  *	 0	info
292*b30d1939SAndy Fiddaman  *	 1	warning
293*b30d1939SAndy Fiddaman  *	 2	error
294*b30d1939SAndy Fiddaman  *	>2	exit(level-2)
295*b30d1939SAndy Fiddaman  */
296*b30d1939SAndy Fiddaman 
297*b30d1939SAndy Fiddaman static void
report(int level,char * text,char * item,unsigned long stamp)298*b30d1939SAndy Fiddaman report(int level, char* text, char* item, unsigned long stamp)
299*b30d1939SAndy Fiddaman {
300*b30d1939SAndy Fiddaman 	int	i;
301*b30d1939SAndy Fiddaman 
302*b30d1939SAndy Fiddaman 	if (level >= state.debug)
303*b30d1939SAndy Fiddaman 	{
304*b30d1939SAndy Fiddaman 		if (level)
305*b30d1939SAndy Fiddaman 			identify(stderr);
306*b30d1939SAndy Fiddaman 		if (level < 0)
307*b30d1939SAndy Fiddaman 		{
308*b30d1939SAndy Fiddaman 			fprintf(stderr, "debug%d: ", level);
309*b30d1939SAndy Fiddaman 			for (i = 1; i < state.indent; i++)
310*b30d1939SAndy Fiddaman 				fprintf(stderr, "  ");
311*b30d1939SAndy Fiddaman 		}
312*b30d1939SAndy Fiddaman 		else
313*b30d1939SAndy Fiddaman 		{
314*b30d1939SAndy Fiddaman 			if (state.sp && state.sp->line)
315*b30d1939SAndy Fiddaman 			{
316*b30d1939SAndy Fiddaman 				if (state.sp->file)
317*b30d1939SAndy Fiddaman 					fprintf(stderr, "%s: ", state.sp->file);
318*b30d1939SAndy Fiddaman 				fprintf(stderr, "%ld: ", state.sp->line);
319*b30d1939SAndy Fiddaman 			}
320*b30d1939SAndy Fiddaman 			if (level == 1)
321*b30d1939SAndy Fiddaman 				fprintf(stderr, "warning: ");
322*b30d1939SAndy Fiddaman 			else if (level > 1)
323*b30d1939SAndy Fiddaman 				state.errors = 1;
324*b30d1939SAndy Fiddaman 		}
325*b30d1939SAndy Fiddaman 		if (item)
326*b30d1939SAndy Fiddaman 			fprintf(stderr, "%s: ", item);
327*b30d1939SAndy Fiddaman 		fprintf(stderr, "%s", text);
328*b30d1939SAndy Fiddaman 		if (stamp && state.debug <= -2)
329*b30d1939SAndy Fiddaman 			fprintf(stderr, " %10lu", stamp);
330*b30d1939SAndy Fiddaman 		fprintf(stderr, "\n");
331*b30d1939SAndy Fiddaman 		if (level > 2)
332*b30d1939SAndy Fiddaman 			exit(level - 2);
333*b30d1939SAndy Fiddaman 	}
334*b30d1939SAndy Fiddaman }
335*b30d1939SAndy Fiddaman 
336*b30d1939SAndy Fiddaman /*
337*b30d1939SAndy Fiddaman  * don't know how to make or exit code making
338*b30d1939SAndy Fiddaman  */
339*b30d1939SAndy Fiddaman 
340*b30d1939SAndy Fiddaman static void
dont(Rule_t * r,int code,int keepgoing)341*b30d1939SAndy Fiddaman dont(Rule_t* r, int code, int keepgoing)
342*b30d1939SAndy Fiddaman {
343*b30d1939SAndy Fiddaman 	identify(stderr);
344*b30d1939SAndy Fiddaman 	if (!code)
345*b30d1939SAndy Fiddaman 		fprintf(stderr, "don't know how to make %s\n", r->name);
346*b30d1939SAndy Fiddaman 	else
347*b30d1939SAndy Fiddaman 	{
348*b30d1939SAndy Fiddaman 		fprintf(stderr, "*** exit code %d making %s%s\n", code, r->name, state.ignore ? " ignored" : "");
349*b30d1939SAndy Fiddaman 		unlink(r->name);
350*b30d1939SAndy Fiddaman 		if (state.ignore)
351*b30d1939SAndy Fiddaman 			return;
352*b30d1939SAndy Fiddaman 	}
353*b30d1939SAndy Fiddaman 	if (!keepgoing)
354*b30d1939SAndy Fiddaman 		exit(1);
355*b30d1939SAndy Fiddaman 	state.errors++;
356*b30d1939SAndy Fiddaman 	r->flags |= RULE_error;
357*b30d1939SAndy Fiddaman }
358*b30d1939SAndy Fiddaman 
359*b30d1939SAndy Fiddaman /*
360*b30d1939SAndy Fiddaman  * local strrchr()
361*b30d1939SAndy Fiddaman  */
362*b30d1939SAndy Fiddaman 
363*b30d1939SAndy Fiddaman static char*
last(register char * s,register int c)364*b30d1939SAndy Fiddaman last(register char* s, register int c)
365*b30d1939SAndy Fiddaman {
366*b30d1939SAndy Fiddaman 	register char*	r = 0;
367*b30d1939SAndy Fiddaman 
368*b30d1939SAndy Fiddaman 	for (r = 0; *s; s++)
369*b30d1939SAndy Fiddaman 		if (*s == c)
370*b30d1939SAndy Fiddaman 			r = s;
371*b30d1939SAndy Fiddaman 	return r;
372*b30d1939SAndy Fiddaman }
373*b30d1939SAndy Fiddaman 
374*b30d1939SAndy Fiddaman /*
375*b30d1939SAndy Fiddaman  * open a buffer stream
376*b30d1939SAndy Fiddaman  */
377*b30d1939SAndy Fiddaman 
378*b30d1939SAndy Fiddaman static Buf_t*
buffer(void)379*b30d1939SAndy Fiddaman buffer(void)
380*b30d1939SAndy Fiddaman {
381*b30d1939SAndy Fiddaman 	register Buf_t*	buf;
382*b30d1939SAndy Fiddaman 
383*b30d1939SAndy Fiddaman 	if (buf = state.old)
384*b30d1939SAndy Fiddaman 		state.old = state.old->old;
385*b30d1939SAndy Fiddaman 	else if (!(buf = newof(0, Buf_t, 1, 0)) || !(buf->buf = newof(0, char, CHUNK, 0)))
386*b30d1939SAndy Fiddaman 		report(3, "out of space [buffer]", NiL, (unsigned long)0);
387*b30d1939SAndy Fiddaman 	buf->end = buf->buf + CHUNK;
388*b30d1939SAndy Fiddaman 	buf->nxt = buf->buf;
389*b30d1939SAndy Fiddaman 	return buf;
390*b30d1939SAndy Fiddaman }
391*b30d1939SAndy Fiddaman 
392*b30d1939SAndy Fiddaman /*
393*b30d1939SAndy Fiddaman  * close a buffer stream
394*b30d1939SAndy Fiddaman  */
395*b30d1939SAndy Fiddaman 
396*b30d1939SAndy Fiddaman static void
drop(Buf_t * buf)397*b30d1939SAndy Fiddaman drop(Buf_t* buf)
398*b30d1939SAndy Fiddaman {
399*b30d1939SAndy Fiddaman 	buf->old = state.old;
400*b30d1939SAndy Fiddaman 	state.old = buf;
401*b30d1939SAndy Fiddaman }
402*b30d1939SAndy Fiddaman 
403*b30d1939SAndy Fiddaman /*
404*b30d1939SAndy Fiddaman  * append str length n to buffer and return the buffer base
405*b30d1939SAndy Fiddaman  */
406*b30d1939SAndy Fiddaman 
407*b30d1939SAndy Fiddaman static char*
appendn(Buf_t * buf,char * str,int n)408*b30d1939SAndy Fiddaman appendn(Buf_t* buf, char* str, int n)
409*b30d1939SAndy Fiddaman {
410*b30d1939SAndy Fiddaman 	int	m;
411*b30d1939SAndy Fiddaman 	int	i;
412*b30d1939SAndy Fiddaman 
413*b30d1939SAndy Fiddaman 	if ((n + 1) >= (buf->end - buf->nxt))
414*b30d1939SAndy Fiddaman 	{
415*b30d1939SAndy Fiddaman 		i = buf->nxt - buf->buf;
416*b30d1939SAndy Fiddaman 		m = (((buf->end - buf->buf) + n + CHUNK + 1) / CHUNK) * CHUNK;
417*b30d1939SAndy Fiddaman 		if (!(buf->buf = newof(buf->buf, char, m, 0)))
418*b30d1939SAndy Fiddaman 			report(3, "out of space [buffer resize]", NiL, (unsigned long)0);
419*b30d1939SAndy Fiddaman 		buf->end = buf->buf + m;
420*b30d1939SAndy Fiddaman 		buf->nxt = buf->buf + i;
421*b30d1939SAndy Fiddaman 	}
422*b30d1939SAndy Fiddaman 	memcpy(buf->nxt, str, n + 1);
423*b30d1939SAndy Fiddaman 	buf->nxt += n;
424*b30d1939SAndy Fiddaman 	return buf->buf;
425*b30d1939SAndy Fiddaman }
426*b30d1939SAndy Fiddaman 
427*b30d1939SAndy Fiddaman /*
428*b30d1939SAndy Fiddaman  * append str to buffer and return the buffer base
429*b30d1939SAndy Fiddaman  * if str==0 then next pointer reset to base
430*b30d1939SAndy Fiddaman  */
431*b30d1939SAndy Fiddaman 
432*b30d1939SAndy Fiddaman static char*
append(Buf_t * buf,char * str)433*b30d1939SAndy Fiddaman append(Buf_t* buf, char* str)
434*b30d1939SAndy Fiddaman {
435*b30d1939SAndy Fiddaman 	if (str)
436*b30d1939SAndy Fiddaman 		return appendn(buf, str, strlen(str));
437*b30d1939SAndy Fiddaman 	buf->nxt = buf->buf;
438*b30d1939SAndy Fiddaman 	return buf->buf;
439*b30d1939SAndy Fiddaman }
440*b30d1939SAndy Fiddaman 
441*b30d1939SAndy Fiddaman /*
442*b30d1939SAndy Fiddaman  * allocate space for s and return the copy
443*b30d1939SAndy Fiddaman  */
444*b30d1939SAndy Fiddaman 
445*b30d1939SAndy Fiddaman static char*
duplicate(char * s)446*b30d1939SAndy Fiddaman duplicate(char* s)
447*b30d1939SAndy Fiddaman {
448*b30d1939SAndy Fiddaman 	char*	t;
449*b30d1939SAndy Fiddaman 	int	n;
450*b30d1939SAndy Fiddaman 
451*b30d1939SAndy Fiddaman 	n = strlen(s);
452*b30d1939SAndy Fiddaman 	if (!(t = newof(0, char, n, 1)))
453*b30d1939SAndy Fiddaman 		report(3, "out of space [duplicate]", s, (unsigned long)0);
454*b30d1939SAndy Fiddaman 	strcpy(t, s);
455*b30d1939SAndy Fiddaman 	return t;
456*b30d1939SAndy Fiddaman }
457*b30d1939SAndy Fiddaman 
458*b30d1939SAndy Fiddaman /*
459*b30d1939SAndy Fiddaman  * open a new dictionary
460*b30d1939SAndy Fiddaman  */
461*b30d1939SAndy Fiddaman 
462*b30d1939SAndy Fiddaman static Dict_t*
dictionary(void)463*b30d1939SAndy Fiddaman dictionary(void)
464*b30d1939SAndy Fiddaman {
465*b30d1939SAndy Fiddaman 	Dict_t*	dict;
466*b30d1939SAndy Fiddaman 
467*b30d1939SAndy Fiddaman 	if (!(dict = newof(0, Dict_t, 1, 0)))
468*b30d1939SAndy Fiddaman 		report(3, "out of space [dictionary]", NiL, (unsigned long)0);
469*b30d1939SAndy Fiddaman 	return dict;
470*b30d1939SAndy Fiddaman }
471*b30d1939SAndy Fiddaman 
472*b30d1939SAndy Fiddaman /*
473*b30d1939SAndy Fiddaman  * return the value for item name in dictionary dict
474*b30d1939SAndy Fiddaman  * if value!=0 then name entry value is created if necessary and set
475*b30d1939SAndy Fiddaman  * uses top-down splaying (ala Tarjan and Sleator)
476*b30d1939SAndy Fiddaman  */
477*b30d1939SAndy Fiddaman 
478*b30d1939SAndy Fiddaman static void*
search(register Dict_t * dict,char * name,void * value)479*b30d1939SAndy Fiddaman search(register Dict_t* dict, char* name, void* value)
480*b30d1939SAndy Fiddaman {
481*b30d1939SAndy Fiddaman 	register int		cmp;
482*b30d1939SAndy Fiddaman 	register Dict_item_t*	root;
483*b30d1939SAndy Fiddaman 	register Dict_item_t*	t;
484*b30d1939SAndy Fiddaman 	register Dict_item_t*	left;
485*b30d1939SAndy Fiddaman 	register Dict_item_t*	right;
486*b30d1939SAndy Fiddaman 	register Dict_item_t*	lroot;
487*b30d1939SAndy Fiddaman 	register Dict_item_t*	rroot;
488*b30d1939SAndy Fiddaman 
489*b30d1939SAndy Fiddaman 	root = dict->root;
490*b30d1939SAndy Fiddaman 	left = right = lroot = rroot = 0;
491*b30d1939SAndy Fiddaman 	while (root)
492*b30d1939SAndy Fiddaman 	{
493*b30d1939SAndy Fiddaman 		if (!(cmp = strcmp(name, root->name)))
494*b30d1939SAndy Fiddaman 			break;
495*b30d1939SAndy Fiddaman 		else if (cmp < 0)
496*b30d1939SAndy Fiddaman 		{
497*b30d1939SAndy Fiddaman 			if (root->left && (cmp = strcmp(name, root->left->name)) <= 0)
498*b30d1939SAndy Fiddaman 			{
499*b30d1939SAndy Fiddaman 				ROTATE(root, left, right, t);
500*b30d1939SAndy Fiddaman 				if (!cmp)
501*b30d1939SAndy Fiddaman 					break;
502*b30d1939SAndy Fiddaman 			}
503*b30d1939SAndy Fiddaman 			if (right)
504*b30d1939SAndy Fiddaman 				right->left = root;
505*b30d1939SAndy Fiddaman 			else
506*b30d1939SAndy Fiddaman 				rroot = root;
507*b30d1939SAndy Fiddaman 			right = root;
508*b30d1939SAndy Fiddaman 			root = root->left;
509*b30d1939SAndy Fiddaman 			right->left = 0;
510*b30d1939SAndy Fiddaman 		}
511*b30d1939SAndy Fiddaman 		else
512*b30d1939SAndy Fiddaman 		{
513*b30d1939SAndy Fiddaman 			if (root->right && (cmp = strcmp(name, root->right->name)) >= 0)
514*b30d1939SAndy Fiddaman 			{
515*b30d1939SAndy Fiddaman 				ROTATE(root, right, left, t);
516*b30d1939SAndy Fiddaman 				if (!cmp)
517*b30d1939SAndy Fiddaman 					break;
518*b30d1939SAndy Fiddaman 			}
519*b30d1939SAndy Fiddaman 			if (left)
520*b30d1939SAndy Fiddaman 				left->right = root;
521*b30d1939SAndy Fiddaman 			else
522*b30d1939SAndy Fiddaman 				lroot = root;
523*b30d1939SAndy Fiddaman 			left = root;
524*b30d1939SAndy Fiddaman 			root = root->right;
525*b30d1939SAndy Fiddaman 			left->right = 0;
526*b30d1939SAndy Fiddaman 		}
527*b30d1939SAndy Fiddaman 	}
528*b30d1939SAndy Fiddaman 	if (root)
529*b30d1939SAndy Fiddaman 	{
530*b30d1939SAndy Fiddaman 		if (right)
531*b30d1939SAndy Fiddaman 			right->left = root->right;
532*b30d1939SAndy Fiddaman 		else
533*b30d1939SAndy Fiddaman 			rroot = root->right;
534*b30d1939SAndy Fiddaman 		if (left)
535*b30d1939SAndy Fiddaman 			left->right = root->left;
536*b30d1939SAndy Fiddaman 		else
537*b30d1939SAndy Fiddaman 			lroot = root->left;
538*b30d1939SAndy Fiddaman 	}
539*b30d1939SAndy Fiddaman 	else if (value)
540*b30d1939SAndy Fiddaman 	{
541*b30d1939SAndy Fiddaman 		if (!(root = newof(0, Dict_item_t, 1, strlen(name))))
542*b30d1939SAndy Fiddaman 			report(3, "out of space [dictionary]", name, (unsigned long)0);
543*b30d1939SAndy Fiddaman 		strcpy(root->name, name);
544*b30d1939SAndy Fiddaman 	}
545*b30d1939SAndy Fiddaman 	if (root)
546*b30d1939SAndy Fiddaman 	{
547*b30d1939SAndy Fiddaman 		if (value)
548*b30d1939SAndy Fiddaman 			root->value = value;
549*b30d1939SAndy Fiddaman 		root->left = lroot;
550*b30d1939SAndy Fiddaman 		root->right = rroot;
551*b30d1939SAndy Fiddaman 		dict->root = root;
552*b30d1939SAndy Fiddaman 		return value ? (void*)root->name : root->value;
553*b30d1939SAndy Fiddaman 	}
554*b30d1939SAndy Fiddaman 	if (left)
555*b30d1939SAndy Fiddaman 	{
556*b30d1939SAndy Fiddaman 		left->right = rroot;
557*b30d1939SAndy Fiddaman 		dict->root = lroot;
558*b30d1939SAndy Fiddaman 	}
559*b30d1939SAndy Fiddaman 	else if (right)
560*b30d1939SAndy Fiddaman 	{
561*b30d1939SAndy Fiddaman 		right->left = lroot;
562*b30d1939SAndy Fiddaman 		dict->root = rroot;
563*b30d1939SAndy Fiddaman 	}
564*b30d1939SAndy Fiddaman 	return 0;
565*b30d1939SAndy Fiddaman }
566*b30d1939SAndy Fiddaman 
567*b30d1939SAndy Fiddaman /*
568*b30d1939SAndy Fiddaman  * low level for walk()
569*b30d1939SAndy Fiddaman  */
570*b30d1939SAndy Fiddaman 
571*b30d1939SAndy Fiddaman static int
apply(Dict_t * dict,Dict_item_t * item,int (* func)(Dict_item_t *,void *),void * handle)572*b30d1939SAndy Fiddaman apply(Dict_t* dict, Dict_item_t* item, int (*func)(Dict_item_t*, void*), void* handle)
573*b30d1939SAndy Fiddaman {
574*b30d1939SAndy Fiddaman 	register Dict_item_t*	right;
575*b30d1939SAndy Fiddaman 
576*b30d1939SAndy Fiddaman 	do
577*b30d1939SAndy Fiddaman 	{
578*b30d1939SAndy Fiddaman 		right = item->right;
579*b30d1939SAndy Fiddaman 		if (item->left && apply(dict, item->left, func, handle))
580*b30d1939SAndy Fiddaman 			return -1;
581*b30d1939SAndy Fiddaman 		if ((*func)(item, handle))
582*b30d1939SAndy Fiddaman 			return -1;
583*b30d1939SAndy Fiddaman 	} while (item = right);
584*b30d1939SAndy Fiddaman 	return 0;
585*b30d1939SAndy Fiddaman }
586*b30d1939SAndy Fiddaman 
587*b30d1939SAndy Fiddaman /*
588*b30d1939SAndy Fiddaman  * apply func to each dictionary item
589*b30d1939SAndy Fiddaman  */
590*b30d1939SAndy Fiddaman 
591*b30d1939SAndy Fiddaman static int
walk(Dict_t * dict,int (* func)(Dict_item_t *,void *),void * handle)592*b30d1939SAndy Fiddaman walk(Dict_t* dict, int (*func)(Dict_item_t*, void*), void* handle)
593*b30d1939SAndy Fiddaman {
594*b30d1939SAndy Fiddaman 	return dict->root ? apply(dict, dict->root, func, handle) : 0;
595*b30d1939SAndy Fiddaman }
596*b30d1939SAndy Fiddaman 
597*b30d1939SAndy Fiddaman /*
598*b30d1939SAndy Fiddaman  * return a rule pointer for name
599*b30d1939SAndy Fiddaman  */
600*b30d1939SAndy Fiddaman 
601*b30d1939SAndy Fiddaman static Rule_t*
rule(char * name)602*b30d1939SAndy Fiddaman rule(char* name)
603*b30d1939SAndy Fiddaman {
604*b30d1939SAndy Fiddaman 	Rule_t*	r;
605*b30d1939SAndy Fiddaman 
606*b30d1939SAndy Fiddaman 	if (!(r = (Rule_t*)search(state.rules, name, NiL)))
607*b30d1939SAndy Fiddaman 	{
608*b30d1939SAndy Fiddaman 		if (!(r = newof(0, Rule_t, 1, 0)))
609*b30d1939SAndy Fiddaman 			report(3, "out of space [rule]", name, (unsigned long)0);
610*b30d1939SAndy Fiddaman 		r->name = (char*)search(state.rules, name, (void*)r);
611*b30d1939SAndy Fiddaman 	}
612*b30d1939SAndy Fiddaman 	return r;
613*b30d1939SAndy Fiddaman }
614*b30d1939SAndy Fiddaman 
615*b30d1939SAndy Fiddaman /*
616*b30d1939SAndy Fiddaman  * prepend p onto rule r prereqs
617*b30d1939SAndy Fiddaman  */
618*b30d1939SAndy Fiddaman 
619*b30d1939SAndy Fiddaman static void
cons(Rule_t * r,Rule_t * p)620*b30d1939SAndy Fiddaman cons(Rule_t* r, Rule_t* p)
621*b30d1939SAndy Fiddaman {
622*b30d1939SAndy Fiddaman 	register List_t*	x;
623*b30d1939SAndy Fiddaman 
624*b30d1939SAndy Fiddaman 	for (x = r->prereqs; x && x->rule != p; x = x->next);
625*b30d1939SAndy Fiddaman 	if (!x)
626*b30d1939SAndy Fiddaman 	{
627*b30d1939SAndy Fiddaman 		if (!(x = newof(0, List_t, 1, 0)))
628*b30d1939SAndy Fiddaman 			report(3, "out of space [list]", r->name, (unsigned long)0);
629*b30d1939SAndy Fiddaman 		x->rule = p;
630*b30d1939SAndy Fiddaman 		x->next = r->prereqs;
631*b30d1939SAndy Fiddaman 		r->prereqs = x;
632*b30d1939SAndy Fiddaman 	}
633*b30d1939SAndy Fiddaman }
634*b30d1939SAndy Fiddaman 
635*b30d1939SAndy Fiddaman /*
636*b30d1939SAndy Fiddaman  * initialize the viewpath
637*b30d1939SAndy Fiddaman  */
638*b30d1939SAndy Fiddaman 
639*b30d1939SAndy Fiddaman static void
view(void)640*b30d1939SAndy Fiddaman view(void)
641*b30d1939SAndy Fiddaman {
642*b30d1939SAndy Fiddaman 	register char*		s;
643*b30d1939SAndy Fiddaman 	register char*		t;
644*b30d1939SAndy Fiddaman 	register char*		p;
645*b30d1939SAndy Fiddaman 	register View_t*	vp;
646*b30d1939SAndy Fiddaman 
647*b30d1939SAndy Fiddaman 	View_t*			zp;
648*b30d1939SAndy Fiddaman 	int			c;
649*b30d1939SAndy Fiddaman 	int			n;
650*b30d1939SAndy Fiddaman 
651*b30d1939SAndy Fiddaman 	Stat_t			st;
652*b30d1939SAndy Fiddaman 	Stat_t			ts;
653*b30d1939SAndy Fiddaman 
654*b30d1939SAndy Fiddaman 	char			buf[CHUNK];
655*b30d1939SAndy Fiddaman 
656*b30d1939SAndy Fiddaman 	if (stat(".", &st))
657*b30d1939SAndy Fiddaman 		report(3, "cannot stat", ".", (unsigned long)0);
658*b30d1939SAndy Fiddaman 	if ((s = (char*)search(state.vars, "PWD", NiL)) && !stat(s, &ts) &&
659*b30d1939SAndy Fiddaman 	    ts.st_dev == st.st_dev && ts.st_ino == st.st_ino)
660*b30d1939SAndy Fiddaman 		state.pwd = s;
661*b30d1939SAndy Fiddaman 	if (!state.pwd)
662*b30d1939SAndy Fiddaman 	{
663*b30d1939SAndy Fiddaman 		if (!getcwd(buf, sizeof(buf) - 1))
664*b30d1939SAndy Fiddaman 			report(3, "cannot determine PWD", NiL, (unsigned long)0);
665*b30d1939SAndy Fiddaman 		state.pwd = duplicate(buf);
666*b30d1939SAndy Fiddaman 		search(state.vars, "PWD", state.pwd);
667*b30d1939SAndy Fiddaman 	}
668*b30d1939SAndy Fiddaman 	if ((s = (char*)search(state.vars, "VPATH", NiL)) && *s)
669*b30d1939SAndy Fiddaman 	{
670*b30d1939SAndy Fiddaman 		zp = 0;
671*b30d1939SAndy Fiddaman 		for (;;)
672*b30d1939SAndy Fiddaman 		{
673*b30d1939SAndy Fiddaman 			for (t = s; *t && *t != ':'; t++);
674*b30d1939SAndy Fiddaman 			if (c = *t)
675*b30d1939SAndy Fiddaman 				*t = 0;
676*b30d1939SAndy Fiddaman 			if (!state.view)
677*b30d1939SAndy Fiddaman 			{
678*b30d1939SAndy Fiddaman 				/*
679*b30d1939SAndy Fiddaman 				 * determine the viewpath offset
680*b30d1939SAndy Fiddaman 				 */
681*b30d1939SAndy Fiddaman 
682*b30d1939SAndy Fiddaman 				if (stat(s, &st))
683*b30d1939SAndy Fiddaman 					report(3, "cannot stat top view", s, (unsigned long)0);
684*b30d1939SAndy Fiddaman 				if (stat(state.pwd, &ts))
685*b30d1939SAndy Fiddaman 					report(3, "cannot stat", state.pwd, (unsigned long)0);
686*b30d1939SAndy Fiddaman 				if (ts.st_dev == st.st_dev && ts.st_ino == st.st_ino)
687*b30d1939SAndy Fiddaman 					p = ".";
688*b30d1939SAndy Fiddaman 				else
689*b30d1939SAndy Fiddaman 				{
690*b30d1939SAndy Fiddaman 					p = state.pwd + strlen(state.pwd);
691*b30d1939SAndy Fiddaman 					while (p > state.pwd)
692*b30d1939SAndy Fiddaman 						if (*--p == '/')
693*b30d1939SAndy Fiddaman 						{
694*b30d1939SAndy Fiddaman 							if (p == state.pwd)
695*b30d1939SAndy Fiddaman 								report(3, ". not under VPATH", s, (unsigned long)0);
696*b30d1939SAndy Fiddaman 							*p = 0;
697*b30d1939SAndy Fiddaman 							if (stat(state.pwd, &ts))
698*b30d1939SAndy Fiddaman 								report(3, "cannot stat", state.pwd, (unsigned long)0);
699*b30d1939SAndy Fiddaman 							*p = '/';
700*b30d1939SAndy Fiddaman 							if (ts.st_dev == st.st_dev && ts.st_ino == st.st_ino)
701*b30d1939SAndy Fiddaman 							{
702*b30d1939SAndy Fiddaman 								p++;
703*b30d1939SAndy Fiddaman 								break;
704*b30d1939SAndy Fiddaman 							}
705*b30d1939SAndy Fiddaman 						}
706*b30d1939SAndy Fiddaman 					if (p <= state.pwd)
707*b30d1939SAndy Fiddaman 						report(3, "cannot determine viewpath offset", s, (unsigned long)0);
708*b30d1939SAndy Fiddaman 				}
709*b30d1939SAndy Fiddaman 			}
710*b30d1939SAndy Fiddaman 			n = strlen(s);
711*b30d1939SAndy Fiddaman 			if (!(vp = newof(0, View_t, 1, strlen(p) + n + 1)))
712*b30d1939SAndy Fiddaman 				report(3, "out of space [view]", s, (unsigned long)0);
713*b30d1939SAndy Fiddaman 			vp->node = n + 1;
714*b30d1939SAndy Fiddaman 			strcpy(vp->dir, s);
715*b30d1939SAndy Fiddaman 			*(vp->dir + n) = '/';
716*b30d1939SAndy Fiddaman 			strcpy(vp->dir + n + 1, p);
717*b30d1939SAndy Fiddaman 			report(-4, vp->dir, "view", (unsigned long)0);
718*b30d1939SAndy Fiddaman 			if (!state.view)
719*b30d1939SAndy Fiddaman 				state.view = zp = vp;
720*b30d1939SAndy Fiddaman 			else
721*b30d1939SAndy Fiddaman 				zp = zp->next = vp;
722*b30d1939SAndy Fiddaman 			if (!c)
723*b30d1939SAndy Fiddaman 				break;
724*b30d1939SAndy Fiddaman 			*t++ = c;
725*b30d1939SAndy Fiddaman 			s = t;
726*b30d1939SAndy Fiddaman 		}
727*b30d1939SAndy Fiddaman 	}
728*b30d1939SAndy Fiddaman }
729*b30d1939SAndy Fiddaman 
730*b30d1939SAndy Fiddaman /*
731*b30d1939SAndy Fiddaman  * return next '?' or '}' in nested '}'
732*b30d1939SAndy Fiddaman  */
733*b30d1939SAndy Fiddaman 
734*b30d1939SAndy Fiddaman static char*
cond(register char * s)735*b30d1939SAndy Fiddaman cond(register char* s)
736*b30d1939SAndy Fiddaman {
737*b30d1939SAndy Fiddaman 	register int	n;
738*b30d1939SAndy Fiddaman 
739*b30d1939SAndy Fiddaman 	if (*s == '?')
740*b30d1939SAndy Fiddaman 		s++;
741*b30d1939SAndy Fiddaman 	n = 0;
742*b30d1939SAndy Fiddaman 	for (;;)
743*b30d1939SAndy Fiddaman 	{
744*b30d1939SAndy Fiddaman 		switch (*s++)
745*b30d1939SAndy Fiddaman 		{
746*b30d1939SAndy Fiddaman 		case 0:
747*b30d1939SAndy Fiddaman 			break;
748*b30d1939SAndy Fiddaman 		case '{':
749*b30d1939SAndy Fiddaman 			n++;
750*b30d1939SAndy Fiddaman 			continue;
751*b30d1939SAndy Fiddaman 		case '}':
752*b30d1939SAndy Fiddaman 			if (!n--)
753*b30d1939SAndy Fiddaman 				break;
754*b30d1939SAndy Fiddaman 			continue;
755*b30d1939SAndy Fiddaman 		case '?':
756*b30d1939SAndy Fiddaman 			if (!n)
757*b30d1939SAndy Fiddaman 				break;
758*b30d1939SAndy Fiddaman 			continue;
759*b30d1939SAndy Fiddaman 		default:
760*b30d1939SAndy Fiddaman 			continue;
761*b30d1939SAndy Fiddaman 		}
762*b30d1939SAndy Fiddaman 		break;
763*b30d1939SAndy Fiddaman 	}
764*b30d1939SAndy Fiddaman 	return s - 1;
765*b30d1939SAndy Fiddaman }
766*b30d1939SAndy Fiddaman 
767*b30d1939SAndy Fiddaman /*
768*b30d1939SAndy Fiddaman  * expand var refs from s into buf
769*b30d1939SAndy Fiddaman  */
770*b30d1939SAndy Fiddaman 
771*b30d1939SAndy Fiddaman static void
substitute(Buf_t * buf,register char * s)772*b30d1939SAndy Fiddaman substitute(Buf_t* buf, register char* s)
773*b30d1939SAndy Fiddaman {
774*b30d1939SAndy Fiddaman 	register char*	t;
775*b30d1939SAndy Fiddaman 	register char*	v;
776*b30d1939SAndy Fiddaman 	register char*	q;
777*b30d1939SAndy Fiddaman 	register char*	b;
778*b30d1939SAndy Fiddaman 	register int	c;
779*b30d1939SAndy Fiddaman 	register int	n;
780*b30d1939SAndy Fiddaman 	int		a = 0;
781*b30d1939SAndy Fiddaman 	int		i;
782*b30d1939SAndy Fiddaman 
783*b30d1939SAndy Fiddaman 	while (c = *s++)
784*b30d1939SAndy Fiddaman 	{
785*b30d1939SAndy Fiddaman 		if (c == '$' && *s == '{')
786*b30d1939SAndy Fiddaman 		{
787*b30d1939SAndy Fiddaman 			b = s - 1;
788*b30d1939SAndy Fiddaman 			i = 1;
789*b30d1939SAndy Fiddaman 			for (n = *(t = ++s) == '-' ? 0 : '-'; (c = *s) && c != '?' && c != '+' && c != n && c != ':' && c != '=' && c != '[' && c != '}'; s++)
790*b30d1939SAndy Fiddaman 				if (!isalnum(c) && c != '_')
791*b30d1939SAndy Fiddaman 					i = 0;
792*b30d1939SAndy Fiddaman 			*s = 0;
793*b30d1939SAndy Fiddaman 			if (c == '[')
794*b30d1939SAndy Fiddaman 			{
795*b30d1939SAndy Fiddaman 				append(buf, b);
796*b30d1939SAndy Fiddaman 				*s = c;
797*b30d1939SAndy Fiddaman 				continue;
798*b30d1939SAndy Fiddaman 			}
799*b30d1939SAndy Fiddaman 			v = (char*)search(state.vars, t, NiL);
800*b30d1939SAndy Fiddaman 			if ((c == ':' || c == '=') && (!v || c == ':' && !*v))
801*b30d1939SAndy Fiddaman 			{
802*b30d1939SAndy Fiddaman 				append(buf, b);
803*b30d1939SAndy Fiddaman 				*s = c;
804*b30d1939SAndy Fiddaman 				continue;
805*b30d1939SAndy Fiddaman 			}
806*b30d1939SAndy Fiddaman 			if (t[0] == 'A' && t[1] == 'R' && t[2] == 0)
807*b30d1939SAndy Fiddaman 				a = 1;
808*b30d1939SAndy Fiddaman 			*s = c;
809*b30d1939SAndy Fiddaman 			if (c && c != '}')
810*b30d1939SAndy Fiddaman 			{
811*b30d1939SAndy Fiddaman 				n = 1;
812*b30d1939SAndy Fiddaman 				for (t = ++s; *s; s++)
813*b30d1939SAndy Fiddaman 					if (*s == '{')
814*b30d1939SAndy Fiddaman 						n++;
815*b30d1939SAndy Fiddaman 					else if (*s == '}' && !--n)
816*b30d1939SAndy Fiddaman 						break;
817*b30d1939SAndy Fiddaman 			}
818*b30d1939SAndy Fiddaman 			switch (c)
819*b30d1939SAndy Fiddaman 			{
820*b30d1939SAndy Fiddaman 			case '?':
821*b30d1939SAndy Fiddaman 				q = cond(t - 1);
822*b30d1939SAndy Fiddaman 				if (v)
823*b30d1939SAndy Fiddaman 				{
824*b30d1939SAndy Fiddaman 					if (((q - t) != 1 || *t != '*') && strncmp(v, t, q - t))
825*b30d1939SAndy Fiddaman 						v = 0;
826*b30d1939SAndy Fiddaman 				}
827*b30d1939SAndy Fiddaman 				else if (q == t)
828*b30d1939SAndy Fiddaman 					v = s;
829*b30d1939SAndy Fiddaman 				t = cond(q);
830*b30d1939SAndy Fiddaman 				if (v)
831*b30d1939SAndy Fiddaman 				{
832*b30d1939SAndy Fiddaman 					if (t > q)
833*b30d1939SAndy Fiddaman 					{
834*b30d1939SAndy Fiddaman 						c = *t;
835*b30d1939SAndy Fiddaman 						*t = 0;
836*b30d1939SAndy Fiddaman 						substitute(buf, q + 1);
837*b30d1939SAndy Fiddaman 						*t = c;
838*b30d1939SAndy Fiddaman 					}
839*b30d1939SAndy Fiddaman 				}
840*b30d1939SAndy Fiddaman 				else
841*b30d1939SAndy Fiddaman 				{
842*b30d1939SAndy Fiddaman 					q = cond(t);
843*b30d1939SAndy Fiddaman 					if (q > t)
844*b30d1939SAndy Fiddaman 					{
845*b30d1939SAndy Fiddaman 						c = *q;
846*b30d1939SAndy Fiddaman 						*q = 0;
847*b30d1939SAndy Fiddaman 						substitute(buf, t + 1);
848*b30d1939SAndy Fiddaman 						*q = c;
849*b30d1939SAndy Fiddaman 					}
850*b30d1939SAndy Fiddaman 				}
851*b30d1939SAndy Fiddaman 				break;
852*b30d1939SAndy Fiddaman 			case '+':
853*b30d1939SAndy Fiddaman 			case '-':
854*b30d1939SAndy Fiddaman 				if ((v == 0 || *v == 0) == (c == '-'))
855*b30d1939SAndy Fiddaman 				{
856*b30d1939SAndy Fiddaman 					c = *s;
857*b30d1939SAndy Fiddaman 					*s = 0;
858*b30d1939SAndy Fiddaman 					substitute(buf, t);
859*b30d1939SAndy Fiddaman 					*s = c;
860*b30d1939SAndy Fiddaman 					break;
861*b30d1939SAndy Fiddaman 				}
862*b30d1939SAndy Fiddaman 				if (c != '-')
863*b30d1939SAndy Fiddaman 					break;
864*b30d1939SAndy Fiddaman 				/*FALLTHROUGH*/
865*b30d1939SAndy Fiddaman 			case 0:
866*b30d1939SAndy Fiddaman 			case '=':
867*b30d1939SAndy Fiddaman 			case '}':
868*b30d1939SAndy Fiddaman 				if (v)
869*b30d1939SAndy Fiddaman 				{
870*b30d1939SAndy Fiddaman 					if (a && t[0] == 'm' && t[1] == 'a' && t[2] == 'm' && t[3] == '_' && t[4] == 'l' && t[5] == 'i' && t[6] == 'b')
871*b30d1939SAndy Fiddaman 					{
872*b30d1939SAndy Fiddaman 						for (t = v; *t == ' '; t++);
873*b30d1939SAndy Fiddaman 						for (; *t && *t != ' '; t++);
874*b30d1939SAndy Fiddaman 						if (*t)
875*b30d1939SAndy Fiddaman 							*t = 0;
876*b30d1939SAndy Fiddaman 						else
877*b30d1939SAndy Fiddaman 							t = 0;
878*b30d1939SAndy Fiddaman 						substitute(buf, v);
879*b30d1939SAndy Fiddaman 						if (t)
880*b30d1939SAndy Fiddaman 							*t = ' ';
881*b30d1939SAndy Fiddaman 					}
882*b30d1939SAndy Fiddaman 					else
883*b30d1939SAndy Fiddaman 						substitute(buf, v);
884*b30d1939SAndy Fiddaman 				}
885*b30d1939SAndy Fiddaman 				else if (i)
886*b30d1939SAndy Fiddaman 				{
887*b30d1939SAndy Fiddaman 					c = *s;
888*b30d1939SAndy Fiddaman 					*s = 0;
889*b30d1939SAndy Fiddaman 					append(buf, b);
890*b30d1939SAndy Fiddaman 					*s = c;
891*b30d1939SAndy Fiddaman 					continue;
892*b30d1939SAndy Fiddaman 				}
893*b30d1939SAndy Fiddaman 				break;
894*b30d1939SAndy Fiddaman 			}
895*b30d1939SAndy Fiddaman 			if (*s)
896*b30d1939SAndy Fiddaman 				s++;
897*b30d1939SAndy Fiddaman 		}
898*b30d1939SAndy Fiddaman 		else
899*b30d1939SAndy Fiddaman 			add(buf, c);
900*b30d1939SAndy Fiddaman 	}
901*b30d1939SAndy Fiddaman }
902*b30d1939SAndy Fiddaman 
903*b30d1939SAndy Fiddaman /*
904*b30d1939SAndy Fiddaman  * expand var refs from s into buf and return buf base
905*b30d1939SAndy Fiddaman  */
906*b30d1939SAndy Fiddaman 
907*b30d1939SAndy Fiddaman static char*
expand(Buf_t * buf,char * s)908*b30d1939SAndy Fiddaman expand(Buf_t* buf, char* s)
909*b30d1939SAndy Fiddaman {
910*b30d1939SAndy Fiddaman 	substitute(buf, s);
911*b30d1939SAndy Fiddaman 	return use(buf);
912*b30d1939SAndy Fiddaman }
913*b30d1939SAndy Fiddaman 
914*b30d1939SAndy Fiddaman /*
915*b30d1939SAndy Fiddaman  * stat() with .exe check
916*b30d1939SAndy Fiddaman  */
917*b30d1939SAndy Fiddaman 
918*b30d1939SAndy Fiddaman static char*
status(Buf_t * buf,int off,char * path,struct stat * st)919*b30d1939SAndy Fiddaman status(Buf_t* buf, int off, char* path, struct stat* st)
920*b30d1939SAndy Fiddaman {
921*b30d1939SAndy Fiddaman 	int		r;
922*b30d1939SAndy Fiddaman 	char*		s;
923*b30d1939SAndy Fiddaman 	Buf_t*		tmp;
924*b30d1939SAndy Fiddaman 
925*b30d1939SAndy Fiddaman 	if (!stat(path, st))
926*b30d1939SAndy Fiddaman 		return path;
927*b30d1939SAndy Fiddaman 	if (!(tmp = buf))
928*b30d1939SAndy Fiddaman 	{
929*b30d1939SAndy Fiddaman 		tmp = buffer();
930*b30d1939SAndy Fiddaman 		off = 0;
931*b30d1939SAndy Fiddaman 	}
932*b30d1939SAndy Fiddaman 	if (off)
933*b30d1939SAndy Fiddaman 		set(tmp, off);
934*b30d1939SAndy Fiddaman 	else
935*b30d1939SAndy Fiddaman 		append(tmp, path);
936*b30d1939SAndy Fiddaman 	append(tmp, ".exe");
937*b30d1939SAndy Fiddaman 	s = use(tmp);
938*b30d1939SAndy Fiddaman 	r = stat(s, st);
939*b30d1939SAndy Fiddaman 	if (!buf)
940*b30d1939SAndy Fiddaman 	{
941*b30d1939SAndy Fiddaman 		drop(tmp);
942*b30d1939SAndy Fiddaman 		s = path;
943*b30d1939SAndy Fiddaman 	}
944*b30d1939SAndy Fiddaman 	if (r)
945*b30d1939SAndy Fiddaman 	{
946*b30d1939SAndy Fiddaman 		if (off)
947*b30d1939SAndy Fiddaman 			s[off] = 0;
948*b30d1939SAndy Fiddaman 		s = 0;
949*b30d1939SAndy Fiddaman 	}
950*b30d1939SAndy Fiddaman 	return s;
951*b30d1939SAndy Fiddaman }
952*b30d1939SAndy Fiddaman 
953*b30d1939SAndy Fiddaman /*
954*b30d1939SAndy Fiddaman  * return path to file
955*b30d1939SAndy Fiddaman  */
956*b30d1939SAndy Fiddaman 
957*b30d1939SAndy Fiddaman static char*
find(Buf_t * buf,char * file,struct stat * st)958*b30d1939SAndy Fiddaman find(Buf_t* buf, char* file, struct stat* st)
959*b30d1939SAndy Fiddaman {
960*b30d1939SAndy Fiddaman 	char*		s;
961*b30d1939SAndy Fiddaman 	View_t*		vp;
962*b30d1939SAndy Fiddaman 	int		node;
963*b30d1939SAndy Fiddaman 	int		c;
964*b30d1939SAndy Fiddaman 	int		o;
965*b30d1939SAndy Fiddaman 
966*b30d1939SAndy Fiddaman 	if (s = status(buf, 0, file, st))
967*b30d1939SAndy Fiddaman 	{
968*b30d1939SAndy Fiddaman 		report(-3, s, "find", (unsigned long)0);
969*b30d1939SAndy Fiddaman 		return s;
970*b30d1939SAndy Fiddaman 	}
971*b30d1939SAndy Fiddaman 	if (vp = state.view)
972*b30d1939SAndy Fiddaman 	{
973*b30d1939SAndy Fiddaman 		node = 0;
974*b30d1939SAndy Fiddaman 		if (*file == '/')
975*b30d1939SAndy Fiddaman 		{
976*b30d1939SAndy Fiddaman 			do
977*b30d1939SAndy Fiddaman 			{
978*b30d1939SAndy Fiddaman 				if (!strncmp(file, vp->dir, vp->node))
979*b30d1939SAndy Fiddaman 				{
980*b30d1939SAndy Fiddaman 					file += vp->node;
981*b30d1939SAndy Fiddaman 					node = 2;
982*b30d1939SAndy Fiddaman 					break;
983*b30d1939SAndy Fiddaman 				}
984*b30d1939SAndy Fiddaman 			} while (vp = vp->next);
985*b30d1939SAndy Fiddaman 		}
986*b30d1939SAndy Fiddaman 		else
987*b30d1939SAndy Fiddaman 			vp = vp->next;
988*b30d1939SAndy Fiddaman 		if (vp)
989*b30d1939SAndy Fiddaman 			do
990*b30d1939SAndy Fiddaman 			{
991*b30d1939SAndy Fiddaman 				if (node)
992*b30d1939SAndy Fiddaman 				{
993*b30d1939SAndy Fiddaman 					c = vp->dir[vp->node];
994*b30d1939SAndy Fiddaman 					vp->dir[vp->node] = 0;
995*b30d1939SAndy Fiddaman 					append(buf, vp->dir);
996*b30d1939SAndy Fiddaman 					vp->dir[vp->node] = c;
997*b30d1939SAndy Fiddaman 				}
998*b30d1939SAndy Fiddaman 				else
999*b30d1939SAndy Fiddaman 				{
1000*b30d1939SAndy Fiddaman 					append(buf, vp->dir);
1001*b30d1939SAndy Fiddaman 					append(buf, "/");
1002*b30d1939SAndy Fiddaman 				}
1003*b30d1939SAndy Fiddaman 				append(buf, file);
1004*b30d1939SAndy Fiddaman 				o = get(buf);
1005*b30d1939SAndy Fiddaman 				s = use(buf);
1006*b30d1939SAndy Fiddaman 				if (s = status(buf, o, s, st))
1007*b30d1939SAndy Fiddaman 				{
1008*b30d1939SAndy Fiddaman 					report(-3, s, "find", (unsigned long)0);
1009*b30d1939SAndy Fiddaman 					return s;
1010*b30d1939SAndy Fiddaman 				}
1011*b30d1939SAndy Fiddaman 			} while (vp = vp->next);
1012*b30d1939SAndy Fiddaman 	}
1013*b30d1939SAndy Fiddaman 	return 0;
1014*b30d1939SAndy Fiddaman }
1015*b30d1939SAndy Fiddaman 
1016*b30d1939SAndy Fiddaman /*
1017*b30d1939SAndy Fiddaman  * bind r to a file and return the modify time
1018*b30d1939SAndy Fiddaman  */
1019*b30d1939SAndy Fiddaman 
1020*b30d1939SAndy Fiddaman static unsigned long
bind(Rule_t * r)1021*b30d1939SAndy Fiddaman bind(Rule_t* r)
1022*b30d1939SAndy Fiddaman {
1023*b30d1939SAndy Fiddaman 	char*		s;
1024*b30d1939SAndy Fiddaman 	Buf_t*		buf;
1025*b30d1939SAndy Fiddaman 	struct stat	st;
1026*b30d1939SAndy Fiddaman 
1027*b30d1939SAndy Fiddaman 	buf = buffer();
1028*b30d1939SAndy Fiddaman 	if (s = find(buf, r->name, &st))
1029*b30d1939SAndy Fiddaman 	{
1030*b30d1939SAndy Fiddaman 		if (s != r->name)
1031*b30d1939SAndy Fiddaman 			r->path = duplicate(s);
1032*b30d1939SAndy Fiddaman 		r->time = st.st_mtime;
1033*b30d1939SAndy Fiddaman 		r->flags |= RULE_exists;
1034*b30d1939SAndy Fiddaman 	}
1035*b30d1939SAndy Fiddaman 	drop(buf);
1036*b30d1939SAndy Fiddaman 	return r->time;
1037*b30d1939SAndy Fiddaman }
1038*b30d1939SAndy Fiddaman 
1039*b30d1939SAndy Fiddaman /*
1040*b30d1939SAndy Fiddaman  * pop the current input file
1041*b30d1939SAndy Fiddaman  */
1042*b30d1939SAndy Fiddaman 
1043*b30d1939SAndy Fiddaman static int
pop(void)1044*b30d1939SAndy Fiddaman pop(void)
1045*b30d1939SAndy Fiddaman {
1046*b30d1939SAndy Fiddaman 	int	r;
1047*b30d1939SAndy Fiddaman 
1048*b30d1939SAndy Fiddaman 	if (!state.sp)
1049*b30d1939SAndy Fiddaman 		report(3, "input stack underflow", NiL, (unsigned long)0);
1050*b30d1939SAndy Fiddaman 	if (!state.sp->fp || (state.sp->flags & STREAM_KEEP))
1051*b30d1939SAndy Fiddaman 		r = 0;
1052*b30d1939SAndy Fiddaman 	else if (state.sp->flags & STREAM_PIPE)
1053*b30d1939SAndy Fiddaman 		r = pclose(state.sp->fp);
1054*b30d1939SAndy Fiddaman 	else
1055*b30d1939SAndy Fiddaman 		r = fclose(state.sp->fp);
1056*b30d1939SAndy Fiddaman 	if (state.sp == state.streams)
1057*b30d1939SAndy Fiddaman 		state.sp = 0;
1058*b30d1939SAndy Fiddaman 	else
1059*b30d1939SAndy Fiddaman 		state.sp--;
1060*b30d1939SAndy Fiddaman 	return r;
1061*b30d1939SAndy Fiddaman }
1062*b30d1939SAndy Fiddaman 
1063*b30d1939SAndy Fiddaman /*
1064*b30d1939SAndy Fiddaman  * push file onto the input stack
1065*b30d1939SAndy Fiddaman  */
1066*b30d1939SAndy Fiddaman 
1067*b30d1939SAndy Fiddaman static int
push(char * file,Stdio_t * fp,int flags)1068*b30d1939SAndy Fiddaman push(char* file, Stdio_t* fp, int flags)
1069*b30d1939SAndy Fiddaman {
1070*b30d1939SAndy Fiddaman 	char*		path;
1071*b30d1939SAndy Fiddaman 	Buf_t*		buf;
1072*b30d1939SAndy Fiddaman 	struct stat	st;
1073*b30d1939SAndy Fiddaman 
1074*b30d1939SAndy Fiddaman 	if (!state.sp)
1075*b30d1939SAndy Fiddaman 		state.sp = state.streams;
1076*b30d1939SAndy Fiddaman 	else if (++state.sp >= &state.streams[elementsof(state.streams)])
1077*b30d1939SAndy Fiddaman 		report(3, "input stream stack overflow", NiL, (unsigned long)0);
1078*b30d1939SAndy Fiddaman 	if (state.sp->fp = fp)
1079*b30d1939SAndy Fiddaman 		state.sp->file = "pipeline";
1080*b30d1939SAndy Fiddaman 	else if (flags & STREAM_PIPE)
1081*b30d1939SAndy Fiddaman 		report(3, "pipe error", file, (unsigned long)0);
1082*b30d1939SAndy Fiddaman 	else if (!file || !strcmp(file, "-") || !strcmp(file, "/dev/stdin"))
1083*b30d1939SAndy Fiddaman 	{
1084*b30d1939SAndy Fiddaman 		flags |= STREAM_KEEP;
1085*b30d1939SAndy Fiddaman 		state.sp->file = "/dev/stdin";
1086*b30d1939SAndy Fiddaman 		state.sp->fp = stdin;
1087*b30d1939SAndy Fiddaman 	}
1088*b30d1939SAndy Fiddaman 	else
1089*b30d1939SAndy Fiddaman 	{
1090*b30d1939SAndy Fiddaman 		buf = buffer();
1091*b30d1939SAndy Fiddaman 		if (path = find(buf, file, &st))
1092*b30d1939SAndy Fiddaman 		{
1093*b30d1939SAndy Fiddaman 			if (!(state.sp->fp = fopen(path, "r")))
1094*b30d1939SAndy Fiddaman 				report(3, "cannot read", path, (unsigned long)0);
1095*b30d1939SAndy Fiddaman 			state.sp->file = duplicate(path);
1096*b30d1939SAndy Fiddaman 			drop(buf);
1097*b30d1939SAndy Fiddaman 		}
1098*b30d1939SAndy Fiddaman 		else
1099*b30d1939SAndy Fiddaman 		{
1100*b30d1939SAndy Fiddaman 			drop(buf);
1101*b30d1939SAndy Fiddaman 			pop();
1102*b30d1939SAndy Fiddaman 			if (flags & STREAM_MUST)
1103*b30d1939SAndy Fiddaman 				report(3, "not found", file, (unsigned long)0);
1104*b30d1939SAndy Fiddaman 			return 0;
1105*b30d1939SAndy Fiddaman 		}
1106*b30d1939SAndy Fiddaman 	}
1107*b30d1939SAndy Fiddaman 	state.sp->flags = flags;
1108*b30d1939SAndy Fiddaman 	state.sp->line = 0;
1109*b30d1939SAndy Fiddaman 	return 1;
1110*b30d1939SAndy Fiddaman }
1111*b30d1939SAndy Fiddaman 
1112*b30d1939SAndy Fiddaman /*
1113*b30d1939SAndy Fiddaman  * return the next input line
1114*b30d1939SAndy Fiddaman  */
1115*b30d1939SAndy Fiddaman 
1116*b30d1939SAndy Fiddaman static char*
input(void)1117*b30d1939SAndy Fiddaman input(void)
1118*b30d1939SAndy Fiddaman {
1119*b30d1939SAndy Fiddaman 	char*	e;
1120*b30d1939SAndy Fiddaman 
1121*b30d1939SAndy Fiddaman 	if (!state.sp)
1122*b30d1939SAndy Fiddaman 		report(3, "no input file stream", NiL, (unsigned long)0);
1123*b30d1939SAndy Fiddaman 	if (state.peek)
1124*b30d1939SAndy Fiddaman 		state.peek = 0;
1125*b30d1939SAndy Fiddaman 	else if (!fgets(state.input, sizeof(state.input), state.sp->fp))
1126*b30d1939SAndy Fiddaman 		return 0;
1127*b30d1939SAndy Fiddaman 	else if (*state.input && *(e = state.input + strlen(state.input) - 1) == '\n')
1128*b30d1939SAndy Fiddaman 		*e = 0;
1129*b30d1939SAndy Fiddaman 	state.sp->line++;
1130*b30d1939SAndy Fiddaman 	return state.input;
1131*b30d1939SAndy Fiddaman }
1132*b30d1939SAndy Fiddaman 
1133*b30d1939SAndy Fiddaman /*
1134*b30d1939SAndy Fiddaman  * pass shell action s to ${SHELL:-/bin/sh}
1135*b30d1939SAndy Fiddaman  * the -c wrapper ensures that scripts are run in the selected shell
1136*b30d1939SAndy Fiddaman  * even on systems that otherwise demand #! magic (can you say cygwin)
1137*b30d1939SAndy Fiddaman  */
1138*b30d1939SAndy Fiddaman 
1139*b30d1939SAndy Fiddaman static int
execute(register char * s)1140*b30d1939SAndy Fiddaman execute(register char* s)
1141*b30d1939SAndy Fiddaman {
1142*b30d1939SAndy Fiddaman 	register int	c;
1143*b30d1939SAndy Fiddaman 	Buf_t*		buf;
1144*b30d1939SAndy Fiddaman 
1145*b30d1939SAndy Fiddaman 	if (!state.shell && (!(state.shell = (char*)search(state.vars, "SHELL", NiL)) || !strcmp(state.shell, sh)))
1146*b30d1939SAndy Fiddaman 		state.shell = sh;
1147*b30d1939SAndy Fiddaman 	buf = buffer();
1148*b30d1939SAndy Fiddaman 	append(buf, state.shell);
1149*b30d1939SAndy Fiddaman 	append(buf, " -c '");
1150*b30d1939SAndy Fiddaman 	while (c = *s++)
1151*b30d1939SAndy Fiddaman 	{
1152*b30d1939SAndy Fiddaman 		if (c == '\'')
1153*b30d1939SAndy Fiddaman 		{
1154*b30d1939SAndy Fiddaman 			add(buf, c);
1155*b30d1939SAndy Fiddaman 			for (s--; *s == c; s++)
1156*b30d1939SAndy Fiddaman 			{
1157*b30d1939SAndy Fiddaman 				add(buf, '\\');
1158*b30d1939SAndy Fiddaman 				add(buf, c);
1159*b30d1939SAndy Fiddaman 			}
1160*b30d1939SAndy Fiddaman 		}
1161*b30d1939SAndy Fiddaman 		add(buf, c);
1162*b30d1939SAndy Fiddaman 	}
1163*b30d1939SAndy Fiddaman 	add(buf, '\'');
1164*b30d1939SAndy Fiddaman 	s = use(buf);
1165*b30d1939SAndy Fiddaman 	report(-5, s, "exec", (unsigned long)0);
1166*b30d1939SAndy Fiddaman 	if ((c = system(s)) > 255)
1167*b30d1939SAndy Fiddaman 		c >>= 8;
1168*b30d1939SAndy Fiddaman 	drop(buf);
1169*b30d1939SAndy Fiddaman 	return c;
1170*b30d1939SAndy Fiddaman }
1171*b30d1939SAndy Fiddaman 
1172*b30d1939SAndy Fiddaman /*
1173*b30d1939SAndy Fiddaman  * run action s to update r
1174*b30d1939SAndy Fiddaman  */
1175*b30d1939SAndy Fiddaman 
1176*b30d1939SAndy Fiddaman static unsigned long
run(Rule_t * r,register char * s)1177*b30d1939SAndy Fiddaman run(Rule_t* r, register char* s)
1178*b30d1939SAndy Fiddaman {
1179*b30d1939SAndy Fiddaman 	register Rule_t*	q;
1180*b30d1939SAndy Fiddaman 	register char*		t;
1181*b30d1939SAndy Fiddaman 	register int		c;
1182*b30d1939SAndy Fiddaman 	register View_t*	v;
1183*b30d1939SAndy Fiddaman 	int			i;
1184*b30d1939SAndy Fiddaman 	int			j;
1185*b30d1939SAndy Fiddaman 	int			x;
1186*b30d1939SAndy Fiddaman 	Stat_t			st;
1187*b30d1939SAndy Fiddaman 	Buf_t*			buf;
1188*b30d1939SAndy Fiddaman 
1189*b30d1939SAndy Fiddaman 	if (r->flags & RULE_error)
1190*b30d1939SAndy Fiddaman 		return r->time;
1191*b30d1939SAndy Fiddaman 	buf = buffer();
1192*b30d1939SAndy Fiddaman 	if (!strncmp(s, "mamake -r ", 10))
1193*b30d1939SAndy Fiddaman 	{
1194*b30d1939SAndy Fiddaman 		state.verified = 1;
1195*b30d1939SAndy Fiddaman 		x = !state.never;
1196*b30d1939SAndy Fiddaman 	}
1197*b30d1939SAndy Fiddaman 	else
1198*b30d1939SAndy Fiddaman 		x = state.exec;
1199*b30d1939SAndy Fiddaman 	if (x)
1200*b30d1939SAndy Fiddaman 		append(buf, "trap - 1 2 3 15\nPATH=.:$PATH\nset -x\n");
1201*b30d1939SAndy Fiddaman 	if (state.view)
1202*b30d1939SAndy Fiddaman 	{
1203*b30d1939SAndy Fiddaman 		do
1204*b30d1939SAndy Fiddaman 		{
1205*b30d1939SAndy Fiddaman 			for (; delimiter(*s); s++)
1206*b30d1939SAndy Fiddaman 				add(buf, *s);
1207*b30d1939SAndy Fiddaman 			for (t = s; *s && !delimiter(*s); s++);
1208*b30d1939SAndy Fiddaman 			c = *s;
1209*b30d1939SAndy Fiddaman 			*s = 0;
1210*b30d1939SAndy Fiddaman 			if (c == '=')
1211*b30d1939SAndy Fiddaman 			{
1212*b30d1939SAndy Fiddaman 				append(buf, t);
1213*b30d1939SAndy Fiddaman 				continue;
1214*b30d1939SAndy Fiddaman 			}
1215*b30d1939SAndy Fiddaman 			if ((q = (Rule_t*)search(state.rules, t, NiL)) && q->path && !(q->flags & RULE_generated))
1216*b30d1939SAndy Fiddaman 				append(buf, q->path);
1217*b30d1939SAndy Fiddaman 			else
1218*b30d1939SAndy Fiddaman 			{
1219*b30d1939SAndy Fiddaman 				append(buf, t);
1220*b30d1939SAndy Fiddaman 				if (*t == '-' && *(t + 1) == 'I' && (*(t + 2) || c))
1221*b30d1939SAndy Fiddaman 				{
1222*b30d1939SAndy Fiddaman 					if (*(t + 2))
1223*b30d1939SAndy Fiddaman 						i = 2;
1224*b30d1939SAndy Fiddaman 					else
1225*b30d1939SAndy Fiddaman 					{
1226*b30d1939SAndy Fiddaman 						for (i = 3; *(t + i) == ' ' || *(t + i) == '\t'; i++);
1227*b30d1939SAndy Fiddaman 						*s = c;
1228*b30d1939SAndy Fiddaman 						for (s = t + i; *s && *s != ' ' && *s != '\t' && *s != '\n'; s++);
1229*b30d1939SAndy Fiddaman 						c = *s;
1230*b30d1939SAndy Fiddaman 						*s = 0;
1231*b30d1939SAndy Fiddaman 						append(buf, t + 2);
1232*b30d1939SAndy Fiddaman 					}
1233*b30d1939SAndy Fiddaman 					if (*(t + i) && *(t + i) != '/')
1234*b30d1939SAndy Fiddaman 					{
1235*b30d1939SAndy Fiddaman 						v = state.view;
1236*b30d1939SAndy Fiddaman 						while (v = v->next)
1237*b30d1939SAndy Fiddaman 						{
1238*b30d1939SAndy Fiddaman 							add(buf, ' ');
1239*b30d1939SAndy Fiddaman 							for (j = 0; j < i; j++)
1240*b30d1939SAndy Fiddaman 								add(buf, *(t + j));
1241*b30d1939SAndy Fiddaman 							append(buf, v->dir);
1242*b30d1939SAndy Fiddaman 							if (*(t + i) != '.' || *(t + i + 1))
1243*b30d1939SAndy Fiddaman 							{
1244*b30d1939SAndy Fiddaman 								add(buf, '/');
1245*b30d1939SAndy Fiddaman 								append(buf, t + i);
1246*b30d1939SAndy Fiddaman 							}
1247*b30d1939SAndy Fiddaman 						}
1248*b30d1939SAndy Fiddaman 					}
1249*b30d1939SAndy Fiddaman 				}
1250*b30d1939SAndy Fiddaman 			}
1251*b30d1939SAndy Fiddaman 		} while (*s = c);
1252*b30d1939SAndy Fiddaman 		s = use(buf);
1253*b30d1939SAndy Fiddaman 	}
1254*b30d1939SAndy Fiddaman 	else if (x)
1255*b30d1939SAndy Fiddaman 	{
1256*b30d1939SAndy Fiddaman 		append(buf, s);
1257*b30d1939SAndy Fiddaman 		s = use(buf);
1258*b30d1939SAndy Fiddaman 	}
1259*b30d1939SAndy Fiddaman 	if (x)
1260*b30d1939SAndy Fiddaman 	{
1261*b30d1939SAndy Fiddaman 		if (c = execute(s))
1262*b30d1939SAndy Fiddaman 			dont(r, c, state.keepgoing);
1263*b30d1939SAndy Fiddaman 		if (status((Buf_t*)0, 0, r->name, &st))
1264*b30d1939SAndy Fiddaman 		{
1265*b30d1939SAndy Fiddaman 			r->time = st.st_mtime;
1266*b30d1939SAndy Fiddaman 			r->flags |= RULE_exists;
1267*b30d1939SAndy Fiddaman 		}
1268*b30d1939SAndy Fiddaman 		else
1269*b30d1939SAndy Fiddaman 			r->time = NOW;
1270*b30d1939SAndy Fiddaman 	}
1271*b30d1939SAndy Fiddaman 	else
1272*b30d1939SAndy Fiddaman 	{
1273*b30d1939SAndy Fiddaman 		fprintf(stdout, "%s\n", s);
1274*b30d1939SAndy Fiddaman 		if (state.debug)
1275*b30d1939SAndy Fiddaman 			fflush(stdout);
1276*b30d1939SAndy Fiddaman 		r->time = NOW;
1277*b30d1939SAndy Fiddaman 		r->flags |= RULE_exists;
1278*b30d1939SAndy Fiddaman 	}
1279*b30d1939SAndy Fiddaman 	drop(buf);
1280*b30d1939SAndy Fiddaman 	return r->time;
1281*b30d1939SAndy Fiddaman }
1282*b30d1939SAndy Fiddaman 
1283*b30d1939SAndy Fiddaman /*
1284*b30d1939SAndy Fiddaman  * return the full path for s using buf workspace
1285*b30d1939SAndy Fiddaman  */
1286*b30d1939SAndy Fiddaman 
1287*b30d1939SAndy Fiddaman static char*
path(Buf_t * buf,char * s,int must)1288*b30d1939SAndy Fiddaman path(Buf_t* buf, char* s, int must)
1289*b30d1939SAndy Fiddaman {
1290*b30d1939SAndy Fiddaman 	register char*	p;
1291*b30d1939SAndy Fiddaman 	register char*	d;
1292*b30d1939SAndy Fiddaman 	register char*	x;
1293*b30d1939SAndy Fiddaman 	char*		e;
1294*b30d1939SAndy Fiddaman 	register int	c;
1295*b30d1939SAndy Fiddaman 	int		t;
1296*b30d1939SAndy Fiddaman 	int		o;
1297*b30d1939SAndy Fiddaman 	Stat_t		st;
1298*b30d1939SAndy Fiddaman 
1299*b30d1939SAndy Fiddaman 	for (e = s; *e && *e != ' ' && *e != '\t'; e++);
1300*b30d1939SAndy Fiddaman 	t = *e;
1301*b30d1939SAndy Fiddaman 	if ((x = status(buf, 0, s, &st)) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
1302*b30d1939SAndy Fiddaman 		return x;
1303*b30d1939SAndy Fiddaman 	if (!(p = (char*)search(state.vars, "PATH", NiL)))
1304*b30d1939SAndy Fiddaman 		report(3, "variable not defined", "PATH", (unsigned long)0);
1305*b30d1939SAndy Fiddaman 	do
1306*b30d1939SAndy Fiddaman 	{
1307*b30d1939SAndy Fiddaman 		for (d = p; *p && *p != ':'; p++);
1308*b30d1939SAndy Fiddaman 		c = *p;
1309*b30d1939SAndy Fiddaman 		*p = 0;
1310*b30d1939SAndy Fiddaman 		if (*d && (*d != '.' || *(d + 1)))
1311*b30d1939SAndy Fiddaman 		{
1312*b30d1939SAndy Fiddaman 			append(buf, d);
1313*b30d1939SAndy Fiddaman 			add(buf, '/');
1314*b30d1939SAndy Fiddaman 		}
1315*b30d1939SAndy Fiddaman 		*p = c;
1316*b30d1939SAndy Fiddaman 		if (t)
1317*b30d1939SAndy Fiddaman 			*e = 0;
1318*b30d1939SAndy Fiddaman 		append(buf, s);
1319*b30d1939SAndy Fiddaman 		if (t)
1320*b30d1939SAndy Fiddaman 			*e = t;
1321*b30d1939SAndy Fiddaman 		o = get(buf);
1322*b30d1939SAndy Fiddaman 		x = use(buf);
1323*b30d1939SAndy Fiddaman 		if ((x = status(buf, o, x, &st)) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
1324*b30d1939SAndy Fiddaman 			return x;
1325*b30d1939SAndy Fiddaman 	} while (*p++);
1326*b30d1939SAndy Fiddaman 	if (must)
1327*b30d1939SAndy Fiddaman 		report(3, "command not found", s, (unsigned long)0);
1328*b30d1939SAndy Fiddaman 	return 0;
1329*b30d1939SAndy Fiddaman }
1330*b30d1939SAndy Fiddaman 
1331*b30d1939SAndy Fiddaman /*
1332*b30d1939SAndy Fiddaman  * generate (if necessary) and read the MAM probe information
1333*b30d1939SAndy Fiddaman  * done on the first `setv CC ...'
1334*b30d1939SAndy Fiddaman  */
1335*b30d1939SAndy Fiddaman 
1336*b30d1939SAndy Fiddaman static void
probe(void)1337*b30d1939SAndy Fiddaman probe(void)
1338*b30d1939SAndy Fiddaman {
1339*b30d1939SAndy Fiddaman 	register char*	cc;
1340*b30d1939SAndy Fiddaman 	register char*	s;
1341*b30d1939SAndy Fiddaman 	unsigned long	h;
1342*b30d1939SAndy Fiddaman 	unsigned long	q;
1343*b30d1939SAndy Fiddaman 	Buf_t*		buf;
1344*b30d1939SAndy Fiddaman 	Buf_t*		pro;
1345*b30d1939SAndy Fiddaman 	Buf_t*		tmp;
1346*b30d1939SAndy Fiddaman 	struct stat	st;
1347*b30d1939SAndy Fiddaman 
1348*b30d1939SAndy Fiddaman 	static char	let[] = "ABCDEFGHIJKLMNOP";
1349*b30d1939SAndy Fiddaman 	static char	cmd[] = "mamprobe";
1350*b30d1939SAndy Fiddaman 
1351*b30d1939SAndy Fiddaman 	if (!(cc = (char*)search(state.vars, "CC", NiL)))
1352*b30d1939SAndy Fiddaman 		cc = "cc";
1353*b30d1939SAndy Fiddaman 	buf = buffer();
1354*b30d1939SAndy Fiddaman 	s = path(buf, cmd, 1);
1355*b30d1939SAndy Fiddaman 	q = stat(s, &st) ? (unsigned long)0 : (unsigned long)st.st_mtime;
1356*b30d1939SAndy Fiddaman 	pro = buffer();
1357*b30d1939SAndy Fiddaman 	s = cc = path(pro, cc, 1);
1358*b30d1939SAndy Fiddaman 	for (h = 0; *s; s++)
1359*b30d1939SAndy Fiddaman 		h = h * 0x63c63cd9L + *s + 0x9c39c33dL;
1360*b30d1939SAndy Fiddaman 	if (!(s = (char*)search(state.vars, "INSTALLROOT", NiL)))
1361*b30d1939SAndy Fiddaman 		report(3, "variable must be defined", "INSTALLROOT", (unsigned long)0);
1362*b30d1939SAndy Fiddaman 	append(buf, s);
1363*b30d1939SAndy Fiddaman 	append(buf, "/lib/probe/C/mam/");
1364*b30d1939SAndy Fiddaman 	for (h &= 0xffffffffL; h; h >>= 4)
1365*b30d1939SAndy Fiddaman 		add(buf, let[h & 0xf]);
1366*b30d1939SAndy Fiddaman 	s = use(buf);
1367*b30d1939SAndy Fiddaman 	h = stat(s, &st) ? (unsigned long)0 : (unsigned long)st.st_mtime;
1368*b30d1939SAndy Fiddaman 	if (h < q || !push(s, (Stdio_t*)0, 0))
1369*b30d1939SAndy Fiddaman 	{
1370*b30d1939SAndy Fiddaman 		tmp = buffer();
1371*b30d1939SAndy Fiddaman 		append(tmp, cmd);
1372*b30d1939SAndy Fiddaman 		add(tmp, ' ');
1373*b30d1939SAndy Fiddaman 		append(tmp, s);
1374*b30d1939SAndy Fiddaman 		add(tmp, ' ');
1375*b30d1939SAndy Fiddaman 		append(tmp, cc);
1376*b30d1939SAndy Fiddaman 		if (execute(use(tmp)))
1377*b30d1939SAndy Fiddaman 			report(3, "cannot generate probe info", s, (unsigned long)0);
1378*b30d1939SAndy Fiddaman 		drop(tmp);
1379*b30d1939SAndy Fiddaman 		if (!push(s, (Stdio_t*)0, 0))
1380*b30d1939SAndy Fiddaman 			report(3, "cannot read probe info", s, (unsigned long)0);
1381*b30d1939SAndy Fiddaman 	}
1382*b30d1939SAndy Fiddaman 	drop(pro);
1383*b30d1939SAndy Fiddaman 	drop(buf);
1384*b30d1939SAndy Fiddaman 	make(rule(""));
1385*b30d1939SAndy Fiddaman 	pop();
1386*b30d1939SAndy Fiddaman }
1387*b30d1939SAndy Fiddaman 
1388*b30d1939SAndy Fiddaman /*
1389*b30d1939SAndy Fiddaman  * add attributes in s to r
1390*b30d1939SAndy Fiddaman  */
1391*b30d1939SAndy Fiddaman 
1392*b30d1939SAndy Fiddaman static void
attributes(register Rule_t * r,register char * s)1393*b30d1939SAndy Fiddaman attributes(register Rule_t* r, register char* s)
1394*b30d1939SAndy Fiddaman {
1395*b30d1939SAndy Fiddaman 	register char*	t;
1396*b30d1939SAndy Fiddaman 	register int	n;
1397*b30d1939SAndy Fiddaman 
1398*b30d1939SAndy Fiddaman 	for (;;)
1399*b30d1939SAndy Fiddaman 	{
1400*b30d1939SAndy Fiddaman 		for (; *s == ' '; s++);
1401*b30d1939SAndy Fiddaman 		for (t = s; *s && *s != ' '; s++);
1402*b30d1939SAndy Fiddaman 		if (!(n = s - t))
1403*b30d1939SAndy Fiddaman 			break;
1404*b30d1939SAndy Fiddaman 		switch (*t)
1405*b30d1939SAndy Fiddaman 		{
1406*b30d1939SAndy Fiddaman 		case 'd':
1407*b30d1939SAndy Fiddaman 			if (n == 8 && !strncmp(t, "dontcare", n))
1408*b30d1939SAndy Fiddaman 				r->flags |= RULE_dontcare;
1409*b30d1939SAndy Fiddaman 			break;
1410*b30d1939SAndy Fiddaman 		case 'g':
1411*b30d1939SAndy Fiddaman 			if (n == 9 && !strncmp(t, "generated", n))
1412*b30d1939SAndy Fiddaman 				r->flags |= RULE_generated;
1413*b30d1939SAndy Fiddaman 			break;
1414*b30d1939SAndy Fiddaman 		case 'i':
1415*b30d1939SAndy Fiddaman 			if (n == 6 && !strncmp(t, "ignore", n))
1416*b30d1939SAndy Fiddaman 				r->flags |= RULE_ignore;
1417*b30d1939SAndy Fiddaman 			else if (n == 8 && !strncmp(t, "implicit", n))
1418*b30d1939SAndy Fiddaman 				r->flags |= RULE_implicit;
1419*b30d1939SAndy Fiddaman 			break;
1420*b30d1939SAndy Fiddaman 		case 'v':
1421*b30d1939SAndy Fiddaman 			if (n == 7 && !strncmp(t, "virtual", n))
1422*b30d1939SAndy Fiddaman 				r->flags |= RULE_virtual;
1423*b30d1939SAndy Fiddaman 			break;
1424*b30d1939SAndy Fiddaman 		}
1425*b30d1939SAndy Fiddaman 	}
1426*b30d1939SAndy Fiddaman }
1427*b30d1939SAndy Fiddaman 
1428*b30d1939SAndy Fiddaman /*
1429*b30d1939SAndy Fiddaman  * define ${mam_libX} for library reference lib
1430*b30d1939SAndy Fiddaman  */
1431*b30d1939SAndy Fiddaman 
1432*b30d1939SAndy Fiddaman static char*
require(char * lib,int dontcare)1433*b30d1939SAndy Fiddaman require(char* lib, int dontcare)
1434*b30d1939SAndy Fiddaman {
1435*b30d1939SAndy Fiddaman 	register int	c;
1436*b30d1939SAndy Fiddaman 	char*		s;
1437*b30d1939SAndy Fiddaman 	char*		r;
1438*b30d1939SAndy Fiddaman 	FILE*		f;
1439*b30d1939SAndy Fiddaman 	Buf_t*		buf;
1440*b30d1939SAndy Fiddaman 	Buf_t*		tmp;
1441*b30d1939SAndy Fiddaman 	struct stat	st;
1442*b30d1939SAndy Fiddaman 
1443*b30d1939SAndy Fiddaman 	static int	dynamic = -1;
1444*b30d1939SAndy Fiddaman 
1445*b30d1939SAndy Fiddaman 	if (dynamic < 0)
1446*b30d1939SAndy Fiddaman 		dynamic = (s = search(state.vars, "mam_cc_L", NiL)) ? atoi(s) : 0;
1447*b30d1939SAndy Fiddaman 	if (!(r = search(state.vars, lib, NiL)))
1448*b30d1939SAndy Fiddaman 	{
1449*b30d1939SAndy Fiddaman 		buf = buffer();
1450*b30d1939SAndy Fiddaman 		tmp = buffer();
1451*b30d1939SAndy Fiddaman 		s = 0;
1452*b30d1939SAndy Fiddaman 		for (;;)
1453*b30d1939SAndy Fiddaman 		{
1454*b30d1939SAndy Fiddaman 			if (s)
1455*b30d1939SAndy Fiddaman 				append(buf, s);
1456*b30d1939SAndy Fiddaman 			if (r = search(state.vars, "mam_cc_PREFIX_ARCHIVE", NiL))
1457*b30d1939SAndy Fiddaman 				append(buf, r);
1458*b30d1939SAndy Fiddaman 			append(buf, lib + 2);
1459*b30d1939SAndy Fiddaman 			if (r = search(state.vars, "mam_cc_SUFFIX_ARCHIVE", NiL))
1460*b30d1939SAndy Fiddaman 				append(buf, r);
1461*b30d1939SAndy Fiddaman 			r = expand(tmp, use(buf));
1462*b30d1939SAndy Fiddaman 			if (!stat(r, &st))
1463*b30d1939SAndy Fiddaman 				break;
1464*b30d1939SAndy Fiddaman 			if (s)
1465*b30d1939SAndy Fiddaman 			{
1466*b30d1939SAndy Fiddaman 				r = lib;
1467*b30d1939SAndy Fiddaman 				break;
1468*b30d1939SAndy Fiddaman 			}
1469*b30d1939SAndy Fiddaman 			s = "${INSTALLROOT}/lib/";
1470*b30d1939SAndy Fiddaman 			if (dynamic)
1471*b30d1939SAndy Fiddaman 			{
1472*b30d1939SAndy Fiddaman 				append(buf, s);
1473*b30d1939SAndy Fiddaman 				if (r = search(state.vars, "mam_cc_PREFIX_SHARED", NiL))
1474*b30d1939SAndy Fiddaman 					append(buf, r);
1475*b30d1939SAndy Fiddaman 				append(buf, lib + 2);
1476*b30d1939SAndy Fiddaman 				if (r = search(state.vars, "mam_cc_SUFFIX_SHARED", NiL))
1477*b30d1939SAndy Fiddaman 					append(buf, r);
1478*b30d1939SAndy Fiddaman 				r = expand(tmp, use(buf));
1479*b30d1939SAndy Fiddaman 				if (!stat(r, &st))
1480*b30d1939SAndy Fiddaman 				{
1481*b30d1939SAndy Fiddaman 					r = lib;
1482*b30d1939SAndy Fiddaman 					break;
1483*b30d1939SAndy Fiddaman 				}
1484*b30d1939SAndy Fiddaman 			}
1485*b30d1939SAndy Fiddaman 		}
1486*b30d1939SAndy Fiddaman 		if (r != lib)
1487*b30d1939SAndy Fiddaman 			r = duplicate(r);
1488*b30d1939SAndy Fiddaman 		search(state.vars, lib, r);
1489*b30d1939SAndy Fiddaman 		append(tmp, lib + 2);
1490*b30d1939SAndy Fiddaman 		append(tmp, ".req");
1491*b30d1939SAndy Fiddaman 		if (!(f = fopen(use(tmp), "r")))
1492*b30d1939SAndy Fiddaman 		{
1493*b30d1939SAndy Fiddaman 			append(tmp, "${INSTALLROOT}/lib/lib/");
1494*b30d1939SAndy Fiddaman 			append(tmp, lib + 2);
1495*b30d1939SAndy Fiddaman 			f = fopen(expand(buf, use(tmp)), "r");
1496*b30d1939SAndy Fiddaman 		}
1497*b30d1939SAndy Fiddaman 		if (f)
1498*b30d1939SAndy Fiddaman 		{
1499*b30d1939SAndy Fiddaman 			for (;;)
1500*b30d1939SAndy Fiddaman 			{
1501*b30d1939SAndy Fiddaman 				while ((c = fgetc(f)) == ' ' || c == '\t' || c == '\n');
1502*b30d1939SAndy Fiddaman 				if (c == EOF)
1503*b30d1939SAndy Fiddaman 					break;
1504*b30d1939SAndy Fiddaman 				do
1505*b30d1939SAndy Fiddaman 				{
1506*b30d1939SAndy Fiddaman 					add(tmp, c);
1507*b30d1939SAndy Fiddaman 				} while ((c = fgetc(f)) != EOF && c != ' ' && c != '\t' && c != '\n');
1508*b30d1939SAndy Fiddaman 				s = use(tmp);
1509*b30d1939SAndy Fiddaman 				if (s[0] && (s[0] != '-' || s[1]))
1510*b30d1939SAndy Fiddaman 				{
1511*b30d1939SAndy Fiddaman 					add(buf, ' ');
1512*b30d1939SAndy Fiddaman 					append(buf, require(s, 0));
1513*b30d1939SAndy Fiddaman 				}
1514*b30d1939SAndy Fiddaman 			}
1515*b30d1939SAndy Fiddaman 			fclose(f);
1516*b30d1939SAndy Fiddaman 			r = use(buf);
1517*b30d1939SAndy Fiddaman 		}
1518*b30d1939SAndy Fiddaman 		else if (dontcare)
1519*b30d1939SAndy Fiddaman 		{
1520*b30d1939SAndy Fiddaman 			append(tmp, "set -\n");
1521*b30d1939SAndy Fiddaman 			append(tmp, "cd /tmp\n");
1522*b30d1939SAndy Fiddaman 			append(tmp, "echo 'int main(){return 0;}' > x.${!-$$}.c\n");
1523*b30d1939SAndy Fiddaman 			append(tmp, "${CC} ${CCFLAGS} -o x.${!-$$}.x x.${!-$$}.c ");
1524*b30d1939SAndy Fiddaman 			append(tmp, r);
1525*b30d1939SAndy Fiddaman 			append(tmp, " >/dev/null 2>&1\n");
1526*b30d1939SAndy Fiddaman 			append(tmp, "c=$?\n");
1527*b30d1939SAndy Fiddaman 			append(tmp, "rm -f x.${!-$$}.[cox]\n");
1528*b30d1939SAndy Fiddaman 			append(tmp, "exit $c\n");
1529*b30d1939SAndy Fiddaman 			if (execute(expand(buf, use(tmp))))
1530*b30d1939SAndy Fiddaman 				r = "";
1531*b30d1939SAndy Fiddaman 		}
1532*b30d1939SAndy Fiddaman 		r = duplicate(r);
1533*b30d1939SAndy Fiddaman 		search(state.vars, lib, r);
1534*b30d1939SAndy Fiddaman 		append(tmp, "mam_lib");
1535*b30d1939SAndy Fiddaman 		append(tmp, lib + 2);
1536*b30d1939SAndy Fiddaman 		search(state.vars, use(tmp), r);
1537*b30d1939SAndy Fiddaman 		drop(tmp);
1538*b30d1939SAndy Fiddaman 		drop(buf);
1539*b30d1939SAndy Fiddaman 	}
1540*b30d1939SAndy Fiddaman 	return r;
1541*b30d1939SAndy Fiddaman }
1542*b30d1939SAndy Fiddaman 
1543*b30d1939SAndy Fiddaman /*
1544*b30d1939SAndy Fiddaman  * input() until `done r'
1545*b30d1939SAndy Fiddaman  */
1546*b30d1939SAndy Fiddaman 
1547*b30d1939SAndy Fiddaman static unsigned long
make(Rule_t * r)1548*b30d1939SAndy Fiddaman make(Rule_t* r)
1549*b30d1939SAndy Fiddaman {
1550*b30d1939SAndy Fiddaman 	register char*		s;
1551*b30d1939SAndy Fiddaman 	register char*		t;
1552*b30d1939SAndy Fiddaman 	register char*		u;
1553*b30d1939SAndy Fiddaman 	register char*		v;
1554*b30d1939SAndy Fiddaman 	register Rule_t*	q;
1555*b30d1939SAndy Fiddaman 	unsigned long		z;
1556*b30d1939SAndy Fiddaman 	unsigned long		x;
1557*b30d1939SAndy Fiddaman 	Buf_t*			buf;
1558*b30d1939SAndy Fiddaman 	Buf_t*			cmd;
1559*b30d1939SAndy Fiddaman 
1560*b30d1939SAndy Fiddaman 	r->making++;
1561*b30d1939SAndy Fiddaman 	if (r->flags & RULE_active)
1562*b30d1939SAndy Fiddaman 		state.active++;
1563*b30d1939SAndy Fiddaman 	if (*r->name)
1564*b30d1939SAndy Fiddaman 	{
1565*b30d1939SAndy Fiddaman 		z = bind(r);
1566*b30d1939SAndy Fiddaman 		state.indent++;
1567*b30d1939SAndy Fiddaman 		report(-1, r->name, "make", r->time);
1568*b30d1939SAndy Fiddaman 	}
1569*b30d1939SAndy Fiddaman 	else
1570*b30d1939SAndy Fiddaman 		z = 0;
1571*b30d1939SAndy Fiddaman 	buf = buffer();
1572*b30d1939SAndy Fiddaman 	cmd = 0;
1573*b30d1939SAndy Fiddaman 	while (s = input())
1574*b30d1939SAndy Fiddaman 	{
1575*b30d1939SAndy Fiddaman 		for (; *s == ' '; s++);
1576*b30d1939SAndy Fiddaman 		for (; isdigit(*s); s++);
1577*b30d1939SAndy Fiddaman 		for (; *s == ' '; s++);
1578*b30d1939SAndy Fiddaman 		for (u = s; *s && *s != ' '; s++);
1579*b30d1939SAndy Fiddaman 		if (*s)
1580*b30d1939SAndy Fiddaman 		{
1581*b30d1939SAndy Fiddaman 			for (*s++ = 0; *s == ' '; s++);
1582*b30d1939SAndy Fiddaman 			for (t = s; *s && *s != ' '; s++);
1583*b30d1939SAndy Fiddaman 			if (*s)
1584*b30d1939SAndy Fiddaman 				for (*s++ = 0; *s == ' '; s++);
1585*b30d1939SAndy Fiddaman 			v = s;
1586*b30d1939SAndy Fiddaman 		}
1587*b30d1939SAndy Fiddaman 		else
1588*b30d1939SAndy Fiddaman 			t = v = s;
1589*b30d1939SAndy Fiddaman 		switch (KEY(u[0], u[1], u[2], u[3]))
1590*b30d1939SAndy Fiddaman 		{
1591*b30d1939SAndy Fiddaman 		case KEY('b','i','n','d'):
1592*b30d1939SAndy Fiddaman 			if ((t[0] == '-' || t[0] == '+') && t[1] == 'l' && (s = require(t, !strcmp(v, "dontcare"))) && strncmp(r->name, "FEATURE/", 8) && strcmp(r->name, "configure.h"))
1593*b30d1939SAndy Fiddaman 				for (;;)
1594*b30d1939SAndy Fiddaman 				{
1595*b30d1939SAndy Fiddaman 					for (t = s; *s && *s != ' '; s++);
1596*b30d1939SAndy Fiddaman 					if (*s)
1597*b30d1939SAndy Fiddaman 						*s = 0;
1598*b30d1939SAndy Fiddaman 					else
1599*b30d1939SAndy Fiddaman 						s = 0;
1600*b30d1939SAndy Fiddaman 					if (*t)
1601*b30d1939SAndy Fiddaman 					{
1602*b30d1939SAndy Fiddaman 						q = rule(expand(buf, t));
1603*b30d1939SAndy Fiddaman 						attributes(q, v);
1604*b30d1939SAndy Fiddaman 						x = bind(q);
1605*b30d1939SAndy Fiddaman 						if (z < x)
1606*b30d1939SAndy Fiddaman 							z = x;
1607*b30d1939SAndy Fiddaman 						if (q->flags & RULE_error)
1608*b30d1939SAndy Fiddaman 							r->flags |= RULE_error;
1609*b30d1939SAndy Fiddaman 					}
1610*b30d1939SAndy Fiddaman 					if (!s)
1611*b30d1939SAndy Fiddaman 						break;
1612*b30d1939SAndy Fiddaman 					for (*s++ = ' '; *s == ' '; s++);
1613*b30d1939SAndy Fiddaman 				}
1614*b30d1939SAndy Fiddaman 			continue;
1615*b30d1939SAndy Fiddaman 		case KEY('d','o','n','e'):
1616*b30d1939SAndy Fiddaman 			q = rule(expand(buf, t));
1617*b30d1939SAndy Fiddaman 			if (q != r)
1618*b30d1939SAndy Fiddaman 				report(2, "improper done statement", t, (unsigned long)0);
1619*b30d1939SAndy Fiddaman 			attributes(r, v);
1620*b30d1939SAndy Fiddaman 			if (cmd && state.active && (state.force || r->time < z || !r->time && !z))
1621*b30d1939SAndy Fiddaman 			{
1622*b30d1939SAndy Fiddaman 				if (state.explain && !state.force)
1623*b30d1939SAndy Fiddaman 				{
1624*b30d1939SAndy Fiddaman 					if (!r->time)
1625*b30d1939SAndy Fiddaman 						fprintf(stderr, "%s [not found]\n", r->name);
1626*b30d1939SAndy Fiddaman 					else
1627*b30d1939SAndy Fiddaman 						fprintf(stderr, "%s [%lu] older than prerequisites [%lu]\n", r->name, r->time, z);
1628*b30d1939SAndy Fiddaman 				}
1629*b30d1939SAndy Fiddaman 				substitute(buf, use(cmd));
1630*b30d1939SAndy Fiddaman 				x = run(r, use(buf));
1631*b30d1939SAndy Fiddaman 				if (z < x)
1632*b30d1939SAndy Fiddaman 					z = x;
1633*b30d1939SAndy Fiddaman 			}
1634*b30d1939SAndy Fiddaman 			r->flags |= RULE_made;
1635*b30d1939SAndy Fiddaman 			if (!(r->flags & (RULE_dontcare|RULE_error|RULE_exists|RULE_generated|RULE_implicit|RULE_virtual)))
1636*b30d1939SAndy Fiddaman 				dont(r, 0, state.keepgoing);
1637*b30d1939SAndy Fiddaman 			break;
1638*b30d1939SAndy Fiddaman 		case KEY('e','x','e','c'):
1639*b30d1939SAndy Fiddaman 			r->flags |= RULE_generated;
1640*b30d1939SAndy Fiddaman 			if (r->path)
1641*b30d1939SAndy Fiddaman 			{
1642*b30d1939SAndy Fiddaman 				free(r->path);
1643*b30d1939SAndy Fiddaman 				r->path = 0;
1644*b30d1939SAndy Fiddaman 				r->time = 0;
1645*b30d1939SAndy Fiddaman 			}
1646*b30d1939SAndy Fiddaman 			if (state.active)
1647*b30d1939SAndy Fiddaman 			{
1648*b30d1939SAndy Fiddaman 				if (cmd)
1649*b30d1939SAndy Fiddaman 					add(cmd, '\n');
1650*b30d1939SAndy Fiddaman 				else
1651*b30d1939SAndy Fiddaman 					cmd = buffer();
1652*b30d1939SAndy Fiddaman 				append(cmd, v);
1653*b30d1939SAndy Fiddaman 			}
1654*b30d1939SAndy Fiddaman 			continue;
1655*b30d1939SAndy Fiddaman 		case KEY('m','a','k','e'):
1656*b30d1939SAndy Fiddaman 			q = rule(expand(buf, t));
1657*b30d1939SAndy Fiddaman 			if (!q->making)
1658*b30d1939SAndy Fiddaman 			{
1659*b30d1939SAndy Fiddaman 				attributes(q, v);
1660*b30d1939SAndy Fiddaman 				x = make(q);
1661*b30d1939SAndy Fiddaman 				if (!(q->flags & RULE_ignore) && z < x)
1662*b30d1939SAndy Fiddaman 					z = x;
1663*b30d1939SAndy Fiddaman 				if (q->flags & RULE_error)
1664*b30d1939SAndy Fiddaman 					r->flags |= RULE_error;
1665*b30d1939SAndy Fiddaman 			}
1666*b30d1939SAndy Fiddaman 			continue;
1667*b30d1939SAndy Fiddaman 		case KEY('p','r','e','v'):
1668*b30d1939SAndy Fiddaman 			q = rule(expand(buf, t));
1669*b30d1939SAndy Fiddaman 			if (!q->making)
1670*b30d1939SAndy Fiddaman 			{
1671*b30d1939SAndy Fiddaman 				if (!(q->flags & RULE_ignore) && z < q->time)
1672*b30d1939SAndy Fiddaman 					z = q->time;
1673*b30d1939SAndy Fiddaman 				if (q->flags & RULE_error)
1674*b30d1939SAndy Fiddaman 					r->flags |= RULE_error;
1675*b30d1939SAndy Fiddaman 				state.indent++;
1676*b30d1939SAndy Fiddaman 				report(-2, q->name, "prev", q->time);
1677*b30d1939SAndy Fiddaman 				state.indent--;
1678*b30d1939SAndy Fiddaman 			}
1679*b30d1939SAndy Fiddaman 			continue;
1680*b30d1939SAndy Fiddaman 		case KEY('s','e','t','v'):
1681*b30d1939SAndy Fiddaman 			if (!search(state.vars, t, NiL))
1682*b30d1939SAndy Fiddaman 			{
1683*b30d1939SAndy Fiddaman 				if (*v == '"')
1684*b30d1939SAndy Fiddaman 				{
1685*b30d1939SAndy Fiddaman 					s = v + strlen(v) - 1;
1686*b30d1939SAndy Fiddaman 					if (*s == '"')
1687*b30d1939SAndy Fiddaman 					{
1688*b30d1939SAndy Fiddaman 						*s = 0;
1689*b30d1939SAndy Fiddaman 						v++;
1690*b30d1939SAndy Fiddaman 					}
1691*b30d1939SAndy Fiddaman 				}
1692*b30d1939SAndy Fiddaman 				search(state.vars, t, duplicate(expand(buf, v)));
1693*b30d1939SAndy Fiddaman 			}
1694*b30d1939SAndy Fiddaman 			if (!state.probed && t[0] == 'C' && t[1] == 'C' && !t[2])
1695*b30d1939SAndy Fiddaman 			{
1696*b30d1939SAndy Fiddaman 				state.probed = 1;
1697*b30d1939SAndy Fiddaman 				probe();
1698*b30d1939SAndy Fiddaman 			}
1699*b30d1939SAndy Fiddaman 			continue;
1700*b30d1939SAndy Fiddaman 		default:
1701*b30d1939SAndy Fiddaman 			continue;
1702*b30d1939SAndy Fiddaman 		}
1703*b30d1939SAndy Fiddaman 		break;
1704*b30d1939SAndy Fiddaman 	}
1705*b30d1939SAndy Fiddaman 	drop(buf);
1706*b30d1939SAndy Fiddaman 	if (cmd)
1707*b30d1939SAndy Fiddaman 		drop(cmd);
1708*b30d1939SAndy Fiddaman 	if (*r->name)
1709*b30d1939SAndy Fiddaman 	{
1710*b30d1939SAndy Fiddaman 		report(-1, r->name, "done", z);
1711*b30d1939SAndy Fiddaman 		state.indent--;
1712*b30d1939SAndy Fiddaman 	}
1713*b30d1939SAndy Fiddaman 	if (r->flags & RULE_active)
1714*b30d1939SAndy Fiddaman 		state.active--;
1715*b30d1939SAndy Fiddaman 	r->making--;
1716*b30d1939SAndy Fiddaman 	return r->time = z;
1717*b30d1939SAndy Fiddaman }
1718*b30d1939SAndy Fiddaman 
1719*b30d1939SAndy Fiddaman /*
1720*b30d1939SAndy Fiddaman  * verify that active targets were made
1721*b30d1939SAndy Fiddaman  */
1722*b30d1939SAndy Fiddaman 
1723*b30d1939SAndy Fiddaman static int
verify(Dict_item_t * item,void * handle)1724*b30d1939SAndy Fiddaman verify(Dict_item_t* item, void* handle)
1725*b30d1939SAndy Fiddaman {
1726*b30d1939SAndy Fiddaman 	Rule_t*	r = (Rule_t*)item->value;
1727*b30d1939SAndy Fiddaman 
1728*b30d1939SAndy Fiddaman 	if ((r->flags & (RULE_active|RULE_error|RULE_made)) == RULE_active)
1729*b30d1939SAndy Fiddaman 		dont(r, 0, 1);
1730*b30d1939SAndy Fiddaman 	return 0;
1731*b30d1939SAndy Fiddaman }
1732*b30d1939SAndy Fiddaman 
1733*b30d1939SAndy Fiddaman /*
1734*b30d1939SAndy Fiddaman  * return 1 if name is an initializer
1735*b30d1939SAndy Fiddaman  */
1736*b30d1939SAndy Fiddaman 
1737*b30d1939SAndy Fiddaman static int
initializer(char * name)1738*b30d1939SAndy Fiddaman initializer(char* name)
1739*b30d1939SAndy Fiddaman {
1740*b30d1939SAndy Fiddaman 	register char*	s;
1741*b30d1939SAndy Fiddaman 
1742*b30d1939SAndy Fiddaman 	if (s = last(name, '/'))
1743*b30d1939SAndy Fiddaman 		s++;
1744*b30d1939SAndy Fiddaman 	else
1745*b30d1939SAndy Fiddaman 		s = name;
1746*b30d1939SAndy Fiddaman 	return s[0] == 'I' && s[1] == 'N' && s[2] == 'I' && s[3] == 'T';
1747*b30d1939SAndy Fiddaman }
1748*b30d1939SAndy Fiddaman 
1749*b30d1939SAndy Fiddaman /*
1750*b30d1939SAndy Fiddaman  * update recursion leaf r and its prerequisites
1751*b30d1939SAndy Fiddaman  */
1752*b30d1939SAndy Fiddaman 
1753*b30d1939SAndy Fiddaman static int
update(register Rule_t * r)1754*b30d1939SAndy Fiddaman update(register Rule_t* r)
1755*b30d1939SAndy Fiddaman {
1756*b30d1939SAndy Fiddaman 	register List_t*	x;
1757*b30d1939SAndy Fiddaman 	Buf_t*			buf;
1758*b30d1939SAndy Fiddaman 
1759*b30d1939SAndy Fiddaman 	static char		cmd[] = "${MAMAKE} -C ";
1760*b30d1939SAndy Fiddaman 	static char		arg[] = " ${MAMAKEARGS}";
1761*b30d1939SAndy Fiddaman 
1762*b30d1939SAndy Fiddaman 	r->flags |= RULE_made;
1763*b30d1939SAndy Fiddaman 	if (r->leaf)
1764*b30d1939SAndy Fiddaman 		r->leaf->flags |= RULE_made;
1765*b30d1939SAndy Fiddaman 	for (x = r->prereqs; x; x = x->next)
1766*b30d1939SAndy Fiddaman 		if (x->rule->leaf && !(x->rule->flags & RULE_made))
1767*b30d1939SAndy Fiddaman 			update(x->rule);
1768*b30d1939SAndy Fiddaman 	buf = buffer();
1769*b30d1939SAndy Fiddaman 	substitute(buf, cmd);
1770*b30d1939SAndy Fiddaman 	append(buf, r->name);
1771*b30d1939SAndy Fiddaman 	substitute(buf, arg);
1772*b30d1939SAndy Fiddaman 	run(r, use(buf));
1773*b30d1939SAndy Fiddaman 	drop(buf);
1774*b30d1939SAndy Fiddaman 	return 0;
1775*b30d1939SAndy Fiddaman }
1776*b30d1939SAndy Fiddaman 
1777*b30d1939SAndy Fiddaman /*
1778*b30d1939SAndy Fiddaman  * scan makefile prereqs
1779*b30d1939SAndy Fiddaman  */
1780*b30d1939SAndy Fiddaman 
1781*b30d1939SAndy Fiddaman static int
scan(Dict_item_t * item,void * handle)1782*b30d1939SAndy Fiddaman scan(Dict_item_t* item, void* handle)
1783*b30d1939SAndy Fiddaman {
1784*b30d1939SAndy Fiddaman 	register Rule_t*	r = (Rule_t*)item->value;
1785*b30d1939SAndy Fiddaman 	register char*		s;
1786*b30d1939SAndy Fiddaman 	register char*		t;
1787*b30d1939SAndy Fiddaman 	register char*		u;
1788*b30d1939SAndy Fiddaman 	register char*		w;
1789*b30d1939SAndy Fiddaman 	Rule_t*			q;
1790*b30d1939SAndy Fiddaman 	int			i;
1791*b30d1939SAndy Fiddaman 	int			j;
1792*b30d1939SAndy Fiddaman 	int			k;
1793*b30d1939SAndy Fiddaman 	int			p;
1794*b30d1939SAndy Fiddaman 	Buf_t*			buf;
1795*b30d1939SAndy Fiddaman 
1796*b30d1939SAndy Fiddaman 	static char*		files[] =
1797*b30d1939SAndy Fiddaman 				{
1798*b30d1939SAndy Fiddaman 					"Nmakefile",
1799*b30d1939SAndy Fiddaman 					"nmakefile",
1800*b30d1939SAndy Fiddaman 					"Makefile",
1801*b30d1939SAndy Fiddaman 					"makefile"
1802*b30d1939SAndy Fiddaman 				};
1803*b30d1939SAndy Fiddaman 
1804*b30d1939SAndy Fiddaman 	/*
1805*b30d1939SAndy Fiddaman 	 * drop non-leaf rules
1806*b30d1939SAndy Fiddaman 	 */
1807*b30d1939SAndy Fiddaman 
1808*b30d1939SAndy Fiddaman 	if (!r->leaf)
1809*b30d1939SAndy Fiddaman 		return 0;
1810*b30d1939SAndy Fiddaman 
1811*b30d1939SAndy Fiddaman 	/*
1812*b30d1939SAndy Fiddaman 	 * always make initializers
1813*b30d1939SAndy Fiddaman 	 */
1814*b30d1939SAndy Fiddaman 
1815*b30d1939SAndy Fiddaman 	if (initializer(r->name))
1816*b30d1939SAndy Fiddaman 	{
1817*b30d1939SAndy Fiddaman 		if (!(r->flags & RULE_made))
1818*b30d1939SAndy Fiddaman 			update(r);
1819*b30d1939SAndy Fiddaman 		return 0;
1820*b30d1939SAndy Fiddaman 	}
1821*b30d1939SAndy Fiddaman 	buf = buffer();
1822*b30d1939SAndy Fiddaman 	for (i = 0; i < elementsof(files); i++)
1823*b30d1939SAndy Fiddaman 	{
1824*b30d1939SAndy Fiddaman 		append(buf, r->name);
1825*b30d1939SAndy Fiddaman 		add(buf, '/');
1826*b30d1939SAndy Fiddaman 		append(buf, files[i]);
1827*b30d1939SAndy Fiddaman 		if (push(use(buf), (Stdio_t*)0, 0))
1828*b30d1939SAndy Fiddaman 		{
1829*b30d1939SAndy Fiddaman 			while (s = input())
1830*b30d1939SAndy Fiddaman 			{
1831*b30d1939SAndy Fiddaman 				j = p = 0;
1832*b30d1939SAndy Fiddaman 				while (*s)
1833*b30d1939SAndy Fiddaman 				{
1834*b30d1939SAndy Fiddaman 					for (k = 1; (i = *s) == ' ' || i == '\t' || i == '"' || i == '\''; s++);
1835*b30d1939SAndy Fiddaman 					for (t = s; (i = *s) && i != ' ' && i != '\t' && i != '"' && i != '\'' && i != '\\' && i != ':'; s++)
1836*b30d1939SAndy Fiddaman 						if (i == '/')
1837*b30d1939SAndy Fiddaman 							t = s + 1;
1838*b30d1939SAndy Fiddaman 						else if (i == '.' && *(s + 1) != 'c' && *(s + 1) != 'C' && *(s + 1) != 'h' && *(s + 1) != 'H' && t[0] == 'l' && t[1] == 'i' && t[2] == 'b')
1839*b30d1939SAndy Fiddaman 							*s = 0;
1840*b30d1939SAndy Fiddaman 					if (*s)
1841*b30d1939SAndy Fiddaman 						*s++ = 0;
1842*b30d1939SAndy Fiddaman 					if (!t[0])
1843*b30d1939SAndy Fiddaman 						k = 0;
1844*b30d1939SAndy Fiddaman 					else if ((t[0] == '-' || t[0] == '+') && t[1] == 'l' && t[2])
1845*b30d1939SAndy Fiddaman 					{
1846*b30d1939SAndy Fiddaman 						append(buf, "lib");
1847*b30d1939SAndy Fiddaman 						append(buf, t + 2);
1848*b30d1939SAndy Fiddaman 						t = use(buf);
1849*b30d1939SAndy Fiddaman 					}
1850*b30d1939SAndy Fiddaman 					else if (p)
1851*b30d1939SAndy Fiddaman 					{
1852*b30d1939SAndy Fiddaman 						if (t[0] == '+' && !t[1])
1853*b30d1939SAndy Fiddaman 							p = 2;
1854*b30d1939SAndy Fiddaman 						else if (p == 1)
1855*b30d1939SAndy Fiddaman 						{
1856*b30d1939SAndy Fiddaman 							if (i != ':' || strncmp(s, "command", 7))
1857*b30d1939SAndy Fiddaman 							{
1858*b30d1939SAndy Fiddaman 								append(buf, "lib");
1859*b30d1939SAndy Fiddaman 								append(buf, t);
1860*b30d1939SAndy Fiddaman 								t = use(buf);
1861*b30d1939SAndy Fiddaman 							}
1862*b30d1939SAndy Fiddaman 							if (i == ':')
1863*b30d1939SAndy Fiddaman 								while (*s && (*s == ' ' || *s == '\t'))
1864*b30d1939SAndy Fiddaman 									s++;
1865*b30d1939SAndy Fiddaman 						}
1866*b30d1939SAndy Fiddaman 					}
1867*b30d1939SAndy Fiddaman 					else if (i == ':')
1868*b30d1939SAndy Fiddaman 					{
1869*b30d1939SAndy Fiddaman 						if (j != ':' || !isupper(*t))
1870*b30d1939SAndy Fiddaman 							k = 0;
1871*b30d1939SAndy Fiddaman 						else if (!strcmp(t, "PACKAGE"))
1872*b30d1939SAndy Fiddaman 						{
1873*b30d1939SAndy Fiddaman 							p = 1;
1874*b30d1939SAndy Fiddaman 							k = 0;
1875*b30d1939SAndy Fiddaman 						}
1876*b30d1939SAndy Fiddaman 						else
1877*b30d1939SAndy Fiddaman 							for (u = t; *u; u++)
1878*b30d1939SAndy Fiddaman 								if (isupper(*u))
1879*b30d1939SAndy Fiddaman 									*u = tolower(*u);
1880*b30d1939SAndy Fiddaman 								else if (!isalnum(*u))
1881*b30d1939SAndy Fiddaman 								{
1882*b30d1939SAndy Fiddaman 									k = 0;
1883*b30d1939SAndy Fiddaman 									break;
1884*b30d1939SAndy Fiddaman 								}
1885*b30d1939SAndy Fiddaman 					}
1886*b30d1939SAndy Fiddaman 					else if (t[0] != 'l' || t[1] != 'i' || t[2] != 'b')
1887*b30d1939SAndy Fiddaman 						k = 0;
1888*b30d1939SAndy Fiddaman 					else
1889*b30d1939SAndy Fiddaman 						for (u = t + 3; *u; u++)
1890*b30d1939SAndy Fiddaman 							if (!isalnum(*u))
1891*b30d1939SAndy Fiddaman 							{
1892*b30d1939SAndy Fiddaman 								k = 0;
1893*b30d1939SAndy Fiddaman 								break;
1894*b30d1939SAndy Fiddaman 							}
1895*b30d1939SAndy Fiddaman 					if (k && ((q = (Rule_t*)search(state.leaf, t, NiL)) && q != r || *t++ == 'l' && *t++ == 'i' && *t++ == 'b' && *t && (q = (Rule_t*)search(state.leaf, t, NiL)) && q != r))
1896*b30d1939SAndy Fiddaman 					{
1897*b30d1939SAndy Fiddaman 						for (t = w = r->name; *w; w++)
1898*b30d1939SAndy Fiddaman 							if (*w == '/')
1899*b30d1939SAndy Fiddaman 								t = w + 1;
1900*b30d1939SAndy Fiddaman 						if (t[0] == 'l' && t[1] == 'i' && t[2] == 'b')
1901*b30d1939SAndy Fiddaman 							t += 3;
1902*b30d1939SAndy Fiddaman 						for (u = w = q->name; *w; w++)
1903*b30d1939SAndy Fiddaman 							if (*w == '/')
1904*b30d1939SAndy Fiddaman 								u = w + 1;
1905*b30d1939SAndy Fiddaman 						if (strcmp(t, u))
1906*b30d1939SAndy Fiddaman 							cons(r, q);
1907*b30d1939SAndy Fiddaman 					}
1908*b30d1939SAndy Fiddaman 					j = i;
1909*b30d1939SAndy Fiddaman 				}
1910*b30d1939SAndy Fiddaman 			}
1911*b30d1939SAndy Fiddaman 			pop();
1912*b30d1939SAndy Fiddaman 			for (s = 0, w = r->name; *w; w++)
1913*b30d1939SAndy Fiddaman 				if (*w == '/')
1914*b30d1939SAndy Fiddaman 					s = w;
1915*b30d1939SAndy Fiddaman 			if (s)
1916*b30d1939SAndy Fiddaman 			{
1917*b30d1939SAndy Fiddaman 				if ((s - r->name) > 3 && *(s - 1) == 'b' && *(s - 2) == 'i' && *(s - 3) == 'l' && *(s - 4) != '/')
1918*b30d1939SAndy Fiddaman 				{
1919*b30d1939SAndy Fiddaman 					/*
1920*b30d1939SAndy Fiddaman 					 * foolib : foo : libfoo
1921*b30d1939SAndy Fiddaman 					 */
1922*b30d1939SAndy Fiddaman 
1923*b30d1939SAndy Fiddaman 					*(s - 3) = 0;
1924*b30d1939SAndy Fiddaman 					q = (Rule_t*)search(state.leaf, r->name, NiL);
1925*b30d1939SAndy Fiddaman 					if (q && q != r)
1926*b30d1939SAndy Fiddaman 						cons(r, q);
1927*b30d1939SAndy Fiddaman 					for (t = w = r->name; *w; w++)
1928*b30d1939SAndy Fiddaman 						if (*w == '/')
1929*b30d1939SAndy Fiddaman 							t = w + 1;
1930*b30d1939SAndy Fiddaman 					append(buf, "lib");
1931*b30d1939SAndy Fiddaman 					append(buf, t);
1932*b30d1939SAndy Fiddaman 					q = (Rule_t*)search(state.leaf, use(buf), NiL);
1933*b30d1939SAndy Fiddaman 					if (q && q != r)
1934*b30d1939SAndy Fiddaman 						cons(r, q);
1935*b30d1939SAndy Fiddaman 					*(s - 3) = 'l';
1936*b30d1939SAndy Fiddaman 				}
1937*b30d1939SAndy Fiddaman 				else if (((s - r->name) != 3 || *(s - 1) != 'b' || *(s - 2) != 'i' || *(s - 3) != 'l') && (*(s + 1) != 'l' || *(s + 2) != 'i' || *(s + 3) != 'b'))
1938*b30d1939SAndy Fiddaman 				{
1939*b30d1939SAndy Fiddaman 					/*
1940*b30d1939SAndy Fiddaman 					 * huh/foobar : lib/libfoo
1941*b30d1939SAndy Fiddaman 					 */
1942*b30d1939SAndy Fiddaman 
1943*b30d1939SAndy Fiddaman 					s++;
1944*b30d1939SAndy Fiddaman 					t = s + strlen(s);
1945*b30d1939SAndy Fiddaman 					while (--t > s)
1946*b30d1939SAndy Fiddaman 					{
1947*b30d1939SAndy Fiddaman 						append(buf, "lib/lib");
1948*b30d1939SAndy Fiddaman 						appendn(buf, s, t - s);
1949*b30d1939SAndy Fiddaman 						q = (Rule_t*)search(state.leaf, use(buf), NiL);
1950*b30d1939SAndy Fiddaman 						if (q && q != r)
1951*b30d1939SAndy Fiddaman 							cons(r, q);
1952*b30d1939SAndy Fiddaman 					}
1953*b30d1939SAndy Fiddaman 				}
1954*b30d1939SAndy Fiddaman 			}
1955*b30d1939SAndy Fiddaman 			break;
1956*b30d1939SAndy Fiddaman 		}
1957*b30d1939SAndy Fiddaman 	}
1958*b30d1939SAndy Fiddaman 	drop(buf);
1959*b30d1939SAndy Fiddaman 	return 0;
1960*b30d1939SAndy Fiddaman }
1961*b30d1939SAndy Fiddaman 
1962*b30d1939SAndy Fiddaman /*
1963*b30d1939SAndy Fiddaman  * descend into op and its prereqs
1964*b30d1939SAndy Fiddaman  */
1965*b30d1939SAndy Fiddaman 
1966*b30d1939SAndy Fiddaman static int
descend(Dict_item_t * item,void * handle)1967*b30d1939SAndy Fiddaman descend(Dict_item_t* item, void* handle)
1968*b30d1939SAndy Fiddaman {
1969*b30d1939SAndy Fiddaman 	Rule_t*	r = (Rule_t*)item->value;
1970*b30d1939SAndy Fiddaman 
1971*b30d1939SAndy Fiddaman 	if (!state.active && (!(r->flags & RULE_active) || !(r = (Rule_t*)search(state.leaf, r->name, NiL))))
1972*b30d1939SAndy Fiddaman 		return 0;
1973*b30d1939SAndy Fiddaman 	return r->leaf && !(r->flags & RULE_made) ? update(r) : 0;
1974*b30d1939SAndy Fiddaman }
1975*b30d1939SAndy Fiddaman 
1976*b30d1939SAndy Fiddaman /*
1977*b30d1939SAndy Fiddaman  * append the non-leaf active targets to state.opt
1978*b30d1939SAndy Fiddaman  */
1979*b30d1939SAndy Fiddaman 
1980*b30d1939SAndy Fiddaman static int
active(Dict_item_t * item,void * handle)1981*b30d1939SAndy Fiddaman active(Dict_item_t* item, void* handle)
1982*b30d1939SAndy Fiddaman {
1983*b30d1939SAndy Fiddaman 	Rule_t*	r = (Rule_t*)item->value;
1984*b30d1939SAndy Fiddaman 
1985*b30d1939SAndy Fiddaman 	if (r->flags & RULE_active)
1986*b30d1939SAndy Fiddaman 	{
1987*b30d1939SAndy Fiddaman 		if (r->leaf || search(state.leaf, r->name, NiL))
1988*b30d1939SAndy Fiddaman 			state.active = 0;
1989*b30d1939SAndy Fiddaman 		else
1990*b30d1939SAndy Fiddaman 		{
1991*b30d1939SAndy Fiddaman 			add(state.opt, ' ');
1992*b30d1939SAndy Fiddaman 			append(state.opt, r->name);
1993*b30d1939SAndy Fiddaman 		}
1994*b30d1939SAndy Fiddaman 	}
1995*b30d1939SAndy Fiddaman 	return 0;
1996*b30d1939SAndy Fiddaman }
1997*b30d1939SAndy Fiddaman 
1998*b30d1939SAndy Fiddaman /*
1999*b30d1939SAndy Fiddaman  * recurse on mamfiles in subdirs matching pattern
2000*b30d1939SAndy Fiddaman  */
2001*b30d1939SAndy Fiddaman 
2002*b30d1939SAndy Fiddaman static int
recurse(char * pattern)2003*b30d1939SAndy Fiddaman recurse(char* pattern)
2004*b30d1939SAndy Fiddaman {
2005*b30d1939SAndy Fiddaman 	register char*	s;
2006*b30d1939SAndy Fiddaman 	register char*	t;
2007*b30d1939SAndy Fiddaman 	Rule_t*		r;
2008*b30d1939SAndy Fiddaman 	Buf_t*		buf;
2009*b30d1939SAndy Fiddaman 	Buf_t*		tmp;
2010*b30d1939SAndy Fiddaman 	struct stat	st;
2011*b30d1939SAndy Fiddaman 
2012*b30d1939SAndy Fiddaman 	/*
2013*b30d1939SAndy Fiddaman 	 * first determine the MAM subdirs
2014*b30d1939SAndy Fiddaman 	 */
2015*b30d1939SAndy Fiddaman 
2016*b30d1939SAndy Fiddaman 	tmp = buffer();
2017*b30d1939SAndy Fiddaman 	buf = buffer();
2018*b30d1939SAndy Fiddaman 	state.exec = !state.never;
2019*b30d1939SAndy Fiddaman 	state.leaf = dictionary();
2020*b30d1939SAndy Fiddaman 	append(buf, "ls -d ");
2021*b30d1939SAndy Fiddaman 	append(buf, pattern);
2022*b30d1939SAndy Fiddaman 	s = use(buf);
2023*b30d1939SAndy Fiddaman 	push("recurse", popen(s, "r"), STREAM_PIPE);
2024*b30d1939SAndy Fiddaman 	while (s = input())
2025*b30d1939SAndy Fiddaman 	{
2026*b30d1939SAndy Fiddaman 		append(buf, s);
2027*b30d1939SAndy Fiddaman 		add(buf, '/');
2028*b30d1939SAndy Fiddaman 		append(buf, mamfile);
2029*b30d1939SAndy Fiddaman 		if (find(tmp, use(buf), &st))
2030*b30d1939SAndy Fiddaman 		{
2031*b30d1939SAndy Fiddaman 			r = rule(s);
2032*b30d1939SAndy Fiddaman 			if (t = last(r->name, '/'))
2033*b30d1939SAndy Fiddaman 				t++;
2034*b30d1939SAndy Fiddaman 			else
2035*b30d1939SAndy Fiddaman 				t = r->name;
2036*b30d1939SAndy Fiddaman 			r->leaf = rule(t);
2037*b30d1939SAndy Fiddaman 			search(state.leaf, t, r);
2038*b30d1939SAndy Fiddaman 		}
2039*b30d1939SAndy Fiddaman 	}
2040*b30d1939SAndy Fiddaman 	pop();
2041*b30d1939SAndy Fiddaman 	drop(buf);
2042*b30d1939SAndy Fiddaman 	drop(tmp);
2043*b30d1939SAndy Fiddaman 
2044*b30d1939SAndy Fiddaman 	/*
2045*b30d1939SAndy Fiddaman 	 * grab the non-leaf active targets
2046*b30d1939SAndy Fiddaman 	 */
2047*b30d1939SAndy Fiddaman 
2048*b30d1939SAndy Fiddaman 	if (!state.active)
2049*b30d1939SAndy Fiddaman 	{
2050*b30d1939SAndy Fiddaman 		state.active = 1;
2051*b30d1939SAndy Fiddaman 		walk(state.rules, active, NiL);
2052*b30d1939SAndy Fiddaman 	}
2053*b30d1939SAndy Fiddaman 	search(state.vars, "MAMAKEARGS", duplicate(use(state.opt) + 1));
2054*b30d1939SAndy Fiddaman 
2055*b30d1939SAndy Fiddaman 	/*
2056*b30d1939SAndy Fiddaman 	 * scan the makefile and descend
2057*b30d1939SAndy Fiddaman 	 */
2058*b30d1939SAndy Fiddaman 
2059*b30d1939SAndy Fiddaman 	walk(state.rules, scan, NiL);
2060*b30d1939SAndy Fiddaman 	state.view = 0;
2061*b30d1939SAndy Fiddaman 	walk(state.rules, descend, NiL);
2062*b30d1939SAndy Fiddaman 	return 0;
2063*b30d1939SAndy Fiddaman }
2064*b30d1939SAndy Fiddaman 
2065*b30d1939SAndy Fiddaman int
main(int argc,char ** argv)2066*b30d1939SAndy Fiddaman main(int argc, char** argv)
2067*b30d1939SAndy Fiddaman {
2068*b30d1939SAndy Fiddaman 	register char**		e;
2069*b30d1939SAndy Fiddaman 	register char*		s;
2070*b30d1939SAndy Fiddaman 	register char*		t;
2071*b30d1939SAndy Fiddaman 	register char*		v;
2072*b30d1939SAndy Fiddaman 	Buf_t*			tmp;
2073*b30d1939SAndy Fiddaman 	int			c;
2074*b30d1939SAndy Fiddaman 
2075*b30d1939SAndy Fiddaman 	/*
2076*b30d1939SAndy Fiddaman 	 * initialize the state
2077*b30d1939SAndy Fiddaman 	 */
2078*b30d1939SAndy Fiddaman 
2079*b30d1939SAndy Fiddaman 	state.id = "mamake";
2080*b30d1939SAndy Fiddaman 	state.active = 1;
2081*b30d1939SAndy Fiddaman 	state.exec = 1;
2082*b30d1939SAndy Fiddaman 	state.file = mamfile;
2083*b30d1939SAndy Fiddaman 	state.opt = buffer();
2084*b30d1939SAndy Fiddaman 	state.rules = dictionary();
2085*b30d1939SAndy Fiddaman 	state.vars = dictionary();
2086*b30d1939SAndy Fiddaman 	search(state.vars, "MAMAKE", *argv);
2087*b30d1939SAndy Fiddaman 
2088*b30d1939SAndy Fiddaman 	/*
2089*b30d1939SAndy Fiddaman 	 * parse the options
2090*b30d1939SAndy Fiddaman 	 */
2091*b30d1939SAndy Fiddaman 
2092*b30d1939SAndy Fiddaman #if _PACKAGE_ast
2093*b30d1939SAndy Fiddaman 	error_info.id = state.id;
2094*b30d1939SAndy Fiddaman 	for (;;)
2095*b30d1939SAndy Fiddaman 	{
2096*b30d1939SAndy Fiddaman 		switch (optget(argv, usage))
2097*b30d1939SAndy Fiddaman 		{
2098*b30d1939SAndy Fiddaman 		case 'e':
2099*b30d1939SAndy Fiddaman 			append(state.opt, " -e");
2100*b30d1939SAndy Fiddaman 			state.explain = 1;
2101*b30d1939SAndy Fiddaman 			continue;
2102*b30d1939SAndy Fiddaman 		case 'i':
2103*b30d1939SAndy Fiddaman 			append(state.opt, " -i");
2104*b30d1939SAndy Fiddaman 			state.ignore = 1;
2105*b30d1939SAndy Fiddaman 			continue;
2106*b30d1939SAndy Fiddaman 		case 'k':
2107*b30d1939SAndy Fiddaman 			append(state.opt, " -k");
2108*b30d1939SAndy Fiddaman 			state.keepgoing = 1;
2109*b30d1939SAndy Fiddaman 			continue;
2110*b30d1939SAndy Fiddaman 		case 'N':
2111*b30d1939SAndy Fiddaman 			state.never = 1;
2112*b30d1939SAndy Fiddaman 			/*FALLTHROUGH*/
2113*b30d1939SAndy Fiddaman 		case 'n':
2114*b30d1939SAndy Fiddaman 			append(state.opt, " -n");
2115*b30d1939SAndy Fiddaman 			state.exec = 0;
2116*b30d1939SAndy Fiddaman 			continue;
2117*b30d1939SAndy Fiddaman 		case 'F':
2118*b30d1939SAndy Fiddaman 			append(state.opt, " -F");
2119*b30d1939SAndy Fiddaman 			state.force = 1;
2120*b30d1939SAndy Fiddaman 			continue;
2121*b30d1939SAndy Fiddaman 		case 'K':
2122*b30d1939SAndy Fiddaman 			continue;
2123*b30d1939SAndy Fiddaman 		case 'V':
2124*b30d1939SAndy Fiddaman 			fprintf(stdout, "%s\n", id + 10);
2125*b30d1939SAndy Fiddaman 			exit(0);
2126*b30d1939SAndy Fiddaman 		case 'f':
2127*b30d1939SAndy Fiddaman 			append(state.opt, " -f ");
2128*b30d1939SAndy Fiddaman 			append(state.opt, opt_info.arg);
2129*b30d1939SAndy Fiddaman 			state.file = opt_info.arg;
2130*b30d1939SAndy Fiddaman 			continue;
2131*b30d1939SAndy Fiddaman 		case 'r':
2132*b30d1939SAndy Fiddaman 			state.recurse = opt_info.arg;
2133*b30d1939SAndy Fiddaman 			continue;
2134*b30d1939SAndy Fiddaman 		case 'C':
2135*b30d1939SAndy Fiddaman 			state.directory = opt_info.arg;
2136*b30d1939SAndy Fiddaman 			continue;
2137*b30d1939SAndy Fiddaman 		case 'D':
2138*b30d1939SAndy Fiddaman 			append(state.opt, " -D");
2139*b30d1939SAndy Fiddaman 			append(state.opt, opt_info.arg);
2140*b30d1939SAndy Fiddaman 			state.debug = -opt_info.num;
2141*b30d1939SAndy Fiddaman 			continue;
2142*b30d1939SAndy Fiddaman 		case 'G':
2143*b30d1939SAndy Fiddaman 			append(state.opt, " -G");
2144*b30d1939SAndy Fiddaman 			search(state.vars, "-debug-symbols", "1");
2145*b30d1939SAndy Fiddaman 			continue;
2146*b30d1939SAndy Fiddaman 		case 'S':
2147*b30d1939SAndy Fiddaman 			append(state.opt, " -S");
2148*b30d1939SAndy Fiddaman 			search(state.vars, "-strip-symbols", "1");
2149*b30d1939SAndy Fiddaman 			continue;
2150*b30d1939SAndy Fiddaman 		case '?':
2151*b30d1939SAndy Fiddaman 			error(ERROR_USAGE|4, "%s", opt_info.arg);
2152*b30d1939SAndy Fiddaman 			continue;
2153*b30d1939SAndy Fiddaman 		case ':':
2154*b30d1939SAndy Fiddaman 			error(2, "%s", opt_info.arg);
2155*b30d1939SAndy Fiddaman 			continue;
2156*b30d1939SAndy Fiddaman 		}
2157*b30d1939SAndy Fiddaman 		break;
2158*b30d1939SAndy Fiddaman 	}
2159*b30d1939SAndy Fiddaman 	if (error_info.errors)
2160*b30d1939SAndy Fiddaman 		error(ERROR_USAGE|4, "%s", optusage(NiL));
2161*b30d1939SAndy Fiddaman 	argv += opt_info.index;
2162*b30d1939SAndy Fiddaman #else
2163*b30d1939SAndy Fiddaman 	while ((s = *++argv) && *s == '-')
2164*b30d1939SAndy Fiddaman 	{
2165*b30d1939SAndy Fiddaman 		if (*(s + 1) == '-')
2166*b30d1939SAndy Fiddaman 		{
2167*b30d1939SAndy Fiddaman 			if (!*(s + 2))
2168*b30d1939SAndy Fiddaman 			{
2169*b30d1939SAndy Fiddaman 				append(state.opt, " --");
2170*b30d1939SAndy Fiddaman 				argv++;
2171*b30d1939SAndy Fiddaman 				break;
2172*b30d1939SAndy Fiddaman 			}
2173*b30d1939SAndy Fiddaman 			for (t = s += 2; *t && *t != '='; t++);
2174*b30d1939SAndy Fiddaman 			if (!strncmp(s, "debug-symbols", t - s) && append(state.opt, " -G") || !strncmp(s, "strip-symbols", t - s) && append(state.opt, " -S"))
2175*b30d1939SAndy Fiddaman 			{
2176*b30d1939SAndy Fiddaman 				if (*t)
2177*b30d1939SAndy Fiddaman 				{
2178*b30d1939SAndy Fiddaman 					v = t + 1;
2179*b30d1939SAndy Fiddaman 					if (t > s && *(t - 1) == '+')
2180*b30d1939SAndy Fiddaman 						t--;
2181*b30d1939SAndy Fiddaman 					c = *t;
2182*b30d1939SAndy Fiddaman 					*t = 0;
2183*b30d1939SAndy Fiddaman 				}
2184*b30d1939SAndy Fiddaman 				else
2185*b30d1939SAndy Fiddaman 				{
2186*b30d1939SAndy Fiddaman 					c = 0;
2187*b30d1939SAndy Fiddaman 					v = "1";
2188*b30d1939SAndy Fiddaman 				}
2189*b30d1939SAndy Fiddaman 				search(state.vars, s - 1, v);
2190*b30d1939SAndy Fiddaman 				if (c)
2191*b30d1939SAndy Fiddaman 					*t = c;
2192*b30d1939SAndy Fiddaman 				continue;
2193*b30d1939SAndy Fiddaman 			}
2194*b30d1939SAndy Fiddaman 			usage();
2195*b30d1939SAndy Fiddaman 			break;
2196*b30d1939SAndy Fiddaman 		}
2197*b30d1939SAndy Fiddaman 		for (;;)
2198*b30d1939SAndy Fiddaman 		{
2199*b30d1939SAndy Fiddaman 			switch (*++s)
2200*b30d1939SAndy Fiddaman 			{
2201*b30d1939SAndy Fiddaman 			case 0:
2202*b30d1939SAndy Fiddaman 				break;
2203*b30d1939SAndy Fiddaman 			case 'e':
2204*b30d1939SAndy Fiddaman 				append(state.opt, " -e");
2205*b30d1939SAndy Fiddaman 				state.explain = 1;
2206*b30d1939SAndy Fiddaman 				continue;
2207*b30d1939SAndy Fiddaman 			case 'i':
2208*b30d1939SAndy Fiddaman 				append(state.opt, " -i");
2209*b30d1939SAndy Fiddaman 				state.ignore = 1;
2210*b30d1939SAndy Fiddaman 				continue;
2211*b30d1939SAndy Fiddaman 			case 'k':
2212*b30d1939SAndy Fiddaman 				append(state.opt, " -k");
2213*b30d1939SAndy Fiddaman 				state.keepgoing = 1;
2214*b30d1939SAndy Fiddaman 				continue;
2215*b30d1939SAndy Fiddaman 			case 'N':
2216*b30d1939SAndy Fiddaman 				state.never = 1;
2217*b30d1939SAndy Fiddaman 				/*FALLTHROUGH*/
2218*b30d1939SAndy Fiddaman 			case 'n':
2219*b30d1939SAndy Fiddaman 				append(state.opt, " -n");
2220*b30d1939SAndy Fiddaman 				state.exec = 0;
2221*b30d1939SAndy Fiddaman 				continue;
2222*b30d1939SAndy Fiddaman 			case 'F':
2223*b30d1939SAndy Fiddaman 				append(state.opt, " -F");
2224*b30d1939SAndy Fiddaman 				state.force = 1;
2225*b30d1939SAndy Fiddaman 				continue;
2226*b30d1939SAndy Fiddaman 			case 'G':
2227*b30d1939SAndy Fiddaman 				append(state.opt, " -G");
2228*b30d1939SAndy Fiddaman 				search(state.vars, "-debug-symbols", "1");
2229*b30d1939SAndy Fiddaman 				continue;
2230*b30d1939SAndy Fiddaman 			case 'K':
2231*b30d1939SAndy Fiddaman 				continue;
2232*b30d1939SAndy Fiddaman 			case 'S':
2233*b30d1939SAndy Fiddaman 				append(state.opt, " -S");
2234*b30d1939SAndy Fiddaman 				search(state.vars, "-strip-symbols", "1");
2235*b30d1939SAndy Fiddaman 				continue;
2236*b30d1939SAndy Fiddaman 			case 'V':
2237*b30d1939SAndy Fiddaman 				fprintf(stdout, "%s\n", id + 10);
2238*b30d1939SAndy Fiddaman 				exit(0);
2239*b30d1939SAndy Fiddaman 			case 'f':
2240*b30d1939SAndy Fiddaman 			case 'r':
2241*b30d1939SAndy Fiddaman 			case 'C':
2242*b30d1939SAndy Fiddaman 			case 'D':
2243*b30d1939SAndy Fiddaman 				t = s;
2244*b30d1939SAndy Fiddaman 				if (!*++s && !(s = *++argv))
2245*b30d1939SAndy Fiddaman 				{
2246*b30d1939SAndy Fiddaman 					report(2, "option value expected", t, (unsigned long)0);
2247*b30d1939SAndy Fiddaman 					usage();
2248*b30d1939SAndy Fiddaman 				}
2249*b30d1939SAndy Fiddaman 				else
2250*b30d1939SAndy Fiddaman 					switch (*t)
2251*b30d1939SAndy Fiddaman 					{
2252*b30d1939SAndy Fiddaman 					case 'f':
2253*b30d1939SAndy Fiddaman 						append(state.opt, " -f ");
2254*b30d1939SAndy Fiddaman 						append(state.opt, s);
2255*b30d1939SAndy Fiddaman 						state.file = s;
2256*b30d1939SAndy Fiddaman 						break;
2257*b30d1939SAndy Fiddaman 					case 'r':
2258*b30d1939SAndy Fiddaman 						state.recurse = s;
2259*b30d1939SAndy Fiddaman 						break;
2260*b30d1939SAndy Fiddaman 					case 'C':
2261*b30d1939SAndy Fiddaman 						state.directory = s;
2262*b30d1939SAndy Fiddaman 						break;
2263*b30d1939SAndy Fiddaman 					case 'D':
2264*b30d1939SAndy Fiddaman 						append(state.opt, " -D");
2265*b30d1939SAndy Fiddaman 						append(state.opt, s);
2266*b30d1939SAndy Fiddaman 						state.debug = -atoi(s);
2267*b30d1939SAndy Fiddaman 						break;
2268*b30d1939SAndy Fiddaman 					}
2269*b30d1939SAndy Fiddaman 				break;
2270*b30d1939SAndy Fiddaman 			default:
2271*b30d1939SAndy Fiddaman 				report(2, "unknown option", s, (unsigned long)0);
2272*b30d1939SAndy Fiddaman 			case '?':
2273*b30d1939SAndy Fiddaman 				usage();
2274*b30d1939SAndy Fiddaman 				break;
2275*b30d1939SAndy Fiddaman 			}
2276*b30d1939SAndy Fiddaman 			break;
2277*b30d1939SAndy Fiddaman 		}
2278*b30d1939SAndy Fiddaman 	}
2279*b30d1939SAndy Fiddaman #endif
2280*b30d1939SAndy Fiddaman 
2281*b30d1939SAndy Fiddaman 	/*
2282*b30d1939SAndy Fiddaman 	 * load the environment
2283*b30d1939SAndy Fiddaman 	 */
2284*b30d1939SAndy Fiddaman 
2285*b30d1939SAndy Fiddaman 	for (e = environ; s = *e; e++)
2286*b30d1939SAndy Fiddaman 		for (t = s; *t; t++)
2287*b30d1939SAndy Fiddaman 			if (*t == '=')
2288*b30d1939SAndy Fiddaman 			{
2289*b30d1939SAndy Fiddaman 				*t = 0;
2290*b30d1939SAndy Fiddaman 				search(state.vars, s, t + 1);
2291*b30d1939SAndy Fiddaman 				*t = '=';
2292*b30d1939SAndy Fiddaman 				break;
2293*b30d1939SAndy Fiddaman 			}
2294*b30d1939SAndy Fiddaman 
2295*b30d1939SAndy Fiddaman 	/*
2296*b30d1939SAndy Fiddaman 	 * grab the command line targets and variable definitions
2297*b30d1939SAndy Fiddaman 	 */
2298*b30d1939SAndy Fiddaman 
2299*b30d1939SAndy Fiddaman 	while (s = *argv++)
2300*b30d1939SAndy Fiddaman 	{
2301*b30d1939SAndy Fiddaman 		for (t = s; *t; t++)
2302*b30d1939SAndy Fiddaman 			if (*t == '=')
2303*b30d1939SAndy Fiddaman 			{
2304*b30d1939SAndy Fiddaman 				v = t + 1;
2305*b30d1939SAndy Fiddaman 				if (t > s && *(t - 1) == '+')
2306*b30d1939SAndy Fiddaman 					t--;
2307*b30d1939SAndy Fiddaman 				c = *t;
2308*b30d1939SAndy Fiddaman 				*t = 0;
2309*b30d1939SAndy Fiddaman 				search(state.vars, s, v);
2310*b30d1939SAndy Fiddaman 				tmp = buffer();
2311*b30d1939SAndy Fiddaman 				append(tmp, s);
2312*b30d1939SAndy Fiddaman 				append(tmp, ".FORCE");
2313*b30d1939SAndy Fiddaman 				search(state.vars, use(tmp), v);
2314*b30d1939SAndy Fiddaman 				drop(tmp);
2315*b30d1939SAndy Fiddaman 				*t = c;
2316*b30d1939SAndy Fiddaman 				break;
2317*b30d1939SAndy Fiddaman 			}
2318*b30d1939SAndy Fiddaman 		if (!*t)
2319*b30d1939SAndy Fiddaman 		{
2320*b30d1939SAndy Fiddaman 			/*
2321*b30d1939SAndy Fiddaman 			 * handle a few targets for nmake compatibility
2322*b30d1939SAndy Fiddaman 			 */
2323*b30d1939SAndy Fiddaman 
2324*b30d1939SAndy Fiddaman 			if (*s == 'e' && !strncmp(s, "error 0 $(MAKEVERSION:", 22))
2325*b30d1939SAndy Fiddaman 				exit(1);
2326*b30d1939SAndy Fiddaman 			if (*s == 'r' && !strcmp(s, "recurse") || *s == 'c' && !strncmp(s, "cc-", 3))
2327*b30d1939SAndy Fiddaman 				continue;
2328*b30d1939SAndy Fiddaman 			rule(s)->flags |= RULE_active;
2329*b30d1939SAndy Fiddaman 			state.active = 0;
2330*b30d1939SAndy Fiddaman 			if (state.recurse)
2331*b30d1939SAndy Fiddaman 				continue;
2332*b30d1939SAndy Fiddaman 		}
2333*b30d1939SAndy Fiddaman 		add(state.opt, ' ');
2334*b30d1939SAndy Fiddaman 		add(state.opt, '\'');
2335*b30d1939SAndy Fiddaman 		append(state.opt, s);
2336*b30d1939SAndy Fiddaman 		add(state.opt, '\'');
2337*b30d1939SAndy Fiddaman 	}
2338*b30d1939SAndy Fiddaman 
2339*b30d1939SAndy Fiddaman 	/*
2340*b30d1939SAndy Fiddaman 	 * initialize the views
2341*b30d1939SAndy Fiddaman 	 */
2342*b30d1939SAndy Fiddaman 
2343*b30d1939SAndy Fiddaman 	if (state.directory && chdir(state.directory))
2344*b30d1939SAndy Fiddaman 		report(3, "cannot change working directory", NiL, (unsigned long)0);
2345*b30d1939SAndy Fiddaman 	view();
2346*b30d1939SAndy Fiddaman 
2347*b30d1939SAndy Fiddaman 	/*
2348*b30d1939SAndy Fiddaman 	 * recursion drops out here
2349*b30d1939SAndy Fiddaman 	 */
2350*b30d1939SAndy Fiddaman 
2351*b30d1939SAndy Fiddaman 	if (state.recurse)
2352*b30d1939SAndy Fiddaman 		return recurse(state.recurse);
2353*b30d1939SAndy Fiddaman 
2354*b30d1939SAndy Fiddaman 	/*
2355*b30d1939SAndy Fiddaman 	 * read the mamfile(s) and bring the targets up to date
2356*b30d1939SAndy Fiddaman 	 */
2357*b30d1939SAndy Fiddaman 
2358*b30d1939SAndy Fiddaman 	search(state.vars, "MAMAKEARGS", duplicate(use(state.opt) + 1));
2359*b30d1939SAndy Fiddaman 	push(state.file, (Stdio_t*)0, STREAM_MUST);
2360*b30d1939SAndy Fiddaman 	make(rule(""));
2361*b30d1939SAndy Fiddaman 	pop();
2362*b30d1939SAndy Fiddaman 
2363*b30d1939SAndy Fiddaman 	/*
2364*b30d1939SAndy Fiddaman 	 * verify that active targets were made
2365*b30d1939SAndy Fiddaman 	 */
2366*b30d1939SAndy Fiddaman 
2367*b30d1939SAndy Fiddaman 	if (!state.active && !state.verified)
2368*b30d1939SAndy Fiddaman 		walk(state.rules, verify, NiL);
2369*b30d1939SAndy Fiddaman 
2370*b30d1939SAndy Fiddaman 	/*
2371*b30d1939SAndy Fiddaman 	 * done
2372*b30d1939SAndy Fiddaman 	 */
2373*b30d1939SAndy Fiddaman 
2374*b30d1939SAndy Fiddaman 	return state.errors != 0;
2375*b30d1939SAndy Fiddaman }
2376