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