xref: /illumos-gate/usr/src/cmd/make/bin/read2.cc (revision 1e56f352c1c208679012bca47d552e127f5b1072)
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 RackTop Systems.
26  */
27 
28 /*
29  *	read.c
30  *
31  *	This file contains the makefile reader.
32  */
33 
34 /*
35  * Included files
36  */
37 #include <mk/defs.h>
38 #include <mksh/dosys.h>		/* sh_command2string() */
39 #include <mksh/macro.h>		/* expand_value() */
40 #include <mksh/misc.h>		/* retmem() */
41 #include <stdarg.h>		/* va_list, va_start(), va_end() */
42 #include <libintl.h>
43 
44 /*
45  * Defined macros
46  */
47 
48 /*
49  * typedefs & structs
50  */
51 
52 /*
53  * Static variables
54  */
55 static	Boolean		built_last_make_run_seen;
56 
57 /*
58  * File table of contents
59  */
60 static	Name_vector	enter_member_name(wchar_t *lib_start, wchar_t *member_start, wchar_t *string_end, Name_vector current_names, Name_vector *extra_names);
61 extern	Name		normalize_name(wchar_t *name_string, int length);
62 static	void		read_suffixes_list(Name_vector depes);
63 static	void		make_relative(wchar_t *to, wchar_t *result);
64 static	void		print_rule(Cmd_line command);
65 static	void		sh_transform(Name *name, Name *value);
66 
67 
68 /*
69  *	enter_name(string, tail_present, string_start, string_end,
70  *	      current_names, extra_names, target_group_seen)
71  *
72  *	Take one string and enter it as a name. The string is passed in
73  *	two parts. A make string and possibly a C string to append to it.
74  *	The result is stuffed in the vector current_names.
75  *	extra_names points to a vector that is used if current_names overflows.
76  *	This is allocad in the calling routine.
77  *	Here we handle the "lib.a[members]" notation.
78  *
79  *	Return value:
80  *				The name vector that was used
81  *
82  *	Parameters:
83  *		tail_present	Indicates if both C and make string was passed
84  *		string_start	C string
85  *		string_end	Pointer to char after last in C string
86  *		string		make style string with head of name
87  *		current_names	Vector to deposit the name in
88  *		extra_names	Where to get next name vector if we run out
89  *		target_group_seen Pointer to boolean that is set if "+" is seen
90  *
91  *	Global variables used:
92  *		makefile_type	When we read a report file we normalize paths
93  *		plus		Points to the Name "+"
94  */
95 
96 Name_vector
97 enter_name(String string, Boolean tail_present, wchar_t *string_start, wchar_t *string_end, Name_vector current_names, Name_vector *extra_names, Boolean *target_group_seen)
98 {
99 	Name			name;
100 	wchar_t	*cp;
101 	wchar_t			ch;
102 
103 	/* If we were passed a separate tail of the name we append it to the */
104 	/* make string with the rest of it */
105 	if (tail_present) {
106 		append_string(string_start, string, string_end - string_start);
107 		string_start = string->buffer.start;
108 		string_end = string->text.p;
109 	}
110 	ch = *string_end;
111 	*string_end = (int) nul_char;
112 	/*
113 	 * Check if there are any ( or [ that are not prefixed with $.
114 	 * If there are, we have to deal with the lib.a(members) format.
115 	 */
116 	for (cp = (wchar_t *) wcschr(string_start, (int) parenleft_char);
117 	     cp != NULL;
118 	     cp = (wchar_t *) wcschr(cp + 1, (int) parenleft_char)) {
119 		if (*(cp - 1) != (int) dollar_char) {
120 			*string_end = ch;
121 			return enter_member_name(string_start,
122 						 cp,
123 						 string_end,
124 						 current_names,
125 						 extra_names);
126 		}
127 	}
128 	*string_end = ch;
129 
130 	if (makefile_type == reading_cpp_file) {
131 		/* Remove extra ../ constructs if we are reading from a report file */
132 		name = normalize_name(string_start, string_end - string_start);
133 	} else {
134 		/*
135 		 * /tolik, fix bug 1197477/
136 		 * Normalize every target name before entering.
137 		 * ..//obj/a.o and ../obj//a.o are not two different targets.
138 		 * There is only one target ../obj/a.o
139 		 */
140 		/*name = GETNAME(string_start, string_end - string_start);*/
141 		name = normalize_name(string_start, string_end - string_start);
142 	}
143 
144 	/* Internalize the name. Detect the name "+" (target group here) */
145 if(current_names->used != 0 && current_names->names[current_names->used-1] == plus) {
146 	if(name == plus) {
147 		return current_names;
148 	}
149 }
150 	/* If the current_names vector is full we patch in the one from */
151 	/* extra_names */
152 	if (current_names->used == VSIZEOF(current_names->names)) {
153 		if (current_names->next != NULL) {
154 			current_names = current_names->next;
155 		} else {
156 			current_names->next = *extra_names;
157 			*extra_names = NULL;
158 			current_names = current_names->next;
159 			current_names->used = 0;
160 			current_names->next = NULL;
161 		}
162 	}
163 	current_names->target_group[current_names->used] = NULL;
164 	current_names->names[current_names->used++] = name;
165 	if (name == plus) {
166 		*target_group_seen = true;
167 	}
168 	if (tail_present && string->free_after_use) {
169 		retmem(string->buffer.start);
170 	}
171 	return current_names;
172 }
173 
174 /*
175  *	enter_member_name(lib_start, member_start, string_end,
176  *		  current_names, extra_names)
177  *
178  *	A string has been found to contain member names.
179  *	(The "lib.a[members]" and "lib.a(members)" notation)
180  *	Handle it pretty much as enter_name() does for simple names.
181  *
182  *	Return value:
183  *				The name vector that was used
184  *
185  *	Parameters:
186  *		lib_start	Points to the of start of "lib.a(member.o)"
187  *		member_start	Points to "member.o" from above string.
188  *		string_end	Points to char after last of above string.
189  *		current_names	Vector to deposit the name in
190  *		extra_names	Where to get next name vector if we run out
191  *
192  *	Global variables used:
193  */
194 static Name_vector
195 enter_member_name(wchar_t *lib_start, wchar_t *member_start, wchar_t *string_end, Name_vector current_names, Name_vector *extra_names)
196 {
197 	Boolean	entry = false;
198 	wchar_t			buffer[STRING_BUFFER_LENGTH];
199 	Name			lib;
200 	Name			member;
201 	Name			name;
202 	Property		prop;
203 	wchar_t			*memberp;
204 	wchar_t			*q;
205 	int		paren_count;
206 	Boolean	has_dollar;
207 	wchar_t	*cq;
208 	Name			long_member_name = NULL;
209 
210 	/* Internalize the name of the library */
211 	lib = GETNAME(lib_start, member_start - lib_start);
212 	lib->is_member = true;
213 	member_start++;
214 	if (*member_start == (int) parenleft_char) {
215 		/* This is really the "lib.a((entries))" format */
216 		entry = true;
217 		member_start++;
218 	}
219 	/* Move the library name to the buffer where we intend to build the */
220 	/* "lib.a(member)" for each member */
221 	(void) wcsncpy(buffer, lib_start, member_start - lib_start);
222 	memberp = buffer + (member_start-lib_start);
223 	while (1) {
224 		long_member_name = NULL;
225 		/* Skip leading spaces */
226 		for (;
227 		     (member_start < string_end) && iswspace(*member_start);
228 		     member_start++);
229 		/* Find the end of the member name. Allow nested (). Detect $*/
230 		for (cq = memberp, has_dollar = false, paren_count = 0;
231 		     (member_start < string_end) &&
232 		     ((*member_start != (int) parenright_char) ||
233 		      (paren_count > 0)) &&
234 		     !iswspace(*member_start);
235 		     *cq++ = *member_start++) {
236 			switch (*member_start) {
237 			case parenleft_char:
238 				paren_count++;
239 				break;
240 			case parenright_char:
241 				paren_count--;
242 				break;
243 			case dollar_char:
244 				has_dollar = true;
245 			}
246 		}
247 		/* Internalize the member name */
248 		member = GETNAME(memberp, cq - memberp);
249 		*cq = 0;
250 		if ((q = (wchar_t *) wcsrchr(memberp, (int) slash_char)) == NULL) {
251 			q = memberp;
252 		}
253 		if ((cq - q > (int) ar_member_name_len) &&
254 		    !has_dollar) {
255 			*cq++ = (int) parenright_char;
256 			if (entry) {
257 				*cq++ = (int) parenright_char;
258 			}
259 			long_member_name = GETNAME(buffer, cq - buffer);
260 			cq = q + (int) ar_member_name_len;
261 		}
262 		*cq++ = (int) parenright_char;
263 		if (entry) {
264 			*cq++ = (int) parenright_char;
265 		}
266 		/* Internalize the "lib.a(member)" notation for this member */
267 		name = GETNAME(buffer, cq - buffer);
268 		name->is_member = lib->is_member;
269 		if (long_member_name != NULL) {
270 			prop = append_prop(name, long_member_name_prop);
271 			name->has_long_member_name = true;
272 			prop->body.long_member_name.member_name =
273 			  long_member_name;
274 		}
275 		/* And add the member prop */
276 		prop = append_prop(name, member_prop);
277 		prop->body.member.library = lib;
278 		if (entry) {
279 			/* "lib.a((entry))" notation */
280 			prop->body.member.entry = member;
281 			prop->body.member.member = NULL;
282 		} else {
283 			/* "lib.a(member)" Notation */
284 			prop->body.member.entry = NULL;
285 			prop->body.member.member = member;
286 		}
287 		/* Handle overflow of current_names */
288 		if (current_names->used == VSIZEOF(current_names->names)) {
289 			if (current_names->next != NULL) {
290 				current_names = current_names->next;
291 			} else {
292 				if (*extra_names == NULL) {
293 					current_names =
294 					  current_names->next =
295 					    ALLOC(Name_vector);
296 				} else {
297 					current_names =
298 					  current_names->next =
299 					    *extra_names;
300 					*extra_names = NULL;
301 				}
302 				current_names->used = 0;
303 				current_names->next = NULL;
304 			}
305 		}
306 		current_names->target_group[current_names->used] = NULL;
307 		current_names->names[current_names->used++] = name;
308 		while (iswspace(*member_start)) {
309 			member_start++;
310 		}
311 		/* Check if there are more members */
312 		if ((*member_start == (int) parenright_char) ||
313 		    (member_start >= string_end)) {
314 			return current_names;
315 		}
316 	}
317 	/* NOTREACHED */
318 }
319 
320 /*
321  *	normalize_name(name_string, length)
322  *
323  *	Take a namestring and remove redundant ../, // and ./ constructs
324  *
325  *	Return value:
326  *				The normalized name
327  *
328  *	Parameters:
329  *		name_string	Path string to normalize
330  *		length		Length of that string
331  *
332  *	Global variables used:
333  *		dot		The Name ".", compared against
334  *		dotdot		The Name "..", compared against
335  */
336 Name
337 normalize_name(wchar_t *name_string, int length)
338 {
339 	static Name		dotdot;
340 	wchar_t	*string = ALLOC_WC(length + 1);
341 	wchar_t	*string2;
342 	wchar_t	*cdp;
343 	wchar_t			*current_component;
344 	Name			name;
345 	int		count;
346 
347 	if (dotdot == NULL) {
348 		MBSTOWCS(wcs_buffer, "..");
349 		dotdot = GETNAME(wcs_buffer, FIND_LENGTH);
350 	}
351 
352 	/*
353 	 * Copy string removing ./ and //.
354 	 * First strip leading ./
355 	 */
356 	while ((length > 1) &&
357 	       (name_string[0] == (int) period_char) &&
358 	       (name_string[1] == (int) slash_char)) {
359 		name_string += 2;
360 		length -= 2;
361 		while ((length > 0) && (name_string[0] == (int) slash_char)) {
362 			name_string++;
363 			length--;
364 		}
365 	}
366 	/* Then copy the rest of the string removing /./ & // */
367 	cdp = string;
368 	while (length > 0) {
369 		if (((length > 2) &&
370 		     (name_string[0] == (int) slash_char) &&
371 		     (name_string[1] == (int) period_char) &&
372 		     (name_string[2] == (int) slash_char)) ||
373 		    ((length == 2) &&
374 		     (name_string[0] == (int) slash_char) &&
375 		     (name_string[1] == (int) period_char))) {
376 			name_string += 2;
377 			length -= 2;
378 			continue;
379 		}
380 		if ((length > 1) &&
381 		    (name_string[0] == (int) slash_char) &&
382 		    (name_string[1] == (int) slash_char)) {
383 			name_string++;
384 			length--;
385 			continue;
386 		}
387 		*cdp++ = *name_string++;
388 		length--;
389 	}
390 	*cdp = (int) nul_char;
391 	/*
392 	 * Now scan for <name>/../ and remove such combinations iff <name>
393 	 * is not another ..
394 	 * Each time something is removed, the whole process is restarted.
395 	 */
396 removed_one:
397 	name_string = string;
398 	string2 = name_string;		/*save for free*/
399 	current_component =
400 	  cdp =
401 	    string =
402 	      ALLOC_WC((length = wcslen(name_string)) + 1);
403 	while (length > 0) {
404 		if (((length > 3) &&
405 		     (name_string[0] == (int) slash_char) &&
406 		     (name_string[1] == (int) period_char) &&
407 		     (name_string[2] == (int) period_char) &&
408 		     (name_string[3] == (int) slash_char)) ||
409 		    ((length == 3) &&
410 		     (name_string[0] == (int) slash_char) &&
411 		     (name_string[1] == (int) period_char) &&
412 		     (name_string[2] == (int) period_char))) {
413 			/* Positioned on the / that starts a /.. sequence */
414 			if (((count = cdp - current_component) != 0) &&
415 			    (exists(name = GETNAME(string, cdp - string)) > file_doesnt_exist) &&
416 			    (!name->stat.is_sym_link)) {
417 				name = GETNAME(current_component, count);
418 				if(name != dotdot) {
419 					cdp = current_component;
420 					name_string += 3;
421 					length -= 3;
422 					if (length > 0) {
423 						name_string++;	/* skip slash */
424 						length--;
425 						while (length > 0) {
426 							*cdp++ = *name_string++;
427 							length--;
428 						}
429 					}
430 					*cdp = (int) nul_char;
431 					retmem(string2);
432 					goto removed_one;
433 				}
434 			}
435 		}
436 		if ((*cdp++ = *name_string++) == (int) slash_char) {
437 			current_component = cdp;
438 		}
439 		length--;
440 	}
441 	*cdp = (int) nul_char;
442 	if (string[0] == (int) nul_char) {
443 		name = dot;
444 	} else {
445 		name = GETNAME(string, FIND_LENGTH);
446 	}
447 	retmem(string);
448 	retmem(string2);
449 	return name;
450 }
451 
452 /*
453  *	find_target_groups(target_list)
454  *
455  *	If a "+" was seen when the target list was scanned we need to extract
456  *	the groups. Each target in the name vector that is a member of a
457  *	group gets a pointer to a chain of all the members stuffed in its
458  *	target_group vector slot
459  *
460  *	Parameters:
461  *		target_list	The list of targets that contains "+"
462  *
463  *	Global variables used:
464  *		plus		The Name "+", compared against
465  */
466 Chain
467 find_target_groups(Name_vector target_list, int i, Boolean reset)
468 {
469 	static Chain		target_group = NULL;
470 	static Chain		tail_target_group = NULL;
471 	static Name		*next;
472 	static Boolean	clear_target_group = false;
473 
474 	if (reset) {
475 		target_group = NULL;
476 		tail_target_group = NULL;
477 		clear_target_group = false;
478 	}
479 
480 	/* Scan the list of targets */
481 	/* If the previous target terminated a group */
482 	/* we flush the pointer to that member chain */
483 	if (clear_target_group) {
484 		clear_target_group = false;
485 		target_group = NULL;
486 	}
487 	/* Pick up a pointer to the cell with */
488 	/* the next target */
489 	if (i + 1 != target_list->used) {
490 		next = &target_list->names[i + 1];
491 	} else {
492 		next = (target_list->next != NULL) ?
493 		  &target_list->next->names[0] : NULL;
494 	}
495 	/* We have four states here :
496 	 *	0:	No target group started and next element is not "+"
497 	 *		This is not interesting.
498 	 *	1:	A target group is being built and the next element
499 	 *		is not "+". This terminates the group.
500 	 *	2:	No target group started and the next member is "+"
501 	 *		This is the first target in a group.
502 	 *	3:	A target group started and the next member is a "+"
503 	 *		The group continues.
504 	 */
505 	switch ((target_group ? 1 : 0) +
506 		(next && (*next == plus) ?
507 		 2 : 0)) {
508 	      case 0:	/* Not target_group */
509 		break;
510 	      case 1:	/* Last group member */
511 		/* We need to keep this pointer so */
512 		/* we can stuff it for last member */
513 		clear_target_group = true;
514 		/* FALLTHROUGH */
515 	      case 3:	/* Middle group member */
516 		/* Add this target to the */
517 		/* current chain */
518 		tail_target_group->next = ALLOC(Chain);
519 		tail_target_group = tail_target_group->next;
520 		tail_target_group->next = NULL;
521 		tail_target_group->name = target_list->names[i];
522 		break;
523 	      case 2:	/* First group member */
524 		/* Start a new chain */
525 		target_group = tail_target_group = ALLOC(Chain);
526 		target_group->next = NULL;
527 		target_group->name = target_list->names[i];
528 		break;
529 	}
530 	/* Stuff the current chain, if any, in the */
531 	/* targets group slot */
532 	target_list->target_group[i] = target_group;
533 	if ((next != NULL) &&
534 	    (*next == plus)) {
535 		*next = NULL;
536 	}
537 	return (tail_target_group);
538 }
539 
540 /*
541  *	enter_dependencies(target, target_group, depes, command, separator)
542  *
543  *	Take one target and a list of dependencies and process the whole thing.
544  *	The target might be special in some sense in which case that is handled
545  *
546  *	Parameters:
547  *		target		The target we want to enter
548  *		target_group	Non-NULL if target is part of a group this time
549  *		depes		A list of dependencies for the target
550  *		command		The command the target should be entered with
551  *		separator	Indicates if this is a ":" or a "::" rule
552  *
553  *	Static variables used:
554  *		built_last_make_run_seen If the previous target was
555  *					.BUILT_LAST_MAKE_RUN we say to rewrite
556  *					the state file later on
557  *
558  *	Global variables used:
559  *		command_changed	Set to indicate if .make.state needs rewriting
560  *		default_target_to_build Set to the target if reading makefile
561  *					and this is the first regular target
562  *		force		The Name " FORCE", used with "::" targets
563  *		makefile_type	We do different things for makefile vs. report
564  *		not_auto	The Name ".NOT_AUTO", compared against
565  *		recursive_name	The Name ".RECURSIVE", compared against
566  *		temp_file_number Used to figure out when to clear stale
567  *					automatic dependencies
568  *		trace_reader	Indicates that we should echo stuff we read
569  */
570 void
571 enter_dependencies(Name target, Chain target_group, Name_vector depes, Cmd_line command, Separator separator)
572 {
573 	int		i;
574 	Property	line;
575 	Name			name;
576 	Name			directory;
577 	wchar_t			*namep;
578 	char			*mb_namep;
579 	Dependency		dp;
580 	Dependency		*dpp;
581 	Property		line2;
582 	wchar_t			relative[MAXPATHLEN];
583 	int		recursive_state;
584 	Boolean			register_as_auto;
585 	Boolean			not_auto_found;
586 	char			*slash;
587 	Wstring			depstr;
588 
589 	/* Check if this is a .RECURSIVE line */
590 	if ((depes->used >= 3) &&
591 	    (depes->names[0] == recursive_name)) {
592 		target->has_recursive_dependency = true;
593 		depes->names[0] = NULL;
594 		recursive_state = 0;
595 		dp = NULL;
596 		dpp = &dp;
597 		/* Read the dependencies. They are "<directory> <target-made>*/
598 		/* <makefile>*" */
599 		for (; depes != NULL; depes = depes->next) {
600 			for (i = 0; i < depes->used; i++) {
601 				if (depes->names[i] != NULL) {
602 					switch (recursive_state++) {
603 					case 0:	/* Directory */
604 					{
605 						depstr.init(depes->names[i]);
606 						make_relative(depstr.get_string(),
607 							      relative);
608 						directory =
609 						  GETNAME(relative,
610 							  FIND_LENGTH);
611 					}
612 						break;
613 					case 1:	/* Target */
614 						name = depes->names[i];
615 						break;
616 					default:	/* Makefiles */
617 						*dpp = ALLOC(Dependency);
618 						(*dpp)->next = NULL;
619 						(*dpp)->name = depes->names[i];
620 						(*dpp)->automatic = false;
621 						(*dpp)->stale = false;
622 						(*dpp)->built = false;
623 						dpp = &((*dpp)->next);
624 						break;
625 					}
626 				}
627 			}
628 		}
629 		/* Check if this recursion already has been reported else */
630 		/* enter the recursive prop for the target */
631 		/* The has_built flag is used to tell if this .RECURSIVE */
632 		/* was discovered from this run (read from a tmp file) */
633 		/* or was from discovered from the original .make.state */
634 		/* file */
635 		for (line = get_prop(target->prop, recursive_prop);
636 		     line != NULL;
637 		     line = get_prop(line->next, recursive_prop)) {
638 			if ((line->body.recursive.directory == directory) &&
639 			    (line->body.recursive.target == name)) {
640 				line->body.recursive.makefiles = dp;
641 				line->body.recursive.has_built =
642 				  (Boolean)
643 				    (makefile_type == reading_cpp_file);
644 				return;
645 			}
646 		}
647 		line2 = append_prop(target, recursive_prop);
648 		line2->body.recursive.directory = directory;
649 		line2->body.recursive.target = name;
650 		line2->body.recursive.makefiles = dp;
651 		line2->body.recursive.has_built =
652 		    (Boolean) (makefile_type == reading_cpp_file);
653 		line2->body.recursive.in_depinfo = false;
654 		return;
655 	}
656 	/* If this is the first target that doesnt start with a "." in the */
657 	/* makefile we remember that */
658 	Wstring tstr(target);
659 	wchar_t * wcb = tstr.get_string();
660 	if ((makefile_type == reading_makefile) &&
661 	    (default_target_to_build == NULL) &&
662 	    ((wcb[0] != (int) period_char) ||
663 	     wcschr(wcb, (int) slash_char))) {
664 
665 /* BID 1181577: $(EMPTY_MACRO) + $(EMPTY_MACRO):
666 ** The target with empty name cannot be default_target_to_build
667 */
668 		if (target->hash.length != 0)
669 			default_target_to_build = target;
670 	}
671 	/* Check if the line is ":" or "::" */
672 	if (makefile_type == reading_makefile) {
673 		if (target->colons == no_colon) {
674 			target->colons = separator;
675 		} else {
676 			if (target->colons != separator) {
677 				fatal_reader(gettext(":/:: conflict for target `%s'"),
678 					     target->string_mb);
679 			}
680 		}
681 		if (target->colons == two_colon) {
682 			if (depes->used == 0) {
683 				/* If this is a "::" type line with no */
684 				/* dependencies we add one "FRC" type */
685 				/* dependency for free */
686 				depes->used = 1; /* Force :: targets with no
687 						  * depes to always run */
688 				depes->names[0] = force;
689 			}
690 			/* Do not delete "::" type targets when interrupted */
691 			target->stat.is_precious = true;
692 			/*
693 			 * Build a synthetic target "<number>%target"
694 			 * for "target".
695 			 */
696 			mb_namep = getmem((int) (strlen(target->string_mb) + 10));
697 			namep = ALLOC_WC((int) (target->hash.length + 10));
698 			slash = strrchr(target->string_mb, (int) slash_char);
699 			if (slash == NULL) {
700 				(void) sprintf(mb_namep,
701 					        "%d@%s",
702 					        target->colon_splits++,
703 					        target->string_mb);
704 			} else {
705 				*slash = 0;
706 				(void) sprintf(mb_namep,
707 					        "%s/%d@%s",
708 					        target->string_mb,
709 					        target->colon_splits++,
710 					        slash + 1);
711 				*slash = (int) slash_char;
712 			}
713 			MBSTOWCS(namep, mb_namep);
714 			retmem_mb(mb_namep);
715 			name = GETNAME(namep, FIND_LENGTH);
716 			retmem(namep);
717 			if (trace_reader) {
718 				(void) printf("%s:\t", target->string_mb);
719 			}
720 			/* Make "target" depend on "<number>%target */
721 			line2 = maybe_append_prop(target, line_prop);
722 			enter_dependency(line2, name, true);
723 			line2->body.line.target = target;
724 			/* Put a prop on "<number>%target that makes */
725 			/* appear as "target" */
726 			/* when it is processed */
727 			maybe_append_prop(name, target_prop)->
728 			  body.target.target = target;
729 			target->is_double_colon_parent = true;
730 			name->is_double_colon = true;
731 			name->has_target_prop = true;
732 			if (trace_reader) {
733 				(void) printf("\n");
734 			}
735 			(target = name)->stat.is_file = true;
736 		}
737 	}
738 	/* This really is a regular dependency line. Just enter it */
739 	line = maybe_append_prop(target, line_prop);
740 	line->body.line.target = target;
741 	/* Depending on what kind of makefile we are reading we have to */
742 	/* treat things differently */
743 	switch (makefile_type) {
744 	case reading_makefile:
745 		/* Reading regular makefile. Just notice whether this */
746 		/* redefines the rule for the  target */
747 		if (command != NULL) {
748 			if (line->body.line.command_template != NULL) {
749 				line->body.line.command_template_redefined =
750 				  true;
751 				if ((wcb[0] == (int) period_char) &&
752 				    !wcschr(wcb, (int) slash_char)) {
753 					line->body.line.command_template =
754 					  command;
755 				}
756 			} else {
757 				line->body.line.command_template = command;
758 			}
759 		} else {
760 			if ((wcb[0] == (int) period_char) &&
761 			    !wcschr(wcb, (int) slash_char)) {
762 				line->body.line.command_template = command;
763 			}
764 		}
765 		break;
766 	case rereading_statefile:
767 		/* Rereading the statefile. We only enter thing that changed */
768 		/* since the previous time we read it */
769 		if (!built_last_make_run_seen) {
770 			for (Cmd_line next, cmd = command; cmd != NULL; cmd = next) {
771 				next = cmd->next;
772 				free(cmd);
773 			}
774 			return;
775 		}
776 		built_last_make_run_seen = false;
777 		command_changed = true;
778 		target->ran_command = true;
779 		/* FALLTHROUGH */
780 	case reading_statefile:
781 		/* Reading the statefile for the first time. Enter the rules */
782 		/* as "Commands used" not "templates to use" */
783 		if (command != NULL) {
784 			for (Cmd_line next, cmd = line->body.line.command_used;
785 			     cmd != NULL; cmd = next) {
786 				next = cmd->next;
787 				free(cmd);
788 			}
789 			line->body.line.command_used = command;
790 		}
791 		/* FALLTHROUGH */
792 	case reading_cpp_file:
793 		/* Reading report file from programs that reports */
794 		/* dependencies. If this is the first time the target is */
795 		/* read from this reportfile we clear all old */
796 		/* automatic depes */
797 		if (target->temp_file_number == temp_file_number) {
798 			break;
799 		}
800 		target->temp_file_number = temp_file_number;
801 		command_changed = true;
802 		if (line != NULL) {
803 			for (dp = line->body.line.dependencies;
804 			     dp != NULL;
805 			     dp = dp->next) {
806 				if (dp->automatic) {
807 					dp->stale = true;
808 				}
809 			}
810 		}
811 		break;
812 	default:
813 		fatal_reader(gettext("Internal error. Unknown makefile type %d"),
814 			     makefile_type);
815 	}
816 	/* A target may only be involved in one target group */
817 	if (line->body.line.target_group != NULL) {
818 		if (target_group != NULL) {
819 			fatal_reader(gettext("Too many target groups for target `%s'"),
820 				     target->string_mb);
821 		}
822 	} else {
823 		line->body.line.target_group = target_group;
824 	}
825 
826 	if (trace_reader) {
827 		(void) printf("%s:\t", target->string_mb);
828 	}
829 	/* Enter the dependencies */
830 	register_as_auto = BOOLEAN(makefile_type != reading_makefile);
831 	not_auto_found = false;
832 	for (;
833 	     (depes != NULL) && !not_auto_found;
834 	     depes = depes->next) {
835 		for (i = 0; i < depes->used; i++) {
836 			/* the dependency .NOT_AUTO signals beginning of
837 			 * explicit dependancies which were put at end of
838 			 * list in .make.state file - we stop entering
839 			 * dependencies at this point
840 			 */
841 			if (depes->names[i] == not_auto) {
842 				not_auto_found = true;
843 				break;
844 			}
845 			enter_dependency(line,
846 					 depes->names[i],
847 					 register_as_auto);
848 		}
849 	}
850 	if (trace_reader) {
851 		(void) printf("\n");
852 		print_rule(command);
853 	}
854 }
855 
856 /*
857  *	enter_dependency(line, depe, automatic)
858  *
859  *	Enter one dependency. Do not enter duplicates.
860  *
861  *	Parameters:
862  *		line		The line block that the dependeny is
863  *				entered for
864  *		depe		The dependency to enter
865  *		automatic	Used to set the field "automatic"
866  *
867  *	Global variables used:
868  *		makefile_type	We do different things for makefile vs. report
869  *		trace_reader	Indicates that we should echo stuff we read
870  *		wait_name	The Name ".WAIT", compared against
871  */
872 void
873 enter_dependency(Property line, Name depe, Boolean automatic)
874 {
875 	Dependency	dp;
876 	Dependency	*insert;
877 
878 	if (trace_reader) {
879 		(void) printf("%s ", depe->string_mb);
880 	}
881 	/* Find the end of the list and check for duplicates */
882 	for (insert = &line->body.line.dependencies, dp = *insert;
883 	     dp != NULL;
884 	     insert = &dp->next, dp = *insert) {
885 		if ((dp->name == depe) && (depe != wait_name)) {
886 			if (dp->automatic) {
887 				dp->automatic = automatic;
888 				if (automatic) {
889 					dp->built = false;
890 					depe->stat.is_file = true;
891 				}
892 			}
893 			dp->stale = false;
894 			return;
895 		}
896 	}
897 	/* Insert the new dependency since we couldnt find it */
898 	dp = *insert = ALLOC(Dependency);
899 	dp->name = depe;
900 	dp->next = NULL;
901 	dp->automatic = automatic;
902 	dp->stale = false;
903 	dp->built = false;
904 	depe->stat.is_file = true;
905 
906 	if ((makefile_type == reading_makefile) &&
907 	    (line != NULL) &&
908 	    (line->body.line.target != NULL)) {
909 		line->body.line.target->has_regular_dependency = true;
910 	}
911 }
912 
913 /*
914  *	enter_percent(target, depes, command)
915  *
916  *	Enter "x%y : a%b" type lines
917  *	% patterns are stored in four parts head and tail for target and source
918  *
919  *	Parameters:
920  *		target		Left hand side of pattern
921  *		depes		The dependency list with the rh pattern
922  *		command		The command for the pattern
923  *
924  *	Global variables used:
925  *		empty_name	The Name "", compared against
926  *		percent_list	The list of all percent rules, added to
927  *		trace_reader	Indicates that we should echo stuff we read
928  */
929 Percent
930 enter_percent(Name target, Chain target_group, Name_vector depes, Cmd_line command)
931 {
932 	Percent	result = ALLOC(Percent);
933 	Percent	depe;
934 	Percent	*depe_tail = &result->dependencies;
935 	Percent	*insert;
936 	wchar_t	*cp, *cp1;
937 	Name_vector		nvp;
938 	int			i;
939 	int			pattern;
940 
941 	result->next = NULL;
942 	result->patterns = NULL;
943 	result->patterns_total = 0;
944 	result->command_template = command;
945 	result->being_expanded = false;
946 	result->name = target;
947 	result->dependencies = NULL;
948 	result->target_group = target_group;
949 
950 	/* get patterns count */
951 	Wstring wcb(target);
952 	cp = wcb.get_string();
953 	while (true) {
954 		cp = (wchar_t *) wcschr(cp, (int) percent_char);
955 		if (cp != NULL) {
956 			result->patterns_total++;
957 			cp++;
958 		} else {
959 			break;
960 		}
961 	}
962 	result->patterns_total++;
963 
964 	/* allocate storage for patterns */
965 	result->patterns = (Name *) getmem(sizeof(Name) * result->patterns_total);
966 
967 	/* then create patterns */
968 	cp = wcb.get_string();
969 	pattern = 0;
970 	while (true) {
971 		cp1 = (wchar_t *) wcschr(cp, (int) percent_char);
972 		if (cp1 != NULL) {
973 			result->patterns[pattern] = GETNAME(cp, cp1 - cp);
974 			cp = cp1 + 1;
975 			pattern++;
976 		} else {
977 			result->patterns[pattern] = GETNAME(cp, (int) target->hash.length - (cp - wcb.get_string()));
978 			break;
979 		}
980 	}
981 
982 	Wstring wcb1;
983 
984 	/* build dependencies list */
985 	for (nvp = depes; nvp != NULL; nvp = nvp->next) {
986 		for (i = 0; i < nvp->used; i++) {
987 			depe = ALLOC(Percent);
988 			depe->next = NULL;
989 			depe->patterns = NULL;
990 			depe->patterns_total = 0;
991 			depe->name = nvp->names[i];
992 			depe->dependencies = NULL;
993 			depe->command_template = NULL;
994 			depe->being_expanded = false;
995 			depe->target_group = NULL;
996 
997 			*depe_tail = depe;
998 			depe_tail = &depe->next;
999 
1000 			if (depe->name->percent) {
1001 				/* get patterns count */
1002 				wcb1.init(depe->name);
1003 				cp = wcb1.get_string();
1004 				while (true) {
1005 					cp = (wchar_t *) wcschr(cp, (int) percent_char);
1006 					if (cp != NULL) {
1007 						depe->patterns_total++;
1008 						cp++;
1009 					} else {
1010 						break;
1011 					}
1012 				}
1013 				depe->patterns_total++;
1014 
1015 				/* allocate storage for patterns */
1016 				depe->patterns = (Name *) getmem(sizeof(Name) * depe->patterns_total);
1017 
1018 				/* then create patterns */
1019 				cp = wcb1.get_string();
1020 				pattern = 0;
1021 				while (true) {
1022 					cp1 = (wchar_t *) wcschr(cp, (int) percent_char);
1023 					if (cp1 != NULL) {
1024 						depe->patterns[pattern] = GETNAME(cp, cp1 - cp);
1025 						cp = cp1 + 1;
1026 						pattern++;
1027 					} else {
1028 						depe->patterns[pattern] = GETNAME(cp, (int) depe->name->hash.length - (cp - wcb1.get_string()));
1029 						break;
1030 					}
1031 				}
1032 			}
1033 		}
1034 	}
1035 
1036 	/* Find the end of the percent list and append the new pattern */
1037 	for (insert = &percent_list; (*insert) != NULL; insert = &(*insert)->next);
1038 	*insert = result;
1039 
1040 	if (trace_reader) {
1041 		(void) printf("%s:", result->name->string_mb);
1042 
1043 		for (depe = result->dependencies; depe != NULL; depe = depe->next) {
1044 			(void) printf(" %s", depe->name->string_mb);
1045 		}
1046 
1047 		(void) printf("\n");
1048 
1049 		print_rule(command);
1050 	}
1051 
1052 	return result;
1053 }
1054 
1055 /*
1056  *	enter_dyntarget(target)
1057  *
1058  *	Enter "$$(MACRO) : b" type lines
1059  *
1060  *	Parameters:
1061  *		target		Left hand side of pattern
1062  *
1063  *	Global variables used:
1064  *		dyntarget_list	The list of all percent rules, added to
1065  *		trace_reader	Indicates that we should echo stuff we read
1066  */
1067 Dyntarget
1068 enter_dyntarget(Name target)
1069 {
1070 	Dyntarget	result = ALLOC(Dyntarget);
1071 	Dyntarget		p;
1072 	Dyntarget		*insert;
1073 	int				i;
1074 
1075 	result->next = NULL;
1076 	result->name = target;
1077 
1078 
1079 	/* Find the end of the dyntarget list and append the new pattern */
1080 	for (insert = &dyntarget_list, p = *insert;
1081 	     p != NULL;
1082 	     insert = &p->next, p = *insert);
1083 	*insert = result;
1084 
1085 	if (trace_reader) {
1086 		(void) printf("Dynamic target %s:\n", result->name->string_mb);
1087 	}
1088 	return( result);
1089 }
1090 
1091 
1092 /*
1093  *	special_reader(target, depes, command)
1094  *
1095  *	Read the pseudo targets make knows about
1096  *	This handles the special targets that should not be entered as regular
1097  *	target/dependency sets.
1098  *
1099  *	Parameters:
1100  *		target		The special target
1101  *		depes		The list of dependencies it was entered with
1102  *		command		The command it was entered with
1103  *
1104  *	Static variables used:
1105  *		built_last_make_run_seen Set to indicate .BUILT_LAST... seen
1106  *
1107  *	Global variables used:
1108  *		all_parallel	Set to indicate that everything runs parallel
1109  *		svr4		Set when ".SVR4" target is read
1110  *		svr4_name	The Name ".SVR4"
1111  *		posix		Set when ".POSIX" target is read
1112  *		posix_name	The Name ".POSIX"
1113  *		current_make_version The Name "<current version number>"
1114  *		default_rule	Set when ".DEFAULT" target is read
1115  *		default_rule_name The Name ".DEFAULT", used for tracing
1116  *		dot_keep_state	The Name ".KEEP_STATE", used for tracing
1117  *		ignore_errors	Set if ".IGNORE" target is read
1118  *		ignore_name	The Name ".IGNORE", used for tracing
1119  *		keep_state	Set if ".KEEP_STATE" target is read
1120  *		no_parallel_name The Name ".NO_PARALLEL", used for tracing
1121  *		only_parallel	Set to indicate only some targets runs parallel
1122  *		parallel_name	The Name ".PARALLEL", used for tracing
1123  *		precious	The Name ".PRECIOUS", used for tracing
1124  *		sccs_get_name	The Name ".SCCS_GET", used for tracing
1125  *		sccs_get_posix_name The Name ".SCCS_GET_POSIX", used for tracing
1126  *		get_name	The Name ".GET", used for tracing
1127  *		sccs_get_rule	Set when ".SCCS_GET" target is read
1128  *		silent		Set when ".SILENT" target is read
1129  *		silent_name	The Name ".SILENT", used for tracing
1130  *		trace_reader	Indicates that we should echo stuff we read
1131  */
1132 void
1133 special_reader(Name target, Name_vector depes, Cmd_line command)
1134 {
1135 	int		n;
1136 
1137 	switch (target->special_reader) {
1138 
1139 	case svr4_special:
1140 		if (depes->used != 0) {
1141 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1142 				     target->string_mb);
1143 		}
1144 		svr4  = true;
1145 		posix  = false;
1146 		keep_state = false;
1147 		all_parallel = false;
1148 		only_parallel = false;
1149 		if (trace_reader) {
1150 			(void) printf("%s:\n", svr4_name->string_mb);
1151 		}
1152 		break;
1153 
1154 	case posix_special:
1155 		if(svr4)
1156 		  break;
1157 		if (depes->used != 0) {
1158 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1159 				     target->string_mb);
1160 		}
1161 		posix  = true;
1162 			/* with posix on, use the posix get rule */
1163 		sccs_get_rule = sccs_get_posix_rule;
1164 			/* turn keep state off being SunPro make specific */
1165 		keep_state = false;
1166 		/* Use /usr/xpg4/bin/sh on Solaris */
1167 		MBSTOWCS(wcs_buffer, "/usr/xpg4/bin/sh");
1168 		(void) SETVAR(shell_name, GETNAME(wcs_buffer, FIND_LENGTH), false);
1169 		if (trace_reader) {
1170 			(void) printf("%s:\n", posix_name->string_mb);
1171 		}
1172 		break;
1173 
1174 	case built_last_make_run_special:
1175 		built_last_make_run_seen = true;
1176 		break;
1177 
1178 	case default_special:
1179 		if (depes->used != 0) {
1180 			warning(gettext("Illegal dependency list for target `%s'"),
1181 				target->string_mb);
1182 		}
1183 		default_rule = command;
1184 		if (trace_reader) {
1185 			(void) printf("%s:\n",
1186 				      default_rule_name->string_mb);
1187 			print_rule(command);
1188 		}
1189 		break;
1190 
1191 
1192 	case ignore_special:
1193 		if ((depes->used != 0) &&(!posix)){
1194 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1195 				     target->string_mb);
1196 		}
1197 		if (depes->used == 0)
1198 		{
1199 		   ignore_errors_all = true;
1200 		}
1201 		if(svr4) {
1202 		  ignore_errors_all = true;
1203 		  break;
1204 		}
1205 		for (; depes != NULL; depes = depes->next) {
1206 			for (n = 0; n < depes->used; n++) {
1207 				depes->names[n]->ignore_error_mode = true;
1208 			}
1209 		}
1210 		if (trace_reader) {
1211 			(void) printf("%s:\n", ignore_name->string_mb);
1212 		}
1213 		break;
1214 
1215 	case keep_state_special:
1216 		if(svr4)
1217 		  break;
1218 			/* ignore keep state, being SunPro make specific */
1219 		if(posix)
1220 		  break;
1221 		if (depes->used != 0) {
1222 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1223 				     target->string_mb);
1224 		}
1225 		keep_state = true;
1226 		if (trace_reader) {
1227 			(void) printf("%s:\n",
1228 				      dot_keep_state->string_mb);
1229 		}
1230 		break;
1231 
1232 	case keep_state_file_special:
1233 		if(svr4)
1234 		  break;
1235 		if(posix)
1236 		  break;
1237 			/* it's not necessary to specify KEEP_STATE, if this
1238 			** is given, so set the keep_state.
1239 			*/
1240 		keep_state = true;
1241 		if (depes->used != 0) {
1242 		   if((!make_state) ||(!strcmp(make_state->string_mb,".make.state"))) {
1243 		     make_state = depes->names[0];
1244 		   }
1245 		}
1246 		break;
1247 	case make_version_special:
1248 		if(svr4)
1249 		  break;
1250 		if (depes->used != 1) {
1251 			fatal_reader(gettext("Illegal dependency list for target `%s'"),
1252 				     target->string_mb);
1253 		}
1254 		if (depes->names[0] != current_make_version) {
1255 			/*
1256 			 * Special case the fact that version 1.0 and 1.1
1257 			 * are identical.
1258 			 */
1259 			if (!IS_EQUAL(depes->names[0]->string_mb,
1260 				      "VERSION-1.1") ||
1261 			    !IS_EQUAL(current_make_version->string_mb,
1262 				      "VERSION-1.0")) {
1263 				/*
1264 				 * Version mismatches should cause the
1265 				 * .make.state file to be skipped.
1266 				 * This is currently not true - it is read
1267 				 * anyway.
1268 				 */
1269 				warning(gettext("Version mismatch between current version `%s' and `%s'"),
1270 					current_make_version->string_mb,
1271 					depes->names[0]->string_mb);
1272 			}
1273 		}
1274 		break;
1275 
1276 	case no_parallel_special:
1277 		if(svr4)
1278 		  break;
1279 		/* Set the no_parallel bit for all the targets on */
1280 		/* the dependency list */
1281 		if (depes->used == 0) {
1282 			/* only those explicitly made parallel */
1283 			only_parallel = true;
1284 			all_parallel = false;
1285 		}
1286 		for (; depes != NULL; depes = depes->next) {
1287 			for (n = 0; n < depes->used; n++) {
1288 				if (trace_reader) {
1289 					(void) printf("%s:\t%s\n",
1290 						      no_parallel_name->string_mb,
1291 						      depes->names[n]->string_mb);
1292 				}
1293 				depes->names[n]->no_parallel = true;
1294 				depes->names[n]->parallel = false;
1295 			}
1296 		}
1297 		break;
1298 
1299 	case parallel_special:
1300 		if(svr4)
1301 		  break;
1302 		if (depes->used == 0) {
1303 			/* everything runs in parallel */
1304 			all_parallel = true;
1305 			only_parallel = false;
1306 		}
1307 		/* Set the parallel bit for all the targets on */
1308 		/* the dependency list */
1309 		for (; depes != NULL; depes = depes->next) {
1310 			for (n = 0; n < depes->used; n++) {
1311 				if (trace_reader) {
1312 					(void) printf("%s:\t%s\n",
1313 						      parallel_name->string_mb,
1314 						      depes->names[n]->string_mb);
1315 				}
1316 				depes->names[n]->parallel = true;
1317 				depes->names[n]->no_parallel = false;
1318 			}
1319 		}
1320 		break;
1321 
1322 	case localhost_special:
1323 		if(svr4)
1324 		  break;
1325 		/* Set the no_parallel bit for all the targets on */
1326 		/* the dependency list */
1327 		if (depes->used == 0) {
1328 			/* only those explicitly made parallel */
1329 			only_parallel = true;
1330 			all_parallel = false;
1331 		}
1332 		for (; depes != NULL; depes = depes->next) {
1333 			for (n = 0; n < depes->used; n++) {
1334 				if (trace_reader) {
1335 					(void) printf("%s:\t%s\n",
1336 						      localhost_name->string_mb,
1337 						      depes->names[n]->string_mb);
1338 				}
1339 				depes->names[n]->no_parallel = true;
1340 				depes->names[n]->parallel = false;
1341 				depes->names[n]->localhost = true;
1342 			}
1343 		}
1344 		break;
1345 
1346 	case precious_special:
1347 		if (depes->used == 0) {
1348 			/* everything is precious      */
1349 			all_precious = true;
1350 		} else {
1351 			all_precious = false;
1352 		}
1353 		if(svr4) {
1354 		  all_precious = true;
1355 		  break;
1356 		}
1357 		/* Set the precious bit for all the targets on */
1358 		/* the dependency list */
1359 		for (; depes != NULL; depes = depes->next) {
1360 			for (n = 0; n < depes->used; n++) {
1361 				if (trace_reader) {
1362 					(void) printf("%s:\t%s\n",
1363 						      precious->string_mb,
1364 						      depes->names[n]->string_mb);
1365 				}
1366 				depes->names[n]->stat.is_precious = true;
1367 			}
1368 		}
1369 		break;
1370 
1371 	case sccs_get_special:
1372 		if (depes->used != 0) {
1373 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1374 				     target->string_mb);
1375 		}
1376 		sccs_get_rule = command;
1377 		sccs_get_org_rule = command;
1378 		if (trace_reader) {
1379 			(void) printf("%s:\n", sccs_get_name->string_mb);
1380 			print_rule(command);
1381 		}
1382 		break;
1383 
1384 	case sccs_get_posix_special:
1385 		if (depes->used != 0) {
1386 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1387 				     target->string_mb);
1388 		}
1389 		sccs_get_posix_rule = command;
1390 		if (trace_reader) {
1391 			(void) printf("%s:\n", sccs_get_posix_name->string_mb);
1392 			print_rule(command);
1393 		}
1394 		break;
1395 
1396 	case get_posix_special:
1397 		if (depes->used != 0) {
1398 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1399 				     target->string_mb);
1400 		}
1401 		get_posix_rule = command;
1402 		if (trace_reader) {
1403 			(void) printf("%s:\n", get_posix_name->string_mb);
1404 			print_rule(command);
1405 		}
1406 		break;
1407 
1408 	case get_special:
1409 		if(!svr4) {
1410 		  break;
1411 		}
1412 		if (depes->used != 0) {
1413 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1414 				     target->string_mb);
1415 		}
1416 		get_rule = command;
1417 		sccs_get_rule = command;
1418 		if (trace_reader) {
1419 			(void) printf("%s:\n", get_name->string_mb);
1420 			print_rule(command);
1421 		}
1422 		break;
1423 
1424 	case silent_special:
1425 		if ((depes->used != 0) && (!posix)){
1426 			fatal_reader(gettext("Illegal dependencies for target `%s'"),
1427 				     target->string_mb);
1428 		}
1429 		if (depes->used == 0)
1430 		{
1431 		   silent_all = true;
1432 		}
1433 		if(svr4) {
1434 		  silent_all = true;
1435 		  break;
1436 		}
1437 		for (; depes != NULL; depes = depes->next) {
1438 			for (n = 0; n < depes->used; n++) {
1439 				depes->names[n]->silent_mode = true;
1440 			}
1441 		}
1442 		if (trace_reader) {
1443 			(void) printf("%s:\n", silent_name->string_mb);
1444 		}
1445 		break;
1446 
1447 	case suffixes_special:
1448 		read_suffixes_list(depes);
1449 		break;
1450 
1451 	default:
1452 
1453 		fatal_reader(gettext("Internal error: Unknown special reader"));
1454 	}
1455 }
1456 
1457 /*
1458  *	read_suffixes_list(depes)
1459  *
1460  *	Read the special list .SUFFIXES. If it is empty the old list is
1461  *	cleared. Else the new one is appended. Suffixes with ~ are extracted
1462  *	and marked.
1463  *
1464  *	Parameters:
1465  *		depes		The list of suffixes
1466  *
1467  *	Global variables used:
1468  *		hashtab		The central hashtable for Names.
1469  *		suffixes	The list of suffixes, set or appended to
1470  *		suffixes_name	The Name ".SUFFIXES", used for tracing
1471  *		trace_reader	Indicates that we should echo stuff we read
1472  */
1473 static void
1474 read_suffixes_list(Name_vector depes)
1475 {
1476 	int		n;
1477 	Dependency	dp;
1478 	Dependency	*insert_dep;
1479 	Name		np;
1480 	Name			np2;
1481 	Boolean	first = true;
1482 
1483 	if (depes->used == 0) {
1484 		/* .SUFFIXES with no dependency list clears the */
1485 		/* suffixes list */
1486 		for (Name_set::iterator np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
1487 				np->with_squiggle =
1488 				  np->without_squiggle =
1489 				    false;
1490 		}
1491 		suffixes = NULL;
1492 		if (trace_reader) {
1493 			(void) printf("%s:\n", suffixes_name->string_mb);
1494 		}
1495 		return;
1496 	}
1497 	Wstring str;
1498 	/* Otherwise we append to the list */
1499 	for (; depes != NULL; depes = depes->next) {
1500 		for (n = 0; n < depes->used; n++) {
1501 			np = depes->names[n];
1502 			/* Find the end of the list and check if the */
1503 			/* suffix already has been entered */
1504 			for (insert_dep = &suffixes, dp = *insert_dep;
1505 			     dp != NULL;
1506 			     insert_dep = &dp->next, dp = *insert_dep) {
1507 				if (dp->name == np) {
1508 					goto duplicate_suffix;
1509 				}
1510 			}
1511 			if (trace_reader) {
1512 				if (first) {
1513 					(void) printf("%s:\t",
1514 						      suffixes_name->string_mb);
1515 					first = false;
1516 				}
1517 				(void) printf("%s ", depes->names[n]->string_mb);
1518 			}
1519 		if(!(posix|svr4)) {
1520 			/* If the suffix is suffixed with "~" we */
1521 			/* strip that and mark the suffix nameblock */
1522 			str.init(np);
1523 			wchar_t * wcb = str.get_string();
1524 			if (wcb[np->hash.length - 1] ==
1525 			    (int) tilde_char) {
1526 				np2 = GETNAME(wcb,
1527 					      (int)(np->hash.length - 1));
1528 				np2->with_squiggle = true;
1529 				if (np2->without_squiggle) {
1530 					continue;
1531 				}
1532 				np = np2;
1533 			}
1534 		}
1535 			np->without_squiggle = true;
1536 			/* Add the suffix to the list */
1537 			dp = *insert_dep = ALLOC(Dependency);
1538 			insert_dep = &dp->next;
1539 			dp->next = NULL;
1540 			dp->name = np;
1541 			dp->built = false;
1542 		duplicate_suffix:;
1543 		}
1544 	}
1545 	if (trace_reader) {
1546 		(void) printf("\n");
1547 	}
1548 }
1549 
1550 /*
1551  *	make_relative(to, result)
1552  *
1553  *	Given a file name compose a relative path name from it to the
1554  *	current directory.
1555  *
1556  *	Parameters:
1557  *		to		The path we want to make relative
1558  *		result		Where to put the resulting relative path
1559  *
1560  *	Global variables used:
1561  */
1562 static void
1563 make_relative(wchar_t *to, wchar_t *result)
1564 {
1565 	wchar_t			*from;
1566 	wchar_t			*allocated;
1567 	wchar_t			*cp;
1568 	wchar_t			*tocomp;
1569 	int			ncomps;
1570 	int			i;
1571 	int			len;
1572 
1573 	/* Check if the path is already relative. */
1574 	if (to[0] != (int) slash_char) {
1575 		(void) wcscpy(result, to);
1576 		return;
1577 	}
1578 
1579 	MBSTOWCS(wcs_buffer, get_current_path());
1580 	from = allocated = (wchar_t *) wcsdup(wcs_buffer);
1581 
1582 	/*
1583 	 * Find the number of components in the from name.
1584 	 * ncomp = number of slashes + 1.
1585 	 */
1586 	ncomps = 1;
1587 	for (cp = from; *cp != (int) nul_char; cp++) {
1588 		if (*cp == (int) slash_char) {
1589 			ncomps++;
1590 		}
1591 	}
1592 
1593 	/*
1594 	 * See how many components match to determine how many "..",
1595 	 * if any, will be needed.
1596 	 */
1597 	result[0] = (int) nul_char;
1598 	tocomp = to;
1599 	while ((*from != (int) nul_char) && (*from == *to)) {
1600 		if (*from == (int) slash_char) {
1601 			ncomps--;
1602 			tocomp = &to[1];
1603 		}
1604 		from++;
1605 		to++;
1606 	}
1607 
1608 	/*
1609 	 * Now for some special cases. Check for exact matches and
1610 	 * for either name terminating exactly.
1611 	 */
1612 	if (*from == (int) nul_char) {
1613 		if (*to == (int) nul_char) {
1614 			MBSTOWCS(wcs_buffer, ".");
1615 			(void) wcscpy(result, wcs_buffer);
1616 			retmem(allocated);
1617 			return;
1618 		}
1619 		if (*to == (int) slash_char) {
1620 			ncomps--;
1621 			tocomp = &to[1];
1622 		}
1623 	} else if ((*from == (int) slash_char) && (*to == (int) nul_char)) {
1624 		ncomps--;
1625 		tocomp = to;
1626 	}
1627 	/* Add on the ".."s. */
1628 	for (i = 0; i < ncomps; i++) {
1629 		MBSTOWCS(wcs_buffer, "../");
1630 		(void) wcscat(result, wcs_buffer);
1631 	}
1632 
1633 	/* Add on the remainder of the to name, if any. */
1634 	if (*tocomp == (int) nul_char) {
1635 		len = wcslen(result);
1636 		result[len - 1] = (int) nul_char;
1637 	} else {
1638 		(void) wcscat(result, tocomp);
1639 	}
1640 	retmem(allocated);
1641 	return;
1642 }
1643 
1644 /*
1645  *	print_rule(command)
1646  *
1647  *	Used when tracing the reading of rules
1648  *
1649  *	Parameters:
1650  *		command		Command to print
1651  *
1652  *	Global variables used:
1653  */
1654 static void
1655 print_rule(Cmd_line command)
1656 {
1657 	for (; command != NULL; command = command->next) {
1658 		(void) printf("\t%s\n", command->command_line->string_mb);
1659 	}
1660 }
1661 
1662 /*
1663  *	enter_conditional(target, name, value, append)
1664  *
1665  *	Enter "target := MACRO= value" constructs
1666  *
1667  *	Parameters:
1668  *		target		The target the macro is for
1669  *		name		The name of the macro
1670  *		value		The value for the macro
1671  *		append		Indicates if the assignment is appending or not
1672  *
1673  *	Global variables used:
1674  *		conditionals	A special Name that stores all conditionals
1675  *				where the target is a % pattern
1676  *		trace_reader	Indicates that we should echo stuff we read
1677  */
1678 void
1679 enter_conditional(Name target, Name name, Name value, Boolean append)
1680 {
1681 	Property	conditional;
1682 	static int		sequence;
1683 	Name			orig_target = target;
1684 
1685 	if (name == target_arch) {
1686 		enter_conditional(target, virtual_root, virtual_root, false);
1687 	}
1688 
1689 	if (target->percent) {
1690 		target = conditionals;
1691 	}
1692 
1693 	if (name->colon) {
1694 		sh_transform(&name, &value);
1695 	}
1696 
1697 	/* Count how many conditionals we must activate before building the */
1698 	/* target */
1699 	if (target->percent) {
1700 		target = conditionals;
1701 	}
1702 
1703 	target->conditional_cnt++;
1704 	maybe_append_prop(name, macro_prop)->body.macro.is_conditional = true;
1705 	/* Add the property for the target */
1706 	conditional = append_prop(target, conditional_prop);
1707 	conditional->body.conditional.target = orig_target;
1708 	conditional->body.conditional.name = name;
1709 	conditional->body.conditional.value = value;
1710 	conditional->body.conditional.sequence = sequence++;
1711 	conditional->body.conditional.append = append;
1712 	if (trace_reader) {
1713 		if (value == NULL) {
1714 			(void) printf("%s := %s %c=\n",
1715 				      target->string_mb,
1716 				      name->string_mb,
1717 				      append ?
1718 				      (int) plus_char : (int) space_char);
1719 		} else {
1720 			(void) printf("%s := %s %c= %s\n",
1721 				      target->string_mb,
1722 				      name->string_mb,
1723 				      append ?
1724 				      (int) plus_char : (int) space_char,
1725 				      value->string_mb);
1726 		}
1727 	}
1728 }
1729 
1730 /*
1731  *	enter_equal(name, value, append)
1732  *
1733  *	Enter "MACRO= value" constructs
1734  *
1735  *	Parameters:
1736  *		name		The name of the macro
1737  *		value		The value for the macro
1738  *		append		Indicates if the assignment is appending or not
1739  *
1740  *	Global variables used:
1741  *		trace_reader	Indicates that we should echo stuff we read
1742  */
1743 void
1744 enter_equal(Name name, Name value, Boolean append)
1745 {
1746 	wchar_t		*string;
1747 	Name		temp;
1748 
1749 	if (name->colon) {
1750 		sh_transform(&name, &value);
1751 	}
1752 	(void) SETVAR(name, value, append);
1753 
1754 	/* if we're setting FC, we want to set F77 to the same value. */
1755 	Wstring nms(name);
1756 	wchar_t * wcb = nms.get_string();
1757 	string = wcb;
1758 	if (string[0]=='F' &&
1759 	    string[1]=='C' &&
1760 	    string[2]=='\0') {
1761 		MBSTOWCS(wcs_buffer, "F77");
1762 		temp = GETNAME(wcs_buffer, FIND_LENGTH);
1763 		(void) SETVAR(temp, value, append);
1764 /*
1765 		fprintf(stderr, gettext("warning: FC is obsolete, use F77 instead\n"));
1766  */
1767 	}
1768 
1769 	if (trace_reader) {
1770 		if (value == NULL) {
1771 			(void) printf("%s %c=\n",
1772 				      name->string_mb,
1773 				      append ?
1774 				      (int) plus_char : (int) space_char);
1775 		} else {
1776 			(void) printf("%s %c= %s\n",
1777 				      name->string_mb,
1778 				      append ?
1779 				      (int) plus_char : (int) space_char,
1780 				      value->string_mb);
1781 		}
1782 	}
1783 }
1784 
1785 /*
1786  *	sh_transform(name, value)
1787  *
1788  *	Parameters:
1789  *		name	The name of the macro we might transform
1790  *		value	The value to transform
1791  *
1792  */
1793 static void
1794 sh_transform(Name *name, Name *value)
1795 {
1796 	/* Check if we need :sh transform */
1797 	wchar_t		*colon;
1798 	String_rec	command;
1799 	String_rec	destination;
1800 	wchar_t		buffer[1000];
1801 	wchar_t		buffer1[1000];
1802 
1803 	static wchar_t	colon_sh[4];
1804 	static wchar_t	colon_shell[7];
1805 
1806 	if (colon_sh[0] == (int) nul_char) {
1807 		MBSTOWCS(colon_sh, ":sh");
1808 		MBSTOWCS(colon_shell, ":shell");
1809 	}
1810 	Wstring nms((*name));
1811 	wchar_t * wcb = nms.get_string();
1812 
1813 	colon = (wchar_t *) wcsrchr(wcb, (int) colon_char);
1814 	if ((colon != NULL) && (IS_WEQUAL(colon, colon_sh) || IS_WEQUAL(colon, colon_shell))) {
1815 		INIT_STRING_FROM_STACK(destination, buffer);
1816 
1817 		if(*value == NULL) {
1818 			buffer[0] = 0;
1819 		} else {
1820 			Wstring wcb1((*value));
1821 			if (IS_WEQUAL(colon, colon_shell)) {
1822 				INIT_STRING_FROM_STACK(command, buffer1);
1823 				expand_value(*value, &command, false);
1824 			} else {
1825 				command.text.p = wcb1.get_string() + (*value)->hash.length;
1826 				command.text.end = command.text.p;
1827 				command.buffer.start = wcb1.get_string();
1828 				command.buffer.end = command.text.p;
1829 			}
1830 			sh_command2string(&command, &destination);
1831 		}
1832 
1833 		(*value) = GETNAME(destination.buffer.start, FIND_LENGTH);
1834 		*colon = (int) nul_char;
1835 		(*name) = GETNAME(wcb, FIND_LENGTH);
1836 		*colon = (int) colon_char;
1837 	}
1838 }
1839 
1840 /*
1841  *	fatal_reader(format, args...)
1842  *
1843  *	Parameters:
1844  *		format		printf style format string
1845  *		args		arguments to match the format
1846  *
1847  *	Global variables used:
1848  *		file_being_read	Name of the makefile being read
1849  *		line_number	Line that is being read
1850  *		report_pwd	Indicates whether current path should be shown
1851  *		temp_file_name	When reading tempfile we report that name
1852  */
1853 /*VARARGS*/
1854 void
1855 fatal_reader(char * pattern, ...)
1856 {
1857 	va_list args;
1858 	char	message[1000];
1859 
1860 	va_start(args, pattern);
1861 	if (file_being_read != NULL) {
1862 		WCSTOMBS(mbs_buffer, file_being_read);
1863 		if (line_number != 0) {
1864 			(void) sprintf(message,
1865 				       gettext("%s, line %d: %s"),
1866 				       mbs_buffer,
1867 				       line_number,
1868 				       pattern);
1869 		} else {
1870 			(void) sprintf(message,
1871 				       "%s: %s",
1872 				       mbs_buffer,
1873 				       pattern);
1874 		}
1875 		pattern = message;
1876 	}
1877 
1878 	(void) fflush(stdout);
1879 	(void) fprintf(stderr, gettext("%s: Fatal error in reader: "),
1880 	    getprogname());
1881 	(void) vfprintf(stderr, pattern, args);
1882 	(void) fprintf(stderr, "\n");
1883 	va_end(args);
1884 
1885 	if (temp_file_name != NULL) {
1886 		(void) fprintf(stderr,
1887 			       gettext("%s: Temp-file %s not removed\n"),
1888 			       getprogname(),
1889 			       temp_file_name->string_mb);
1890 		temp_file_name = NULL;
1891 	}
1892 
1893 	if (report_pwd) {
1894 		(void) fprintf(stderr,
1895 			       gettext("Current working directory %s\n"),
1896 			       get_current_path());
1897 	}
1898 	(void) fflush(stderr);
1899 	exit_status = 1;
1900 	exit(1);
1901 }
1902 
1903