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