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