1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2019, Joyent, Inc.
26 * Copyright 2019 RackTop Systems.
27 * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
28 */
29
30/*
31 *	main.cc
32 *
33 *	make program main routine plus some helper routines
34 */
35
36/*
37 * Included files
38 */
39#include <bsd/bsd.h>		/* bsd_signal() */
40
41
42#include <locale.h>		/* setlocale() */
43#include <libgen.h>
44#include <mk/defs.h>
45#include <mksh/macro.h>		/* getvar() */
46#include <mksh/misc.h>		/* getmem(), setup_char_semantics() */
47
48#include <pwd.h>		/* getpwnam() */
49#include <setjmp.h>
50#include <signal.h>
51#include <stdlib.h>
52#include <sys/errno.h>		/* ENOENT */
53#include <sys/stat.h>		/* fstat() */
54#include <fcntl.h>		/* open() */
55
56#	include <sys/systeminfo.h>	/* sysinfo() */
57
58#include <sys/types.h>		/* stat() */
59#include <sys/wait.h>		/* wait() */
60#include <unistd.h>		/* execv(), unlink(), access() */
61#include <vroot/report.h>	/* report_dependency(), get_report_file() */
62
63// From read2.cc
64extern	Name		normalize_name(register wchar_t *name_string, register int length);
65
66extern void job_adjust_fini();
67
68
69/*
70 * Defined macros
71 */
72#define	LD_SUPPORT_ENV_VAR	"SGS_SUPPORT_32"
73#define	LD_SUPPORT_ENV_VAR_32	"SGS_SUPPORT_32"
74#define	LD_SUPPORT_ENV_VAR_64	"SGS_SUPPORT_64"
75#define	LD_SUPPORT_MAKE_LIB	"libmakestate.so.1"
76#ifdef __x86
77#define	LD_SUPPORT_MAKE_ARCH	"i386"
78#elif __sparc
79#define	LD_SUPPORT_MAKE_ARCH	"sparc"
80#else
81#error "Unsupported architecture"
82#endif
83
84/*
85 * typedefs & structs
86 */
87
88/*
89 * Static variables
90 */
91static	char		*argv_zero_string;
92static	Boolean		build_failed_ever_seen;
93static	Boolean		continue_after_error_ever_seen;	/* `-k' */
94static	Boolean		dmake_group_specified;		/* `-g' */
95static	Boolean		dmake_max_jobs_specified;	/* `-j' */
96static	Boolean		dmake_mode_specified;		/* `-m' */
97static	Boolean		dmake_add_mode_specified;	/* `-x' */
98static	Boolean		dmake_output_mode_specified;	/* `-x DMAKE_OUTPUT_MODE=' */
99static	Boolean		dmake_compat_mode_specified;	/* `-x SUN_MAKE_COMPAT_MODE=' */
100static	Boolean		dmake_odir_specified;		/* `-o' */
101static	Boolean		dmake_rcfile_specified;		/* `-c' */
102static	Boolean		env_wins;			/* `-e' */
103static	Boolean		ignore_default_mk;		/* `-r' */
104static	Boolean		list_all_targets;		/* `-T' */
105static	int		mf_argc;
106static	char		**mf_argv;
107static	Dependency_rec  not_auto_depen_struct;
108static	Dependency	not_auto_depen = &not_auto_depen_struct;
109static	Boolean		pmake_cap_r_specified;		/* `-R' */
110static	Boolean		pmake_machinesfile_specified;	/* `-M' */
111static	Boolean		stop_after_error_ever_seen;	/* `-S' */
112static	Boolean		trace_status;			/* `-p' */
113
114#ifdef DMAKE_STATISTICS
115static	Boolean		getname_stat = false;
116#endif
117
118	static	time_t		start_time;
119	static	int		g_argc;
120	static	char		**g_argv;
121
122/*
123 * File table of contents
124 */
125	extern "C" void		cleanup_after_exit(void);
126
127extern "C" {
128	extern	void		dmake_exit_callback(void);
129	extern	void		dmake_message_callback(char *);
130}
131
132extern	Name		normalize_name(register wchar_t *name_string, register int length);
133
134extern	int		main(int, char * []);
135
136static	void		append_makeflags_string(Name, String);
137static	void		doalarm(int);
138static	void		enter_argv_values(int , char **, ASCII_Dyn_Array *);
139static	void		make_targets(int, char **, Boolean);
140static	int		parse_command_option(char);
141static	void		read_command_options(int, char **);
142static	void		read_environment(Boolean);
143static	void		read_files_and_state(int, char **);
144static	Boolean		read_makefile(Name, Boolean, Boolean, Boolean);
145static	void		report_recursion(Name);
146static	void		set_sgs_support(void);
147static	void		setup_for_projectdir(void);
148static	void		setup_makeflags_argv(void);
149static	void		report_dir_enter_leave(Boolean entering);
150
151extern void expand_value(Name, register String , Boolean);
152
153static const char	verstring[] = "illumos make";
154
155jmp_buf jmpbuffer;
156
157/*
158 *	main(argc, argv)
159 *
160 *	Parameters:
161 *		argc			You know what this is
162 *		argv			You know what this is
163 *
164 *	Static variables used:
165 *		list_all_targets	make -T seen
166 *		trace_status		make -p seen
167 *
168 *	Global variables used:
169 *		debug_level		Should we trace make actions?
170 *		keep_state		Set if .KEEP_STATE seen
171 *		makeflags		The Name "MAKEFLAGS", used to get macro
172 *		remote_command_name	Name of remote invocation cmd ("on")
173 *		running_list		List of parallel running processes
174 *		stdout_stderr_same	true if stdout and stderr are the same
175 *		auto_dependencies	The Name "SUNPRO_DEPENDENCIES"
176 *		temp_file_directory	Set to the dir where we create tmp file
177 *		trace_reader		Set to reflect tracing status
178 *		working_on_targets	Set when building user targets
179 */
180int
181main(int argc, char *argv[])
182{
183	/*
184	 * cp is a -> to the value of the MAKEFLAGS env var,
185	 * which has to be regular chars.
186	 */
187	register char		*cp;
188	char			make_state_dir[MAXPATHLEN];
189	Boolean			parallel_flag = false;
190	Boolean			argv_zero_relative = false;
191	char			*prognameptr;
192	char			*slash_ptr;
193	mode_t			um;
194	int			i;
195	struct itimerval	value;
196	char			def_dmakerc_path[MAXPATHLEN];
197	Name			dmake_name, dmake_name2;
198	Name			dmake_value, dmake_value2;
199	Property		prop, prop2;
200	struct stat		statbuf;
201	int			statval;
202
203	struct stat		out_stat, err_stat;
204	hostid = gethostid();
205	bsd_signals();
206
207	(void) setlocale(LC_ALL, "");
208
209
210#ifdef DMAKE_STATISTICS
211	if (getenv("DMAKE_STATISTICS")) {
212		getname_stat = true;
213	}
214#endif
215
216#ifndef TEXT_DOMAIN
217#define	TEXT_DOMAIN	"SYS_TEST"
218#endif
219	textdomain(TEXT_DOMAIN);
220
221	g_argc = argc;
222	g_argv = (char **) malloc((g_argc + 1) * sizeof(char *));
223	for (i = 0; i < argc; i++) {
224		g_argv[i] = argv[i];
225	}
226	g_argv[i] = NULL;
227
228	/*
229	 * Set argv_zero_string to some form of argv[0] for
230	 * recursive MAKE builds.
231	 */
232
233	if (*argv[0] == (int) slash_char) {
234		/* argv[0] starts with a slash */
235		argv_zero_string = strdup(argv[0]);
236	} else if (strchr(argv[0], (int) slash_char) == NULL) {
237		/* argv[0] contains no slashes */
238		argv_zero_string = strdup(argv[0]);
239	} else {
240		/*
241		 * argv[0] contains at least one slash,
242		 * but doesn't start with a slash
243		 */
244		char	*tmp_current_path;
245		char	*tmp_string;
246
247		tmp_current_path = get_current_path();
248		tmp_string = getmem(strlen(tmp_current_path) + 1 +
249		                    strlen(argv[0]) + 1);
250		(void) sprintf(tmp_string,
251		               "%s/%s",
252		               tmp_current_path,
253		               argv[0]);
254		argv_zero_string = strdup(tmp_string);
255		retmem_mb(tmp_string);
256		argv_zero_relative = true;
257	}
258
259	/*
260	 * The following flags are reset if we don't have the
261	 * (.nse_depinfo or .make.state) files locked and only set
262	 * AFTER the file has been locked. This ensures that if the user
263	 * interrupts the program while file_lock() is waiting to lock
264	 * the file, the interrupt handler doesn't remove a lock
265	 * that doesn't belong to us.
266	 */
267	make_state_lockfile = NULL;
268	make_state_locked = false;
269
270
271	/*
272	 * look for last slash char in the path to look at the binary
273	 * name. This is to resolve the hard link and invoke make
274	 * in svr4 mode.
275	 */
276
277	/* Sun OS make standard */
278	svr4 = false;
279	posix = false;
280	if(!strcmp(argv_zero_string, "/usr/xpg4/bin/make")) {
281		svr4 = false;
282		posix = true;
283	} else {
284		prognameptr = strrchr(argv[0], '/');
285		if(prognameptr) {
286			prognameptr++;
287		} else {
288			prognameptr = argv[0];
289		}
290		if(!strcmp(prognameptr, "svr4.make")) {
291			svr4 = true;
292			posix = false;
293		}
294	}
295	if (getenv(USE_SVR4_MAKE) || getenv("USE_SVID")){
296	   svr4 = true;
297	   posix = false;
298	}
299
300	/*
301	 * Find the dmake_compat_mode: posix, sun, svr4, or gnu_style, .
302	 */
303	char * dmake_compat_mode_var = getenv("SUN_MAKE_COMPAT_MODE");
304	if (dmake_compat_mode_var != NULL) {
305		if (0 == strcasecmp(dmake_compat_mode_var, "GNU")) {
306			gnu_style = true;
307		}
308		//svr4 = false;
309		//posix = false;
310	}
311
312	/*
313	 * Temporary directory set up.
314	 */
315	char * tmpdir_var = getenv("TMPDIR");
316	if (tmpdir_var != NULL && *tmpdir_var == '/' && strlen(tmpdir_var) < MAXPATHLEN) {
317		strcpy(mbs_buffer, tmpdir_var);
318		for (tmpdir_var = mbs_buffer+strlen(mbs_buffer);
319			*(--tmpdir_var) == '/' && tmpdir_var > mbs_buffer;
320			*tmpdir_var = '\0');
321		if (strlen(mbs_buffer) + 32 < MAXPATHLEN) { /* 32 = strlen("/dmake.stdout.%d.%d.XXXXXX") */
322			sprintf(mbs_buffer2, "%s/dmake.tst.%d.XXXXXX",
323				mbs_buffer, getpid());
324			int fd = mkstemp(mbs_buffer2);
325			if (fd >= 0) {
326				close(fd);
327				unlink(mbs_buffer2);
328				tmpdir = strdup(mbs_buffer);
329			}
330		}
331	}
332
333	/* find out if stdout and stderr point to the same place */
334	if (fstat(1, &out_stat) < 0) {
335		fatal(gettext("fstat of standard out failed: %s"), errmsg(errno));
336	}
337	if (fstat(2, &err_stat) < 0) {
338		fatal(gettext("fstat of standard error failed: %s"), errmsg(errno));
339	}
340	if ((out_stat.st_dev == err_stat.st_dev) &&
341	    (out_stat.st_ino == err_stat.st_ino)) {
342		stdout_stderr_same = true;
343	} else {
344		stdout_stderr_same = false;
345	}
346	/* Make the vroot package scan the path using shell semantics */
347	set_path_style(0);
348
349	setup_char_semantics();
350
351	/*
352	 * If running with .KEEP_STATE, curdir will be set with
353	 * the connected directory.
354	 */
355	(void) atexit(cleanup_after_exit);
356
357	load_cached_names();
358
359/*
360 *	Set command line flags
361 */
362	setup_makeflags_argv();
363	read_command_options(mf_argc, mf_argv);
364	read_command_options(argc, argv);
365	if (debug_level > 0) {
366		cp = getenv(makeflags->string_mb);
367		(void) printf(gettext("MAKEFLAGS value: %s\n"), cp == NULL ? "" : cp);
368	}
369
370	/*
371	 * Reset argv_zero_string if it was built from a relative path and the
372	 * -C option was specified.
373	 */
374	if (argv_zero_relative && rebuild_arg0) {
375		char	*tmp_current_path;
376		char	*tmp_string;
377
378		free(argv_zero_string);
379		tmp_current_path = get_current_path();
380		tmp_string = getmem(strlen(tmp_current_path) + 1 +
381		                    strlen(argv[0]) + 1);
382		(void) sprintf(tmp_string,
383		               "%s/%s",
384		               tmp_current_path,
385		               argv[0]);
386		argv_zero_string = strdup(tmp_string);
387		retmem_mb(tmp_string);
388	}
389
390	setup_for_projectdir();
391
392	setup_interrupt(handle_interrupt);
393
394	read_files_and_state(argc, argv);
395
396	/*
397	 * Find the dmake_output_mode: TXT1, TXT2 or HTML1.
398	 */
399	MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
400	dmake_name2 = GETNAME(wcs_buffer, FIND_LENGTH);
401	prop2 = get_prop(dmake_name2->prop, macro_prop);
402	if (prop2 == NULL) {
403		/* DMAKE_OUTPUT_MODE not defined, default to TXT1 mode */
404		output_mode = txt1_mode;
405	} else {
406		dmake_value2 = prop2->body.macro.value;
407		if ((dmake_value2 == NULL) ||
408		    (IS_EQUAL(dmake_value2->string_mb, "TXT1"))) {
409			output_mode = txt1_mode;
410		} else if (IS_EQUAL(dmake_value2->string_mb, "TXT2")) {
411			output_mode = txt2_mode;
412		} else if (IS_EQUAL(dmake_value2->string_mb, "HTML1")) {
413			output_mode = html1_mode;
414		} else {
415			warning(gettext("Unsupported value `%s' for DMAKE_OUTPUT_MODE after -x flag (ignored)"),
416			      dmake_value2->string_mb);
417		}
418	}
419	/*
420	 * Find the dmake_mode: parallel, or serial.
421	 */
422    if ((!pmake_cap_r_specified) &&
423        (!pmake_machinesfile_specified)) {
424	char *s, *b;
425
426	if ((s = strdup(argv[0])) == NULL)
427		fatal(gettext("Out of memory"));
428
429	b = basename(s);
430
431	MBSTOWCS(wcs_buffer, "DMAKE_MODE");
432	dmake_name2 = GETNAME(wcs_buffer, FIND_LENGTH);
433	prop2 = get_prop(dmake_name2->prop, macro_prop);
434	// If we're invoked as 'make' run serially, regardless of DMAKE_MODE
435	// If we're invoked as 'make' but passed -j, run parallel
436	// If we're invoked as 'dmake', without DMAKE_MODE, default parallel
437	// If we're invoked as 'dmake' and DMAKE_MODE is set, honour it.
438	if ((strcmp(b, "make") == 0) &&
439	    !dmake_max_jobs_specified) {
440		dmake_mode_type = serial_mode;
441		no_parallel = true;
442	} else if (prop2 == NULL) {
443		/* DMAKE_MODE not defined, default based on our name */
444		if (strcmp(b, "dmake") == 0) {
445			dmake_mode_type = parallel_mode;
446			no_parallel = false;
447		}
448	} else {
449		dmake_value2 = prop2->body.macro.value;
450		if (IS_EQUAL(dmake_value2->string_mb, "parallel")) {
451			dmake_mode_type = parallel_mode;
452			no_parallel = false;
453		} else if (IS_EQUAL(dmake_value2->string_mb, "serial")) {
454			dmake_mode_type = serial_mode;
455			no_parallel = true;
456		} else {
457			fatal(gettext("Unknown dmake mode argument `%s' after -m flag"), dmake_value2->string_mb);
458		}
459	}
460	free(s);
461    }
462
463	parallel_flag = true;
464	putenv(strdup("DMAKE_CHILD=TRUE"));
465
466//
467// If dmake is running with -t option, set dmake_mode_type to serial.
468// This is done because doname() calls touch_command() that runs serially.
469// If we do not do that, maketool will have problems.
470//
471	if(touch) {
472		dmake_mode_type = serial_mode;
473		no_parallel = true;
474	}
475
476	/*
477	 * Check whether stdout and stderr are physically same.
478	 * This is in order to decide whether we need to redirect
479	 * stderr separately from stdout.
480	 * This check is performed only if __DMAKE_SEPARATE_STDERR
481	 * is not set. This variable may be used in order to preserve
482	 * the 'old' behaviour.
483	 */
484	out_err_same = true;
485	char * dmake_sep_var = getenv("__DMAKE_SEPARATE_STDERR");
486	if (dmake_sep_var == NULL || (0 != strcasecmp(dmake_sep_var, "NO"))) {
487		struct stat stdout_stat;
488		struct stat stderr_stat;
489		if( (fstat(1, &stdout_stat) == 0)
490		 && (fstat(2, &stderr_stat) == 0) )
491		{
492			if( (stdout_stat.st_dev != stderr_stat.st_dev)
493			 || (stdout_stat.st_ino != stderr_stat.st_ino) )
494			{
495				out_err_same = false;
496			}
497		}
498	}
499
500
501/*
502 *	Enable interrupt handler for alarms
503 */
504        (void) bsd_signal(SIGALRM, (SIG_PF)doalarm);
505
506/*
507 *	Check if make should report
508 */
509	if (getenv(sunpro_dependencies->string_mb) != NULL) {
510		FILE	*report_file;
511
512		report_dependency("");
513		report_file = get_report_file();
514		if ((report_file != NULL) && (report_file != (FILE*)-1)) {
515			(void) fprintf(report_file, "\n");
516		}
517	}
518
519/*
520 *	Make sure SUNPRO_DEPENDENCIES is exported (or not) properly.
521 */
522	if (keep_state) {
523		maybe_append_prop(sunpro_dependencies, macro_prop)->
524		  body.macro.exported = true;
525	} else {
526		maybe_append_prop(sunpro_dependencies, macro_prop)->
527		  body.macro.exported = false;
528	}
529
530	working_on_targets = true;
531	if (trace_status) {
532		dump_make_state();
533		fclose(stdout);
534		fclose(stderr);
535		exit_status = 0;
536		exit(0);
537	}
538	if (list_all_targets) {
539		dump_target_list();
540		fclose(stdout);
541		fclose(stderr);
542		exit_status = 0;
543		exit(0);
544	}
545	trace_reader = false;
546
547	/*
548	 * Set temp_file_directory to the directory the .make.state
549	 * file is written to.
550	 */
551	if ((slash_ptr = strrchr(make_state->string_mb, (int) slash_char)) == NULL) {
552		temp_file_directory = strdup(get_current_path());
553	} else {
554		*slash_ptr = (int) nul_char;
555		(void) strcpy(make_state_dir, make_state->string_mb);
556		*slash_ptr = (int) slash_char;
557		   /* when there is only one slash and it's the first
558		   ** character, make_state_dir should point to '/'.
559		   */
560		if(make_state_dir[0] == '\0') {
561		   make_state_dir[0] = '/';
562		   make_state_dir[1] = '\0';
563		}
564		if (make_state_dir[0] == (int) slash_char) {
565			temp_file_directory = strdup(make_state_dir);
566		} else {
567			char	tmp_current_path2[MAXPATHLEN];
568
569			(void) sprintf(tmp_current_path2,
570			               "%s/%s",
571			               get_current_path(),
572			               make_state_dir);
573			temp_file_directory = strdup(tmp_current_path2);
574		}
575	}
576
577
578	report_dir_enter_leave(true);
579
580	make_targets(argc, argv, parallel_flag);
581
582	report_dir_enter_leave(false);
583
584	if (build_failed_ever_seen) {
585		if (posix) {
586			exit_status = 1;
587		}
588		exit(1);
589	}
590	exit_status = 0;
591	exit(0);
592	/* NOTREACHED */
593}
594
595/*
596 *	cleanup_after_exit()
597 *
598 *	Called from exit(), performs cleanup actions.
599 *
600 *	Parameters:
601 *		status		The argument exit() was called with
602 *		arg		Address of an argument vector to
603 *				cleanup_after_exit()
604 *
605 *	Global variables used:
606 *		command_changed	Set if we think .make.state should be rewritten
607 *		current_line	Is set we set commands_changed
608 *		do_not_exec_rule
609 *				True if -n flag on
610 *		done		The Name ".DONE", rule we run
611 *		keep_state	Set if .KEEP_STATE seen
612 *		parallel	True if building in parallel
613 *		quest		If -q is on we do not run .DONE
614 *		report_dependencies
615 *				True if -P flag on
616 *		running_list	List of parallel running processes
617 *		temp_file_name	The temp file is removed, if any
618 */
619extern "C" void
620cleanup_after_exit(void)
621{
622	Running		rp;
623
624extern long	getname_bytes_count;
625extern long	getname_names_count;
626extern long	getname_struct_count;
627extern long	freename_bytes_count;
628extern long	freename_names_count;
629extern long	freename_struct_count;
630extern long	other_alloc;
631
632extern long	env_alloc_num;
633extern long	env_alloc_bytes;
634
635
636#ifdef DMAKE_STATISTICS
637if(getname_stat) {
638	printf(">>> Getname statistics:\n");
639	printf("  Allocated:\n");
640	printf("        Names: %ld\n", getname_names_count);
641	printf("      Strings: %ld Kb (%ld bytes)\n", getname_bytes_count/1000, getname_bytes_count);
642	printf("      Structs: %ld Kb (%ld bytes)\n", getname_struct_count/1000, getname_struct_count);
643	printf("  Total bytes: %ld Kb (%ld bytes)\n", getname_struct_count/1000 + getname_bytes_count/1000, getname_struct_count + getname_bytes_count);
644
645	printf("\n  Unallocated: %ld\n", freename_names_count);
646	printf("        Names: %ld\n", freename_names_count);
647	printf("      Strings: %ld Kb (%ld bytes)\n", freename_bytes_count/1000, freename_bytes_count);
648	printf("      Structs: %ld Kb (%ld bytes)\n", freename_struct_count/1000, freename_struct_count);
649	printf("  Total bytes: %ld Kb (%ld bytes)\n", freename_struct_count/1000 + freename_bytes_count/1000, freename_struct_count + freename_bytes_count);
650
651	printf("\n  Total used: %ld Kb (%ld bytes)\n", (getname_struct_count/1000 + getname_bytes_count/1000) - (freename_struct_count/1000 + freename_bytes_count/1000), (getname_struct_count + getname_bytes_count) - (freename_struct_count + freename_bytes_count));
652
653	printf("\n>>> Other:\n");
654	printf(
655		"       Env (%ld): %ld Kb (%ld bytes)\n",
656		env_alloc_num,
657		env_alloc_bytes/1000,
658		env_alloc_bytes
659	);
660
661}
662#endif
663
664	parallel = false;
665	/* If we used the SVR4_MAKE, don't build .DONE or .FAILED */
666	if (!getenv(USE_SVR4_MAKE)){
667	    /* Build the target .DONE or .FAILED if we caught an error */
668	    if (!quest && !list_all_targets) {
669		Name		failed_name;
670
671		MBSTOWCS(wcs_buffer, ".FAILED");
672		failed_name = GETNAME(wcs_buffer, FIND_LENGTH);
673		if ((exit_status != 0) && (failed_name->prop != NULL)) {
674			/*
675			 * [tolik] switch DMake to serial mode
676			 */
677			dmake_mode_type = serial_mode;
678			no_parallel = true;
679			(void) doname(failed_name, false, true);
680		} else {
681		    if (!trace_status) {
682			/*
683			 * Switch DMake to serial mode
684			 */
685			dmake_mode_type = serial_mode;
686			no_parallel = true;
687			(void) doname(done, false, true);
688		    }
689		}
690	    }
691	}
692	/*
693	 * Remove the temp file utilities report dependencies thru if it
694	 * is still around
695	 */
696	if (temp_file_name != NULL) {
697		(void) unlink(temp_file_name->string_mb);
698	}
699	/*
700	 * Do not save the current command in .make.state if make
701	 * was interrupted.
702	 */
703	if (current_line != NULL) {
704		command_changed = true;
705		current_line->body.line.command_used = NULL;
706	}
707	/*
708	 * For each parallel build process running, remove the temp files
709	 * and zap the command line so it won't be put in .make.state
710	 */
711	for (rp = running_list; rp != NULL; rp = rp->next) {
712		if (rp->temp_file != NULL) {
713			(void) unlink(rp->temp_file->string_mb);
714		}
715		if (rp->stdout_file != NULL) {
716			(void) unlink(rp->stdout_file);
717			retmem_mb(rp->stdout_file);
718			rp->stdout_file = NULL;
719		}
720		if (rp->stderr_file != NULL) {
721			(void) unlink(rp->stderr_file);
722			retmem_mb(rp->stderr_file);
723			rp->stderr_file = NULL;
724		}
725		command_changed = true;
726/*
727		line = get_prop(rp->target->prop, line_prop);
728		if (line != NULL) {
729			line->body.line.command_used = NULL;
730		}
731 */
732	}
733	/* Remove the statefile lock file if the file has been locked */
734	if ((make_state_lockfile != NULL) && (make_state_locked)) {
735		(void) unlink(make_state_lockfile);
736		make_state_lockfile = NULL;
737		make_state_locked = false;
738	}
739	/* Write .make.state */
740	write_state_file(1, (Boolean) 1);
741
742	job_adjust_fini();
743}
744
745/*
746 *	handle_interrupt()
747 *
748 *	This is where C-C traps are caught.
749 *
750 *	Parameters:
751 *
752 *	Global variables used (except DMake 1.0):
753 *		current_target		Sometimes the current target is removed
754 *		do_not_exec_rule	But not if -n is on
755 *		quest			or -q
756 *		running_list		List of parallel running processes
757 *		touch			Current target is not removed if -t on
758 */
759void
760handle_interrupt(int)
761{
762	Property		member;
763	Running			rp;
764
765	(void) fflush(stdout);
766	if (childPid > 0) {
767		kill(childPid, SIGTERM);
768		childPid = -1;
769	}
770	for (rp = running_list; rp != NULL; rp = rp->next) {
771		if (rp->state != build_running) {
772			continue;
773		}
774		if (rp->pid > 0) {
775			kill(rp->pid, SIGTERM);
776			rp->pid = -1;
777		}
778	}
779	if (getpid() == getpgrp()) {
780		bsd_signal(SIGTERM, SIG_IGN);
781		kill (-getpid(), SIGTERM);
782	}
783	/* Clean up all parallel children already finished */
784        finish_children(false);
785
786	/* Make sure the processes running under us terminate first */
787
788	while (wait((int *) NULL) != -1);
789	/* Delete the current targets unless they are precious */
790	if ((current_target != NULL) &&
791	    current_target->is_member &&
792	    ((member = get_prop(current_target->prop, member_prop)) != NULL)) {
793		current_target = member->body.member.library;
794	}
795	if (!do_not_exec_rule &&
796	    !touch &&
797	    !quest &&
798	    (current_target != NULL) &&
799	    !(current_target->stat.is_precious || all_precious)) {
800
801/* BID_1030811 */
802/* azv 16 Oct 95 */
803		current_target->stat.time = file_no_time;
804
805		if (exists(current_target) != file_doesnt_exist) {
806			(void) fprintf(stderr,
807				       "\n*** %s ",
808				       current_target->string_mb);
809			if (current_target->stat.is_dir) {
810				(void) fprintf(stderr,
811					       gettext("not removed.\n"),
812					       current_target->string_mb);
813			} else if (unlink(current_target->string_mb) == 0) {
814				(void) fprintf(stderr,
815					       gettext("removed.\n"),
816					       current_target->string_mb);
817			} else {
818				(void) fprintf(stderr,
819					       gettext("could not be removed: %s.\n"),
820					       current_target->string_mb,
821					       errmsg(errno));
822			}
823		}
824	}
825	for (rp = running_list; rp != NULL; rp = rp->next) {
826		if (rp->state != build_running) {
827			continue;
828		}
829		if (rp->target->is_member &&
830		    ((member = get_prop(rp->target->prop, member_prop)) !=
831		     NULL)) {
832			rp->target = member->body.member.library;
833		}
834		if (!do_not_exec_rule &&
835		    !touch &&
836		    !quest &&
837		    !(rp->target->stat.is_precious || all_precious)) {
838
839			rp->target->stat.time = file_no_time;
840			if (exists(rp->target) != file_doesnt_exist) {
841				(void) fprintf(stderr,
842					       "\n*** %s ",
843					       rp->target->string_mb);
844				if (rp->target->stat.is_dir) {
845					(void) fprintf(stderr,
846						       gettext("not removed.\n"),
847						       rp->target->string_mb);
848				} else if (unlink(rp->target->string_mb) == 0) {
849					(void) fprintf(stderr,
850						       gettext("removed.\n"),
851						       rp->target->string_mb);
852				} else {
853					(void) fprintf(stderr,
854						       gettext("could not be removed: %s.\n"),
855						       rp->target->string_mb,
856						       errmsg(errno));
857				}
858			}
859		}
860	}
861
862
863	/* Have we locked .make.state or .nse_depinfo? */
864	if ((make_state_lockfile != NULL) && (make_state_locked)) {
865		unlink(make_state_lockfile);
866		make_state_lockfile = NULL;
867		make_state_locked = false;
868	}
869	/*
870	 * Re-read .make.state file (it might be changed by recursive make)
871	 */
872	check_state(NULL);
873
874	report_dir_enter_leave(false);
875
876	exit_status = 2;
877	exit(2);
878}
879
880/*
881 *	doalarm(sig, ...)
882 *
883 *	Handle the alarm interrupt but do nothing.  Side effect is to
884 *	cause return from wait3.
885 *
886 *	Parameters:
887 *		sig
888 *
889 *	Global variables used:
890 */
891static void
892doalarm(int sig __attribute__((unused)))
893{
894	return;
895}
896
897
898/*
899 *	read_command_options(argc, argv)
900 *
901 *	Scan the cmd line options and process the ones that start with "-"
902 *
903 *	Return value:
904 *				-M argument, if any
905 *
906 *	Parameters:
907 *		argc		You know what this is
908 *		argv		You know what this is
909 *
910 *	Global variables used:
911 */
912static void
913read_command_options(register int argc, register char **argv)
914{
915	register int		ch;
916	int			current_optind = 1;
917	int			last_optind_with_double_hyphen = 0;
918	int			last_optind;
919	int			last_current_optind;
920	register int		i;
921	register int		j;
922	register int		k;
923	register int		makefile_next = 0; /*
924						    * flag to note options:
925						    * -c, f, g, j, m, o
926						    */
927	const char		*tptr;
928	const char		*CMD_OPTS;
929
930	extern char		*optarg;
931	extern int		optind, opterr, optopt;
932
933#define SUNPRO_CMD_OPTS	"-~Bbc:C:Ddef:g:ij:K:kM:m:NnO:o:PpqRrSsTtuVvwx:"
934
935#	define SVR4_CMD_OPTS   "-c:C:ef:g:ij:km:nO:o:pqrsTtVv"
936
937	/*
938	 * Added V in SVR4_CMD_OPTS also, which is going to be a hidden
939	 * option, just to make sure that the getopt doesn't fail when some
940	 * users leave their USE_SVR4_MAKE set and try to use the makefiles
941	 * that are designed to issue commands like $(MAKE) -V. Anyway it
942	 * sets the same flag but ensures that getopt doesn't fail.
943	 */
944
945	opterr = 0;
946	optind = 1;
947	while (1) {
948		last_optind=optind;			/* Save optind and current_optind values */
949		last_current_optind=current_optind;	/* in case we have to repeat this round. */
950		if (svr4) {
951			CMD_OPTS=SVR4_CMD_OPTS;
952			ch = getopt(argc, argv, SVR4_CMD_OPTS);
953		} else {
954			CMD_OPTS=SUNPRO_CMD_OPTS;
955			ch = getopt(argc, argv, SUNPRO_CMD_OPTS);
956		}
957		if (ch == EOF) {
958			if(optind < argc) {
959				/*
960				 * Fixing bug 4102537:
961				 *    Strange behaviour of command make using -- option.
962				 * Not all argv have been processed
963				 * Skip non-flag argv and continue processing.
964				 */
965				optind++;
966				current_optind++;
967				continue;
968			} else {
969				break;
970			}
971
972		}
973		if (ch == '?') {
974			if (optopt == '-') {
975				/* Bug 5060758: getopt() changed behavior (s10_60),
976				 * and now we have to deal with cases when options
977				 * with double hyphen appear here, from -$(MAKEFLAGS)
978				 */
979				i = current_optind;
980				if (argv[i][0] == '-') {
981				  if (argv[i][1] == '-') {
982				    if (argv[i][2] != '\0') {
983				      /* Check if this option is allowed */
984				      tptr = strchr(CMD_OPTS, argv[i][2]);
985				      if (tptr) {
986				        if (last_optind_with_double_hyphen != current_optind) {
987				          /* This is first time we are trying to fix "--"
988				           * problem with this option. If we come here second
989				           * time, we will go to fatal error.
990				           */
991				          last_optind_with_double_hyphen = current_optind;
992
993				          /* Eliminate first hyphen character */
994				          for (j=0; argv[i][j] != '\0'; j++) {
995				            argv[i][j] = argv[i][j+1];
996				          }
997
998				          /* Repeat the processing of this argument */
999				          optind=last_optind;
1000				          current_optind=last_current_optind;
1001				          continue;
1002				        }
1003				      }
1004				    }
1005				  }
1006				}
1007			}
1008		}
1009
1010		if (ch == '?') {
1011			if (svr4) {
1012				fprintf(stderr,
1013					gettext("Usage : dmake [ -f makefile ][ -c dmake_rcfile ][ -g dmake_group ][-C directory]\n"));
1014				fprintf(stderr,
1015					gettext("              [ -j dmake_max_jobs ][ -m dmake_mode ][ -o dmake_odir ]...\n"));
1016				fprintf(stderr,
1017					gettext("              [ -e ][ -i ][ -k ][ -n ][ -p ][ -q ][ -r ][ -s ][ -t ][ -v ]\n"));
1018				tptr = strchr(SVR4_CMD_OPTS, optopt);
1019			} else {
1020				fprintf(stderr,
1021					gettext("Usage : dmake [ -f makefile ][ -c dmake_rcfile ][ -g dmake_group ][-C directory]\n"));
1022				fprintf(stderr,
1023					gettext("              [ -j dmake_max_jobs ][ -K statefile ][ -m dmake_mode ][ -x MODE_NAME=VALUE ][ -o dmake_odir ]...\n"));
1024				fprintf(stderr,
1025					gettext("              [ -d ][ -dd ][ -D ][ -DD ][ -e ][ -i ][ -k ][ -n ][ -p ][ -P ][ -u ][ -w ]\n"));
1026				fprintf(stderr,
1027					gettext("              [ -q ][ -r ][ -s ][ -S ][ -t ][ -v ][ -V ][ target... ][ macro=value... ][ \"macro +=value\"... ]\n"));
1028				tptr = strchr(SUNPRO_CMD_OPTS, optopt);
1029			}
1030			if (!tptr) {
1031				fatal(gettext("Unknown option `-%c'"), optopt);
1032			} else {
1033				fatal(gettext("Missing argument after `-%c'"), optopt);
1034			}
1035		}
1036
1037
1038
1039		makefile_next |= parse_command_option(ch);
1040		/*
1041		 * If we're done processing all of the options of
1042		 * ONE argument string...
1043		 */
1044		if (current_optind < optind) {
1045			i = current_optind;
1046			k = 0;
1047			/* If there's an argument for an option... */
1048			if ((optind - current_optind) > 1) {
1049				k = i + 1;
1050			}
1051			switch (makefile_next) {
1052			case 0:
1053				argv[i] = NULL;
1054				/* This shouldn't happen */
1055				if (k) {
1056					argv[k] = NULL;
1057				}
1058				break;
1059			case 1:	/* -f seen */
1060				argv[i] = (char *)"-f";
1061				break;
1062			case 2:	/* -c seen */
1063				argv[i] = (char *)"-c";
1064				break;
1065			case 4:	/* -g seen */
1066				argv[i] = (char *)"-g";
1067				break;
1068			case 8:	/* -j seen */
1069				argv[i] = (char *)"-j";
1070				break;
1071			case 16: /* -M seen */
1072				argv[i] = (char *)"-M";
1073				break;
1074			case 32: /* -m seen */
1075				argv[i] = (char *)"-m";
1076				break;
1077			case 128: /* -O seen */
1078				argv[i] = (char *)"-O";
1079				break;
1080			case 256: /* -K seen */
1081				argv[i] = (char *)"-K";
1082			        break;
1083			case 512:	/* -o seen */
1084				argv[i] = (char *)"-o";
1085				break;
1086			case 1024: /* -x seen */
1087				argv[i] = (char *)"-x";
1088				break;
1089			case 2048:
1090				argv[i] = (char *)"-C";
1091				if (chdir(argv[k]) != 0) {
1092					fatal(gettext("failed to change to directory %s: %s"),
1093					    argv[k], strerror(errno));
1094				}
1095				path_reset = true;
1096				rebuild_arg0 = true;
1097				(void) get_current_path();
1098				break;
1099			default: /* > 1 of -c, f, g, j, K, M, m, O, o, x seen */
1100				fatal(gettext("Illegal command line. More than one option requiring\nan argument given in the same argument group"));
1101			}
1102
1103			makefile_next = 0;
1104			current_optind = optind;
1105		}
1106	}
1107}
1108
1109static void
1110quote_str(char *str, char *qstr)
1111{
1112	char		*to;
1113	char		*from;
1114
1115	to = qstr;
1116	for (from = str; *from; from++) {
1117		switch (*from) {
1118		case ';':	/* End of command */
1119		case '(':	/* Start group */
1120		case ')':	/* End group */
1121		case '{':	/* Start group */
1122		case '}':	/* End group */
1123		case '[':	/* Reg expr - any of a set of chars */
1124		case ']':	/* End of set of chars */
1125		case '|':	/* Pipe or logical-or */
1126		case '^':	/* Old-fashioned pipe */
1127		case '&':	/* Background or logical-and */
1128		case '<':	/* Redirect stdin */
1129		case '>':	/* Redirect stdout */
1130		case '*':	/* Reg expr - any sequence of chars */
1131		case '?':	/* Reg expr - any single char */
1132		case '$':	/* Variable substitution */
1133		case '\'':	/* Singe quote - turn off all magic */
1134		case '"':	/* Double quote - span whitespace */
1135		case '`':	/* Backquote - run a command */
1136		case '#':	/* Comment */
1137		case ' ':	/* Space (for MACRO=value1 value2  */
1138		case '\\':	/* Escape char - turn off magic of next char */
1139			*to++ = '\\';
1140			break;
1141
1142		default:
1143			break;
1144		}
1145		*to++ = *from;
1146	}
1147	*to = '\0';
1148}
1149
1150static void
1151unquote_str(char *str, char *qstr)
1152{
1153	char		*to;
1154	char		*from;
1155
1156	to = qstr;
1157	for (from = str; *from; from++) {
1158		if (*from == '\\') {
1159			from++;
1160		}
1161		*to++ = *from;
1162	}
1163	*to = '\0';
1164}
1165
1166/*
1167 * Convert the MAKEFLAGS string value into a vector of char *, similar
1168 * to argv.
1169 */
1170static void
1171setup_makeflags_argv()
1172{
1173	char		*cp;
1174	char		*cp1;
1175	char		*cp2;
1176	char		*cp3;
1177	char		*cp_orig;
1178	Boolean		add_hyphen;
1179	int		i;
1180	char		tmp_char;
1181
1182	mf_argc = 1;
1183	cp = getenv(makeflags->string_mb);
1184	cp_orig = cp;
1185
1186	if (cp) {
1187		/*
1188		 * If new MAKEFLAGS format, no need to add hyphen.
1189		 * If old MAKEFLAGS format, add hyphen before flags.
1190		 */
1191
1192		if ((strchr(cp, (int) hyphen_char) != NULL) ||
1193		    (strchr(cp, (int) equal_char) != NULL)) {
1194
1195			/* New MAKEFLAGS format */
1196
1197			add_hyphen = false;
1198
1199			/* Check if MAKEFLAGS value begins with multiple
1200			 * hyphen characters, and remove all duplicates.
1201			 * Usually it happens when the next command is
1202			 * used: $(MAKE) -$(MAKEFLAGS)
1203			 *
1204			 * This was a workaround for BugID 5060758, but
1205			 * appears to have survived as a fix in make.
1206			 */
1207			while (*cp) {
1208				if (*cp != (int) hyphen_char) {
1209					break;
1210				}
1211				cp++;
1212				if (*cp == (int) hyphen_char) {
1213					/* There are two hyphens. Skip one */
1214					cp_orig = cp;
1215					cp++;
1216				}
1217				if (!(*cp)) {
1218					/* There are hyphens only. Skip all */
1219					cp_orig = cp;
1220					break;
1221				}
1222			}
1223		} else {
1224
1225			/* Old MAKEFLAGS format */
1226
1227			add_hyphen = true;
1228		}
1229	}
1230
1231	/* Find the number of arguments in MAKEFLAGS */
1232	while (cp && *cp) {
1233		/* Skip white spaces */
1234		while (cp && *cp && isspace(*cp)) {
1235			cp++;
1236		}
1237		if (cp && *cp) {
1238			/* Increment arg count */
1239			mf_argc++;
1240			/* Go to next white space */
1241			while (cp && *cp && !isspace(*cp)) {
1242				if(*cp == (int) backslash_char) {
1243					cp++;
1244				}
1245				cp++;
1246			}
1247		}
1248	}
1249	/* Allocate memory for the new MAKEFLAGS argv */
1250	mf_argv = (char **) malloc((mf_argc + 1) * sizeof(char *));
1251	mf_argv[0] = (char *)"MAKEFLAGS";
1252	/*
1253	 * Convert the MAKEFLAGS string value into a vector of char *,
1254	 * similar to argv.
1255	 */
1256	cp = cp_orig;
1257	for (i = 1; i < mf_argc; i++) {
1258		/* Skip white spaces */
1259		while (cp && *cp && isspace(*cp)) {
1260			cp++;
1261		}
1262		if (cp && *cp) {
1263			cp_orig = cp;
1264			/* Go to next white space */
1265			while (cp && *cp && !isspace(*cp)) {
1266				if(*cp == (int) backslash_char) {
1267					cp++;
1268				}
1269				cp++;
1270			}
1271			tmp_char = *cp;
1272			*cp = (int) nul_char;
1273			if (add_hyphen) {
1274				mf_argv[i] = getmem(2 + strlen(cp_orig));
1275				mf_argv[i][0] = '\0';
1276				(void) strcat(mf_argv[i], "-");
1277				// (void) strcat(mf_argv[i], cp_orig);
1278				unquote_str(cp_orig, mf_argv[i]+1);
1279			} else {
1280				mf_argv[i] = getmem(2 + strlen(cp_orig));
1281				//mf_argv[i] = strdup(cp_orig);
1282				unquote_str(cp_orig, mf_argv[i]);
1283			}
1284			*cp = tmp_char;
1285		}
1286	}
1287	mf_argv[i] = NULL;
1288}
1289
1290/*
1291 *	parse_command_option(ch)
1292 *
1293 *	Parse make command line options.
1294 *
1295 *	Return value:
1296 *				Indicates if any -f -c or -M were seen
1297 *
1298 *	Parameters:
1299 *		ch		The character to parse
1300 *
1301 *	Static variables used:
1302 *		dmake_group_specified	Set for make -g
1303 *		dmake_max_jobs_specified	Set for make -j
1304 *		dmake_mode_specified	Set for make -m
1305 *		dmake_add_mode_specified	Set for make -x
1306 *		dmake_compat_mode_specified	Set for make -x SUN_MAKE_COMPAT_MODE=
1307 *		dmake_output_mode_specified	Set for make -x DMAKE_OUTPUT_MODE=
1308 *		dmake_odir_specified	Set for make -o
1309 *		dmake_rcfile_specified	Set for make -c
1310 *		env_wins		Set for make -e
1311 *		ignore_default_mk	Set for make -r
1312 *		trace_status		Set for make -p
1313 *
1314 *	Global variables used:
1315 *		.make.state path & name set for make -K
1316 *		continue_after_error	Set for make -k
1317 *		debug_level		Set for make -d
1318 *		do_not_exec_rule	Set for make -n
1319 *		filter_stderr		Set for make -X
1320 *		ignore_errors_all	Set for make -i
1321 *		no_parallel		Set for make -R
1322 *		quest			Set for make -q
1323 *		read_trace_level	Set for make -D
1324 *		report_dependencies	Set for make -P
1325 *		silent_all		Set for make -s
1326 *		touch			Set for make -t
1327 */
1328static int
1329parse_command_option(register char ch)
1330{
1331	static int		invert_next = 0;
1332	int			invert_this = invert_next;
1333
1334	invert_next = 0;
1335	switch (ch) {
1336	case '-':			 /* Ignore "--" */
1337		return 0;
1338	case '~':			 /* Invert next option */
1339		invert_next = 1;
1340		return 0;
1341	case 'B':			 /* Obsolete */
1342		return 0;
1343	case 'b':			 /* Obsolete */
1344		return 0;
1345	case 'c':			 /* Read alternative dmakerc file */
1346		if (invert_this) {
1347			dmake_rcfile_specified = false;
1348		} else {
1349			dmake_rcfile_specified = true;
1350		}
1351		return 2;
1352	case 'C':			/* Change directory */
1353		return 2048;
1354	case 'D':			 /* Show lines read */
1355		if (invert_this) {
1356			read_trace_level--;
1357		} else {
1358			read_trace_level++;
1359		}
1360		return 0;
1361	case 'd':			 /* Debug flag */
1362		if (invert_this) {
1363			debug_level--;
1364		} else {
1365			debug_level++;
1366		}
1367		return 0;
1368	case 'e':			 /* Environment override flag */
1369		if (invert_this) {
1370			env_wins = false;
1371		} else {
1372			env_wins = true;
1373		}
1374		return 0;
1375	case 'f':			 /* Read alternative makefile(s) */
1376		return 1;
1377	case 'g':			 /* Use alternative DMake group */
1378		if (invert_this) {
1379			dmake_group_specified = false;
1380		} else {
1381			dmake_group_specified = true;
1382		}
1383		return 4;
1384	case 'i':			 /* Ignore errors */
1385		if (invert_this) {
1386			ignore_errors_all = false;
1387		} else {
1388			ignore_errors_all = true;
1389		}
1390		return 0;
1391	case 'j':			 /* Use alternative DMake max jobs */
1392		if (invert_this) {
1393			dmake_max_jobs_specified = false;
1394		} else {
1395			dmake_mode_type = parallel_mode;
1396			no_parallel = false;
1397			dmake_max_jobs_specified = true;
1398		}
1399		return 8;
1400	case 'K':			 /* Read alternative .make.state */
1401		return 256;
1402	case 'k':			 /* Keep making even after errors */
1403		if (invert_this) {
1404			continue_after_error = false;
1405		} else {
1406			continue_after_error = true;
1407			continue_after_error_ever_seen = true;
1408		}
1409		return 0;
1410	case 'M':			 /* Read alternative make.machines file */
1411		if (invert_this) {
1412			pmake_machinesfile_specified = false;
1413		} else {
1414			pmake_machinesfile_specified = true;
1415			dmake_mode_type = parallel_mode;
1416			no_parallel = false;
1417		}
1418		return 16;
1419	case 'm':			 /* Use alternative DMake build mode */
1420		if (invert_this) {
1421			dmake_mode_specified = false;
1422		} else {
1423			dmake_mode_specified = true;
1424		}
1425		return 32;
1426	case 'x':			 /* Use alternative DMake mode */
1427		if (invert_this) {
1428			dmake_add_mode_specified = false;
1429		} else {
1430			dmake_add_mode_specified = true;
1431		}
1432		return 1024;
1433	case 'N':			 /* Reverse -n */
1434		if (invert_this) {
1435			do_not_exec_rule = true;
1436		} else {
1437			do_not_exec_rule = false;
1438		}
1439		return 0;
1440	case 'n':			 /* Print, not exec commands */
1441		if (invert_this) {
1442			do_not_exec_rule = false;
1443		} else {
1444			do_not_exec_rule = true;
1445		}
1446		return 0;
1447	case 'O':			 /* Integrate with maketool, obsolete */
1448		return 0;
1449	case 'o':			 /* Use alternative dmake output dir */
1450		if (invert_this) {
1451			dmake_odir_specified = false;
1452		} else {
1453			dmake_odir_specified = true;
1454		}
1455		return 512;
1456	case 'P':			 /* Print for selected targets */
1457		if (invert_this) {
1458			report_dependencies_level--;
1459		} else {
1460			report_dependencies_level++;
1461		}
1462		return 0;
1463	case 'p':			 /* Print description */
1464		if (invert_this) {
1465			trace_status = false;
1466			do_not_exec_rule = false;
1467		} else {
1468			trace_status = true;
1469			do_not_exec_rule = true;
1470		}
1471		return 0;
1472	case 'q':			 /* Question flag */
1473		if (invert_this) {
1474			quest = false;
1475		} else {
1476			quest = true;
1477		}
1478		return 0;
1479	case 'R':			 /* Don't run in parallel */
1480		if (invert_this) {
1481			pmake_cap_r_specified = false;
1482			no_parallel = false;
1483		} else {
1484			pmake_cap_r_specified = true;
1485			dmake_mode_type = serial_mode;
1486			no_parallel = true;
1487		}
1488		return 0;
1489	case 'r':			 /* Turn off internal rules */
1490		if (invert_this) {
1491			ignore_default_mk = false;
1492		} else {
1493			ignore_default_mk = true;
1494		}
1495		return 0;
1496	case 'S':			 /* Reverse -k */
1497		if (invert_this) {
1498			continue_after_error = true;
1499		} else {
1500			continue_after_error = false;
1501			stop_after_error_ever_seen = true;
1502		}
1503		return 0;
1504	case 's':			 /* Silent flag */
1505		if (invert_this) {
1506			silent_all = false;
1507		} else {
1508			silent_all = true;
1509		}
1510		return 0;
1511	case 'T':			 /* Print target list */
1512		if (invert_this) {
1513			list_all_targets = false;
1514			do_not_exec_rule = false;
1515		} else {
1516			list_all_targets = true;
1517			do_not_exec_rule = true;
1518		}
1519		return 0;
1520	case 't':			 /* Touch flag */
1521		if (invert_this) {
1522			touch = false;
1523		} else {
1524			touch = true;
1525		}
1526		return 0;
1527	case 'u':			 /* Unconditional flag */
1528		if (invert_this) {
1529			build_unconditional = false;
1530		} else {
1531			build_unconditional = true;
1532		}
1533		return 0;
1534	case 'V':			/* SVR4 mode */
1535		svr4 = true;
1536		return 0;
1537	case 'v':			/* Version flag */
1538		if (invert_this) {
1539		} else {
1540			fprintf(stdout, "%s: %s\n", getprogname(), verstring);
1541			exit_status = 0;
1542			exit(0);
1543		}
1544		return 0;
1545	case 'w':			 /* Unconditional flag */
1546		if (invert_this) {
1547			report_cwd = false;
1548		} else {
1549			report_cwd = true;
1550		}
1551		return 0;
1552#if 0
1553	case 'X':			/* Filter stdout */
1554		if (invert_this) {
1555			filter_stderr = false;
1556		} else {
1557			filter_stderr = true;
1558		}
1559		return 0;
1560#endif
1561	default:
1562		break;
1563	}
1564	return 0;
1565}
1566
1567/*
1568 *	setup_for_projectdir()
1569 *
1570 *	Read the PROJECTDIR variable, if defined, and set the sccs path
1571 *
1572 *	Parameters:
1573 *
1574 *	Global variables used:
1575 *		sccs_dir_path	Set to point to SCCS dir to use
1576 */
1577static void
1578setup_for_projectdir(void)
1579{
1580static char	path[MAXPATHLEN];
1581char		cwdpath[MAXPATHLEN];
1582uid_t uid;
1583int   done=0;
1584
1585	/* Check if we should use PROJECTDIR when reading the SCCS dir. */
1586	sccs_dir_path = getenv("PROJECTDIR");
1587	if ((sccs_dir_path != NULL) &&
1588	    (sccs_dir_path[0] != (int) slash_char)) {
1589		struct passwd *pwent;
1590
1591	     {
1592		uid = getuid();
1593		pwent = getpwuid(uid);
1594		if (pwent == NULL) {
1595		   fatal(gettext("Bogus USERID "));
1596		}
1597		if ((pwent = getpwnam(sccs_dir_path)) == NULL) {
1598			/*empty block : it'll go & check cwd  */
1599		}
1600		else {
1601		  (void) sprintf(path, "%s/src", pwent->pw_dir);
1602		  if (access(path, F_OK) == 0) {
1603			sccs_dir_path = path;
1604			done = 1;
1605		  } else {
1606			(void) sprintf(path, "%s/source", pwent->pw_dir);
1607			if (access(path, F_OK) == 0) {
1608				sccs_dir_path = path;
1609				done = 1;
1610			}
1611		     }
1612		}
1613		if (!done) {
1614		    if (getcwd(cwdpath, MAXPATHLEN - 1 )) {
1615
1616		       (void) sprintf(path, "%s/%s", cwdpath,sccs_dir_path);
1617		       if (access(path, F_OK) == 0) {
1618				sccs_dir_path = path;
1619				done = 1;
1620		        } else {
1621				fatal(gettext("Bogus PROJECTDIR '%s'"), sccs_dir_path);
1622		        }
1623		    }
1624		}
1625	   }
1626	}
1627}
1628
1629char *
1630make_install_prefix(void)
1631{
1632	int ret;
1633	char origin[PATH_MAX];
1634	char *dir;
1635
1636	if ((ret = readlink("/proc/self/path/a.out", origin,
1637	    PATH_MAX - 1)) < 0)
1638		fatal("failed to read origin from /proc\n");
1639
1640
1641	origin[ret] = '\0';
1642	return strdup(dirname(origin));
1643}
1644
1645static char *
1646add_to_env(const char *var, const char *value, const char *fallback)
1647{
1648	const char *oldpath;
1649	char *newpath;
1650
1651	oldpath = getenv(var);
1652	if (oldpath == NULL) {
1653		if (value != NULL) {
1654			asprintf(&newpath, "%s=%s",
1655			    var, value);
1656		} else {
1657			asprintf(&newpath, "%s=%s",
1658			    var, fallback);
1659		}
1660	} else {
1661		if (value != NULL) {
1662			asprintf(&newpath, "%s=%s:%s",
1663			    var, oldpath, value);
1664		} else {
1665			asprintf(&newpath, "%s=%s:%s",
1666			    var, oldpath, fallback);
1667		}
1668	}
1669
1670	return (newpath);
1671}
1672
1673/*
1674 *	set_sgs_support()
1675 *
1676 *	Add the libmakestate.so.1 lib to the env var SGS_SUPPORT
1677 *	  if it's not already in there.
1678 *	The SGS_SUPPORT env var and libmakestate.so.1 is used by
1679 *	  the linker ld to report .make.state info back to make.
1680 *
1681 * In the new world we always will set the 32-bit and 64-bit versions of this
1682 * variable explicitly so that we can take into account the correct isa and our
1683 * prefix. So say that the prefix was /opt/local. Then we would want to search
1684 * /opt/local/lib/libmakestate.so.1:libmakestate.so.1. We still want to search
1685 * the original location just as a safety measure.
1686 */
1687static void
1688set_sgs_support()
1689{
1690	int		len;
1691	char		*newpath, *newpath64;
1692	char		*lib32, *lib64;
1693	static char	*prev_path, *prev_path64;
1694	char		*origin = make_install_prefix();
1695	struct stat st;
1696
1697	asprintf(&lib32, "%s/%s/%s", origin, "../lib",
1698	    LD_SUPPORT_MAKE_LIB);
1699
1700	if (stat(lib32, &st) != 0) {
1701		free(lib32);
1702		// Try the tools path
1703		asprintf(&lib32, "%s/%s/%s/%s", origin, "../../lib/",
1704		    LD_SUPPORT_MAKE_ARCH, LD_SUPPORT_MAKE_LIB);
1705
1706		if (stat(lib32, &st) != 0) {
1707			free(lib32);
1708			lib32 = NULL;
1709		}
1710	}
1711
1712	asprintf(&lib64, "%s/%s/64/%s", origin, "../lib",
1713	    LD_SUPPORT_MAKE_LIB);
1714
1715	if (stat(lib64, &st) != 0) {
1716		free(lib64);
1717		// Try the tools path
1718		asprintf(&lib64, "%s/%s/%s/64/%s", origin, "../../lib/",
1719		    LD_SUPPORT_MAKE_ARCH, LD_SUPPORT_MAKE_LIB);
1720
1721		if (stat(lib64, &st) != 0) {
1722			free(lib64);
1723			lib64 = NULL;
1724		}
1725	}
1726
1727	newpath = add_to_env(LD_SUPPORT_ENV_VAR_32, lib32, LD_SUPPORT_MAKE_LIB);
1728	newpath64 = add_to_env(LD_SUPPORT_ENV_VAR_64, lib64, LD_SUPPORT_MAKE_LIB);
1729
1730	putenv(newpath);
1731	if (prev_path) {
1732		free(prev_path);
1733	}
1734	prev_path = newpath;
1735
1736	putenv(newpath64);
1737	if (prev_path64) {
1738		free(prev_path64);
1739	}
1740	prev_path64 = newpath64;
1741	free(lib32);
1742	free(lib64);
1743	free(origin);
1744}
1745
1746/*
1747 *	read_files_and_state(argc, argv)
1748 *
1749 *	Read the makefiles we care about and the environment
1750 *	Also read the = style command line options
1751 *
1752 *	Parameters:
1753 *		argc		You know what this is
1754 *		argv		You know what this is
1755 *
1756 *	Static variables used:
1757 *		env_wins	make -e, determines if env vars are RO
1758 *		ignore_default_mk make -r, determines if make.rules is read
1759 *		not_auto_depen	dwight
1760 *
1761 *	Global variables used:
1762 *		default_target_to_build	Set to first proper target from file
1763 *		do_not_exec_rule Set to false when makfile is made
1764 *		dot		The Name ".", used to read current dir
1765 *		empty_name	The Name "", use as macro value
1766 *		keep_state	Set if KEEP_STATE is in environment
1767 *		make_state	The Name ".make.state", used to read file
1768 *		makefile_type	Set to type of file being read
1769 *		makeflags	The Name "MAKEFLAGS", used to set macro value
1770 *		not_auto	dwight
1771 *		read_trace_level Checked to se if the reader should trace
1772 *		report_dependencies If -P is on we do not read .make.state
1773 *		trace_reader	Set if reader should trace
1774 *		virtual_root	The Name "VIRTUAL_ROOT", used to check value
1775 */
1776static void
1777read_files_and_state(int argc, char **argv)
1778{
1779	wchar_t			buffer[1000];
1780	wchar_t			buffer_posix[1000];
1781	register char		ch;
1782	register char		*cp;
1783	Property		def_make_macro = NULL;
1784	Name			def_make_name;
1785	Name			default_makefile;
1786	String_rec		dest;
1787	wchar_t			destbuffer[STRING_BUFFER_LENGTH];
1788	register int		i;
1789	register int		j;
1790	Name			keep_state_name;
1791	int			length;
1792	Name			Makefile;
1793	register Property	macro;
1794	struct stat		make_state_stat;
1795	Name			makefile_name;
1796        register int		makefile_next = 0;
1797	register Boolean	makefile_read = false;
1798	String_rec		makeflags_string;
1799	String_rec		makeflags_string_posix;
1800	String_rec *		makeflags_string_current;
1801	Name			makeflags_value_saved;
1802	register Name		name;
1803	Name			new_make_value;
1804	Boolean			save_do_not_exec_rule;
1805	static wchar_t		state_file_str;
1806	static char		state_file_str_mb[MAXPATHLEN];
1807	static struct _Name	state_filename;
1808	Boolean			temp;
1809	char			tmp_char;
1810	wchar_t			*tmp_wcs_buffer;
1811	register Name		value;
1812	ASCII_Dyn_Array		makeflags_and_macro;
1813	Boolean			is_xpg4;
1814
1815/*
1816 *	Remember current mode. It may be changed after reading makefile
1817 *	and we will have to correct MAKEFLAGS variable.
1818 */
1819	is_xpg4 = posix;
1820
1821	MBSTOWCS(wcs_buffer, "KEEP_STATE");
1822	keep_state_name = GETNAME(wcs_buffer, FIND_LENGTH);
1823	MBSTOWCS(wcs_buffer, "Makefile");
1824	Makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1825	MBSTOWCS(wcs_buffer, "makefile");
1826	makefile_name = GETNAME(wcs_buffer, FIND_LENGTH);
1827
1828/*
1829 *	initialize global dependency entry for .NOT_AUTO
1830 */
1831	not_auto_depen->next = NULL;
1832	not_auto_depen->name = not_auto;
1833	not_auto_depen->automatic = not_auto_depen->stale = false;
1834
1835/*
1836 *	Read internal definitions and rules.
1837 */
1838	if (read_trace_level > 1) {
1839		trace_reader = true;
1840	}
1841	if (!ignore_default_mk) {
1842		if (svr4) {
1843			MBSTOWCS(wcs_buffer, "svr4.make.rules");
1844			default_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1845		} else {
1846			MBSTOWCS(wcs_buffer, "make.rules");
1847			default_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
1848		}
1849		default_makefile->stat.is_file = true;
1850
1851		(void) read_makefile(default_makefile,
1852				     true,
1853				     false,
1854				     true);
1855	}
1856
1857	/*
1858	 * If the user did not redefine the MAKE macro in the
1859	 * default makefile (make.rules), then we'd like to
1860	 * change the macro value of MAKE to be some form
1861	 * of argv[0] for recursive MAKE builds.
1862	 */
1863	MBSTOWCS(wcs_buffer, "MAKE");
1864	def_make_name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
1865	def_make_macro = get_prop(def_make_name->prop, macro_prop);
1866	if ((def_make_macro != NULL) &&
1867	    (IS_EQUAL(def_make_macro->body.macro.value->string_mb,
1868	              "make"))) {
1869		MBSTOWCS(wcs_buffer, argv_zero_string);
1870		new_make_value = GETNAME(wcs_buffer, wcslen(wcs_buffer));
1871		(void) SETVAR(def_make_name,
1872		              new_make_value,
1873		              false);
1874	}
1875
1876	default_target_to_build = NULL;
1877	trace_reader = false;
1878
1879/*
1880 *	Read environment args. Let file args which follow override unless
1881 *	-e option seen. If -e option is not mentioned.
1882 */
1883	read_environment(env_wins);
1884	if (getvar(virtual_root)->hash.length == 0) {
1885		maybe_append_prop(virtual_root, macro_prop)
1886		  ->body.macro.exported = true;
1887		MBSTOWCS(wcs_buffer, "/");
1888		(void) SETVAR(virtual_root,
1889			      GETNAME(wcs_buffer, FIND_LENGTH),
1890			      false);
1891	}
1892
1893/*
1894 * We now scan mf_argv and argv to see if we need to set
1895 * any of the DMake-added options/variables in MAKEFLAGS.
1896 */
1897
1898	makeflags_and_macro.start = 0;
1899	makeflags_and_macro.size = 0;
1900	enter_argv_values(mf_argc, mf_argv, &makeflags_and_macro);
1901	enter_argv_values(argc, argv, &makeflags_and_macro);
1902
1903/*
1904 *	Set MFLAGS and MAKEFLAGS
1905 *
1906 *	Before reading makefile we do not know exactly which mode
1907 *	(posix or not) is used. So prepare two MAKEFLAGS strings
1908 *	for both posix and solaris modes because they are different.
1909 */
1910	INIT_STRING_FROM_STACK(makeflags_string, buffer);
1911	INIT_STRING_FROM_STACK(makeflags_string_posix, buffer_posix);
1912	append_char((int) hyphen_char, &makeflags_string);
1913	append_char((int) hyphen_char, &makeflags_string_posix);
1914
1915	switch (read_trace_level) {
1916	case 2:
1917		append_char('D', &makeflags_string);
1918		append_char('D', &makeflags_string_posix);
1919		/* FALLTHROUGH */
1920	case 1:
1921		append_char('D', &makeflags_string);
1922		append_char('D', &makeflags_string_posix);
1923	}
1924	switch (debug_level) {
1925	case 2:
1926		append_char('d', &makeflags_string);
1927		append_char('d', &makeflags_string_posix);
1928		/* FALLTHROUGH */
1929	case 1:
1930		append_char('d', &makeflags_string);
1931		append_char('d', &makeflags_string_posix);
1932	}
1933	if (env_wins) {
1934		append_char('e', &makeflags_string);
1935		append_char('e', &makeflags_string_posix);
1936	}
1937	if (ignore_errors_all) {
1938		append_char('i', &makeflags_string);
1939		append_char('i', &makeflags_string_posix);
1940	}
1941	if (continue_after_error) {
1942		if (stop_after_error_ever_seen) {
1943			append_char('S', &makeflags_string_posix);
1944			append_char((int) space_char, &makeflags_string_posix);
1945			append_char((int) hyphen_char, &makeflags_string_posix);
1946		}
1947		append_char('k', &makeflags_string);
1948		append_char('k', &makeflags_string_posix);
1949	} else {
1950		if (stop_after_error_ever_seen
1951		    && continue_after_error_ever_seen) {
1952			append_char('k', &makeflags_string_posix);
1953			append_char((int) space_char, &makeflags_string_posix);
1954			append_char((int) hyphen_char, &makeflags_string_posix);
1955			append_char('S', &makeflags_string_posix);
1956		}
1957	}
1958	if (do_not_exec_rule) {
1959		append_char('n', &makeflags_string);
1960		append_char('n', &makeflags_string_posix);
1961	}
1962	switch (report_dependencies_level) {
1963	case 4:
1964		append_char('P', &makeflags_string);
1965		append_char('P', &makeflags_string_posix);
1966		/* FALLTHROUGH */
1967	case 3:
1968		append_char('P', &makeflags_string);
1969		append_char('P', &makeflags_string_posix);
1970		/* FALLTHROUGH */
1971	case 2:
1972		append_char('P', &makeflags_string);
1973		append_char('P', &makeflags_string_posix);
1974		/* FALLTHROUGH */
1975	case 1:
1976		append_char('P', &makeflags_string);
1977		append_char('P', &makeflags_string_posix);
1978	}
1979	if (trace_status) {
1980		append_char('p', &makeflags_string);
1981		append_char('p', &makeflags_string_posix);
1982	}
1983	if (quest) {
1984		append_char('q', &makeflags_string);
1985		append_char('q', &makeflags_string_posix);
1986	}
1987	if (silent_all) {
1988		append_char('s', &makeflags_string);
1989		append_char('s', &makeflags_string_posix);
1990	}
1991	if (touch) {
1992		append_char('t', &makeflags_string);
1993		append_char('t', &makeflags_string_posix);
1994	}
1995	if (build_unconditional) {
1996		append_char('u', &makeflags_string);
1997		append_char('u', &makeflags_string_posix);
1998	}
1999	if (report_cwd) {
2000		append_char('w', &makeflags_string);
2001		append_char('w', &makeflags_string_posix);
2002	}
2003	/* -c dmake_rcfile */
2004	if (dmake_rcfile_specified) {
2005		MBSTOWCS(wcs_buffer, "DMAKE_RCFILE");
2006		dmake_rcfile = GETNAME(wcs_buffer, FIND_LENGTH);
2007		append_makeflags_string(dmake_rcfile, &makeflags_string);
2008		append_makeflags_string(dmake_rcfile, &makeflags_string_posix);
2009	}
2010	/* -g dmake_group */
2011	if (dmake_group_specified) {
2012		MBSTOWCS(wcs_buffer, "DMAKE_GROUP");
2013		dmake_group = GETNAME(wcs_buffer, FIND_LENGTH);
2014		append_makeflags_string(dmake_group, &makeflags_string);
2015		append_makeflags_string(dmake_group, &makeflags_string_posix);
2016	}
2017	/* -j dmake_max_jobs */
2018	if (dmake_max_jobs_specified) {
2019		MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
2020		dmake_max_jobs = GETNAME(wcs_buffer, FIND_LENGTH);
2021		append_makeflags_string(dmake_max_jobs, &makeflags_string);
2022		append_makeflags_string(dmake_max_jobs, &makeflags_string_posix);
2023	}
2024	/* -m dmake_mode */
2025	if (dmake_mode_specified) {
2026		MBSTOWCS(wcs_buffer, "DMAKE_MODE");
2027		dmake_mode = GETNAME(wcs_buffer, FIND_LENGTH);
2028		append_makeflags_string(dmake_mode, &makeflags_string);
2029		append_makeflags_string(dmake_mode, &makeflags_string_posix);
2030	}
2031	/* -x dmake_compat_mode */
2032//	if (dmake_compat_mode_specified) {
2033//		MBSTOWCS(wcs_buffer, "SUN_MAKE_COMPAT_MODE");
2034//		dmake_compat_mode = GETNAME(wcs_buffer, FIND_LENGTH);
2035//		append_makeflags_string(dmake_compat_mode, &makeflags_string);
2036//		append_makeflags_string(dmake_compat_mode, &makeflags_string_posix);
2037//	}
2038	/* -x dmake_output_mode */
2039	if (dmake_output_mode_specified) {
2040		MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
2041		dmake_output_mode = GETNAME(wcs_buffer, FIND_LENGTH);
2042		append_makeflags_string(dmake_output_mode, &makeflags_string);
2043		append_makeflags_string(dmake_output_mode, &makeflags_string_posix);
2044	}
2045	/* -o dmake_odir */
2046	if (dmake_odir_specified) {
2047		MBSTOWCS(wcs_buffer, "DMAKE_ODIR");
2048		dmake_odir = GETNAME(wcs_buffer, FIND_LENGTH);
2049		append_makeflags_string(dmake_odir, &makeflags_string);
2050		append_makeflags_string(dmake_odir, &makeflags_string_posix);
2051	}
2052	/* -M pmake_machinesfile */
2053	if (pmake_machinesfile_specified) {
2054		MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
2055		pmake_machinesfile = GETNAME(wcs_buffer, FIND_LENGTH);
2056		append_makeflags_string(pmake_machinesfile, &makeflags_string);
2057		append_makeflags_string(pmake_machinesfile, &makeflags_string_posix);
2058	}
2059	/* -R */
2060	if (pmake_cap_r_specified) {
2061		append_char((int) space_char, &makeflags_string);
2062		append_char((int) hyphen_char, &makeflags_string);
2063		append_char('R', &makeflags_string);
2064		append_char((int) space_char, &makeflags_string_posix);
2065		append_char((int) hyphen_char, &makeflags_string_posix);
2066		append_char('R', &makeflags_string_posix);
2067	}
2068
2069/*
2070 *	Make sure MAKEFLAGS is exported
2071 */
2072	maybe_append_prop(makeflags, macro_prop)->
2073	  body.macro.exported = true;
2074
2075	if (makeflags_string.buffer.start[1] != (int) nul_char) {
2076		if (makeflags_string.buffer.start[1] != (int) space_char) {
2077			MBSTOWCS(wcs_buffer, "MFLAGS");
2078			(void) SETVAR(GETNAME(wcs_buffer, FIND_LENGTH),
2079				      GETNAME(makeflags_string.buffer.start,
2080					      FIND_LENGTH),
2081				      false);
2082		} else {
2083			MBSTOWCS(wcs_buffer, "MFLAGS");
2084			(void) SETVAR(GETNAME(wcs_buffer, FIND_LENGTH),
2085				      GETNAME(makeflags_string.buffer.start + 2,
2086					      FIND_LENGTH),
2087				      false);
2088		}
2089	}
2090
2091/*
2092 *	Add command line macro to POSIX makeflags_string
2093 */
2094	if (makeflags_and_macro.start) {
2095		tmp_char = (char) space_char;
2096		cp = makeflags_and_macro.start;
2097		do {
2098			append_char(tmp_char, &makeflags_string_posix);
2099		} while ( tmp_char = *cp++ );
2100		retmem_mb(makeflags_and_macro.start);
2101	}
2102
2103/*
2104 *	Now set the value of MAKEFLAGS macro in accordance
2105 *	with current mode.
2106 */
2107	macro = maybe_append_prop(makeflags, macro_prop);
2108	temp = (Boolean) macro->body.macro.read_only;
2109	macro->body.macro.read_only = false;
2110	if(posix || gnu_style) {
2111		makeflags_string_current = &makeflags_string_posix;
2112	} else {
2113		makeflags_string_current = &makeflags_string;
2114	}
2115	if (makeflags_string_current->buffer.start[1] == (int) nul_char) {
2116		makeflags_value_saved =
2117			GETNAME( makeflags_string_current->buffer.start + 1
2118			       , FIND_LENGTH
2119			       );
2120	} else {
2121		if (makeflags_string_current->buffer.start[1] != (int) space_char) {
2122			makeflags_value_saved =
2123				GETNAME( makeflags_string_current->buffer.start
2124				       , FIND_LENGTH
2125				       );
2126		} else {
2127			makeflags_value_saved =
2128				GETNAME( makeflags_string_current->buffer.start + 2
2129				       , FIND_LENGTH
2130				       );
2131		}
2132	}
2133	(void) SETVAR( makeflags
2134	             , makeflags_value_saved
2135	             , false
2136	             );
2137	macro->body.macro.read_only = temp;
2138
2139/*
2140 *	Read command line "-f" arguments and ignore -c, g, j, K, M, m, O and o args.
2141 */
2142	save_do_not_exec_rule = do_not_exec_rule;
2143	do_not_exec_rule = false;
2144	if (read_trace_level > 0) {
2145		trace_reader = true;
2146	}
2147
2148	for (i = 1; i < argc; i++) {
2149		if (argv[i] &&
2150		    (argv[i][0] == (int) hyphen_char) &&
2151		    (argv[i][1] == 'f') &&
2152		    (argv[i][2] == (int) nul_char)) {
2153			argv[i] = NULL;		/* Remove -f */
2154			if (i >= argc - 1) {
2155				fatal(gettext("No filename argument after -f flag"));
2156			}
2157			MBSTOWCS(wcs_buffer, argv[++i]);
2158			primary_makefile = GETNAME(wcs_buffer, FIND_LENGTH);
2159			(void) read_makefile(primary_makefile, true, true, true);
2160			argv[i] = NULL;		/* Remove filename */
2161			makefile_read = true;
2162		} else if (argv[i] &&
2163			   (argv[i][0] == (int) hyphen_char) &&
2164			   (argv[i][1] == 'c' ||
2165			    argv[i][1] == 'g' ||
2166			    argv[i][1] == 'j' ||
2167			    argv[i][1] == 'K' ||
2168			    argv[i][1] == 'M' ||
2169			    argv[i][1] == 'm' ||
2170			    argv[i][1] == 'O' ||
2171			    argv[i][1] == 'o') &&
2172			   (argv[i][2] == (int) nul_char)) {
2173			argv[i] = NULL;
2174			argv[++i] = NULL;
2175		}
2176	}
2177
2178/*
2179 *	If no command line "-f" args then look for "makefile", and then for
2180 *	"Makefile" if "makefile" isn't found.
2181 */
2182	if (!makefile_read) {
2183		(void) read_dir(dot,
2184				(wchar_t *) NULL,
2185				(Property) NULL,
2186				(wchar_t *) NULL);
2187	    if (!posix) {
2188		if (makefile_name->stat.is_file) {
2189			if (Makefile->stat.is_file) {
2190				warning(gettext("Both `makefile' and `Makefile' exist"));
2191			}
2192			primary_makefile = makefile_name;
2193			makefile_read = read_makefile(makefile_name,
2194						      false,
2195						      false,
2196						      true);
2197		}
2198		if (!makefile_read &&
2199		    Makefile->stat.is_file) {
2200			primary_makefile = Makefile;
2201			makefile_read = read_makefile(Makefile,
2202						      false,
2203						      false,
2204						      true);
2205		}
2206	    } else {
2207
2208		enum sccs_stat save_m_has_sccs = NO_SCCS;
2209		enum sccs_stat save_M_has_sccs = NO_SCCS;
2210
2211		if (makefile_name->stat.is_file) {
2212			if (Makefile->stat.is_file) {
2213				warning(gettext("Both `makefile' and `Makefile' exist"));
2214			}
2215		}
2216		if (makefile_name->stat.is_file) {
2217			if (makefile_name->stat.has_sccs == NO_SCCS) {
2218			   primary_makefile = makefile_name;
2219			   makefile_read = read_makefile(makefile_name,
2220						      false,
2221						      false,
2222						      true);
2223			} else {
2224			  save_m_has_sccs = makefile_name->stat.has_sccs;
2225			  makefile_name->stat.has_sccs = NO_SCCS;
2226			  primary_makefile = makefile_name;
2227			  makefile_read = read_makefile(makefile_name,
2228						      false,
2229						      false,
2230						      true);
2231			}
2232		}
2233		if (!makefile_read &&
2234		    Makefile->stat.is_file) {
2235			if (Makefile->stat.has_sccs == NO_SCCS) {
2236			   primary_makefile = Makefile;
2237			   makefile_read = read_makefile(Makefile,
2238						      false,
2239						      false,
2240						      true);
2241			} else {
2242			  save_M_has_sccs = Makefile->stat.has_sccs;
2243			  Makefile->stat.has_sccs = NO_SCCS;
2244			  primary_makefile = Makefile;
2245			  makefile_read = read_makefile(Makefile,
2246						      false,
2247						      false,
2248						      true);
2249			}
2250		}
2251		if (!makefile_read &&
2252		        makefile_name->stat.is_file) {
2253			   makefile_name->stat.has_sccs = save_m_has_sccs;
2254			   primary_makefile = makefile_name;
2255			   makefile_read = read_makefile(makefile_name,
2256						      false,
2257						      false,
2258						      true);
2259		}
2260		if (!makefile_read &&
2261		    Makefile->stat.is_file) {
2262			   Makefile->stat.has_sccs = save_M_has_sccs;
2263			   primary_makefile = Makefile;
2264			   makefile_read = read_makefile(Makefile,
2265						      false,
2266						      false,
2267						      true);
2268		}
2269	    }
2270	}
2271	do_not_exec_rule = save_do_not_exec_rule;
2272	allrules_read = makefile_read;
2273	trace_reader = false;
2274
2275/*
2276 *	Now get current value of MAKEFLAGS and compare it with
2277 *	the saved value we set before reading makefile.
2278 *	If they are different then MAKEFLAGS is subsequently set by
2279 *	makefile, just leave it there. Otherwise, if make mode
2280 *	is changed by using .POSIX target in makefile we need
2281 *	to correct MAKEFLAGS value.
2282 */
2283	Name mf_val = getvar(makeflags);
2284	if( (posix != is_xpg4)
2285	 && (!strcmp(mf_val->string_mb, makeflags_value_saved->string_mb)))
2286	{
2287		if (makeflags_string_posix.buffer.start[1] == (int) nul_char) {
2288			(void) SETVAR(makeflags,
2289				      GETNAME(makeflags_string_posix.buffer.start + 1,
2290					      FIND_LENGTH),
2291				      false);
2292		} else {
2293			if (makeflags_string_posix.buffer.start[1] != (int) space_char) {
2294				(void) SETVAR(makeflags,
2295					      GETNAME(makeflags_string_posix.buffer.start,
2296						      FIND_LENGTH),
2297					      false);
2298			} else {
2299				(void) SETVAR(makeflags,
2300					      GETNAME(makeflags_string_posix.buffer.start + 2,
2301						      FIND_LENGTH),
2302					      false);
2303			}
2304		}
2305	}
2306
2307	if (makeflags_string.free_after_use) {
2308		retmem(makeflags_string.buffer.start);
2309	}
2310	if (makeflags_string_posix.free_after_use) {
2311		retmem(makeflags_string_posix.buffer.start);
2312	}
2313	makeflags_string.buffer.start = NULL;
2314	makeflags_string_posix.buffer.start = NULL;
2315
2316	if (posix) {
2317		/*
2318		 * If the user did not redefine the ARFLAGS macro in the
2319		 * default makefile (make.rules), then we'd like to
2320		 * change the macro value of ARFLAGS to be in accordance
2321		 * with "POSIX" requirements.
2322		 */
2323		MBSTOWCS(wcs_buffer, "ARFLAGS");
2324		name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2325		macro = get_prop(name->prop, macro_prop);
2326		if ((macro != NULL) && /* Maybe (macro == NULL) || ? */
2327		    (IS_EQUAL(macro->body.macro.value->string_mb,
2328		              "rv"))) {
2329			MBSTOWCS(wcs_buffer, "-rv");
2330			value = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2331			(void) SETVAR(name,
2332			              value,
2333			              false);
2334		}
2335	}
2336
2337	if (!posix && !svr4) {
2338		set_sgs_support();
2339	}
2340
2341
2342/*
2343 *	Make sure KEEP_STATE is in the environment if KEEP_STATE is on.
2344 */
2345	macro = get_prop(keep_state_name->prop, macro_prop);
2346	if ((macro != NULL) &&
2347	    macro->body.macro.exported) {
2348		keep_state = true;
2349	}
2350	if (keep_state) {
2351		if (macro == NULL) {
2352			macro = maybe_append_prop(keep_state_name,
2353						  macro_prop);
2354		}
2355		macro->body.macro.exported = true;
2356		(void) SETVAR(keep_state_name,
2357			      empty_name,
2358			      false);
2359
2360		/*
2361		 *	Read state file
2362		 */
2363
2364		/* Before we read state, let's make sure we have
2365		** right state file.
2366		*/
2367		/* just in case macro references are used in make_state file
2368		** name, we better expand them at this stage using expand_value.
2369		*/
2370		INIT_STRING_FROM_STACK(dest, destbuffer);
2371		expand_value(make_state, &dest, false);
2372
2373		make_state = GETNAME(dest.buffer.start, FIND_LENGTH);
2374
2375		if(!stat(make_state->string_mb, &make_state_stat)) {
2376		   if(!(make_state_stat.st_mode & S_IFREG) ) {
2377			/* copy the make_state structure to the other
2378			** and then let make_state point to the new
2379			** one.
2380			*/
2381		      memcpy(&state_filename, make_state,sizeof(state_filename));
2382		      state_filename.string_mb = state_file_str_mb;
2383		/* Just a kludge to avoid two slashes back to back */
2384		      if((make_state->hash.length == 1)&&
2385			        (make_state->string_mb[0] == '/')) {
2386			 make_state->hash.length = 0;
2387			 make_state->string_mb[0] = '\0';
2388		      }
2389		      sprintf(state_file_str_mb,"%s%s",
2390		       make_state->string_mb,"/.make.state");
2391		      make_state = &state_filename;
2392			/* adjust the length to reflect the appended string */
2393		      make_state->hash.length += 12;
2394		   }
2395		} else { /* the file doesn't exist or no permission */
2396		   char tmp_path[MAXPATHLEN];
2397		   char *slashp;
2398
2399		   if (slashp = strrchr(make_state->string_mb, '/')) {
2400		      strncpy(tmp_path, make_state->string_mb,
2401				(slashp - make_state->string_mb));
2402			tmp_path[slashp - make_state->string_mb]=0;
2403		      if(strlen(tmp_path)) {
2404		        if(stat(tmp_path, &make_state_stat)) {
2405			  warning(gettext("directory %s for .KEEP_STATE_FILE does not exist"),tmp_path);
2406		        }
2407		        if (access(tmp_path, F_OK) != 0) {
2408			  warning(gettext("can't access dir %s"),tmp_path);
2409		        }
2410		      }
2411		   }
2412		}
2413		if (report_dependencies_level != 1) {
2414			Makefile_type	makefile_type_temp = makefile_type;
2415			makefile_type = reading_statefile;
2416			if (read_trace_level > 1) {
2417				trace_reader = true;
2418			}
2419			(void) read_simple_file(make_state,
2420						false,
2421						false,
2422						false,
2423						false,
2424						false,
2425						true);
2426			trace_reader = false;
2427			makefile_type = makefile_type_temp;
2428		}
2429	}
2430}
2431
2432/*
2433 * Scan the argv for options and "=" type args and make them readonly.
2434 */
2435static void
2436enter_argv_values(int argc, char *argv[], ASCII_Dyn_Array *makeflags_and_macro)
2437{
2438	register char		*cp;
2439	register int		i;
2440	int			length;
2441	register Name		name;
2442	int			opt_separator = argc;
2443	char			tmp_char;
2444	wchar_t			*tmp_wcs_buffer;
2445	register Name		value;
2446	Boolean			append = false;
2447	Property		macro;
2448	struct stat		statbuf;
2449
2450
2451	/* Read argv options and "=" type args and make them readonly. */
2452	makefile_type = reading_nothing;
2453	for (i = 1; i < argc; ++i) {
2454		append = false;
2455		if (argv[i] == NULL) {
2456			continue;
2457		} else if (((argv[i][0] == '-') && (argv[i][1] == '-')) ||
2458			   ((argv[i][0] == (int) ' ') &&
2459			    (argv[i][1] == (int) '-') &&
2460			    (argv[i][2] == (int) ' ') &&
2461			    (argv[i][3] == (int) '-'))) {
2462			argv[i] = NULL;
2463			opt_separator = i;
2464			continue;
2465		} else if ((i < opt_separator) && (argv[i][0] == (int) hyphen_char)) {
2466			switch (parse_command_option(argv[i][1])) {
2467			case 1:	/* -f seen */
2468				++i;
2469				continue;
2470			case 2:	/* -c seen */
2471				if (argv[i+1] == NULL) {
2472					fatal(gettext("No dmake rcfile argument after -c flag"));
2473				}
2474				MBSTOWCS(wcs_buffer, "DMAKE_RCFILE");
2475				name = GETNAME(wcs_buffer, FIND_LENGTH);
2476				break;
2477			case 4:	/* -g seen */
2478				if (argv[i+1] == NULL) {
2479					fatal(gettext("No dmake group argument after -g flag"));
2480				}
2481				MBSTOWCS(wcs_buffer, "DMAKE_GROUP");
2482				name = GETNAME(wcs_buffer, FIND_LENGTH);
2483				break;
2484			case 8:	/* -j seen */
2485				if (argv[i+1] == NULL) {
2486					fatal(gettext("No dmake max jobs argument after -j flag"));
2487				}
2488				MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
2489				name = GETNAME(wcs_buffer, FIND_LENGTH);
2490				break;
2491			case 16: /* -M seen */
2492				if (argv[i+1] == NULL) {
2493					fatal(gettext("No pmake machinesfile argument after -M flag"));
2494				}
2495				MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
2496				name = GETNAME(wcs_buffer, FIND_LENGTH);
2497				break;
2498			case 32: /* -m seen */
2499				if (argv[i+1] == NULL) {
2500					fatal(gettext("No dmake mode argument after -m flag"));
2501				}
2502				MBSTOWCS(wcs_buffer, "DMAKE_MODE");
2503				name = GETNAME(wcs_buffer, FIND_LENGTH);
2504				break;
2505			case 256: /* -K seen */
2506				if (argv[i+1] == NULL) {
2507					fatal(gettext("No makestate filename argument after -K flag"));
2508				}
2509				MBSTOWCS(wcs_buffer, argv[i+1]);
2510				make_state = GETNAME(wcs_buffer, FIND_LENGTH);
2511				keep_state = true;
2512				argv[i] = NULL;
2513				argv[i+1] = NULL;
2514				continue;
2515			case 512:	/* -o seen */
2516				if (argv[i+1] == NULL) {
2517					fatal(gettext("No dmake output dir argument after -o flag"));
2518				}
2519				MBSTOWCS(wcs_buffer, "DMAKE_ODIR");
2520				name = GETNAME(wcs_buffer, FIND_LENGTH);
2521				break;
2522			case 1024: /* -x seen */
2523				if (argv[i+1] == NULL) {
2524					fatal(gettext("No argument after -x flag"));
2525				}
2526				length = strlen( "SUN_MAKE_COMPAT_MODE=");
2527				if (strncmp(argv[i+1], "SUN_MAKE_COMPAT_MODE=", length) == 0) {
2528					argv[i+1] = &argv[i+1][length];
2529					MBSTOWCS(wcs_buffer, "SUN_MAKE_COMPAT_MODE");
2530					name = GETNAME(wcs_buffer, FIND_LENGTH);
2531					dmake_compat_mode_specified = dmake_add_mode_specified;
2532					break;
2533				}
2534				length = strlen( "DMAKE_OUTPUT_MODE=");
2535				if (strncmp(argv[i+1], "DMAKE_OUTPUT_MODE=", length) == 0) {
2536					argv[i+1] = &argv[i+1][length];
2537					MBSTOWCS(wcs_buffer, "DMAKE_OUTPUT_MODE");
2538					name = GETNAME(wcs_buffer, FIND_LENGTH);
2539					dmake_output_mode_specified = dmake_add_mode_specified;
2540				} else {
2541					warning(gettext("Unknown argument `%s' after -x flag (ignored)"),
2542					      argv[i+1]);
2543					argv[i] = argv[i + 1] = NULL;
2544					continue;
2545				}
2546				break;
2547			case 2048: /* -C seen */
2548				/*
2549				 * The chdir() will have been performed
2550				 * in read_command_options().
2551				 * Just set DMAKE_CDIR here.
2552				 */
2553				if (argv[i + 1] == NULL) {
2554					fatal(gettext(
2555					    "No argument after -C flag"));
2556				}
2557				MBSTOWCS(wcs_buffer, "DMAKE_CDIR");
2558				name = GETNAME(wcs_buffer, FIND_LENGTH);
2559				break;
2560			default: /* Shouldn't reach here */
2561				argv[i] = NULL;
2562				continue;
2563			}
2564			argv[i] = NULL;
2565			if (i == (argc - 1)) {
2566				break;
2567			}
2568			if ((length = strlen(argv[i+1])) >= MAXPATHLEN) {
2569				tmp_wcs_buffer = ALLOC_WC(length + 1);
2570				(void) mbstowcs(tmp_wcs_buffer, argv[i+1], length + 1);
2571				value = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
2572				retmem(tmp_wcs_buffer);
2573			} else {
2574				MBSTOWCS(wcs_buffer, argv[i+1]);
2575				value = GETNAME(wcs_buffer, FIND_LENGTH);
2576			}
2577			argv[i+1] = NULL;
2578		} else if ((cp = strchr(argv[i], (int) equal_char)) != NULL) {
2579/*
2580 * Combine all macro in dynamic array
2581 */
2582			if(*(cp-1) == (int) plus_char)
2583			{
2584				if(isspace(*(cp-2))) {
2585					append = true;
2586					cp--;
2587				}
2588			}
2589			if(!append)
2590				append_or_replace_macro_in_dyn_array(makeflags_and_macro, argv[i]);
2591
2592			while (isspace(*(cp-1))) {
2593				cp--;
2594			}
2595			tmp_char = *cp;
2596			*cp = (int) nul_char;
2597			MBSTOWCS(wcs_buffer, argv[i]);
2598			*cp = tmp_char;
2599			name = GETNAME(wcs_buffer, wcslen(wcs_buffer));
2600			while (*cp != (int) equal_char) {
2601				cp++;
2602			}
2603			cp++;
2604			while (isspace(*cp) && (*cp != (int) nul_char)) {
2605				cp++;
2606			}
2607			if ((length = strlen(cp)) >= MAXPATHLEN) {
2608				tmp_wcs_buffer = ALLOC_WC(length + 1);
2609				(void) mbstowcs(tmp_wcs_buffer, cp, length + 1);
2610				value = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
2611				retmem(tmp_wcs_buffer);
2612			} else {
2613				MBSTOWCS(wcs_buffer, cp);
2614				value = GETNAME(wcs_buffer, FIND_LENGTH);
2615			}
2616			argv[i] = NULL;
2617		} else {
2618			/* Illegal MAKEFLAGS argument */
2619			continue;
2620		}
2621		if(append) {
2622			setvar_append(name, value);
2623			append = false;
2624		} else {
2625			macro = maybe_append_prop(name, macro_prop);
2626			macro->body.macro.exported = true;
2627			SETVAR(name, value, false)->body.macro.read_only = true;
2628		}
2629	}
2630}
2631
2632/*
2633 * Append the DMake option and value to the MAKEFLAGS string.
2634 */
2635static void
2636append_makeflags_string(Name name, register String makeflags_string)
2637{
2638	const char	*option;
2639
2640	if (strcmp(name->string_mb, "DMAKE_GROUP") == 0) {
2641		option = " -g ";
2642	} else if (strcmp(name->string_mb, "DMAKE_MAX_JOBS") == 0) {
2643		option = " -j ";
2644	} else if (strcmp(name->string_mb, "DMAKE_MODE") == 0) {
2645		option = " -m ";
2646	} else if (strcmp(name->string_mb, "DMAKE_ODIR") == 0) {
2647		option = " -o ";
2648	} else if (strcmp(name->string_mb, "DMAKE_RCFILE") == 0) {
2649		option = " -c ";
2650	} else if (strcmp(name->string_mb, "PMAKE_MACHINESFILE") == 0) {
2651		option = " -M ";
2652	} else if (strcmp(name->string_mb, "DMAKE_OUTPUT_MODE") == 0) {
2653		option = " -x DMAKE_OUTPUT_MODE=";
2654	} else if (strcmp(name->string_mb, "SUN_MAKE_COMPAT_MODE") == 0) {
2655		option = " -x SUN_MAKE_COMPAT_MODE=";
2656	} else {
2657		fatal(gettext("Internal error: name not recognized in append_makeflags_string()"));
2658	}
2659	Property prop = maybe_append_prop(name, macro_prop);
2660	if( prop == 0 || prop->body.macro.value == 0 ||
2661	    prop->body.macro.value->string_mb == 0 ) {
2662		return;
2663	}
2664	char mbs_value[MAXPATHLEN + 100];
2665	strcpy(mbs_value, option);
2666	strcat(mbs_value, prop->body.macro.value->string_mb);
2667	MBSTOWCS(wcs_buffer, mbs_value);
2668	append_string(wcs_buffer, makeflags_string, FIND_LENGTH);
2669}
2670
2671/*
2672 *	read_environment(read_only)
2673 *
2674 *	This routine reads the process environment when make starts and enters
2675 *	it as make macros. The environment variable SHELL is ignored.
2676 *
2677 *	Parameters:
2678 *		read_only	Should we make env vars read only?
2679 *
2680 *	Global variables used:
2681 *		report_pwd	Set if this make was started by other make
2682 */
2683static void
2684read_environment(Boolean read_only)
2685{
2686	register char		**environment;
2687	int			length;
2688	wchar_t			*tmp_wcs_buffer;
2689	Boolean			alloced_tmp_wcs_buffer = false;
2690	register wchar_t	*name;
2691	register wchar_t	*value;
2692	register Name		macro;
2693	Property		val;
2694	Boolean			read_only_saved;
2695
2696	reading_environment = true;
2697	environment = environ;
2698	for (; *environment; environment++) {
2699		read_only_saved = read_only;
2700		if ((length = strlen(*environment)) >= MAXPATHLEN) {
2701			tmp_wcs_buffer = ALLOC_WC(length + 1);
2702			alloced_tmp_wcs_buffer = true;
2703			(void) mbstowcs(tmp_wcs_buffer, *environment, length + 1);
2704			name = tmp_wcs_buffer;
2705		} else {
2706			MBSTOWCS(wcs_buffer, *environment);
2707			name = wcs_buffer;
2708		}
2709		value = (wchar_t *) wcschr(name, (int) equal_char);
2710
2711		/*
2712		 * Looks like there's a bug in the system, but sometimes
2713		 * you can get blank lines in *environment.
2714		 */
2715		if (!value) {
2716			continue;
2717		}
2718		MBSTOWCS(wcs_buffer2, "SHELL=");
2719		if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2720			continue;
2721		}
2722		MBSTOWCS(wcs_buffer2, "MAKEFLAGS=");
2723		if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2724			report_pwd = true;
2725			/*
2726			 * In POSIX mode we do not want MAKEFLAGS to be readonly.
2727			 * If the MAKEFLAGS macro is subsequently set by the makefile,
2728			 * it replaces the MAKEFLAGS variable currently found in the
2729			 * environment.
2730			 * See Assertion 50 in section 6.2.5.3 of standard P1003.3.2/D8.
2731			 */
2732			if(posix) {
2733				read_only_saved = false;
2734			}
2735		}
2736
2737		/*
2738		 * We ignore SUNPRO_DEPENDENCIES. This environment variable is
2739		 * set by make and read by cpp which then writes info to
2740		 * .make.dependency.xxx.  When make is invoked by another make
2741		 * (recursive make), we don't want to read this because then
2742		 * the child make will end up writing to the parent
2743		 * directory's .make.state and clobbering them.
2744		 */
2745		MBSTOWCS(wcs_buffer2, "SUNPRO_DEPENDENCIES");
2746		if (IS_WEQUALN(name, wcs_buffer2, wcslen(wcs_buffer2))) {
2747			continue;
2748		}
2749
2750		macro = GETNAME(name, value - name);
2751		maybe_append_prop(macro, macro_prop)->body.macro.exported =
2752		  true;
2753		if ((value == NULL) || ((value + 1)[0] == (int) nul_char)) {
2754			val = setvar_daemon(macro,
2755					    (Name) NULL,
2756					    false, no_daemon, false, debug_level);
2757		} else {
2758			val = setvar_daemon(macro,
2759					    GETNAME(value + 1, FIND_LENGTH),
2760					    false, no_daemon, false, debug_level);
2761		}
2762		val->body.macro.read_only = read_only_saved;
2763		if (alloced_tmp_wcs_buffer) {
2764			retmem(tmp_wcs_buffer);
2765			alloced_tmp_wcs_buffer = false;
2766		}
2767	}
2768	reading_environment = false;
2769}
2770
2771/*
2772 *	read_makefile(makefile, complain, must_exist, report_file)
2773 *
2774 *	Read one makefile and check the result
2775 *
2776 *	Return value:
2777 *				false is the read failed
2778 *
2779 *	Parameters:
2780 *		makefile	The file to read
2781 *		complain	Passed thru to read_simple_file()
2782 *		must_exist	Passed thru to read_simple_file()
2783 *		report_file	Passed thru to read_simple_file()
2784 *
2785 *	Global variables used:
2786 *		makefile_type	Set to indicate we are reading main file
2787 *		recursion_level	Initialized
2788 */
2789static Boolean
2790read_makefile(register Name makefile, Boolean complain, Boolean must_exist, Boolean report_file)
2791{
2792	Boolean			b;
2793
2794	makefile_type = reading_makefile;
2795	recursion_level = 0;
2796	reading_dependencies = true;
2797	b = read_simple_file(makefile, true, true, complain,
2798			     must_exist, report_file, false);
2799	reading_dependencies = false;
2800	return b;
2801}
2802
2803/*
2804 *	make_targets(argc, argv, parallel_flag)
2805 *
2806 *	Call doname on the specified targets
2807 *
2808 *	Parameters:
2809 *		argc		You know what this is
2810 *		argv		You know what this is
2811 *		parallel_flag	True if building in parallel
2812 *
2813 *	Global variables used:
2814 *		build_failed_seen Used to generated message after failed -k
2815 *		commands_done	Used to generate message "Up to date"
2816 *		default_target_to_build	First proper target in makefile
2817 *		init		The Name ".INIT", use to run command
2818 *		parallel	Global parallel building flag
2819 *		quest		make -q, suppresses messages
2820 *		recursion_level	Initialized, used for tracing
2821 *		report_dependencies make -P, regroves whole process
2822 */
2823static void
2824make_targets(int argc, char **argv, Boolean parallel_flag)
2825{
2826	int			i;
2827	char			*cp;
2828	Doname			result;
2829	register Boolean	target_to_make_found = false;
2830
2831	(void) doname(init, true, true);
2832	recursion_level = 1;
2833	parallel = parallel_flag;
2834/*
2835 *	make remaining args
2836 */
2837/*
2838	if ((report_dependencies_level == 0) && parallel) {
2839 */
2840	if (parallel) {
2841		/*
2842		 * If building targets in parallel, start all of the
2843		 * remaining args to build in parallel.
2844		 */
2845		for (i = 1; i < argc; i++) {
2846			if ((cp = argv[i]) != NULL) {
2847				commands_done = false;
2848				if ((cp[0] == (int) period_char) &&
2849				    (cp[1] == (int) slash_char)) {
2850					cp += 2;
2851				}
2852				 if((cp[0] == (int) ' ') &&
2853				    (cp[1] == (int) '-') &&
2854				    (cp[2] == (int) ' ') &&
2855				    (cp[3] == (int) '-')) {
2856			            argv[i] = NULL;
2857					continue;
2858				}
2859				MBSTOWCS(wcs_buffer, cp);
2860				//default_target_to_build = GETNAME(wcs_buffer,
2861				//				  FIND_LENGTH);
2862				default_target_to_build = normalize_name(wcs_buffer,
2863								  wcslen(wcs_buffer));
2864				if (default_target_to_build == wait_name) {
2865					if (parallel_process_cnt > 0) {
2866						finish_running();
2867					}
2868					continue;
2869				}
2870				top_level_target = get_wstring(default_target_to_build->string_mb);
2871				/*
2872				 * If we can't execute the current target in
2873				 * parallel, hold off the target processing
2874				 * to preserve the order of the targets as they appeared
2875				 * in command line.
2876				 */
2877				if (!parallel_ok(default_target_to_build, false)
2878						&& parallel_process_cnt > 0) {
2879					finish_running();
2880				}
2881				result = doname_check(default_target_to_build,
2882						      true,
2883						      false,
2884						      false);
2885				gather_recursive_deps();
2886				if (/* !commands_done && */
2887				    (result == build_ok) &&
2888				    !quest &&
2889				    (report_dependencies_level == 0) /*  &&
2890				    (exists(default_target_to_build) > file_doesnt_exist)  */) {
2891					if (posix) {
2892						if (!commands_done) {
2893							(void) printf(gettext("`%s' is updated.\n"),
2894								      default_target_to_build->string_mb);
2895						} else {
2896							if (no_action_was_taken) {
2897								(void) printf(gettext("`%s': no action was taken.\n"),
2898									      default_target_to_build->string_mb);
2899							}
2900						}
2901					} else {
2902						default_target_to_build->stat.time = file_no_time;
2903						if (!commands_done &&
2904						    (exists(default_target_to_build) > file_doesnt_exist)) {
2905							(void) printf(gettext("`%s' is up to date.\n"),
2906								      default_target_to_build->string_mb);
2907						}
2908					}
2909				}
2910			}
2911		}
2912		/* Now wait for all of the targets to finish running */
2913		finish_running();
2914		//		setjmp(jmpbuffer);
2915
2916	}
2917	for (i = 1; i < argc; i++) {
2918		if ((cp = argv[i]) != NULL) {
2919			target_to_make_found = true;
2920			if ((cp[0] == (int) period_char) &&
2921			    (cp[1] == (int) slash_char)) {
2922				cp += 2;
2923			}
2924				 if((cp[0] == (int) ' ') &&
2925				    (cp[1] == (int) '-') &&
2926				    (cp[2] == (int) ' ') &&
2927				    (cp[3] == (int) '-')) {
2928			            argv[i] = NULL;
2929					continue;
2930				}
2931			MBSTOWCS(wcs_buffer, cp);
2932			default_target_to_build = normalize_name(wcs_buffer, wcslen(wcs_buffer));
2933			top_level_target = get_wstring(default_target_to_build->string_mb);
2934			report_recursion(default_target_to_build);
2935			commands_done = false;
2936			if (parallel) {
2937				result = (Doname) default_target_to_build->state;
2938			} else {
2939				result = doname_check(default_target_to_build,
2940						      true,
2941						      false,
2942						      false);
2943			}
2944			gather_recursive_deps();
2945			if (build_failed_seen) {
2946				build_failed_ever_seen = true;
2947				warning(gettext("Target `%s' not remade because of errors"),
2948					default_target_to_build->string_mb);
2949			}
2950			build_failed_seen = false;
2951			if (report_dependencies_level > 0) {
2952				print_dependencies(default_target_to_build,
2953						   get_prop(default_target_to_build->prop,
2954							    line_prop));
2955			}
2956			default_target_to_build->stat.time =
2957			  file_no_time;
2958			if (default_target_to_build->colon_splits > 0) {
2959				default_target_to_build->state =
2960				  build_dont_know;
2961			}
2962			if (!parallel &&
2963			    /* !commands_done && */
2964			    (result == build_ok) &&
2965			    !quest &&
2966			    (report_dependencies_level == 0) /*  &&
2967			    (exists(default_target_to_build) > file_doesnt_exist)  */) {
2968				if (posix) {
2969					if (!commands_done) {
2970						(void) printf(gettext("`%s' is updated.\n"),
2971							      default_target_to_build->string_mb);
2972					} else {
2973						if (no_action_was_taken) {
2974							(void) printf(gettext("`%s': no action was taken.\n"),
2975								      default_target_to_build->string_mb);
2976						}
2977					}
2978				} else {
2979					if (!commands_done &&
2980					    (exists(default_target_to_build) > file_doesnt_exist)) {
2981						(void) printf(gettext("`%s' is up to date.\n"),
2982							      default_target_to_build->string_mb);
2983					}
2984				}
2985			}
2986		}
2987	}
2988
2989/*
2990 *	If no file arguments have been encountered,
2991 *	make the first name encountered that doesnt start with a dot
2992 */
2993	if (!target_to_make_found) {
2994		if (default_target_to_build == NULL) {
2995			fatal(gettext("No arguments to build"));
2996		}
2997		commands_done = false;
2998		top_level_target = get_wstring(default_target_to_build->string_mb);
2999		report_recursion(default_target_to_build);
3000
3001
3002		if (getenv("SPRO_EXPAND_ERRORS")){
3003			(void) printf("::(%s)\n",
3004				      default_target_to_build->string_mb);
3005		}
3006
3007
3008		result = doname_parallel(default_target_to_build, true, false);
3009		gather_recursive_deps();
3010		if (build_failed_seen) {
3011			build_failed_ever_seen = true;
3012			warning(gettext("Target `%s' not remade because of errors"),
3013				default_target_to_build->string_mb);
3014		}
3015		build_failed_seen = false;
3016		if (report_dependencies_level > 0) {
3017			print_dependencies(default_target_to_build,
3018					   get_prop(default_target_to_build->
3019						    prop,
3020						    line_prop));
3021		}
3022		default_target_to_build->stat.time = file_no_time;
3023		if (default_target_to_build->colon_splits > 0) {
3024			default_target_to_build->state = build_dont_know;
3025		}
3026		if (/* !commands_done && */
3027		    (result == build_ok) &&
3028		    !quest &&
3029		    (report_dependencies_level == 0) /*  &&
3030		    (exists(default_target_to_build) > file_doesnt_exist)  */) {
3031			if (posix) {
3032				if (!commands_done) {
3033					(void) printf(gettext("`%s' is updated.\n"),
3034						      default_target_to_build->string_mb);
3035				} else {
3036					if (no_action_was_taken) {
3037						(void) printf(gettext("`%s': no action was taken.\n"),
3038							      default_target_to_build->string_mb);
3039					}
3040				}
3041			} else {
3042				if (!commands_done &&
3043				    (exists(default_target_to_build) > file_doesnt_exist)) {
3044					(void) printf(gettext("`%s' is up to date.\n"),
3045						      default_target_to_build->string_mb);
3046				}
3047			}
3048		}
3049	}
3050}
3051
3052/*
3053 *	report_recursion(target)
3054 *
3055 *	If this is a recursive make and the parent make has KEEP_STATE on
3056 *	this routine reports the dependency to the parent make
3057 *
3058 *	Parameters:
3059 *		target		Target to report
3060 *
3061 *	Global variables used:
3062 *		makefiles_used		List of makefiles read
3063 *		recursive_name		The Name ".RECURSIVE", printed
3064 *		report_dependency	dwight
3065 */
3066static void
3067report_recursion(register Name target)
3068{
3069	register FILE		*report_file = get_report_file();
3070
3071	if ((report_file == NULL) || (report_file == (FILE*)-1)) {
3072		return;
3073	}
3074	if (primary_makefile == NULL) {
3075		/*
3076		 * This can happen when there is no makefile and
3077		 * only implicit rules are being used.
3078		 */
3079		return;
3080	}
3081	(void) fprintf(report_file,
3082		       "%s: %s ",
3083		       get_target_being_reported_for(),
3084		       recursive_name->string_mb);
3085	report_dependency(get_current_path());
3086	report_dependency(target->string_mb);
3087	report_dependency(primary_makefile->string_mb);
3088	(void) fprintf(report_file, "\n");
3089}
3090
3091/* Next function "append_or_replace_macro_in_dyn_array" must be in "misc.cc". */
3092/* NIKMOL */
3093extern void
3094append_or_replace_macro_in_dyn_array(ASCII_Dyn_Array *Ar, char *macro)
3095{
3096	register char	*cp0;	/* work pointer in macro */
3097	register char	*cp1;	/* work pointer in array */
3098	register char	*cp2;	/* work pointer in array */
3099	register char	*cp3;	/* work pointer in array */
3100	register char	*name;	/* macro name */
3101	register char	*value;	/* macro value */
3102	register int	len_array;
3103	register int	len_macro;
3104
3105	char * esc_value = NULL;
3106	int esc_len;
3107
3108	if (!(len_macro = strlen(macro))) return;
3109	name = macro;
3110	while (isspace(*(name))) {
3111		name++;
3112	}
3113	if (!(value = strchr(name, (int) equal_char))) {
3114		/* no '=' in macro */
3115		goto ERROR_MACRO;
3116	}
3117	cp0 = value;
3118	value++;
3119	while (isspace(*(value))) {
3120		value++;
3121	}
3122	while (isspace(*(cp0-1))) {
3123		cp0--;
3124	}
3125	if (cp0 <= name) goto ERROR_MACRO; /* no name */
3126	if (!(Ar->size)) goto ALLOC_ARRAY;
3127	cp1 = Ar->start;
3128
3129LOOK_FOR_NAME:
3130	if (!(cp1 = strchr(cp1, name[0]))) goto APPEND_MACRO;
3131	if (!(cp2 = strchr(cp1, (int) equal_char))) goto APPEND_MACRO;
3132	if (strncmp(cp1, name, (size_t)(cp0-name))) {
3133		/* another name */
3134		cp1++;
3135		goto LOOK_FOR_NAME;
3136	}
3137	if (cp1 != Ar->start) {
3138		if (!isspace(*(cp1-1))) {
3139			/* another name */
3140			cp1++;
3141			goto LOOK_FOR_NAME;
3142		}
3143	}
3144	for (cp3 = cp1 + (cp0-name); cp3 < cp2; cp3++) {
3145		if (isspace(*cp3)) continue;
3146		/* else: another name */
3147		cp1++;
3148		goto LOOK_FOR_NAME;
3149	}
3150	/* Look for the next macro name in array */
3151	cp3 = cp2+1;
3152	if (*cp3 != (int) doublequote_char) {
3153		/* internal error */
3154		goto ERROR_MACRO;
3155	}
3156	if (!(cp3 = strchr(cp3+1, (int) doublequote_char))) {
3157		/* internal error */
3158		goto ERROR_MACRO;
3159	}
3160	cp3++;
3161	while (isspace(*cp3)) {
3162		cp3++;
3163	}
3164
3165	cp2 = cp1;  /* remove old macro */
3166	if ((*cp3) && (cp3 < Ar->start + Ar->size)) {
3167		for (; cp3 < Ar->start + Ar->size; cp3++) {
3168			*cp2++ = *cp3;
3169		}
3170	}
3171	for (; cp2 < Ar->start + Ar->size; cp2++) {
3172		*cp2 = 0;
3173	}
3174	if (*cp1) {
3175		/* check next name */
3176		goto LOOK_FOR_NAME;
3177	}
3178	goto APPEND_MACRO;
3179
3180ALLOC_ARRAY:
3181	if (Ar->size) {
3182		cp1 = Ar->start;
3183	} else {
3184		cp1 = 0;
3185	}
3186	Ar->size += 128;
3187	Ar->start = getmem(Ar->size);
3188	for (len_array=0; len_array < Ar->size; len_array++) {
3189		Ar->start[len_array] = 0;
3190	}
3191	if (cp1) {
3192		strcpy(Ar->start, cp1);
3193		retmem((wchar_t *) cp1);
3194	}
3195
3196APPEND_MACRO:
3197	len_array = strlen(Ar->start);
3198	esc_value = (char*)malloc(strlen(value)*2 + 1);
3199	quote_str(value, esc_value);
3200	esc_len = strlen(esc_value) - strlen(value);
3201	if (len_array + len_macro + esc_len + 5 >= Ar->size) goto  ALLOC_ARRAY;
3202	strcat(Ar->start, " ");
3203	strncat(Ar->start, name, cp0-name);
3204	strcat(Ar->start, "=");
3205	strncat(Ar->start, esc_value, strlen(esc_value));
3206	free(esc_value);
3207	return;
3208ERROR_MACRO:
3209	/* Macro without '=' or with invalid left/right part */
3210	return;
3211}
3212
3213static void
3214report_dir_enter_leave(Boolean entering)
3215{
3216	char	rcwd[MAXPATHLEN];
3217static	char *	mlev = NULL;
3218	char *	make_level_str = NULL;
3219	int	make_level_val = 0;
3220
3221	make_level_str = getenv("MAKELEVEL");
3222	if(make_level_str) {
3223		make_level_val = atoi(make_level_str);
3224	}
3225	if(mlev == NULL) {
3226		mlev = (char*) malloc(MAXPATHLEN);
3227	}
3228	if(entering) {
3229		sprintf(mlev, "MAKELEVEL=%d", make_level_val + 1);
3230	} else {
3231		make_level_val--;
3232		sprintf(mlev, "MAKELEVEL=%d", make_level_val);
3233	}
3234	putenv(mlev);
3235
3236	if(report_cwd) {
3237		if(make_level_val <= 0) {
3238			if(entering) {
3239				sprintf(rcwd,
3240				    gettext("%s: Entering directory `%s'\n"),
3241				    getprogname(),
3242				    get_current_path());
3243			} else {
3244				sprintf(rcwd,
3245				    gettext("%s: Leaving directory `%s'\n"),
3246				    getprogname(),
3247				    get_current_path());
3248			}
3249		} else {
3250			if(entering) {
3251				sprintf(rcwd,
3252				    gettext("%s[%d]: Entering directory `%s'\n"),
3253				    getprogname(),
3254				    make_level_val, get_current_path());
3255			} else {
3256				sprintf(rcwd,
3257				    gettext("%s[%d]: Leaving directory `%s'\n"),
3258				    getprogname(),
3259				    make_level_val, get_current_path());
3260			}
3261		}
3262		printf("%s", rcwd);
3263	}
3264}
3265