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