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