1 /* @(#)make.c	1.228 21/08/20 Copyright 1985, 87, 88, 91, 1995-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)make.c	1.228 21/08/20 Copyright 1985, 87, 88, 91, 1995-2021 J. Schilling";
6 #endif
7 /*
8  *	Make program
9  *
10  *	Copyright (c) 1985, 87, 88, 91, 1995-2021 by J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/stdio.h>
27 #include <schily/standard.h>
28 #include <schily/getargs.h>
29 #include <schily/errno.h>
30 #include <schily/fcntl.h>
31 #include <schily/stdlib.h>
32 #include <schily/string.h>
33 #include <schily/unistd.h>
34 #include <schily/time.h>
35 #include <schily/signal.h>
36 
37 #include <schily/dirent.h>
38 #include <schily/maxpath.h>
39 #include <schily/getcwd.h>
40 #ifdef  USE_NLS
41 #define	GT_COMERR		/* #define comerr gtcomerr */
42 #define	GT_ERROR		/* #define error gterror   */
43 #else
44 #define	NO_NLS
45 #endif
46 #include <schily/schily.h>
47 #include <schily/libport.h>
48 #include <schily/utime.h>
49 #include <schily/nlsdefs.h>
50 
51 #include "make.h"
52 #include "job.h"
53 #include "version.h"
54 
55 #ifndef  USE_NLS
56 #undef	gtprintf
57 #define	gtprintf	printf
58 #endif
59 
60 char	make_version[] = VERSION;
61 
62 #ifdef	NO_DEFAULTS_PATH
63 #undef	DEFAULTS_PATH
64 #define	DEFAULTS_PATH_SEARCH_FIRST
65 #endif
66 
67 #ifdef	_FASCII
68 LOCAL	void	setup_env	__PR((void));
69 #endif
70 EXPORT	void	usage		__PR((int exitcode));
71 LOCAL	void	initmakefiles	__PR((void));
72 LOCAL	int	dochdir		__PR((char *name));
73 LOCAL	int	addmakefile	__PR((char *name));
74 LOCAL	void	read_defs	__PR((void));
75 LOCAL	void	read_makefiles	__PR((void));
76 EXPORT	void	setup_dotvars	__PR((void));
77 LOCAL	void	setup_vars	__PR((void));
78 LOCAL	void	setup_MAKE	__PR((char *name));
79 EXPORT	char	*searchtype	__PR((int mode));
80 LOCAL	void	printdirs	__PR((void));
81 LOCAL	int	addcommandline	__PR((char *  name));
82 LOCAL	void	addcmdlinedef	__PR((char *  name));
83 LOCAL	void	scan_cmdline	__PR((int ac, char **av));
84 LOCAL	void	read_cmdline	__PR((void));
85 EXPORT	void	doexport	__PR((char *));
86 EXPORT	void	dounexport	__PR((char *));
87 LOCAL	void	read_environ	__PR((void));
88 EXPORT	int	main		__PR((int ac, char ** av));
89 LOCAL	void	check_old_makefiles __PR((void));
90 LOCAL	void	getmakeflags	__PR((void));
91 LOCAL	void	read_makemacs	__PR((void));
92 LOCAL	char	*nextmakemac	__PR((char *s));
93 LOCAL	BOOL	read_mac	__PR((char *mf));
94 LOCAL	void	setmakeflags	__PR((void));
95 LOCAL	char	*stripmacros	__PR((char *macbase, char *new));
96 LOCAL	void	setmakeenv	__PR((char *envbase, char *envp));
97 EXPORT	BOOL	move_tgt	__PR((obj_t * from));
98 LOCAL	int	copy_file	__PR((char * from, char * objname));
99 EXPORT	BOOL	touch_file	__PR((char * name));
100 LOCAL	date_t	gcurtime	__PR((void));
101 LOCAL	date_t	gnewtime	__PR((void));
102 EXPORT	date_t	gftime		__PR((char * file));
103 LOCAL	BOOL	isdir		__PR((char * file));
104 EXPORT	Llong	gfileid		__PR((char * file));
105 EXPORT	char	*prtime		__PR((date_t  date));
106 LOCAL	void	handler		__PR((int signo));
107 LOCAL	void	exhandler	__PR((int excode, void *arg));
108 EXPORT	char	*curwdir	__PR((void));
109 LOCAL	char	*getdefaultsfile	__PR((void));
110 LOCAL	int	put_env		__PR((char *new));
111 LOCAL	int	unset_env	__PR((char *name));
112 
113 BOOL	posixmode	= FALSE;	/* We found a .POSIX target	*/
114 BOOL	Aflag		= FALSE;	/* -a Do not run setup_arch()	*/
115 BOOL	Eflag		= FALSE;	/* -e Environment overrides vars*/
116 BOOL	Iflag		= FALSE;	/* -i Ignore command errors	*/
117 BOOL	Kflag		= FALSE;	/* -k Continue on unrelated tgts */
118 BOOL	Stopflag	= FALSE;	/* -S Stop on make errors 	*/
119 BOOL	NSflag		= FALSE;	/* -N Ignore no Source on dep.	*/
120 BOOL	Nflag		= FALSE;	/* -n Only show what to do	*/
121 BOOL	Qflag		= FALSE;	/* -q If up to date exit (0)	*/
122 BOOL	Rflag		= FALSE;	/* -r Turn off internal rules	*/
123 BOOL	Sflag		= FALSE;	/* -s Be silent			*/
124 BOOL	Tflag		= FALSE;	/* -t Touch objects		*/
125 int	Mlevel		= 0;		/* MAKE_LEVEL from environment	*/
126 int	Debug		= 0;		/* -d Print reason for rebuild	*/
127 int	XDebug		= 0;		/* -xd Print extended debug info*/
128 BOOL	Prdep		= FALSE;	/* -xM Print include dependency	*/
129 BOOL	Pr_obj		= FALSE;	/* -probj   Print object tree	*/
130 BOOL	Print		= FALSE;	/* -p Print macro/target definitions*/
131 int	Dmake		= 0;		/* -D Display makefile		*/
132 BOOL	help		= FALSE;	/* -help    Show Usage		*/
133 BOOL	pversion	= FALSE;	/* -version Show version string	*/
134 BOOL	No_Warn		= FALSE;	/* -w No warnings		*/
135 int	Do_Warn		= 0;		/* -W Print extra warnings	*/
136 char	Makeflags[]	= "MAKEFLAGS";
137 char	Make_Flags[]	= "MAKE_FLAGS";
138 char	Make_Macs[]	= "MAKE_MACS";
139 char	Make_Level[]	= "MAKE_LEVEL";
140 char	Envdefs[]	= "Environment defs";
141 char	Makedefs[]	= "Internal Makefile";
142 char	Ldefaults[]	= "defaults.smk";
143 #ifdef	SVR4
144 char	Defaults[]	= "/opt/schily/share/lib/smake/defaults.smk";
145 #else
146 char	Defaults[]	= "/usr/bert/share/lib/smake/defaults.smk";
147 #endif
148 #define	MAKEFILECOUNT	32		/* Max number of Makefiles	*/
149 char	SMakefile[]	= "SMakefile";	/* smake's default Makefile	*/
150 char	Makefile[]	= "Makefile";	/* Primary default Makefile	*/
151 char	_makefile[]	= "makefile";	/* Secondary default Makefile	*/
152 char   **MakeFileNames;			/* To hold all Makefilenames	*/
153 int	Mfileindex;			/* Current Makefile index	*/
154 int	Mfilesize;			/* Size of Makefile array	*/
155 int	Mfilecount;			/* Number of Makefiles found+2	*/
156 char	CmdLMac[]	= "Command Line Macro"; /* Makefile Name for ..	*/
157 char	**CmdLDefs;			/* To hold all Cmdline Macros	*/
158 int	Cmdlinecount;			/* Number of Cmdline Macros	*/
159 int	Cmdlinesize;			/* Size of Cmdline Macro array	*/
160 char	*MFCmdline;			/* Pointer to Cmdl. Macs fr. env*/
161 
162 int	Mflags;
163 
164 char	*ObjDir;		/* .OBJDIR: pathname Target destination dir */
165 int	ObjDirlen;		/* strlen(.OBJDIR)			    */
166 Llong	ObjDirfid;		/* gfileid(.OBJDIR)			    */
167 Llong	dotfid;			/* gfileid(".")				    */
168 int	ObjSearch	= SALL;	/* .OBJSEARCH: searchtype for explicit rules*/
169 list_t	*SearchList;		/* .SEARCHLIST: list of src/obj dir pairs   */
170 list_t	*Suffixes;		/* .SUFFIXES: list of suffixes (POSIX)	    */
171 BOOL	SSuffrules;
172 obj_t	*Init;			/* .INIT: command to execute at startup	    */
173 obj_t	*Done;			/* .DONE: command do execute on success	    */
174 obj_t	*Failed;		/* .FAILED: command to execute on failure   */
175 obj_t	*IncludeFailed;		/* .INCLUDE_FAILED: cmd to exec if missing  */
176 obj_t	*Deflt;			/* .DEFAULT: command to execute if no rule  */
177 obj_t	*Precious;		/* .PRECIOUS: list of targets not to remove */
178 obj_t	*Phony;			/* .PHONY: list of false targets, no check  */
179 obj_t	*curtarget;		/* current target of actually running cmd   */
180 date_t	curtime;		/* Current time				    */
181 date_t	newtime;		/* Special time newer than all		    */
182 
183 #define	MINSECS		60
184 #define	HOURSECS	(MINSECS*60)
185 #define	DAYSECS		(HOURSECS*24)
186 #define	MONTHSECS	(DAYSECS*30)
187 #define	YEARSECS	(DAYSECS*365)
188 #ifdef	USE_NSECS
189 #define	DATESECS	((date_t)(1 << NSEC_SHIFT))
190 #else
191 #define	DATESECS	((date_t)1)
192 #endif
193 
194 char	Nullstr[]	= "";
195 char	slash[]		= PATH_DELIM_STR;
196 int	slashlen	= sizeof (PATH_DELIM_STR) -1;	/* strlen(slash) */
197 
198 LOCAL	BOOL	xpatrules;	/* Have non local pattern rules	in Makefile */
199 EXPORT	int	xssrules;	/* Have non local simple suffix rules	    */
200 
201 #ifdef	_FASCII				/* Mark Williams C		*/
202 char	*_stksize	= (char *) 8192;
203 
204 /*
205  * Old and probably outdated setup that was needed in 1986 to make
206  * 'smake' run on a ATARI ST using the Marc Williams C development tools.
207  */
208 LOCAL void
setup_env()209 setup_env()
210 {
211 	register char	*ep;
212 	extern	 char	*getenv();
213 
214 	if ((ep = getenv("PATH")) == (char *) NULL || *ep == '\0')
215 		putenv("PATH=.bin,,\\bin,\\lib");
216 
217 	if ((ep = getenv("SUFF")) == (char *) NULL || *ep == '\0')
218 		putenv("SUFF=,.prg,.tos,.ttp");
219 
220 	if ((ep = getenv("LIBPATH")) == (char *) NULL || *ep == '\0')
221 		putenv("LIBPATH=\\lib,\\bin");
222 
223 	if ((ep = getenv("TMPDIR")) == (char *) NULL || *ep == '\0')
224 		putenv("TMPDIR=\\tmp");
225 
226 	if ((ep = getenv("INCDIR")) == (char *) NULL || *ep == '\0')
227 		putenv("INCDIR=\\include");
228 }
229 #endif
230 
231 EXPORT void
usage(exitcode)232 usage(exitcode)
233 	int	exitcode;
234 {
235 	error("Usage:	smake [options] [target...] [macro=value...]\n");
236 	error("Options:\n");
237 	error("	-a	Do not set up architecture specific make macros.\n");
238 	error("	-e	Environment overrides variables in Makefile.\n");
239 	error("	-i	Ignore errors from commands.\n");
240 	error("	-j maxj	Specify the number of jobs to run simultaneously.\n");
241 	error("	-k	Ignore target errors, continue on unrelated targets.\n");
242 	error("	-N	Continue if no source for nonexistent dependencies is found.\n");
243 	error("	-n	Don't make - only say what to do.\n");
244 	error("	-p	Print all macro and target definitions.\n");
245 	error("	-q	Question mode. Exit code is 0 if target is up to date.\n");
246 	error("	-r	Turn off internal rules.\n");
247 	error("	-s	Be silent.\n");
248 	error("	-S	Undo the effect of the -k option, terminate on target errors.\n");
249 	error("	-t	Touch Objects instead of executing defined commands.\n");
250 	error("	-w	Don't print warning Messages.\n");
251 	error("	-W	Print extra (debug) warning Messages.\n");
252 	error("	-WW	Print even more (debug) warning Messages.\n");
253 	error("	-D	Display Makefiles as read in.\n");
254 	error("	-DD	Display Makefiles/Rules as read in.\n");
255 	error("	-d	Print reason why a target has to be rebuilt.\n");
256 	error("	-dd	Debug dependency check.\n");
257 	error("	-xM	Print include dependency.\n");
258 	error("	-xd	Print extended debug info.\n");
259 	error("	-probj	Print object tree.\n");
260 	error("	-help	Print this help.\n");
261 	error("	-version Print version number.\n");
262 	error("	-posix	Force POSIX behaviour.\n");
263 	error("	-C dir	Change directory to 'dir' before starting work.\n");
264 	error("	mf=makefilename | -f makefilename\n");
265 	error("More than one -f makefile option may be specified.\n");
266 	exit(exitcode);
267 }
268 
269 LOCAL void
initmakefiles()270 initmakefiles()
271 {
272 	/*
273 	 * Mfilecount	als Index fuer MakeFileNames[] bei addmakefile()
274 	 * Mfileindex	als globale Index Variable fuer den Parser
275 	 *
276 	 * This code needs to be kept in sync with the MF_IDX_* #defines
277 	 * in make.h
278 	 */
279 	Mfilecount = 0;
280 	addmakefile(Makedefs);		/* Implicit rules		*/
281 	addmakefile(Envdefs);		/* Environment strings		*/
282 	addmakefile(Makefile);		/* Default make file		*/
283 	Mfilecount--;			/* -f name overwrites Makefile	*/
284 }
285 
286 /*
287  * Called by getargs() if a -C option was found.
288  */
289 LOCAL int
dochdir(name)290 dochdir(name)
291 	char	*name;
292 {
293 	if (chdir(name) < 0)
294 		comerr("Cannot change directory to '%s'\n", name);
295 
296 	return (1);
297 }
298 
299 /*
300  * Add a new makefile to the list of makefiles.
301  * Called by getargs() if a -f option was found.
302  */
303 LOCAL int
addmakefile(name)304 addmakefile(name)
305 	char	*name;
306 {
307 	if (MakeFileNames == NULL) {
308 		/*
309 		 * Use a default size of 4 as we usually have 4 Makefiles.
310 		 */
311 		Mfilesize = 4;
312 		MakeFileNames = malloc(Mfilesize * sizeof (char *));
313 	} else if (Mfilesize <= (Mfilecount+1)) { /* One spare for CmdLMac */
314 		Mfilesize += 4;
315 		MakeFileNames = realloc(MakeFileNames, Mfilesize * sizeof (char *));
316 	}
317 	if (MakeFileNames == NULL)
318 		comerr("No memory for Makefiles.\n");
319 
320 	MakeFileNames[Mfilecount++] = name;
321 
322 	return (1);
323 }
324 
325 /*
326  * Read the default rules - either compiled in or from file.
327  */
328 LOCAL void
read_defs()329 read_defs()
330 {
331 		int	MFsave = Mfileindex;
332 		char	*deflts;
333 	extern	char	implicit_rules[]; /* Default rules compiled into make */
334 
335 	Dmake--;
336 	Mfileindex = MF_IDX_IMPLICIT;	/* Index 0 Implicit Rules */
337 
338 	if (gftime(Ldefaults) != 0) {
339 		MakeFileNames[0] = Ldefaults;
340 		readfile(Ldefaults, TRUE);
341 #ifdef	DEFAULTS_PATH_SEARCH_FIRST
342 	} else if ((deflts = getdefaultsfile()) != NULL) {
343 		MakeFileNames[0] = deflts;
344 		readfile(deflts, TRUE);
345 #endif
346 #ifdef	DEFAULTS_PATH				/* This is the install path */
347 	} else if (gftime(DEFAULTS_PATH) != 0) {
348 		MakeFileNames[0] = DEFAULTS_PATH;
349 		readfile(DEFAULTS_PATH, TRUE);
350 #endif
351 	} else if (gftime(Defaults) != 0) {
352 		MakeFileNames[0] = Defaults;
353 		readfile(Defaults, TRUE);
354 #ifndef	DEFAULTS_PATH_SEARCH_FIRST
355 	} else if ((deflts = getdefaultsfile()) != NULL) {
356 		MakeFileNames[0] = deflts;
357 		readfile(deflts, TRUE);
358 #endif
359 	} else {
360 		readstring(implicit_rules, Makedefs);
361 	}
362 	Dmake++;
363 	Mfileindex = MFsave;
364 }
365 
366 /*
367  * Read in all external makefiles. Use either the names from command line
368  * or look for the default names "Makefile" and "makefile".
369  */
370 LOCAL void
read_makefiles()371 read_makefiles()
372 {
373 	int	MFsave = Mfileindex;
374 	patr_t	*oPatrules = Patrules;
375 	patr_t	**opattail = pattail;
376 
377 	Patrules = 0;
378 	pattail = &Patrules;
379 	xssrules = 0;
380 
381 	Mfileindex = MF_IDX_MAKEFILE;	/* Index 2 Default Makefile */
382 	if (Mfilecount == MF_IDX_MAKEFILE) {
383 		if (posixmode) {
384 			/*
385 			 * First look for "makefile"
386 			 * then for "Makefile", then for "SMakefile".
387 			 */
388 			if (gftime(_makefile) != 0) {		/* "makefile" */
389 				Mfilecount++;
390 				MakeFileNames[2] = _makefile;
391 			} else if (gftime(Makefile) != 0) {	/* "Makefile" */
392 				Mfilecount++;
393 				MakeFileNames[2] = Makefile;
394 			} else if (gftime(SMakefile) != 0) {	/* "SMakefile" */
395 				Mfilecount++;
396 				MakeFileNames[2] = SMakefile;
397 			}
398 		} else
399 		/*
400 		 * First look for "SMakefile",
401 		 * then for "Makefile", then for "makefile"
402 		 */
403 		if (gftime(SMakefile) != 0) {		/* "SMakefile" */
404 			Mfilecount++;
405 			MakeFileNames[2] = SMakefile;
406 		} else if (gftime(Makefile) != 0) {	/* "Makefile" */
407 			Mfilecount++;
408 			MakeFileNames[2] = Makefile;
409 		} else if (gftime(_makefile) != 0) {	/* "makefile" */
410 			Mfilecount++;
411 			MakeFileNames[2] = _makefile;
412 		}
413 	}
414 	while (Mfileindex < Mfilecount) {
415 		readfile(MakeFileNames[Mfileindex], TRUE);
416 		Mfileindex++;
417 	}
418 
419 	/*
420 	 * Check for external pattern rule definitions.
421 	 */
422 	xpatrules = Patrules != NULL;
423 	/*
424 	 * The pattern rules which are defined in the external makefiles
425 	 * must supersede the pattern rules from the internal rules.
426 	 * Concat the pattern rules found in internal rules to the end of
427 	 * the patern rules list from external makefiles.
428 	 */
429 	*pattail = oPatrules;
430 	pattail = opattail;
431 
432 	Mfileindex = MFsave;
433 }
434 
435 /*
436  * Setup special variables.
437  *
438  * NOTE: Must be reentrant because it may be called more than once
439  *	 if the "include" directive is used.
440  *	 As there is (currently) no way to delete an object
441  *	 it is OK not to do anything special if objlook() returns NULL.
442  */
443 EXPORT void
setup_dotvars()444 setup_dotvars()
445 {
446 	obj_t	*obj;
447 	list_t	*l;
448 	char	*name;
449 
450 	obj = objlook(".OBJDIR", FALSE);
451 	if (obj != NULL && obj->o_type != ':')	/* Must be a special target */
452 		obj = NULL;
453 
454 	if (obj != NULL) {
455 		if (obj->o_list && (ObjDir = obj->o_list->l_obj->o_name)) {
456 			if (gfileid(ObjDir) == gfileid(".")) {
457 				/*
458 				 * Do not allow moving targets to themselves.
459 				 */
460 				ObjDir = NULL;
461 				ObjDirlen = 0;
462 			} else {
463 				ObjDirlen = strlen(ObjDir);
464 			}
465 		}
466 	}
467 #ifdef	no_longer_needed	/* Has been moved to dynmac expansion */
468 	/*
469 	 * XXX We cannot do this here as we are called more than once and
470 	 * XXX we like to allow $O to be overwritten from Makefiles that
471 	 * XXX do not know about smake's special features.
472 	 */
473 	/*
474 	 * Create special variable $O -> ObjDir
475 	 */
476 	define_var("O", ObjDir ? ObjDir : ".");
477 #endif
478 
479 	obj = objlook(".OBJSEARCH", FALSE);
480 	if (obj != NULL && obj->o_type != ':')	/* Must be a special target */
481 		obj = NULL;
482 	if (obj != NULL) {
483 		if ((l = obj->o_list) != NULL) {
484 			name = l->l_obj->o_name;
485 			if (streql("src", name)) {
486 				ObjSearch = SSRC;
487 			} else if (streql("obj", name)) {
488 				ObjSearch = SOBJ;
489 			} else if (streql("all", name)) {
490 				ObjSearch = SALL;
491 			} else {
492 				/*
493 				 * This is the default.
494 				 */
495 				ObjSearch = SALL;
496 			}
497 		}
498 	}
499 
500 	obj = objlook(".SEARCHLIST", FALSE);
501 	if (obj != NULL && obj->o_type != ':')	/* Must be a special target */
502 		obj = NULL;
503 	if (obj != NULL) {
504 		SearchList = obj->o_list;
505 	} else if ((obj = objlook("VPATH", FALSE)) != NULL && obj->o_type == '=') {
506 		SearchList = cvtvpath(obj->o_list);
507 	}
508 
509 	obj = objlook(".IGNORE", FALSE);
510 	if (obj != NULL && obj->o_type != ':')	/* Must be a special target */
511 		obj = NULL;
512 	if (obj != NULL && obj->o_list == NULL)
513 		Iflag = TRUE;
514 
515 	obj = objlook(".SILENT", FALSE);
516 	if (obj != NULL && obj->o_type != ':')	/* Must be a special target */
517 		obj = NULL;
518 	if (obj != NULL && obj->o_list == NULL)
519 		Sflag = TRUE;
520 
521 	Init = objlook(".INIT", FALSE);
522 	Done = objlook(".DONE", FALSE);
523 	Failed = objlook(".FAILED", FALSE);
524 	IncludeFailed = objlook(".INCLUDE_FAILED", FALSE);
525 	if (IncludeFailed != NULL && IncludeFailed->o_cmd == NULL)
526 		IncludeFailed = NULL;
527 	Deflt = objlook(".DEFAULT", FALSE);
528 	Precious = objlook(".PRECIOUS", FALSE);
529 	Phony = objlook(".PHONY", FALSE);
530 
531 	if (objlook(".POSIX", FALSE))
532 		posixmode = TRUE;
533 	obj = objlook(".SUFFIXES", FALSE);
534 	if (obj != NULL && obj->o_type != ':')	/* Must be a special target */
535 		obj = NULL;
536 	if (obj != NULL)
537 		Suffixes = obj->o_list;
538 	if (Debug > 1 && Suffixes != (list_t *) NULL) {
539 		register list_t *p;
540 
541 		error(".SUFFIXES :\t");
542 		for (p = Suffixes; p; p = p->l_next)
543 			error("%s ", p->l_obj->o_name);
544 		error("\n");
545 	}
546 	SSuffrules = check_ssufftab();
547 }
548 
549 /*
550  * Set up some known special macros.
551  */
552 LOCAL void
setup_vars()553 setup_vars()
554 {
555 	int	i;
556 	char	make_level[64];
557 	char	*p;
558 
559 	define_var("$", "$");			/* Really needed ? */
560 	define_var("NUMBER_SIGN", "#");		/* Allow to use '#' */
561 	define_var("MAKE_NAME", "smake");	/* Needed to identify syntax */
562 	define_var("MAKE_VERSION", make_version); /* Version dependant files? */
563 	if ((p = getenv(Make_Level)) != NULL) {
564 		p = astoi(p, &i);
565 		if (*p == '\0')
566 			Mlevel = i;
567 	}
568 	snprintf(make_level, sizeof (make_level), "%d", Mlevel+1);
569 	define_var(Make_Level, make_level);
570 	doexport(Make_Level);
571 }
572 
573 /*
574  * Set up the special macro $(MAKE).
575  * If we were called with an absolute PATH or without any '/', use argv[0],
576  * else compute the absolute PATH by prepending working dir to argv[0].
577  */
578 LOCAL void
setup_MAKE(name)579 setup_MAKE(name)
580 	char	*name;
581 {
582 	char	wd[MAXPATHNAME + 1];
583 	int	len;
584 
585 	/*
586 	 * If argv[0] starts with a slash or contains no slash,
587 	 * or on DOS like OS starts with MS-DOS drive letter,
588 	 * it is useful as $(MAKE).
589 	 */
590 #ifdef HAVE_DOS_DRIVELETTER
591 	if (name[0] == SLASH || strchr(name, SLASH) == NULL || name[1] == ':') {
592 #else
593 	if (name[0] == SLASH || strchr(name, SLASH) == NULL) {
594 #endif
595 		define_var("MAKE", name);
596 	} else {
597 		/*
598 		 * Compute abs pathname for $(MAKE)
599 		 */
600 		strncpy(wd, curwdir(), sizeof (wd));
601 		wd[sizeof (wd)-1] = '\0';
602 		len = strlen(wd);
603 		if ((strlen(name) + len + 2) < sizeof (wd)) {
604 			strcat(wd, PATH_DELIM_STR);
605 			strcat(wd, name);
606 		}
607 		define_var("MAKE", wd);
608 	}
609 }
610 
611 /*
612  * Transfer object search types into human readable names.
613  */
614 EXPORT char *
searchtype(mode)615 searchtype(mode)
616 	int	mode;
617 {
618 	if (mode == SSRC)
619 		return ("src");
620 	if (mode == SOBJ)
621 		return ("obj");
622 	if (mode == SALL)
623 		return ("all");
624 	return ("invalid Object search mode");
625 }
626 
627 /*
628  * Print some 'smake' special macros:
629  * .OBJDIR, .SEARCHLIST and .OBJSEARCH
630  */
631 LOCAL void
printdirs()632 printdirs()
633 {
634 	if (ObjDir != NULL)
635 		error(".OBJDIR :\t%s\n", ObjDir);
636 
637 	error(".OBJSEARCH :\t%s\n", searchtype(ObjSearch));
638 
639 	if (SearchList != (list_t *) NULL) {
640 		register list_t *p;
641 			error(".SEARCHLIST :\t");
642 		for (p = SearchList; p; p = p->l_next)
643 			error("%s ", p->l_obj->o_name);
644 		error("\n");
645 	}
646 }
647 
648 /*
649  * Check for a command line macro.
650  * This is called by getargs().
651  */
652 LOCAL int
addcommandline(name)653 addcommandline(name)
654 	char	*name;
655 {
656 	if (Debug > 1)
657 		error("got_it: %s\n", name);
658 
659 /* UNIX make: ":;=$\n\t"	*/
660 
661 	if (!strchr(name, '='))
662 		return (NOTAFILE); /* Tell getargs that this may be a flag */
663 	return (1);
664 }
665 
666 /*
667  * Add a command line macro to our list.
668  * This is called by scan_cmdline() past getargs() since getargs() would
669  * not permit spaces, '+' or ':' to the left of a '='.
670  */
671 LOCAL void
addcmdlinedef(name)672 addcmdlinedef(name)
673 	char	*name;
674 {
675 	if (CmdLDefs == NULL) {
676 		Cmdlinesize = 8;
677 		CmdLDefs = malloc(Cmdlinesize * sizeof (char *));
678 	} else if (Cmdlinesize <= Cmdlinecount) {
679 		Cmdlinesize += 8;
680 		CmdLDefs = realloc(CmdLDefs, Cmdlinesize * sizeof (char *));
681 	}
682 	if (CmdLDefs == NULL)
683 		comerr("No memory for Commandline Macros.\n");
684 
685 	CmdLDefs[Cmdlinecount++] = name;
686 }
687 
688 /*
689  * Read in and parse all command line macro definitions from list.
690  */
691 LOCAL void
scan_cmdline(ac,av)692 scan_cmdline(ac, av)
693 	int	ac;
694 	char	**av;
695 {
696 	register int	i;
697 
698 	for (i = 1; i < ac; i++) {
699 		if (av[i][0] == '-')
700 			continue;
701 		if (strchr(av[i], '=') == NULL)
702 			continue;
703 		addcmdlinedef(av[i]);
704 	}
705 }
706 
707 /*
708  * Read in and parse all command line macro definitions from list.
709  */
710 LOCAL void
read_cmdline()711 read_cmdline()
712 {
713 		int	MFsave = Mfileindex;
714 	register int	i;
715 
716 	if (Cmdlinecount == 0)
717 		return;
718 
719 	/*
720 	 * Register the command line macros past the last makefile
721 	 */
722 	Mfileindex = Mfilecount;
723 	if (Mfileindex == MF_IDX_MAKEFILE)
724 		Mfileindex = MF_IDX_MAKEFILE + 1;
725 	MakeFileNames[Mfileindex] = CmdLMac;
726 
727 	Mflags |= (F_READONLY|F_IDXOVERWRT);
728 	for (i = 0; i < Cmdlinecount; i++) {
729 		char	*eq;
730 		char	*sp;
731 
732 		readstring(CmdLDefs[i], CmdLMac);
733 
734 		eq = strchr(CmdLDefs[i], '=');
735 		sp = strchr(CmdLDefs[i], ' ');
736 		if ((sp == NULL || sp > eq) && eq[-1] != ':')
737 			put_env(CmdLDefs[i]);
738 	}
739 	Mflags &= ~(F_READONLY|F_IDXOVERWRT);
740 	Mfileindex = MFsave;
741 }
742 
743 /*
744  * Export a macro into the environment.
745  * This is mainly done by the "export" directive inside a makefile.
746  */
747 EXPORT void
doexport(oname)748 doexport(oname)
749 	char	*oname;
750 {
751 	obj_t	*obj;
752 	list_t	*l;
753 	char	*name;
754 	int	len;
755 
756 	obj = objlook(oname, FALSE);
757 	if (obj != NULL && basetype(obj->o_type) != '=') /* Must be a macro type target */
758 		obj = NULL;
759 	if (obj != NULL) {
760 		if ((l = obj->o_list) != NULL) {
761 			char	*xname;
762 
763 			len = strlen(oname)+1;	/* Env name + '=' */
764 			while (l && l->l_obj->o_name) {
765 				xname = l->l_obj->o_name;
766 				if (gbuf != NULL)
767 					xname = substitute(xname,
768 								NullObj, 0, 0);
769 				len += strlen(xname)+1;
770 				l = l->l_next;
771 			}
772 			name = malloc(len);
773 			if (name == NULL)
774 				comerr("Cannot alloc memory for env.\n");
775 			name[0] = '\0';
776 			l = obj->o_list;
777 			strcat(name, oname);
778 			strcat(name, "=");
779 			while (l && l->l_obj->o_name) {
780 				xname = l->l_obj->o_name;
781 				if (gbuf != NULL)
782 					xname = substitute(xname,
783 								NullObj, 0, 0);
784 				strcat(name, xname);
785 				if (l->l_next == NULL)
786 					break;
787 				strcat(name, " ");
788 				l = l->l_next;
789 			}
790 			put_env(name);
791 		}
792 	}
793 }
794 
795 /*
796  * Unexport a macro from the environment.
797  * This is mainly done by the "unexport" directive inside a makefile.
798  */
799 EXPORT void
dounexport(oname)800 dounexport(oname)
801 	char	*oname;
802 {
803 	unset_env(oname);
804 }
805 
806 
807 /*
808  * Read in and parse all environment vars to make them make macros.
809  */
810 LOCAL void
read_environ()811 read_environ()
812 {
813 		int	MFsave = Mfileindex;
814 	register char	**env;
815 	extern	char	**environ;
816 	char *ev;
817 	char *p;
818 
819 	Dmake -= 2;
820 	Mfileindex = MF_IDX_ENVIRON;	/* Index 1 Environment vars */
821 
822 	if (Eflag)
823 		Mflags |= F_READONLY;
824 	mfname = Envdefs;
825 	for (env = environ; *env; env++) {
826 		ev = *env;
827 		p = strchr(ev, EQUAL);
828 		if (p == NULL)
829 			continue;
830 		if (strncmp(ev, "CURDIR=", 7) == 0)
831 			continue;	/* Never import CURDIR */
832 		if (strncmp(ev, "SHELL=", 6) == 0)
833 			continue;	/* Never import SHELL */
834 		if (strncmp(ev, "FORCE_SHELL=", 12) == 0) {
835 			obj_t	*obj = objlook(".FORCE_SHELL", TRUE);
836 			if (obj->o_type == 0)
837 				obj->o_type = COLON;
838 		}
839 		*p = '\0';
840 		define_var(ev, &p[1]);
841 		*p = EQUAL;
842 	}
843 	mfname = NULL;
844 	Mflags &= ~F_READONLY;
845 
846 	Dmake += 2;
847 	Mfileindex = MFsave;
848 }
849 
850 
851 EXPORT int
main(ac,av)852 main(ac, av)
853 	int	ac;
854 	char	*av[];
855 {
856 		int	failures = 0;
857 		int	i;
858 		int	maxj = 0;
859 		int	cac = ac;
860 		char	* const *cav = av;
861 	static	char	options[] = "help,version,posix,a,e,i,j#,k,n,N,p,q,r,s,S,t,w,W+,d+,D+,xM,xd+,probj,C&,mf&,f&,&";
862 
863 	save_args(ac, av);
864 
865 	(void) setlocale(LC_ALL, "");
866 
867 #ifdef  USE_NLS
868 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
869 #define	TEXT_DOMAIN "smake"	/* Use this only if it weren't */
870 #endif
871 	{ char	*dir;
872 	dir = searchfileinpath("share/locale", F_OK,
873 					SIP_ANY_FILE|SIP_NO_PATH, NULL);
874 	if (dir)
875 		(void) bindtextdomain(TEXT_DOMAIN, dir);
876 	else
877 #if defined(PROTOTYPES) && defined(INS_BASE)
878 	(void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
879 #else
880 	(void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
881 #endif
882 	(void) textdomain(TEXT_DOMAIN);
883 	}
884 #endif 	/* USE_NLS */
885 
886 #ifdef	__DJGPP__
887 	set_progname("smake");	/* We may have strange av[0] on DJGPP */
888 #endif
889 
890 #ifdef	HAVE_GETPID
891 	getpid();		/* Give some info for truss(1) users */
892 #endif
893 #ifdef	HAVE_GETPGRP
894 	getpgrp();		/* Give some info for truss(1) users */
895 #endif
896 
897 #ifdef	_FASCII			/* Mark Williams C	  */
898 	stderr->_ff &= ~_FSTBUF; /* setbuf was called ??? */
899 
900 	setup_env();
901 #endif
902 	getmakeflags();		/* Default options from MAKEFLAGS=	*/
903 	initmakefiles();	/* Set up MakeFileNames[] array		*/
904 
905 	cac--; cav++;
906 	if (getallargs(&cac, &cav, options, &help, &pversion, &posixmode,
907 			&Aflag,
908 			&Eflag, &Iflag, &maxj,
909 			&Kflag, &Nflag, &NSflag, &Print,
910 			&Qflag, &Rflag, &Sflag, &Stopflag, &Tflag,
911 			&No_Warn, &Do_Warn,
912 			&Debug, &Dmake, &Prdep, &XDebug, &Pr_obj,
913 			dochdir, NULL,
914 			addmakefile, NULL,
915 			addmakefile, NULL,
916 			addcommandline, NULL) < 0) {
917 		errmsgno(EX_BAD, "Bad flag: %s.\n", cav[0]);
918 		usage(EX_BAD);
919 	}
920 	if (help)
921 		usage(0);
922 	if (pversion) {
923 		gtprintf("Smake release %s %s (%s-%s-%s) Copyright (C) 1985, 87, 88, 91, 1995-2021 %s\n",
924 				make_version, VERSION_DATE,
925 				HOST_CPU, HOST_VENDOR, HOST_OS,
926 				_("J�rg Schilling"));
927 		exit(0);
928 	}
929 	if (maxj > 0 && maxj <= MAXJOBS_MAX)
930 		maxjobs = maxj;
931 	else if (maxj > 0)
932 		maxjobs = MAXJOBS_MAX;
933 
934 	/*
935 	 * XXX Is this the right place to set the options and cmd line macros
936 	 * XXX to the exported environment?
937 	 * XXX Later in read_makemacs() we may find that MAKEFLAGS= may contain
938 	 * XXX garbage that has been propagated to MFCmdline.
939 	 * For this reason, we call read_makemacs() before, let it parse only
940 	 * and kill any unwanted content from MFCmdline.
941 	 */
942 	if (NullObj == 0)	/* First make sure we may expand vars	*/
943 		NullObj = objlook(Nullstr, TRUE);
944 
945 	scan_cmdline(ac, av);	/* Identify and save cmd line macro defs */
946 	read_makemacs();	/* With gbuf == NULL, this is parse only */
947 	setmakeflags();
948 	if (Qflag) {
949 		Sflag = TRUE;
950 		Nflag = TRUE;
951 	}
952 	if (Tflag && !Nflag) {
953 		Nflag = -1;	/* Hack for touch_file() */
954 	}
955 	if (Stopflag) {
956 		Kflag = FALSE;
957 	}
958 	if (Debug > 0)
959 		error("MAKEFLAGS value: '%s'\n", getenv(Makeflags));
960 
961 	/*
962 	 * XXX Reihenfolge bei UNIX make beachten!!!
963 	 */
964 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
965 		signal(SIGINT, handler);
966 #ifdef	SIGQUIT
967 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
968 		signal(SIGQUIT, handler);
969 #endif
970 #ifdef	SIGHUP
971 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
972 		signal(SIGHUP, handler);
973 #endif
974 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
975 		signal(SIGTERM, handler);
976 	curtime = gcurtime();
977 	newtime = gnewtime();
978 	NullObj->o_date = newtime;	/* Make NullObj "up to date"    */
979 
980 	initchars();
981 	initgbuf(NAMEMAX);	/* Now the Makefile parser becomes usable */
982 
983 	/*
984 	 * The functions read_cmdline() and read_makemacs() are setting
985 	 * the F_READONLY flag in all objects. The function read_environ()
986 	 * sets F_READONLY if the -e option was specified.
987 	 * This differs from the description in POSIX for 'make' but it
988 	 * is the only way to allow 'include' directives to work as expected.
989 	 * For the same reason, we are reading the macros in the opposite
990 	 * order as described in POSIX.
991 	 */
992 	read_cmdline();		/* First read cmd line macros		*/
993 	read_makemacs();	/* then the inherited cmd line macros	*/
994 	if (!Rflag)
995 		read_defs();	/* read "defaults.smk"			*/
996 	setup_MAKE(av[0]);	/* Set up $(MAKE)			*/
997 	setup_SHELL();		/* Set up $(SHELL)			*/
998 	setup_vars();		/* Set up some known special macros	*/
999 	if (!Aflag)
1000 		setup_arch();	/* Set up arch specific macros		*/
1001 	read_environ();		/* Sets F_READONLY if -e flag is present*/
1002 
1003 	if (Debug > 0 && Mlevel > 0)
1004 		error("Starting '%s'[%d] in directory   '%s'\n",
1005 			av[0], Mlevel, curwdir());
1006 
1007 	/*
1008 	 * Clear default target, then look again in makefiles
1009 	 */
1010 	default_tgt = NULL;
1011 	read_makefiles();
1012 
1013 	/*
1014 	 * Let all objects created later seem to bee in
1015 	 * last Makefile or in implicit rules if no
1016 	 * Makefile is present.
1017 	 */
1018 	Mfileindex = Mfilecount - 1;
1019 	if (Mfileindex < MF_IDX_MAKEFILE)
1020 		Mfileindex = MF_IDX_IMPLICIT;
1021 
1022 	setup_dotvars();
1023 	setup_xvars();		/* Set up compat vars like MAKE_SHELL_FLAG */
1024 	if (!Rflag)
1025 		check_old_makefiles();
1026 
1027 	if (Pr_obj)		/* -probj Flag				*/
1028 		printtree();
1029 	if (Print) {		/* -p Flag				*/
1030 		prtree();
1031 		exit(0);	/* XXX Really exit() here for make -p -f /dev/null ??? */
1032 				/* XXX Posix requires make -p -f /dev/null 2>/dev/null */
1033 				/* XXX to print the internal macros	*/
1034 	}
1035 	on_comerr(exhandler, av[0]);
1036 	if (Debug > 0)
1037 		printdirs();	/* .OBJDIR .OBJSEARCH .SEARCHLIST	*/
1038 
1039 	makeincs();		/* Re-make included files */
1040 	omake(Init, TRUE);	/* Make .INIT target	  */
1041 	cac = ac;
1042 	cav = av;
1043 	cac--; cav++;
1044 	for (i = 0; getfiles(&cac, &cav, options); cac--, cav++, i++) {
1045 		if (strchr(cav[0], '=')) { /* Skip command line macro defs */
1046 			i--;
1047 			continue;
1048 		}
1049 		if (!domake(cav[0]))	/* Make targets from command line */
1050 			failures++;
1051 	}
1052 
1053 	if (i == 0 && !domake((char *) NULL))	/* Make default target */
1054 		failures++;
1055 	if (failures && Failed) {
1056 		omake(Failed, TRUE);	/* Make .FAILED target */
1057 	} else {
1058 		omake(Done, TRUE);	/* Make .DONE target */
1059 	}
1060 #ifdef	DEBUG
1061 	prmem();
1062 #endif
1063 	if (failures > 0)
1064 		comexit(1);
1065 	comexit(0);
1066 	return (0);		/* keep lint happy :-) */
1067 }
1068 
1069 /*
1070  * Check for old makefile systems without pattern matching rules.
1071  *
1072  * Old makefile systems only define simple suffix rules. Now that newer smake
1073  * releases support POSIX suffix rules, the makefile system will only work
1074  * if the makefile system uses pattern matching rules.
1075  * We may remove this function in 2005.
1076  */
1077 LOCAL void
check_old_makefiles()1078 check_old_makefiles()
1079 {
1080 	obj_t	*o;
1081 
1082 	if (Suffixes == NULL)	/* No/Empty .SUFFIXES, no compat problems */
1083 		return;
1084 	if (xssrules == 0)	/* Makefile did not define simple suff rule*/
1085 		return;
1086 	if (xpatrules)		/* New makefiles define pattern rules	   */
1087 		return;
1088 
1089 	/*
1090 	 * All makefiles from the Schily (SING) makefile system define
1091 	 * _UNIQ=.XxZzy-
1092 	 */
1093 	if ((o = objlook("_UNIQ", FALSE)) == NULL)
1094 		return;
1095 	if (!streql(".XxZzy-", o->o_list->l_obj->o_name))
1096 		return;
1097 
1098 	errmsgno(EX_BAD, "WARNING: this project uses an old version of the makefile system.\n");
1099 	comerrno(EX_BAD, "Update the makefiles or call 'smake -r'.\n");
1100 }
1101 
1102 /*
1103  * Read in and parse the makeflags we got from the MAKEFLAGS= environment var.
1104  * MAKEFLAGS= may be:
1105  *
1106  * -	"et..."			Only option letters.
1107  *				No space and no macro definitions.
1108  * -	"NAME=value..."		Only a list of macro definitions (like a
1109  *				make command line).
1110  * -	"-et..."		Options as they appear on the command line.
1111  *				Space and multiple '-' are allowed.
1112  *	"-et -- NAME=value..."	A complete make command line (except
1113  *				-f filename options and target arguments).
1114  * BSD make:
1115  *
1116  * -	" NAME=value..."	Only a list of macro definitions.
1117  *
1118  * -	" -e -t"		Only options.
1119  *
1120  * -	" -e -t NAME=value..."	A complete make command line.
1121  *
1122  * SunPro Make:
1123  *
1124  *	"-et  NAME=value..."	A complete make command line.
1125  */
1126 LOCAL void
getmakeflags()1127 getmakeflags()
1128 {
1129 	int	MFsave = Mfileindex;
1130 	char	*mf = getenv(Makeflags);
1131 	BOOL	hasdash = FALSE;
1132 
1133 	if (!mf || *mf == '\0')	/* No MAKEFLAGS= or empty MAKEFLAGS=	*/
1134 		return;
1135 	while (*mf == ' ')
1136 		mf++;
1137 
1138 	Mfileindex = MF_IDX_ENVIRON;	/* Index 1 Environment vars */
1139 	if (*mf != '-') {	/* Only macros if does not start with '-'*/
1140 		char *p = nextmakemac(mf);	/* Next unescaped ' '    */
1141 		char *eql = strchr(mf, '=');
1142 
1143 		/*
1144 		 * Be gracious to non POSIX make programs like 'GNUmake' which
1145 		 * may have "e -- MAKE=smake" in the MAKEFLAGS environment.
1146 		 * The correct string would rather be "-e -- MAKE=smake".
1147 		 */
1148 		if (eql != NULL && (p == NULL || eql < p)) {
1149 			/*
1150 			 * No options at all, only cmdline macros.
1151 			 *
1152 			 * The content returned from getenv("MAKEFLAGS")
1153 			 * has been reported to change on DJGPP.
1154 			 * We need to use strdup() to keep it stable.
1155 			 */
1156 			MFCmdline = strdup(mf);
1157 			if (MFCmdline == NULL)
1158 				MFCmdline = mf;
1159 			goto out;	/* Allow debug prints */
1160 		}
1161 	} else {
1162 		hasdash = TRUE;
1163 	}
1164 
1165 	while (*mf) {
1166 		switch (*mf) {
1167 
1168 		case ' ': {
1169 				char	*p = mf;
1170 
1171 				while (*p == ' ')
1172 					p++;
1173 
1174 				if (*p != '-') {	/* May be a macro */
1175 					if (hasdash) {
1176 						mf = p;
1177 						goto macs;
1178 					}
1179 					break;		/* Ignore blanks */
1180 				}
1181 				mf = p;			/* Starts with '-' */
1182 			}
1183 			/* FALLTHRU */
1184 
1185 		case '-':		/* look for " -- " separator */
1186 			if (mf[1] != '-')
1187 				break;	/* Ignore single '-' */
1188 
1189 			if (mf[2] != ' ') {
1190 				char *p = nextmakemac(mf);
1191 
1192 				errmsgno(EX_BAD,
1193 					"Found illegal option '%s' in MAKEFLAGS.\n",
1194 					mf);
1195 				if (p != NULL) {
1196 					size_t	d = p - mf;
1197 					if (d > 50)
1198 						d = 50;
1199 					errmsgno(EX_BAD,
1200 					"Skipping illegal option '%.*s'.\n",
1201 						(int)d, mf);
1202 					mf = p;
1203 					break;
1204 				} else {
1205 					errmsgno(EX_BAD,
1206 						"Ignoring illegal option '%s'.\n",
1207 						mf);
1208 				}
1209 				goto out; /* Allow debug prints */
1210 			}
1211 			/*
1212 			 * The content returned from getenv("MAKEFLAGS")
1213 			 * has been reported to change on DJGPP.
1214 			 * We need to use strdup() to keep it stable.
1215 			 */
1216 			mf += 3;
1217 		macs:
1218 			MFCmdline = strdup(mf);
1219 			if (MFCmdline == NULL)
1220 				MFCmdline = mf;
1221 			goto out;	/* Allow debug prints */
1222 
1223 		case 'D':		/* Display makefile */
1224 			Dmake++;
1225 			break;
1226 
1227 		case 'd':		/* Debug */
1228 			Debug++;
1229 			break;
1230 
1231 		case 'X':		/* XDebug */
1232 			XDebug++;
1233 			break;
1234 
1235 		case 'a':
1236 			Aflag = TRUE;	/* Do not run setup_arch() */
1237 			break;
1238 
1239 		case 'e':		/* Environment overrides vars */
1240 			Eflag = TRUE;
1241 			break;
1242 
1243 		case 'i':		/* Ignore errors from cmds */
1244 			Iflag = TRUE;
1245 			break;
1246 
1247 		case 'k':		/* Ignore target errors */
1248 			Kflag = TRUE;
1249 			break;
1250 
1251 		case 'N':		/* Ignore no Source on dep. */
1252 			NSflag = TRUE;
1253 			break;
1254 
1255 		case 'n':		/* Do not exec any commands */
1256 			Nflag = TRUE;
1257 			break;
1258 
1259 		case 'P':		/* POSIX mode */
1260 			posixmode = TRUE;
1261 			break;
1262 
1263 		case 'p':		/* Print macros/targets */
1264 			Print = TRUE;
1265 			break;
1266 
1267 		case 'q':		/* Question */
1268 			Qflag = TRUE;
1269 			break;
1270 
1271 		case 'r':		/* Turn off internal Rules */
1272 			Rflag = TRUE;
1273 			break;
1274 
1275 		case 's':		/* Silent */
1276 			Sflag = TRUE;
1277 			break;
1278 
1279 		case 'S':		/* Stop on error (opposite of -k) */
1280 			Stopflag = TRUE;
1281 			break;
1282 
1283 		case 't':		/* Touch */
1284 			Tflag = TRUE;
1285 			break;
1286 
1287 		case 'W':		/* Extra Warnings */
1288 			Do_Warn++;
1289 			break;
1290 
1291 		case 'w':		/* No Warnings */
1292 			No_Warn = TRUE;
1293 			break;
1294 
1295 		case 'Z':		/* Print includes */
1296 			Prdep = TRUE;
1297 			break;
1298 		}
1299 		mf++;
1300 	}
1301 out:
1302 	/*
1303 	 * As this is called before we call getargs(), Debug may only be true
1304 	 * if the 'd' option is present in the MAKEFLAGS environment.
1305 	 */
1306 	if (Debug > 0)
1307 		error("Read MAKEFLAGS:  '%s'\n", getenv(Makeflags));
1308 
1309 	Mfileindex = MFsave;
1310 }
1311 
1312 /*
1313  * Parse a list of macro=value command line macros from the
1314  * MAKEFLAGS= environment and set up the macro in the make tree.
1315  * If gbuf is NULL, read_mac() is parse only.
1316  */
1317 LOCAL void
read_makemacs()1318 read_makemacs()
1319 {
1320 	register char	*mf = MFCmdline;
1321 	register char	*p;
1322 		int	MFsave = Mfileindex;
1323 
1324 	if (mf == NULL)
1325 		return;
1326 
1327 	Mfileindex = MF_IDX_ENVIRON;	/* Index 1 Environment vars */
1328 	while (*mf) {
1329 		p = nextmakemac(mf);
1330 		if (p == NULL) {	/* No other macro def follows */
1331 			if (!read_mac(mf)) {
1332 				errmsgno(EX_BAD,
1333 					"Bad MAKEFLAGS= environment '%s'.\n",
1334 					getenv(Makeflags));
1335 				*mf = '\0';
1336 			}
1337 			break;
1338 		} else {		/* Need to temporarily null terminate */
1339 			*p = '\0';
1340 			if (!read_mac(mf)) {
1341 				errmsgno(EX_BAD,
1342 					"Bad MAKEFLAGS= environment '%s'.\n",
1343 					getenv(Makeflags));
1344 				ovstrcpy(mf, &p[1]);
1345 			} else {
1346 				*p = ' ';
1347 				mf = &p[1];
1348 			}
1349 		}
1350 	}
1351 	Mfileindex = MFsave;
1352 }
1353 
1354 /*
1355  * Find next un-escaped blank (' ') which is a separator
1356  * for a list of macro=value items.
1357  */
1358 LOCAL char *
nextmakemac(s)1359 nextmakemac(s)
1360 	char	*s;
1361 {
1362 	while (*s) {
1363 		if (*s == '\\') {	/* escaped character	*/
1364 			if (*++s == '\0')
1365 				return (NULL);
1366 		} else if (*s == ' ') {	/* un-escaped space	*/
1367 			return (s);
1368 		}
1369 		s++;
1370 	}
1371 	return (NULL);
1372 }
1373 
1374 /*
1375  * Remove the escapes that have been introduced before the name=value
1376  * lists are put together into the MAKEFLAGS= environment.
1377  * Then parse the result as a string.
1378  * If gbuf is NULL, read_mac() is parse only.
1379  */
1380 LOCAL BOOL
read_mac(mf)1381 read_mac(mf)
1382 	char	*mf;
1383 {
1384 	char	*omf = mf;
1385 	char	macdef[NAMEMAX*2+1];
1386 	char	*p;
1387 
1388 	p = macdef;
1389 	while (*mf) {
1390 		if (p >= &macdef[NAMEMAX*2])
1391 			break;
1392 		/*
1393 		 * Only remove those escape sequences, that we created.
1394 		 * This is "\\" and "\ ".
1395 		 */
1396 		if (mf[0] == '\\' && (mf[1] == '\\' || mf[1] == ' '))
1397 			mf++;
1398 		*p++ = *mf++;
1399 	}
1400 	*p = '\0';
1401 
1402 	if (macdef[0] == '\0')			/* Ignore empty definition */
1403 		return (TRUE);
1404 	if (strchr(macdef, '=') == NULL) {	/* Check if it is a macro def*/
1405 		errmsgno(EX_BAD,
1406 			"Found illegal macro definition '%s' in MAKEFLAGS.\n",
1407 			macdef);
1408 		errmsgno(EX_BAD, "The raw macro definition was '%s'.\n", omf);
1409 		return (FALSE);
1410 	}
1411 
1412 	if (gbuf == NULL)			/* Parse only and kill	   */
1413 		return (TRUE);			/* unwanted content	   */
1414 
1415 	Mflags |= F_READONLY;
1416 	readstring(macdef, Makeflags);
1417 	Mflags &= ~F_READONLY;
1418 	return (TRUE);
1419 }
1420 
1421 /*
1422  * Prepare the MAKEFLAGS= environment for export.
1423  */
1424 LOCAL void
setmakeflags()1425 setmakeflags()
1426 {
1427 		/*
1428 		 * MAKEFLAGS=-	12 bytes incl '\0'
1429 		 * 4 x 8 bytes=	32 bytes
1430 		 * 16 flags	16 bytes
1431 		 * '-- '	 3 bytes
1432 		 * =====================
1433 		 *		62 bytes
1434 		 */
1435 #define	MAKEENV_SIZE_STATIC	64
1436 static	char	makeenv[MAKEENV_SIZE_STATIC];
1437 	char	*p;
1438 	int	i;
1439 
1440 	p = strcatl(makeenv, Makeflags, (char *)NULL);
1441 	*p++ = '=';
1442 	*p++ = '-';		/* Posix make includes '-'	*/
1443 				/* "MAKEFLAGS=-" 12 incl. '\0'	*/
1444 
1445 	i = Dmake;		/* Display makefile */
1446 	if (i > 8)
1447 		i = 8;
1448 	while (--i >= 0)
1449 		*p++ = 'D';
1450 
1451 	i = Debug;		/* Debug */
1452 	if (i > 8)
1453 		i = 8;
1454 	while (--i >= 0)
1455 		*p++ = 'd';
1456 
1457 	i = Do_Warn;		/* Do_Wan - Extra Warnings */
1458 	if (i > 8)
1459 		i = 8;
1460 	while (--i >= 0)
1461 		*p++ = 'W';
1462 
1463 	i = XDebug;		/* XDebug */
1464 	if (i > 8)
1465 		i = 8;
1466 	while (--i >= 0)
1467 		*p++ = 'X';
1468 
1469 	if (Aflag)		/* Do not run setup_arch() */
1470 		*p++ = 'a';
1471 	if (Eflag)		/* Environment overrides vars */
1472 		*p++ = 'e';
1473 	if (Iflag)		/* Ignore errors from cmds */
1474 		*p++ = 'i';
1475 	if (Kflag)		/* Ignore target errors */
1476 		*p++ = 'k';
1477 	if (NSflag)		/* Ignore no Source on dep. */
1478 		*p++ = 'N';
1479 	if (Nflag)		/* Do not exec any commands */
1480 		*p++ = 'n';
1481 	if (posixmode)		/* POSIX mode */
1482 		*p++ = 'P';
1483 	if (Print)		/* Print macros/targets */
1484 		*p++ = 'p';
1485 	if (Qflag)		/* Question */
1486 		*p++ = 'q';
1487 	if (Rflag)		/* Turn off internal Rules */
1488 		*p++ = 'r';
1489 	if (Sflag)		/* Silent */
1490 		*p++ = 's';
1491 	if (Stopflag)		/* Stop on error (opposite of -k) */
1492 		*p++ = 'S';
1493 	if (Tflag)		/* Touch */
1494 		*p++ = 't';
1495 	if (No_Warn)		/* No Warnings */
1496 		*p++ = 'w';
1497 	if (Prdep)		/* Print includes */
1498 		*p++ = 'Z';
1499 
1500 	if (p - makeenv == 11)	/* Empty flags, remove '-' */
1501 		--p;
1502 	*p = '\0';
1503 	define_var(Make_Flags, &makeenv[10]);	/* MAKE_FLAGS= ... */
1504 	doexport(Make_Flags);
1505 	setmakeenv(makeenv, p);			/* Add cmdline macs */
1506 }
1507 
1508 /*
1509  * Strip out macro defs inherited from MAKELAGS, that will be overwritten
1510  * by command line macro defs.
1511  * Return new write pointer at end of string.
1512  */
1513 LOCAL char *
stripmacros(macbase,new)1514 stripmacros(macbase, new)
1515 	char	*macbase;
1516 	char	*new;
1517 {
1518 	char	*p = strchr(new, '=');
1519 	char	*p2;
1520 
1521 	if (p == NULL)				/* Paranoia */
1522 		return (macbase + strlen(macbase));
1523 
1524 	do {
1525 		p2 = nextmakemac(macbase);	/* Find next macro delim */
1526 
1527 		if (strncmp(macbase, new, p - new) == 0) {
1528 			/*
1529 			 * Got a match, need to remove this entry.
1530 			 */
1531 			if (p2 == NULL) {	/* This is the only, zap out */
1532 				*macbase = '\0';
1533 			} else {		/* Copy rest over current */
1534 				ovstrcpy(macbase, &p2[1]);
1535 			}
1536 		} else if (p2) {		/* Continue with next extry */
1537 			macbase = &p2[1];
1538 		}
1539 	} while (p2);
1540 	return (macbase + strlen(macbase));
1541 }
1542 
1543 /*
1544  * Add the actual command line macro definitions to the MAKEFLAGS= string
1545  * and then putenv() the result.
1546  */
1547 LOCAL void
setmakeenv(envbase,envp)1548 setmakeenv(envbase, envp)
1549 	char	*envbase;
1550 	char	*envp;
1551 {
1552 	register int	i;
1553 	register int	l;
1554 	register int	len = 0;
1555 	register char	*p;
1556 	register char	*macbase;
1557 
1558 	if (Cmdlinecount == 0 && (MFCmdline == 0 || *MFCmdline == '\0')) {
1559 		/*
1560 		 * No command line macros and no inherited command line
1561 		 * macros from MAKEFLAGS, so just call putenv() and return.
1562 		 */
1563 		put_env(envbase);
1564 		return;
1565 	}
1566 
1567 	if ((envp - envbase) > 10) {	/* envbase[] is currently not empty */
1568 		strcpy(envp, " -- ");	/* we need a separator to the flags */
1569 
1570 		envp += 4;
1571 		*envp = '\0';
1572 	}
1573 	if (MFCmdline)			/* Add one for '\0' or ' ' at end */
1574 		len = strlen(MFCmdline) + 1;
1575 
1576 	for (i = 0; i < Cmdlinecount; i++) {
1577 		p = CmdLDefs[i];
1578 		while (*p) {
1579 			if (*p == '\\' || *p == ' ')
1580 				len++;
1581 			len++;
1582 			p++;
1583 		}
1584 		len += 1;		/* Add one for '\0' or ' ' at end */
1585 	}
1586 
1587 	l = strlen(envbase) + len + 1;	/* Add one (see stripmacro comment) */
1588 	if (l > MAKEENV_SIZE_STATIC) {
1589 		p = malloc(l);
1590 		strcpy(p, envbase);
1591 		envp = p + (envp - envbase);
1592 		envbase = p;
1593 	}
1594 
1595 	macbase = envp;
1596 	if (MFCmdline) {
1597 		for (p = MFCmdline; *p; )
1598 			*envp++ = *p++;
1599 		*envp++ = ' ';
1600 	}
1601 	*envp = '\0';
1602 
1603 	for (i = 0; i < Cmdlinecount; i++) {
1604 		p = CmdLDefs[i];
1605 		envp = stripmacros(macbase, p);
1606 		while (*p) {
1607 			if (*p == '\\' || *p == ' ')
1608 				*envp++ = '\\';
1609 			*envp++ = *p++;
1610 		}
1611 		*envp++ = ' ';
1612 		*envp = '\0';	/* Needed for stripmacros */
1613 	}			/* But overshoots by one  */
1614 	*--envp = '\0';
1615 	put_env(envbase);
1616 	define_var(Make_Macs, macbase);		/* MAKE_MACS= ... */
1617 	doexport(Make_Macs);
1618 }
1619 
1620 #ifdef	tos
1621 #		include "osbind.h"
1622 #endif
1623 
1624 /*
1625  * Move a target file to ObjDir.
1626  *
1627  * Returns:
1628  *	FALSE		Failure
1629  *	TRUE		OK, but no file was moved
1630  *	TRUE + 1	OK, but file was not found
1631  *	TRUE + 2	OK and file actually moved
1632  */
1633 EXPORT int
move_tgt(from)1634 move_tgt(from)
1635 	register obj_t	*from;
1636 {
1637 	date_t	fromtime;
1638 	int	code;
1639 	char	_objname[TYPICAL_NAMEMAX];
1640 	char	*objname = NULL;
1641 	BOOL	ret = TRUE;
1642 
1643 	/*
1644 	 * Move only if:
1645 	 *	objdir to corresponding srcdir exists
1646 	 *	target is known in Makefile
1647 	 */
1648 	if ((ObjDir == NULL && from->o_level == OBJLEVEL) ||
1649 						from->o_level < OBJLEVEL)
1650 		return (TRUE);
1651 
1652 	if (strchr(from->o_name, SLASH)) /* Only move from current directory */
1653 		return (TRUE);
1654 
1655 	fromtime = gftime(from->o_name);
1656 	if (fromtime == 0)		/* Nothing to move found */
1657 		return (TRUE+1);
1658 
1659 	if (Debug > 3) error("move: from->o_level: %d\n", from->o_level);
1660 	if ((objname = build_path(from->o_level, from->o_name, from->o_namelen,
1661 					_objname, sizeof (_objname))) == NULL)
1662 		return (FALSE);
1663 	if (!Sflag || Nflag)
1664 		gtprintf("%smove %s %s\n", posixmode?"\t":"...", from->o_name, objname);
1665 	ret = TRUE + 2;
1666 	if (Nflag) {
1667 		goto out;
1668 	}
1669 
1670 	if ((from->o_name == objname) ||
1671 	    (gfileid(from->o_name) == gfileid(objname))) {
1672 		errmsgno(EX_BAD, "Will not move '%s' to itself.\n",
1673 							from->o_name);
1674 		ret = TRUE;
1675 		goto out;
1676 	}
1677 #	ifdef	tos
1678 	unlink(objname);
1679 	if ((code = Frename(0, from->o_name, objname)) < 0) {
1680 		if (code == EXDEV) {
1681 			code = copy_file(from->o_name, objname);
1682 			if (unlink(from->o_name) < 0)
1683 				errmsg("Can't remove old name '%s'.\n",
1684 								from->o_name);
1685 		} else {
1686 			errmsgno(-code, "Can't rename '%s' to '%s'.\n",
1687 						from->o_name, objname);
1688 		}
1689 	}
1690 	if (code < 0) {
1691 		ret = FALSE;
1692 		goto out;
1693 	}
1694 #	else
1695 	if ((code = rename(from->o_name, objname)) < 0) {
1696 		if (geterrno() == EXDEV) {
1697 			if (rmdir(objname) < 0 && geterrno() == ENOTDIR)
1698 				unlink(objname);
1699 			code = copy_file(from->o_name, objname);
1700 			if (unlink(from->o_name) < 0)
1701 				errmsg("Can't remove old name '%s'.\n",
1702 							from->o_name);
1703 		} else {
1704 			errmsg("Can't rename '%s' to '%s'.\n",
1705 						from->o_name, objname);
1706 		}
1707 	}
1708 	if (code < 0) {
1709 		ret = FALSE;
1710 		goto out;
1711 	}
1712 #endif	/* tos */
1713 out:
1714 	if (objname != NULL && objname != from->o_name && objname != _objname)
1715 		free(objname);
1716 	return (ret);
1717 }
1718 
1719 /*
1720  * Copy File if we cannot rename the file.
1721  */
1722 #ifdef	tos
1723 LOCAL int
copy_file(from,objname)1724 copy_file(from, objname)
1725 	char	*from;
1726 	char	*objname;
1727 {
1728 	int	fin;
1729 	int	fout;
1730 	int	cnt = -1;
1731 
1732 	if ((fin = open(from, O_RDONLY)) < 0)
1733 		errmsg("Can't open '%s'.\n", from);
1734 	else {
1735 		if ((fout = creat(objname, 0666)) < 0)
1736 			errmsg("Can't create '%s'.\n", objname);
1737 		else {
1738 			while ((cnt = read(fin, gbuf, gbufsize)) > 0) {
1739 				if (write(fout, gbuf, cnt) != cnt) {
1740 					errmsg("Write error on '%s'.\n",
1741 								objname);
1742 					close(fout);
1743 					close(fin);
1744 					return (-1);
1745 				}
1746 			}
1747 			if (cnt < 0)
1748 				errmsg("Read error on '%s'.\n", from);
1749 			close(fout);
1750 		}
1751 		close(fin);
1752 	}
1753 	return (cnt);
1754 }
1755 #else
1756 LOCAL int
copy_file(from,objname)1757 copy_file(from, objname)
1758 	char	*from;
1759 	char	*objname;
1760 {
1761 	FILE	*fin;
1762 	FILE	*fout;
1763 	int	cnt = -1;
1764 
1765 	if ((fin = fileopen(from, "rub")) == 0)
1766 		errmsg("Can't open '%s'.\n", from);
1767 	else {
1768 		if ((fout = fileopen(objname, "wtcub")) == 0)
1769 			errmsg("Can't create '%s'.\n", objname);
1770 		else {
1771 			file_raise(fin, FALSE);
1772 			file_raise(fout, FALSE);
1773 			while ((cnt = fileread(fin, gbuf, gbufsize)) > 0) {
1774 				if (filewrite(fout, gbuf, cnt) < 0) {
1775 					errmsg("Write error on '%s'.\n",
1776 								objname);
1777 					fclose(fout);
1778 					fclose(fin);
1779 					return (-1);
1780 				}
1781 			}
1782 			if (cnt < 0)
1783 				errmsg("Read error on '%s'.\n", from);
1784 			fclose(fout);
1785 		}
1786 		fclose(fin);
1787 	}
1788 	return (cnt);
1789 }
1790 #endif
1791 
1792 /*
1793  * This function behaves similar to the UNIX 'touch' command.
1794  */
1795 EXPORT BOOL
touch_file(name)1796 touch_file(name)
1797 	char	*name;
1798 {
1799 	FILE	*f;
1800 	char	_objname[TYPICAL_NAMEMAX];
1801 	char	*objname = _objname;
1802 	size_t	objlen = sizeof (_objname);
1803 	char	*np = NULL;
1804 #ifndef	HAVE_UTIME
1805 	char	c;
1806 #endif
1807 
1808 again:
1809 	if (ObjDir == NULL)
1810 		objname = name;
1811 	else if (snprintf(objname, objlen, "%s%s%s", ObjDir,
1812 				slash, filename(name)) >= objlen) {
1813 		objlen = strlen(filename(name)) + ObjDirlen + slashlen + 1;
1814 		objname = np = ___realloc(np, objlen, "touch path");
1815 		goto again;
1816 	}
1817 #ifdef	__is_this_ok__
1818 	if (!gftime(objname))
1819 		snprintf(_objname, sizeof (_objname), name);
1820 #endif
1821 	if (!Sflag)
1822 		gtprintf("%stouch %s\n", posixmode?"\t":"...", objname);
1823 	if (Nflag > 0)
1824 		return (TRUE);
1825 	/*
1826 	 * No touch if make was called with -n.
1827 	 */
1828 	if ((f = fileopen(objname, "rwcub")) != (FILE *)NULL) {
1829 		file_raise(f, FALSE);
1830 #ifdef	HAVE_UTIME
1831 		utime(objname, NULL);
1832 #else
1833 		c = getc(f);
1834 		fileseek(f, (off_t)0);
1835 		putc(c, f);
1836 #endif
1837 		fclose(f);
1838 		if (np)
1839 			free(np);
1840 		return (TRUE);
1841 	}
1842 	if (np)
1843 		free(np);
1844 	return (FALSE);
1845 }
1846 
1847 #	include <schily/stat.h>
1848 #	define	STATBUF		struct stat
1849 
1850 /*
1851  * Get current time.
1852  */
1853 LOCAL date_t
gcurtime()1854 gcurtime()
1855 {
1856 	struct timespec	ts;
1857 	date_t		d;
1858 
1859 	getnstimeofday(&ts);
1860 	d = ts.tv_sec;
1861 #ifdef	USE_NSECS
1862 	d <<= NSEC_SHIFT;		/* Make space for nanoseconds */
1863 	d |= ts.tv_nsec;
1864 #endif
1865 	if (Debug > 1)
1866 		error("gcurtime() = %s (%llx)\n", prtime(d), (Llong)d);
1867 	return (d);
1868 }
1869 
1870 /*
1871  * Get a time that is in the future (as far as possible).
1872  */
1873 LOCAL date_t
gnewtime()1874 gnewtime()
1875 {
1876 	time_t	t;
1877 	date_t	d;
1878 
1879 	t = TYPE_MAXVAL(time_t);
1880 
1881 	/*
1882 	 * "t" is now the maximum positive number for type time_t.
1883 	 * In case of a 64 bit time_t, this is more than we can have in date_t
1884 	 * so we need to make the number small enough to have space for nsecs.
1885 	 */
1886 	d = t;
1887 #ifdef	USE_NSECS
1888 #if SIZEOF_DATE_T > SIZEOF_TIME_T
1889 	d <<= NSEC_SHIFT;		/* Make space for nanoseconds */
1890 #else
1891 	d >>= NSEC_SHIFT;		/* Shrink d to maximum time_t */
1892 	d <<= NSEC_SHIFT;		/* Make space for nanoseconds */
1893 #endif
1894 	d += 999999999;			/* Add maximum nanosecond value */
1895 #endif	/* USE_NSECS */
1896 
1897 	while (d == NOTIME || d == BADTIME ||
1898 			d == RECURSETIME || d == PHONYTIME) {
1899 		d--;
1900 	}
1901 
1902 /*printf("i: %d, %llu, %llx, %s\n", i, d, d, prtime(-3));*/
1903 
1904 	if (Debug > 1)
1905 		error("gnewtime() = %s (%llx)\n", prtime(d), (Llong)d);
1906 	return (d);
1907 }
1908 
1909 /*
1910  * Get the time of last modification for a file.
1911  * Cannot call it gmtime()
1912  */
1913 EXPORT date_t
gftime(file)1914 gftime(file)
1915 	char	*file;
1916 {
1917 	STATBUF	stbuf;
1918 	char	this_time[42];
1919 	char	cur_time[42];
1920 	date_t	d;
1921 
1922 	/*
1923 	 * XXX should we cache the file times?
1924 	 */
1925 /*#define	nonono__*/
1926 #ifdef	nonono__
1927 	obj_t	*o = objlook(file, FALSE);
1928 
1929 	if (o != NULL && VALIDTIME(o->o_date)) {
1930 		if (o->o_date != newtime)	/* Only if real time */
1931 			return (o->o_date);	/* Cached file time */
1932 	}
1933 #endif
1934 
1935 	stbuf.st_mtime = NOTIME;
1936 	if (stat(file, &stbuf) < 0) {
1937 		/*
1938 		 * GNU libc.6 destroys st_mtime
1939 		 */
1940 		d = NOTIME;
1941 	} else {
1942 #ifdef	USE_NSECS
1943 		long	nsecs;
1944 #endif
1945 		d = stbuf.st_mtime;
1946 #ifdef	USE_NSECS
1947 		d <<= NSEC_SHIFT;
1948 		nsecs = stat_mnsecs(&stbuf);
1949 #if	!defined(HAVE_UTIMENS) && !defined(HAVE_UTIMENSAT)
1950 		/*
1951 		 * If the current platform does not support to willfully
1952 		 * set full nanosecond values, but only microseconds, we
1953 		 * compare time stamps only with microsecond resolution.
1954 		 */
1955 		nsecs -= nsecs % 1000;
1956 #endif
1957 		d |= nsecs;
1958 #endif
1959 		/*
1960 		 * Make sure that the time for an existing file is not
1961 		 * in the list of special time stamps.
1962 		 */
1963 		while (d == NOTIME || d == BADTIME ||
1964 		    d == RECURSETIME || d == MAKETIME || d == PHONYTIME) {
1965 			d++;
1966 		}
1967 #ifdef	nonono__
1968 		if (o == NULL) {
1969 			o = objlook(file, TRUE);
1970 			o->o_date = d;
1971 		}
1972 #endif
1973 	}
1974 
1975 	if (Debug > 3)
1976 		error("gftime(%s) = %s\n", file, prtime(d));
1977 
1978 	/*
1979 	 * If the time stamp retrieved by stat() is more than 5 seconds
1980 	 * ahead of our start time, we check for a possible time skew between
1981 	 * this machine and it's fileserver.
1982 	 */
1983 	if (d > (curtime + (5*DATESECS))) {
1984 		date_t	xcurtime;
1985 
1986 		xcurtime = gcurtime();
1987 		if (d <= (xcurtime + (5*DATESECS))) {
1988 			/*
1989 			 * We run for more than 5 seconds already and the
1990 			 * file's time stamp is not more than 5 seconds ahead
1991 			 * of the current time. Return silently.
1992 			 */
1993 			curtime = xcurtime;
1994 			return (d);
1995 		}
1996 		strncpy(this_time, prtime(d), sizeof (this_time));
1997 		this_time[sizeof (this_time)-1] = '\0';
1998 		strncpy(cur_time, prtime(curtime), sizeof (cur_time));
1999 		cur_time[sizeof (cur_time)-1] = '\0';
2000 		errmsgno(EX_BAD,
2001 			"WARNING: '%s' has modification time in the future (%s > %s).\n",
2002 			file, this_time, cur_time);
2003 	}
2004 	return (d);
2005 }
2006 
2007 /*
2008  * Check if file is a directory.
2009  */
2010 LOCAL BOOL
isdir(file)2011 isdir(file)
2012 	char	*file;
2013 {
2014 	STATBUF	stbuf;
2015 
2016 	/*
2017 	 * It is safe to assume that "." is a directory.
2018 	 */
2019 	if (file[0] == '.' && file[1] == '\0')
2020 		return (TRUE);
2021 
2022 	if (stat(file, &stbuf) < 0)
2023 		return (TRUE);
2024 	if ((stbuf.st_mode&S_IFMT) == S_IFDIR)
2025 		return (TRUE);
2026 	return (FALSE);
2027 }
2028 
2029 /*
2030  * Get a unique number for a file to prevent moving targets to themselves.
2031  * XXX inode number is now long !!!
2032  */
2033 EXPORT Llong
gfileid(file)2034 gfileid(file)
2035 	char	*file;
2036 {
2037 	STATBUF stbuf;
2038 	Llong	result;
2039 
2040 	/*
2041 	 * Cache .OBJDIR and ".".
2042 	 */
2043 	if (file == ObjDir) {
2044 		if (ObjDirfid != 0)
2045 			return (ObjDirfid);
2046 	} else if (file[0] == '.' && file[1] == '\0') {
2047 		if (dotfid != 0)
2048 			return (dotfid);
2049 	}
2050 
2051 	/*
2052 	 * Setup a unique default. In case stat() will fail.
2053 	 */
2054 	stbuf.st_ino = (ino_t) (long) file;
2055 	stbuf.st_dev = 0;
2056 	if (stat(file, &stbuf) < 0) {
2057 		/*
2058 		 * GNU libc.6 destroys st_mtime
2059 		 * Paranoia .... we fall back here too.
2060 		 */
2061 		stbuf.st_ino = (ino_t) (long) file;
2062 		stbuf.st_dev = 0;
2063 	}
2064 #if	SIZEOF_LLONG > 4
2065 	result = stbuf.st_dev;
2066 	result <<= 32;
2067 	result |= stbuf.st_ino;
2068 #else
2069 	result = stbuf.st_dev;
2070 	result <<= 16;
2071 	result |= stbuf.st_ino;
2072 #endif
2073 
2074 	if (file == ObjDir)
2075 		ObjDirfid = result;
2076 	else if (file[0] == '.' && file[1] == '\0')
2077 		dotfid = result;
2078 
2079 	if (Debug > 3)
2080 		error("gfileid: %s %lld\n", file, result);
2081 	return (result);
2082 }
2083 
2084 /*
2085  * Transfer UNIX time stamps into human readable names.
2086  * Take care of our "special timestamps".
2087  */
2088 EXPORT char *
prtime(date)2089 prtime(date)
2090 	date_t	date;
2091 {
2092 	char	*s;
2093 	time_t	t;
2094 	char	nsbuf[20];
2095 	long	nsecs;
2096 
2097 	if (date == (date_t)0)
2098 		return ("File does not exist");
2099 	if (date == BADTIME)
2100 		return ("File could not be made");
2101 	if (date == RECURSETIME)
2102 		return ("Recursive dependencies");
2103 	if (date == MAKETIME)
2104 		return ("File is currently being made");
2105 	if (date == PHONYTIME)
2106 		return ("File is phony");
2107 	if (date == newtime)
2108 		return ("Younger than any file");
2109 
2110 #ifdef	USE_NSECS
2111 	t = date >> NSEC_SHIFT;
2112 #else
2113 	t = date;
2114 #endif
2115 	s = ctime(&t);
2116 	if (s == NULL)
2117 		strcpy(s, "<time range error>");
2118 	else
2119 		s[strlen(s)-1] = '\0';
2120 #ifdef	USE_NSECS
2121 	nsecs = date & 0x3fffffff;
2122 	snprintf(nsbuf, sizeof (nsbuf), ".%9.9ld", nsecs);
2123 	strcat(s, nsbuf);
2124 #endif
2125 	return (s);
2126 }
2127 
2128 /*
2129  * Our general signal handler. Does some needed clean up and includes
2130  * workarounds for buggy OS like Linux.
2131  */
2132 LOCAL void
handler(signo)2133 handler(signo)
2134 	int	signo;
2135 {
2136 	char	*name;
2137 #if	defined(__linux__) || defined(__linux) || \
2138 	defined(SHELL_IS_BASH) || defined(BIN_SHELL_IS_BASH)
2139 #if	defined(HAVE_SIGNAL) && defined(HAVE_KILL) && \
2140 			defined(SIG_IGN) && defined(SIGKILL)
2141 	job	*jobp;
2142 	int	i;
2143 #endif
2144 #endif
2145 
2146 	signal(signo, handler);
2147 	errmsgno(EX_BAD, "Got signal %d\n", signo);
2148 	if (!curtarget)
2149 		goto out;
2150 
2151 	errmsgno(EX_BAD, "Current target is: %s precious: %d phony: %d\n",
2152 			curtarget->o_name,
2153 			isprecious(curtarget),
2154 			isprecious(curtarget));
2155 
2156 /*	while(wait(0) >= 0) */
2157 /*		;*/
2158 	/*
2159 	 * Keine Bibliotheken
2160 	 * Kein -t, -q etc.
2161 	 */
2162 	if (Tflag || Print || Qflag || Nflag)
2163 		goto out;
2164 	if (isprecious(curtarget))
2165 		goto out;
2166 	if (isphony(curtarget))
2167 		goto out;
2168 
2169 	name = curtarget->o_name;
2170 
2171 	if (isdir(name)) {
2172 		error("*** %s not removed.\n", name);
2173 		goto out;
2174 	}
2175 	if (unlink(name) >= 0) {
2176 		error("*** %s removed.\n", name);
2177 	} else {
2178 		errmsg("*** %s could not be removed.\n", name);
2179 	}
2180 	/*
2181 	 * Test ob ObjDir/name existiert und neuer als vorher ist.
2182 	 */
2183 
2184 out:
2185 
2186 #if	defined(__linux__) || defined(__linux) || \
2187 	defined(SHELL_IS_BASH) || defined(BIN_SHELL_IS_BASH)
2188 #if	defined(HAVE_SIGNAL) && defined(HAVE_KILL) && \
2189 			defined(SIG_IGN) && defined(SIGKILL)
2190 	/*
2191 	 * Linux signal handling is broken. This is caused by a bug in 'bash'.
2192 	 * Bash does jobcontrol even if called as "sh -ce 'command'".
2193 	 * This is illegal. Only the foreground (make) process and with some
2194 	 * bash versions the descendant 'make' processes are killed.
2195 	 * The following code tries to kill the others too.
2196 	 */
2197 	signal(signo, SIG_IGN);		/* Make us immune to death ;-)	*/
2198 
2199 	/*
2200 	 * First shoot everyone into the foot.
2201 	 */
2202 	for (jobp = jobs, i = maxjobs; --i >= 0; jobp++) {
2203 		pid_t	pid = jobp->j_pid;
2204 
2205 		if (pid == 0)
2206 			continue;
2207 		kill(pid, signo);	/* Kill bash that is our child	*/
2208 		kill(-pid, signo);	/* Kill possible bash children	*/
2209 	}
2210 	kill(-getpgrp(), signo);	/* Kill our process group	*/
2211 
2212 	/*
2213 	 * Now shoot everyone into the head.
2214 	 */
2215 	for (jobp = jobs, i = maxjobs; --i >= 0; jobp++) {
2216 		pid_t	pid = jobp->j_pid;
2217 
2218 		if (pid == 0)
2219 			continue;
2220 		kill(pid, SIGKILL);	/* Kill bash that is our child	*/
2221 		kill(-pid, SIGKILL);	/* Kill possible bash children	*/
2222 	}
2223 	kill(-getpgrp(), SIGKILL);	/* Kill our process group	*/
2224 #endif
2225 #endif
2226 	comexit(signo);
2227 }
2228 
2229 LOCAL void
exhandler(excode,arg)2230 exhandler(excode, arg)
2231 	int	excode;
2232 	void	*arg;
2233 {
2234 	/*
2235 	 * Ausgabe wenn:
2236 	 *
2237 	 *	-	excode != 0 && Mlevel > 0
2238 	 *	-	Debug > 0   && Mlevel > 0
2239 	 */
2240 	if ((Debug <= 1 && excode == 0) || Mlevel <= 0)
2241 		return;
2242 
2243 	errmsgno(EX_BAD, "Leaving  '%s'[%d] from directory '%s'\n",
2244 			(char *)arg, Mlevel, curwdir());
2245 	if (default_tgt != NULL)
2246 		errmsgno(EX_BAD,
2247 			"Default commandline target: '%s'\n", default_tgt->o_name);
2248 	errmsgno(EX_BAD, "Doing                       exit(%d)\n", excode);
2249 }
2250 
2251 /*
2252  * Return current working directory in an allocated string.
2253  */
2254 EXPORT	char *
curwdir()2255 curwdir()
2256 {
2257 	static	char	*wdir;
2258 		char	wd[MAXPATHNAME + 1];
2259 
2260 	if (wdir != NULL)
2261 		return (wdir);
2262 
2263 	if (getcwd(wd, MAXPATHNAME) == NULL) {
2264 		wd[0] = '/';
2265 		wd[1] = '\0';
2266 	}
2267 	wdir = malloc(strlen(wd)+1);
2268 	if (wdir == NULL)
2269 		comerr("Cannot malloc working dir.\n");
2270 	strcpy(wdir, wd);
2271 	define_var("CURDIR", wdir);
2272 	return (wdir);
2273 }
2274 
2275 /*
2276  * Search for the defaults.smk file in the PATH of the user.
2277  * Assume that the file is ... bin/../share/lib/smake/defaults.smk
2278  */
2279 LOCAL char *
getdefaultsfile()2280 getdefaultsfile()
2281 {
2282 	return (searchfileinpath("share/lib/smake/defaults.smk",
2283 							R_OK, TRUE, NULL));
2284 }
2285 
2286 LOCAL int
put_env(new)2287 put_env(new)
2288 	char	*new;
2289 {
2290 	if (strncmp(new, "SHELL=", 6) == 0)
2291 		return (0);		/* Never export SHELL */
2292 
2293 	return (putenv(new));
2294 }
2295 
2296 LOCAL int
unset_env(name)2297 unset_env(name)
2298 	char	*name;
2299 {
2300 	if (strcmp(name, "SHELL") == 0)
2301 		return (0);		/* Never unexport SHELL */
2302 
2303 	unsetenv(name);			/* OpenBSD deviates and returns void */
2304 	return (0);
2305 }
2306