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