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