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