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