xref: /illumos-gate/usr/src/cmd/make/bin/misc.cc (revision 37395faa43a95e030f79ca75d81f5e4fdfcd2b19)
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 2005 Sun Microsystems, Inc. All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2019, Joyent, Inc.
26  */
27 
28 /*
29  *	misc.cc
30  *
31  *	This file contains various unclassified routines. Some main groups:
32  *		getname
33  *		Memory allocation
34  *		String handling
35  *		Property handling
36  *		Error message handling
37  *		Make internal state dumping
38  *		main routine support
39  */
40 
41 /*
42  * Included files
43  */
44 #include <errno.h>
45 #include <mk/defs.h>
46 #include <mksh/macro.h>		/* SETVAR() */
47 #include <mksh/misc.h>		/* enable_interrupt() */
48 #include <stdarg.h>		/* va_list, va_start(), va_end() */
49 #include <vroot/report.h>	/* SUNPRO_DEPENDENCIES */
50 #include <libintl.h>
51 
52 extern void job_adjust_fini();
53 
54 /*
55  * Defined macros
56  */
57 
58 /*
59  * typedefs & structs
60  */
61 
62 /*
63  * Static variables
64  */
65 
66 /*
67  * File table of contents
68  */
69 static	void		print_rule(register Name target);
70 static	void		print_target_n_deps(register Name target);
71 
72 /*****************************************
73  *
74  *	getname
75  */
76 
77 /*****************************************
78  *
79  *	Memory allocation
80  */
81 
82 /*
83  *	free_chain()
84  *
85  *	frees a chain of Name_vector's
86  *
87  *	Parameters:
88  *		ptr		Pointer to the first element in the chain
89  *				to be freed.
90  *
91  *	Global variables used:
92  */
93 void
94 free_chain(Name_vector ptr)
95 {
96 	if (ptr != NULL) {
97 		if (ptr->next != NULL) {
98 			free_chain(ptr->next);
99 		}
100 		free((char *) ptr);
101 	}
102 }
103 
104 /*****************************************
105  *
106  *	String manipulation
107  */
108 
109 /*****************************************
110  *
111  *	Nameblock property handling
112  */
113 
114 /*****************************************
115  *
116  *	Error message handling
117  */
118 
119 /*
120  *	fatal(format, args...)
121  *
122  *	Print a message and die
123  *
124  *	Parameters:
125  *		format		printf type format string
126  *		args		Arguments to match the format
127  *
128  *	Global variables used:
129  *		fatal_in_progress Indicates if this is a recursive call
130  *		parallel_process_cnt Do we need to wait for anything?
131  *		report_pwd	Should we report the current path?
132  */
133 /*VARARGS*/
134 void
135 fatal(const char *message, ...)
136 {
137 	va_list args;
138 
139 	va_start(args, message);
140 	(void) fflush(stdout);
141 	(void) fprintf(stderr, gettext("%s: Fatal error: "), getprogname());
142 	(void) vfprintf(stderr, message, args);
143 	(void) fprintf(stderr, "\n");
144 	va_end(args);
145 	if (report_pwd) {
146 		(void) fprintf(stderr,
147 			       gettext("Current working directory %s\n"),
148 			       get_current_path());
149 	}
150 	(void) fflush(stderr);
151 	if (fatal_in_progress) {
152 		exit_status = 1;
153 		exit(1);
154 	}
155 	fatal_in_progress = true;
156 	/* Let all parallel children finish */
157 	if ((dmake_mode_type == parallel_mode) &&
158 	    (parallel_process_cnt > 0)) {
159 		(void) fprintf(stderr,
160 			       gettext("Waiting for %d %s to finish\n"),
161 			       parallel_process_cnt,
162 			       parallel_process_cnt == 1 ?
163 			       gettext("job") : gettext("jobs"));
164 		(void) fflush(stderr);
165 	}
166 
167 	while (parallel_process_cnt > 0) {
168 		await_parallel(true);
169 		finish_children(false);
170 	}
171 
172 	job_adjust_fini();
173 
174 	exit_status = 1;
175 	exit(1);
176 }
177 
178 /*
179  *	warning(format, args...)
180  *
181  *	Print a message and continue.
182  *
183  *	Parameters:
184  *		format		printf type format string
185  *		args		Arguments to match the format
186  *
187  *	Global variables used:
188  *		report_pwd	Should we report the current path?
189  */
190 /*VARARGS*/
191 void
192 warning(char * message, ...)
193 {
194 	va_list args;
195 
196 	va_start(args, message);
197 	(void) fflush(stdout);
198 	(void) fprintf(stderr, gettext("%s: Warning: "), getprogname());
199 	(void) vfprintf(stderr, message, args);
200 	(void) fprintf(stderr, "\n");
201 	va_end(args);
202 	if (report_pwd) {
203 		(void) fprintf(stderr,
204 			       gettext("Current working directory %s\n"),
205 			       get_current_path());
206 	}
207 	(void) fflush(stderr);
208 }
209 
210 /*
211  *	time_to_string(time)
212  *
213  *	Take a numeric time value and produce
214  *	a proper string representation.
215  *
216  *	Return value:
217  *				The string representation of the time
218  *
219  *	Parameters:
220  *		time		The time we need to translate
221  *
222  *	Global variables used:
223  */
224 char *
225 time_to_string(const timestruc_t &time)
226 {
227 	struct tm		*tm;
228 	char			buf[128];
229 
230         if (time == file_doesnt_exist) {
231                 return gettext("File does not exist");
232         }
233         if (time == file_max_time) {
234                 return gettext("Younger than any file");
235         }
236 	tm = localtime(&time.tv_sec);
237 	strftime(buf, sizeof (buf), "%c %Z", tm);
238         buf[127] = (int) nul_char;
239         return strdup(buf);
240 }
241 
242 /*
243  *	get_current_path()
244  *
245  *	Stuff current_path with the current path if it isnt there already.
246  *
247  *	Parameters:
248  *
249  *	Global variables used:
250  */
251 char *
252 get_current_path(void)
253 {
254 	char			pwd[(MAXPATHLEN * MB_LEN_MAX)];
255 	static char		*current_path = NULL;
256 
257 	/*
258 	 * When we hit this with path_reset to true, we do not free the older
259 	 * version of current_path at this time, as we don't have confidence
260 	 * that we've properly caught all users of it and they haven't cached
261 	 * the pointer somewhere. As such, since this is only currently set with
262 	 * the -C option is passed in, it seems OK to just let that bit go.
263 	 */
264 	if (current_path == NULL || path_reset == true) {
265 		getcwd(pwd, sizeof(pwd));
266 		if (pwd[0] == (int) nul_char) {
267 			pwd[0] = (int) slash_char;
268 			pwd[1] = (int) nul_char;
269 		}
270 		current_path = strdup(pwd);
271 		path_reset = false;
272 	}
273 	return current_path;
274 }
275 
276 /*****************************************
277  *
278  *	Make internal state dumping
279  *
280  *	This is a set  of routines for dumping the internal make state
281  *	Used for the -p option
282  */
283 
284 /*
285  *	dump_make_state()
286  *
287  *	Dump make's internal state to stdout
288  *
289  *	Parameters:
290  *
291  *	Global variables used:
292  *		svr4			Was ".SVR4" seen in makefile?
293  *		svr4_name		The Name ".SVR4", printed
294  *		posix			Was ".POSIX" seen in makefile?
295  *		posix_name		The Name ".POSIX", printed
296  *		default_rule		Points to the .DEFAULT rule
297  *		default_rule_name	The Name ".DEFAULT", printed
298  *		default_target_to_build	The first target to print
299  *		dot_keep_state		The Name ".KEEP_STATE", printed
300  *		dot_keep_state_file	The Name ".KEEP_STATE_FILE", printed
301  *		hashtab			The make hash table for Name blocks
302  *		ignore_errors		Was ".IGNORE" seen in makefile?
303  *		ignore_name		The Name ".IGNORE", printed
304  *		keep_state		Was ".KEEP_STATE" seen in makefile?
305  *		percent_list		The list of % rules
306  *		precious		The Name ".PRECIOUS", printed
307  *		sccs_get_name		The Name ".SCCS_GET", printed
308  *		sccs_get_posix_name	The Name ".SCCS_GET_POSIX", printed
309  *		get_name		The Name ".GET", printed
310  *		get_posix_name		The Name ".GET_POSIX", printed
311  *		sccs_get_rule		Points to the ".SCCS_GET" rule
312  *		silent			Was ".SILENT" seen in makefile?
313  *		silent_name		The Name ".SILENT", printed
314  *		suffixes		The suffix list from ".SUFFIXES"
315  *		suffixes_name		The Name ".SUFFIX", printed
316  */
317 void
318 dump_make_state(void)
319 {
320 	Name_set::iterator	p, e;
321 	register Property	prop;
322 	register Dependency	dep;
323 	register Cmd_line	rule;
324 	Percent			percent, percent_depe;
325 
326 	/* Default target */
327 	if (default_target_to_build != NULL) {
328 		print_rule(default_target_to_build);
329 	}
330 	(void) printf("\n");
331 
332 	/* .POSIX */
333 	if (posix) {
334 		(void) printf("%s:\n", posix_name->string_mb);
335 	}
336 
337 	/* .DEFAULT */
338 	if (default_rule != NULL) {
339 		(void) printf("%s:\n", default_rule_name->string_mb);
340 		for (rule = default_rule; rule != NULL; rule = rule->next) {
341 			(void) printf("\t%s\n", rule->command_line->string_mb);
342 		}
343 	}
344 
345 	/* .IGNORE */
346 	if (ignore_errors) {
347 		(void) printf("%s:\n", ignore_name->string_mb);
348 	}
349 
350 	/* .KEEP_STATE: */
351 	if (keep_state) {
352 		(void) printf("%s:\n\n", dot_keep_state->string_mb);
353 	}
354 
355 	/* .PRECIOUS */
356 	(void) printf("%s:", precious->string_mb);
357 	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
358 			if ((p->stat.is_precious) || (all_precious)) {
359 				(void) printf(" %s", p->string_mb);
360 			}
361 	}
362 	(void) printf("\n");
363 
364 	/* .SCCS_GET */
365 	if (sccs_get_rule != NULL) {
366 		(void) printf("%s:\n", sccs_get_name->string_mb);
367 		for (rule = sccs_get_rule; rule != NULL; rule = rule->next) {
368 			(void) printf("\t%s\n", rule->command_line->string_mb);
369 		}
370 	}
371 
372 	/* .SILENT */
373 	if (silent) {
374 		(void) printf("%s:\n", silent_name->string_mb);
375 	}
376 
377 	/* .SUFFIXES: */
378 	(void) printf("%s:", suffixes_name->string_mb);
379 	for (dep = suffixes; dep != NULL; dep = dep->next) {
380 		(void) printf(" %s", dep->name->string_mb);
381 		build_suffix_list(dep->name);
382 	}
383 	(void) printf("\n\n");
384 
385 	/* % rules */
386 	for (percent = percent_list;
387 	     percent != NULL;
388 	     percent = percent->next) {
389 		(void) printf("%s:",
390 			      percent->name->string_mb);
391 
392 		for (percent_depe = percent->dependencies;
393 		     percent_depe != NULL;
394 		     percent_depe = percent_depe->next) {
395 			(void) printf(" %s", percent_depe->name->string_mb);
396 		}
397 
398 		(void) printf("\n");
399 
400 		for (rule = percent->command_template;
401 		     rule != NULL;
402 		     rule = rule->next) {
403 			(void) printf("\t%s\n", rule->command_line->string_mb);
404 		}
405 	}
406 
407 	/* Suffix rules */
408 	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
409 			Wstring wcb(p);
410 			if (wcb.get_string()[0] == (int) period_char) {
411 				print_rule(p);
412 			}
413 	}
414 
415 	/* Macro assignments */
416 	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
417 			if (((prop = get_prop(p->prop, macro_prop)) != NULL) &&
418 			    (prop->body.macro.value != NULL)) {
419 				(void) printf("%s", p->string_mb);
420 				print_value(prop->body.macro.value,
421 					    (Daemon) prop->body.macro.daemon);
422 			}
423 	}
424 	(void) printf("\n");
425 
426 	/* Conditional macro assignments */
427 	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
428 			for (prop = get_prop(p->prop, conditional_prop);
429 			     prop != NULL;
430 			     prop = get_prop(prop->next, conditional_prop)) {
431 				(void) printf("%s := %s",
432 					      p->string_mb,
433 					      prop->body.conditional.name->
434 					      string_mb);
435 				if (prop->body.conditional.append) {
436 					printf(" +");
437 				}
438 				else {
439 					printf(" ");
440 				}
441 				print_value(prop->body.conditional.value,
442 					    no_daemon);
443 			}
444 	}
445 	(void) printf("\n");
446 
447 	/* All other dependencies */
448 	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
449 			if (p->colons != no_colon) {
450 				print_rule(p);
451 			}
452 	}
453 	(void) printf("\n");
454 }
455 
456 /*
457  *	print_rule(target)
458  *
459  *	Print the rule for one target
460  *
461  *	Parameters:
462  *		target		Target we print rule for
463  *
464  *	Global variables used:
465  */
466 static void
467 print_rule(register Name target)
468 {
469 	register Cmd_line	rule;
470 	register Property	line;
471 	register Dependency	dependency;
472 
473 	if (target->dependency_printed ||
474 	    ((line = get_prop(target->prop, line_prop)) == NULL) ||
475 	    ((line->body.line.command_template == NULL) &&
476 	     (line->body.line.dependencies == NULL))) {
477 		return;
478 	}
479 	target->dependency_printed = true;
480 
481 	(void) printf("%s:", target->string_mb);
482 
483 	for (dependency = line->body.line.dependencies;
484 	     dependency != NULL;
485 	     dependency = dependency->next) {
486 		(void) printf(" %s", dependency->name->string_mb);
487 	}
488 
489 	(void) printf("\n");
490 
491 	for (rule = line->body.line.command_template;
492 	     rule != NULL;
493 	     rule = rule->next) {
494 		(void) printf("\t%s\n", rule->command_line->string_mb);
495 	}
496 }
497 
498 void
499 dump_target_list(void)
500 {
501 	Name_set::iterator	p, e;
502 	Wstring	str;
503 
504 	for (p = hashtab.begin(), e = hashtab.end(); p != e; p++) {
505 			str.init(p);
506 			wchar_t * wcb = str.get_string();
507 			if ((p->colons != no_colon) &&
508 			    ((wcb[0] != (int) period_char) ||
509 			     ((wcb[0] == (int) period_char) &&
510 			      (wcschr(wcb, (int) slash_char))))) {
511 				print_target_n_deps(p);
512 			}
513 	}
514 }
515 
516 static void
517 print_target_n_deps(register Name target)
518 {
519 	register Cmd_line	rule;
520 	register Property	line;
521 	register Dependency	dependency;
522 
523 	if (target->dependency_printed) {
524 		return;
525 	}
526 	target->dependency_printed = true;
527 
528 	(void) printf("%s\n", target->string_mb);
529 
530 	if ((line = get_prop(target->prop, line_prop)) == NULL) {
531 		return;
532 	}
533 	for (dependency = line->body.line.dependencies;
534 	     dependency != NULL;
535 	     dependency = dependency->next) {
536 		if (!dependency->automatic) {
537 			print_target_n_deps(dependency->name);
538 		}
539 	}
540 }
541 
542 /*****************************************
543  *
544  *	main() support
545  */
546 
547 /*
548  *	load_cached_names()
549  *
550  *	Load the vector of cached names
551  *
552  *	Parameters:
553  *
554  *	Global variables used:
555  *		Many many pointers to Name blocks.
556  */
557 void
558 load_cached_names(void)
559 {
560 	char		*cp;
561 	Name		dollar;
562 
563 	/* Load the cached_names struct */
564 	MBSTOWCS(wcs_buffer, ".BUILT_LAST_MAKE_RUN");
565 	built_last_make_run = GETNAME(wcs_buffer, FIND_LENGTH);
566 	MBSTOWCS(wcs_buffer, "@");
567 	c_at = GETNAME(wcs_buffer, FIND_LENGTH);
568 	MBSTOWCS(wcs_buffer, " *conditionals* ");
569 	conditionals = GETNAME(wcs_buffer, FIND_LENGTH);
570 	/*
571 	 * A version of make was released with NSE 1.0 that used
572 	 * VERSION-1.1 but this version is identical to VERSION-1.0.
573 	 * The version mismatch code makes a special case for this
574 	 * situation.  If the version number is changed from 1.0
575 	 * it should go to 1.2.
576 	 */
577 	MBSTOWCS(wcs_buffer, "VERSION-1.0");
578 	current_make_version = GETNAME(wcs_buffer, FIND_LENGTH);
579 	MBSTOWCS(wcs_buffer, ".SVR4");
580 	svr4_name = GETNAME(wcs_buffer, FIND_LENGTH);
581 	MBSTOWCS(wcs_buffer, ".POSIX");
582 	posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
583 	MBSTOWCS(wcs_buffer, ".DEFAULT");
584 	default_rule_name = GETNAME(wcs_buffer, FIND_LENGTH);
585 	MBSTOWCS(wcs_buffer, "$");
586 	dollar = GETNAME(wcs_buffer, FIND_LENGTH);
587 	MBSTOWCS(wcs_buffer, ".DONE");
588 	done = GETNAME(wcs_buffer, FIND_LENGTH);
589 	MBSTOWCS(wcs_buffer, ".");
590 	dot = GETNAME(wcs_buffer, FIND_LENGTH);
591 	MBSTOWCS(wcs_buffer, ".KEEP_STATE");
592 	dot_keep_state = GETNAME(wcs_buffer, FIND_LENGTH);
593 	MBSTOWCS(wcs_buffer, ".KEEP_STATE_FILE");
594 	dot_keep_state_file = GETNAME(wcs_buffer, FIND_LENGTH);
595 	MBSTOWCS(wcs_buffer, "");
596 	empty_name = GETNAME(wcs_buffer, FIND_LENGTH);
597 	MBSTOWCS(wcs_buffer, " FORCE");
598 	force = GETNAME(wcs_buffer, FIND_LENGTH);
599 	MBSTOWCS(wcs_buffer, "HOST_ARCH");
600 	host_arch = GETNAME(wcs_buffer, FIND_LENGTH);
601 	MBSTOWCS(wcs_buffer, "HOST_MACH");
602 	host_mach = GETNAME(wcs_buffer, FIND_LENGTH);
603 	MBSTOWCS(wcs_buffer, ".IGNORE");
604 	ignore_name = GETNAME(wcs_buffer, FIND_LENGTH);
605 	MBSTOWCS(wcs_buffer, ".INIT");
606 	init = GETNAME(wcs_buffer, FIND_LENGTH);
607 	MBSTOWCS(wcs_buffer, ".LOCAL");
608 	localhost_name = GETNAME(wcs_buffer, FIND_LENGTH);
609 	MBSTOWCS(wcs_buffer, ".make.state");
610 	make_state = GETNAME(wcs_buffer, FIND_LENGTH);
611 	MBSTOWCS(wcs_buffer, "MAKEFLAGS");
612 	makeflags = GETNAME(wcs_buffer, FIND_LENGTH);
613 	MBSTOWCS(wcs_buffer, ".MAKE_VERSION");
614 	make_version = GETNAME(wcs_buffer, FIND_LENGTH);
615 	MBSTOWCS(wcs_buffer, ".NO_PARALLEL");
616 	no_parallel_name = GETNAME(wcs_buffer, FIND_LENGTH);
617 	MBSTOWCS(wcs_buffer, ".NOT_AUTO");
618 	not_auto = GETNAME(wcs_buffer, FIND_LENGTH);
619 	MBSTOWCS(wcs_buffer, ".PARALLEL");
620 	parallel_name = GETNAME(wcs_buffer, FIND_LENGTH);
621 	MBSTOWCS(wcs_buffer, "PATH");
622 	path_name = GETNAME(wcs_buffer, FIND_LENGTH);
623 	MBSTOWCS(wcs_buffer, "+");
624 	plus = GETNAME(wcs_buffer, FIND_LENGTH);
625 	MBSTOWCS(wcs_buffer, ".PRECIOUS");
626 	precious = GETNAME(wcs_buffer, FIND_LENGTH);
627 	MBSTOWCS(wcs_buffer, "?");
628 	query = GETNAME(wcs_buffer, FIND_LENGTH);
629 	MBSTOWCS(wcs_buffer, "^");
630 	hat = GETNAME(wcs_buffer, FIND_LENGTH);
631 	MBSTOWCS(wcs_buffer, ".RECURSIVE");
632 	recursive_name = GETNAME(wcs_buffer, FIND_LENGTH);
633 	MBSTOWCS(wcs_buffer, ".SCCS_GET");
634 	sccs_get_name = GETNAME(wcs_buffer, FIND_LENGTH);
635 	MBSTOWCS(wcs_buffer, ".SCCS_GET_POSIX");
636 	sccs_get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
637 	MBSTOWCS(wcs_buffer, ".GET");
638 	get_name = GETNAME(wcs_buffer, FIND_LENGTH);
639 	MBSTOWCS(wcs_buffer, ".GET_POSIX");
640 	get_posix_name = GETNAME(wcs_buffer, FIND_LENGTH);
641 	MBSTOWCS(wcs_buffer, "SHELL");
642 	shell_name = GETNAME(wcs_buffer, FIND_LENGTH);
643 	MBSTOWCS(wcs_buffer, ".SILENT");
644 	silent_name = GETNAME(wcs_buffer, FIND_LENGTH);
645 	MBSTOWCS(wcs_buffer, ".SUFFIXES");
646 	suffixes_name = GETNAME(wcs_buffer, FIND_LENGTH);
647 	MBSTOWCS(wcs_buffer, SUNPRO_DEPENDENCIES);
648 	sunpro_dependencies = GETNAME(wcs_buffer, FIND_LENGTH);
649 	MBSTOWCS(wcs_buffer, "TARGET_ARCH");
650 	target_arch = GETNAME(wcs_buffer, FIND_LENGTH);
651 	MBSTOWCS(wcs_buffer, "TARGET_MACH");
652 	target_mach = GETNAME(wcs_buffer, FIND_LENGTH);
653 	MBSTOWCS(wcs_buffer, "VIRTUAL_ROOT");
654 	virtual_root = GETNAME(wcs_buffer, FIND_LENGTH);
655 	MBSTOWCS(wcs_buffer, "VPATH");
656 	vpath_name = GETNAME(wcs_buffer, FIND_LENGTH);
657 	MBSTOWCS(wcs_buffer, ".WAIT");
658 	wait_name = GETNAME(wcs_buffer, FIND_LENGTH);
659 
660 	wait_name->state = build_ok;
661 
662 	/* Mark special targets so that the reader treats them properly */
663 	svr4_name->special_reader = svr4_special;
664 	posix_name->special_reader = posix_special;
665 	built_last_make_run->special_reader = built_last_make_run_special;
666 	default_rule_name->special_reader = default_special;
667 	dot_keep_state->special_reader = keep_state_special;
668 	dot_keep_state_file->special_reader = keep_state_file_special;
669 	ignore_name->special_reader = ignore_special;
670 	make_version->special_reader = make_version_special;
671 	no_parallel_name->special_reader = no_parallel_special;
672 	parallel_name->special_reader = parallel_special;
673 	localhost_name->special_reader = localhost_special;
674 	precious->special_reader = precious_special;
675 	sccs_get_name->special_reader = sccs_get_special;
676 	sccs_get_posix_name->special_reader = sccs_get_posix_special;
677 	get_name->special_reader = get_special;
678 	get_posix_name->special_reader = get_posix_special;
679 	silent_name->special_reader = silent_special;
680 	suffixes_name->special_reader = suffixes_special;
681 
682 	/* The value of $$ is $ */
683 	(void) SETVAR(dollar, dollar, false);
684 	dollar->dollar = false;
685 
686 	/* Set the value of $(SHELL) */
687 	if (posix) {
688 	  MBSTOWCS(wcs_buffer, "/usr/xpg4/bin/sh");
689 	} else {
690 	  MBSTOWCS(wcs_buffer, "/bin/sh");
691 	}
692 	(void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
693 
694 	/*
695 	 * Use " FORCE" to simulate a FRC dependency for :: type
696 	 * targets with no dependencies.
697 	 */
698 	(void) append_prop(force, line_prop);
699 	force->stat.time = file_max_time;
700 
701 	/* Make sure VPATH is defined before current dir is read */
702 	if ((cp = getenv(vpath_name->string_mb)) != NULL) {
703 		MBSTOWCS(wcs_buffer, cp);
704 		(void) SETVAR(vpath_name,
705 			      GETNAME(wcs_buffer, FIND_LENGTH),
706 			      false);
707 	}
708 
709 	/* Check if there is NO PATH variable. If not we construct one. */
710 	if (getenv(path_name->string_mb) == NULL) {
711 		vroot_path = NULL;
712 		add_dir_to_path(".", &vroot_path, -1);
713 		add_dir_to_path("/bin", &vroot_path, -1);
714 		add_dir_to_path("/usr/bin", &vroot_path, -1);
715 	}
716 }
717 
718 /*
719  * iterate on list of conditional macros in np, and place them in
720  * a String_rec starting with, and separated by the '$' character.
721  */
722 void
723 cond_macros_into_string(Name np, String_rec *buffer)
724 {
725 	Macro_list	macro_list;
726 
727 	/*
728 	 * Put the version number at the start of the string
729 	 */
730 	MBSTOWCS(wcs_buffer, DEPINFO_FMT_VERSION);
731 	append_string(wcs_buffer, buffer, FIND_LENGTH);
732 	/*
733 	 * Add the rest of the conditional macros to the buffer
734 	 */
735 	if (np->depends_on_conditional){
736 		for (macro_list = np->conditional_macro_list;
737 		     macro_list != NULL; macro_list = macro_list->next){
738 			append_string(macro_list->macro_name, buffer,
739 				FIND_LENGTH);
740 			append_char((int) equal_char, buffer);
741 			append_string(macro_list->value, buffer, FIND_LENGTH);
742 			append_char((int) dollar_char, buffer);
743 		}
744 	}
745 }
746 
747