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