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