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