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