1 /* $NetBSD: suff.c,v 1.357 2021/12/12 20:45:48 sjg Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Adam de Boor. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Copyright (c) 1989 by Berkeley Softworks 37 * All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Adam de Boor. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71 /* 72 * Maintain suffix lists and find implicit dependents using suffix 73 * transformation rules such as ".c.o". 74 * 75 * Interface: 76 * Suff_Init Initialize the module. 77 * 78 * Suff_End Clean up the module. 79 * 80 * Suff_ExtendPaths 81 * Extend the search path of each suffix to include the 82 * default search path. 83 * 84 * Suff_ClearSuffixes 85 * Clear out all the suffixes and transformations. 86 * 87 * Suff_IsTransform 88 * See if the passed string is a transformation rule. 89 * 90 * Suff_AddSuffix Add the passed string as another known suffix. 91 * 92 * Suff_GetPath Return the search path for the given suffix. 93 * 94 * Suff_AddInclude 95 * Mark the given suffix as denoting an include file. 96 * 97 * Suff_AddLib Mark the given suffix as denoting a library. 98 * 99 * Suff_AddTransform 100 * Add another transformation to the suffix graph. 101 * 102 * Suff_SetNull Define the suffix to consider the suffix of 103 * any file that doesn't have a known one. 104 * 105 * Suff_FindDeps Find implicit sources for and the location of 106 * a target based on its suffix. Returns the 107 * bottom-most node added to the graph or NULL 108 * if the target had no implicit sources. 109 * 110 * Suff_FindPath Return the appropriate path to search in order to 111 * find the node. 112 */ 113 114 #include "make.h" 115 #include "dir.h" 116 117 /* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */ 118 MAKE_RCSID("$NetBSD: suff.c,v 1.357 2021/12/12 20:45:48 sjg Exp $"); 119 120 typedef List SuffixList; 121 typedef ListNode SuffixListNode; 122 123 typedef List CandidateList; 124 typedef ListNode CandidateListNode; 125 126 /* The defined suffixes, such as '.c', '.o', '.l'. */ 127 static SuffixList sufflist = LST_INIT; 128 #ifdef CLEANUP 129 /* The suffixes to be cleaned up at the end. */ 130 static SuffixList suffClean = LST_INIT; 131 #endif 132 133 /* 134 * The transformation rules, such as '.c.o' to transform '.c' into '.o', 135 * or simply '.c' to transform 'file.c' into 'file'. 136 */ 137 static GNodeList transforms = LST_INIT; 138 139 /* 140 * Counter for assigning suffix numbers. 141 * TODO: What are these suffix numbers used for? 142 */ 143 static int sNum = 0; 144 145 typedef List SuffixListList; 146 147 /* 148 * A suffix such as ".c" or ".o" that is used in suffix transformation rules 149 * such as ".c.o:". 150 */ 151 typedef struct Suffix { 152 /* The suffix itself, such as ".c" */ 153 char *name; 154 /* Length of the name, to avoid strlen calls */ 155 size_t nameLen; 156 /* 157 * This suffix marks include files. Their search path ends up in the 158 * undocumented special variable '.INCLUDES'. 159 */ 160 bool include:1; 161 /* 162 * This suffix marks library files. Their search path ends up in the 163 * undocumented special variable '.LIBS'. 164 */ 165 bool library:1; 166 /* 167 * The empty suffix. 168 * 169 * XXX: What is the difference between the empty suffix and the null 170 * suffix? 171 * 172 * XXX: Why is SUFF_NULL needed at all? Wouldn't nameLen == 0 mean 173 * the same? 174 */ 175 bool isNull:1; 176 /* The path along which files of this suffix may be found */ 177 SearchPath *searchPath; 178 179 /* The suffix number; TODO: document the purpose of this number */ 180 int sNum; 181 /* Reference count of list membership and several other places */ 182 int refCount; 183 184 /* Suffixes we have a transformation to */ 185 SuffixList parents; 186 /* Suffixes we have a transformation from */ 187 SuffixList children; 188 /* 189 * Lists in which this suffix is referenced. 190 * 191 * XXX: These lists are used nowhere, they are just appended to, for 192 * no apparent reason. They do have the side effect of increasing 193 * refCount though. 194 */ 195 SuffixListList ref; 196 } Suffix; 197 198 /* 199 * A candidate when searching for implied sources. 200 * 201 * For example, when "src.o" is to be made, a typical candidate is "src.c" 202 * via the transformation rule ".c.o". If that doesn't exist, maybe there is 203 * another transformation rule ".pas.c" that would make "src.pas" an indirect 204 * candidate as well. The first such chain that leads to an existing file or 205 * node is finally chosen to be made. 206 */ 207 typedef struct Candidate { 208 /* The file or node to look for. */ 209 char *file; 210 /* The prefix from which file was formed. 211 * Its memory is shared among all candidates. */ 212 char *prefix; 213 /* The suffix on the file. */ 214 Suffix *suff; 215 216 /* The candidate that can be made from this, 217 * or NULL for the top-level candidate. */ 218 struct Candidate *parent; 219 /* The node describing the file. */ 220 GNode *node; 221 222 /* Count of existing children, only used for memory management, so we 223 * don't free this candidate too early or too late. */ 224 int numChildren; 225 #ifdef DEBUG_SRC 226 CandidateList childrenList; 227 #endif 228 } Candidate; 229 230 typedef struct CandidateSearcher { 231 232 CandidateList list; 233 234 /* 235 * TODO: Add HashSet for seen entries, to avoid endless loops such as 236 * in suff-transform-endless.mk. 237 */ 238 239 } CandidateSearcher; 240 241 242 /* TODO: Document the difference between nullSuff and emptySuff. */ 243 /* The NULL suffix for this run */ 244 static Suffix *nullSuff; 245 /* The empty suffix required for POSIX single-suffix transformation rules */ 246 static Suffix *emptySuff; 247 248 249 static Suffix * 250 Suffix_Ref(Suffix *suff) 251 { 252 suff->refCount++; 253 return suff; 254 } 255 256 /* Change the value of a Suffix variable, adjusting the reference counts. */ 257 static void 258 Suffix_Reassign(Suffix **var, Suffix *suff) 259 { 260 if (*var != NULL) 261 (*var)->refCount--; 262 *var = suff; 263 suff->refCount++; 264 } 265 266 /* Set a Suffix variable to NULL, adjusting the reference count. */ 267 static void 268 Suffix_Unassign(Suffix **var) 269 { 270 if (*var != NULL) 271 (*var)->refCount--; 272 *var = NULL; 273 } 274 275 /* 276 * See if pref is a prefix of str. 277 * Return NULL if it ain't, pointer to character in str after prefix if so. 278 */ 279 static const char * 280 StrTrimPrefix(const char *pref, const char *str) 281 { 282 while (*str != '\0' && *pref == *str) { 283 pref++; 284 str++; 285 } 286 287 return *pref != '\0' ? NULL : str; 288 } 289 290 /* 291 * See if suff is a suffix of str, and if so, return the pointer to the suffix 292 * in str, which at the same time marks the end of the prefix. 293 */ 294 static const char * 295 StrTrimSuffix(const char *str, size_t strLen, const char *suff, size_t suffLen) 296 { 297 const char *suffInStr; 298 size_t i; 299 300 if (strLen < suffLen) 301 return NULL; 302 303 suffInStr = str + strLen - suffLen; 304 for (i = 0; i < suffLen; i++) 305 if (suff[i] != suffInStr[i]) 306 return NULL; 307 308 return suffInStr; 309 } 310 311 /* 312 * See if suff is a suffix of name, and if so, return the end of the prefix 313 * in name. 314 */ 315 static const char * 316 Suffix_TrimSuffix(const Suffix *suff, size_t nameLen, const char *nameEnd) 317 { 318 return StrTrimSuffix(nameEnd - nameLen, nameLen, 319 suff->name, suff->nameLen); 320 } 321 322 static bool 323 Suffix_IsSuffix(const Suffix *suff, size_t nameLen, const char *nameEnd) 324 { 325 return Suffix_TrimSuffix(suff, nameLen, nameEnd) != NULL; 326 } 327 328 static Suffix * 329 FindSuffixByNameLen(const char *name, size_t nameLen) 330 { 331 SuffixListNode *ln; 332 333 for (ln = sufflist.first; ln != NULL; ln = ln->next) { 334 Suffix *suff = ln->datum; 335 if (suff->nameLen == nameLen && 336 memcmp(suff->name, name, nameLen) == 0) 337 return suff; 338 } 339 return NULL; 340 } 341 342 static Suffix * 343 FindSuffixByName(const char *name) 344 { 345 return FindSuffixByNameLen(name, strlen(name)); 346 } 347 348 static GNode * 349 FindTransformByName(const char *name) 350 { 351 GNodeListNode *ln; 352 353 for (ln = transforms.first; ln != NULL; ln = ln->next) { 354 GNode *gn = ln->datum; 355 if (strcmp(gn->name, name) == 0) 356 return gn; 357 } 358 return NULL; 359 } 360 361 static void 362 SuffixList_Unref(SuffixList *list, Suffix *suff) 363 { 364 SuffixListNode *ln = Lst_FindDatum(list, suff); 365 if (ln != NULL) { 366 Lst_Remove(list, ln); 367 suff->refCount--; 368 } 369 } 370 371 /* Free up all memory associated with the given suffix structure. */ 372 static void 373 Suffix_Free(Suffix *suff) 374 { 375 376 if (suff == nullSuff) 377 nullSuff = NULL; 378 379 if (suff == emptySuff) 380 emptySuff = NULL; 381 382 #if 0 383 /* We don't delete suffixes in order, so we cannot use this */ 384 if (suff->refCount != 0) 385 Punt("Internal error deleting suffix `%s' with refcount = %d", 386 suff->name, suff->refCount); 387 #endif 388 389 Lst_Done(&suff->ref); 390 Lst_Done(&suff->children); 391 Lst_Done(&suff->parents); 392 SearchPath_Free(suff->searchPath); 393 394 free(suff->name); 395 free(suff); 396 } 397 398 static void 399 SuffFree(void *p) 400 { 401 Suffix_Free(p); 402 } 403 404 /* Remove the suffix from the list, and free if it is otherwise unused. */ 405 static void 406 SuffixList_Remove(SuffixList *list, Suffix *suff) 407 { 408 SuffixList_Unref(list, suff); 409 if (suff->refCount == 0) { 410 /* XXX: can lead to suff->refCount == -1 */ 411 SuffixList_Unref(&sufflist, suff); 412 DEBUG1(SUFF, "Removing suffix \"%s\"\n", suff->name); 413 SuffFree(suff); 414 } 415 } 416 417 /* 418 * Insert the suffix into the list, keeping the list ordered by suffix 419 * number. 420 */ 421 static void 422 SuffixList_Insert(SuffixList *list, Suffix *suff) 423 { 424 SuffixListNode *ln; 425 Suffix *listSuff = NULL; 426 427 for (ln = list->first; ln != NULL; ln = ln->next) { 428 listSuff = ln->datum; 429 if (listSuff->sNum >= suff->sNum) 430 break; 431 } 432 433 if (ln == NULL) { 434 DEBUG2(SUFF, "inserting \"%s\" (%d) at end of list\n", 435 suff->name, suff->sNum); 436 Lst_Append(list, Suffix_Ref(suff)); 437 Lst_Append(&suff->ref, list); 438 } else if (listSuff->sNum != suff->sNum) { 439 DEBUG4(SUFF, "inserting \"%s\" (%d) before \"%s\" (%d)\n", 440 suff->name, suff->sNum, listSuff->name, listSuff->sNum); 441 Lst_InsertBefore(list, ln, Suffix_Ref(suff)); 442 Lst_Append(&suff->ref, list); 443 } else { 444 DEBUG2(SUFF, "\"%s\" (%d) is already there\n", 445 suff->name, suff->sNum); 446 } 447 } 448 449 static void 450 Relate(Suffix *srcSuff, Suffix *targSuff) 451 { 452 SuffixList_Insert(&targSuff->children, srcSuff); 453 SuffixList_Insert(&srcSuff->parents, targSuff); 454 } 455 456 static Suffix * 457 Suffix_New(const char *name) 458 { 459 Suffix *suff = bmake_malloc(sizeof *suff); 460 461 suff->name = bmake_strdup(name); 462 suff->nameLen = strlen(suff->name); 463 suff->searchPath = SearchPath_New(); 464 Lst_Init(&suff->children); 465 Lst_Init(&suff->parents); 466 Lst_Init(&suff->ref); 467 suff->sNum = sNum++; 468 suff->include = false; 469 suff->library = false; 470 suff->isNull = false; 471 suff->refCount = 1; /* XXX: why 1? It's not assigned anywhere yet. */ 472 473 return suff; 474 } 475 476 /* 477 * Nuke the list of suffixes but keep all transformation rules around. The 478 * transformation graph is destroyed in this process, but we leave the list 479 * of rules so when a new graph is formed, the rules will remain. This 480 * function is called when a line '.SUFFIXES:' with an empty suffixes list is 481 * encountered in a makefile. 482 */ 483 void 484 Suff_ClearSuffixes(void) 485 { 486 #ifdef CLEANUP 487 Lst_MoveAll(&suffClean, &sufflist); 488 #endif 489 DEBUG0(SUFF, "Clearing all suffixes\n"); 490 Lst_Init(&sufflist); 491 sNum = 0; 492 if (nullSuff != NULL) 493 SuffFree(nullSuff); 494 emptySuff = nullSuff = Suffix_New(""); 495 496 SearchPath_AddAll(nullSuff->searchPath, &dirSearchPath); 497 nullSuff->include = false; 498 nullSuff->library = false; 499 nullSuff->isNull = true; 500 } 501 502 /* 503 * Parse a transformation string such as ".c.o" to find its two component 504 * suffixes (the source ".c" and the target ".o"). If there are no such 505 * suffixes, try a single-suffix transformation as well. 506 * 507 * Return true if the string is a valid transformation. 508 */ 509 static bool 510 ParseTransform(const char *str, Suffix **out_src, Suffix **out_targ) 511 { 512 SuffixListNode *ln; 513 Suffix *single = NULL; 514 515 /* 516 * Loop looking first for a suffix that matches the start of the 517 * string and then for one that exactly matches the rest of it. If 518 * we can find two that meet these criteria, we've successfully 519 * parsed the string. 520 */ 521 for (ln = sufflist.first; ln != NULL; ln = ln->next) { 522 Suffix *src = ln->datum; 523 524 if (StrTrimPrefix(src->name, str) == NULL) 525 continue; 526 527 if (str[src->nameLen] == '\0') { 528 single = src; 529 } else { 530 Suffix *targ = FindSuffixByName(str + src->nameLen); 531 if (targ != NULL) { 532 *out_src = src; 533 *out_targ = targ; 534 return true; 535 } 536 } 537 } 538 539 if (single != NULL) { 540 /* 541 * There was a suffix that encompassed the entire string, so we 542 * assume it was a transformation to the null suffix (thank you 543 * POSIX; search for "single suffix" or "single-suffix"). 544 * 545 * We still prefer to find a double rule over a singleton, 546 * hence we leave this check until the end. 547 * 548 * XXX: Use emptySuff over nullSuff? 549 */ 550 *out_src = single; 551 *out_targ = nullSuff; 552 return true; 553 } 554 return false; 555 } 556 557 /* 558 * Return true if the given string is a transformation rule, that is, a 559 * concatenation of two known suffixes such as ".c.o" or a single suffix 560 * such as ".o". 561 */ 562 bool 563 Suff_IsTransform(const char *str) 564 { 565 Suffix *src, *targ; 566 567 return ParseTransform(str, &src, &targ); 568 } 569 570 /* 571 * Add the transformation rule to the list of rules and place the 572 * transformation itself in the graph. 573 * 574 * The transformation is linked to the two suffixes mentioned in the name. 575 * 576 * Input: 577 * name must have the form ".from.to" or just ".from" 578 * 579 * Results: 580 * The created or existing transformation node in the transforms list 581 */ 582 GNode * 583 Suff_AddTransform(const char *name) 584 { 585 Suffix *srcSuff; 586 Suffix *targSuff; 587 588 GNode *gn = FindTransformByName(name); 589 if (gn == NULL) { 590 /* 591 * Make a new graph node for the transformation. It will be 592 * filled in by the Parse module. 593 */ 594 gn = GNode_New(name); 595 Lst_Append(&transforms, gn); 596 } else { 597 /* 598 * New specification for transformation rule. Just nuke the 599 * old list of commands so they can be filled in again. We 600 * don't actually free the commands themselves, because a 601 * given command can be attached to several different 602 * transformations. 603 */ 604 Lst_Done(&gn->commands); 605 Lst_Init(&gn->commands); 606 Lst_Done(&gn->children); 607 Lst_Init(&gn->children); 608 } 609 610 gn->type = OP_TRANSFORM; 611 612 { 613 /* TODO: Avoid the redundant parsing here. */ 614 bool ok = ParseTransform(name, &srcSuff, &targSuff); 615 assert(ok); 616 /* LINTED 129 *//* expression has null effect */ 617 (void)ok; 618 } 619 620 /* Link the two together in the proper relationship and order. */ 621 DEBUG2(SUFF, "defining transformation from `%s' to `%s'\n", 622 srcSuff->name, targSuff->name); 623 Relate(srcSuff, targSuff); 624 625 return gn; 626 } 627 628 /* 629 * Handle the finish of a transformation definition, removing the 630 * transformation from the graph if it has neither commands nor sources. 631 * 632 * If the node has no commands or children, the children and parents lists 633 * of the affected suffixes are altered. 634 * 635 * Input: 636 * gn Node for transformation 637 */ 638 void 639 Suff_EndTransform(GNode *gn) 640 { 641 Suffix *srcSuff, *targSuff; 642 SuffixList *srcSuffParents; 643 644 if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty(&gn->cohorts)) 645 gn = gn->cohorts.last->datum; 646 647 if (!(gn->type & OP_TRANSFORM)) 648 return; 649 650 if (!Lst_IsEmpty(&gn->commands) || !Lst_IsEmpty(&gn->children)) { 651 DEBUG1(SUFF, "transformation %s complete\n", gn->name); 652 return; 653 } 654 655 /* 656 * SuffParseTransform() may fail for special rules which are not 657 * actual transformation rules. (e.g. .DEFAULT) 658 */ 659 if (!ParseTransform(gn->name, &srcSuff, &targSuff)) 660 return; 661 662 DEBUG2(SUFF, "deleting incomplete transformation from `%s' to `%s'\n", 663 srcSuff->name, targSuff->name); 664 665 /* 666 * Remember the parents since srcSuff could be deleted in 667 * SuffixList_Remove. 668 */ 669 srcSuffParents = &srcSuff->parents; 670 SuffixList_Remove(&targSuff->children, srcSuff); 671 SuffixList_Remove(srcSuffParents, targSuff); 672 } 673 674 /* 675 * Called from Suff_AddSuffix to search through the list of 676 * existing transformation rules and rebuild the transformation graph when 677 * it has been destroyed by Suff_ClearSuffixes. If the given rule is a 678 * transformation involving this suffix and another, existing suffix, the 679 * proper relationship is established between the two. 680 * 681 * The appropriate links will be made between this suffix and others if 682 * transformation rules exist for it. 683 * 684 * Input: 685 * transform Transformation to test 686 * suff Suffix to rebuild 687 */ 688 static void 689 RebuildGraph(GNode *transform, Suffix *suff) 690 { 691 const char *name = transform->name; 692 size_t nameLen = strlen(name); 693 const char *toName; 694 695 /* See if it is a transformation from this suffix to another suffix. */ 696 toName = StrTrimPrefix(suff->name, name); 697 if (toName != NULL) { 698 Suffix *to = FindSuffixByName(toName); 699 if (to != NULL) { 700 Relate(suff, to); 701 return; 702 } 703 } 704 705 /* See if it is a transformation from another suffix to this suffix. */ 706 toName = Suffix_TrimSuffix(suff, nameLen, name + nameLen); 707 if (toName != NULL) { 708 Suffix *from = FindSuffixByNameLen(name, 709 (size_t)(toName - name)); 710 if (from != NULL) 711 Relate(from, suff); 712 } 713 } 714 715 /* 716 * During Suff_AddSuffix, search through the list of existing targets and find 717 * if any of the existing targets can be turned into a transformation rule. 718 * 719 * If such a target is found and the target is the current main target, the 720 * main target is set to NULL and the next target examined (if that exists) 721 * becomes the main target. 722 * 723 * Results: 724 * true iff a new main target has been selected. 725 */ 726 static bool 727 UpdateTarget(GNode *target, GNode **inout_main, Suffix *suff, 728 bool *inout_removedMain) 729 { 730 Suffix *srcSuff, *targSuff; 731 char *ptr; 732 733 if (*inout_main == NULL && *inout_removedMain && 734 !(target->type & OP_NOTARGET)) { 735 DEBUG1(MAKE, "Setting main node to \"%s\"\n", target->name); 736 *inout_main = target; 737 Targ_SetMain(target); 738 /* 739 * XXX: Why could it be a good idea to return true here? 740 * The main task of this function is to turn ordinary nodes 741 * into transformations, no matter whether or not a new .MAIN 742 * node has been found. 743 */ 744 /* 745 * XXX: Even when changing this to false, none of the existing 746 * unit tests fails. 747 */ 748 return true; 749 } 750 751 if (target->type == OP_TRANSFORM) 752 return false; 753 754 /* 755 * XXX: What about a transformation ".cpp.c"? If ".c" is added as 756 * a new suffix, it seems wrong that this transformation would be 757 * skipped just because ".c" happens to be a prefix of ".cpp". 758 */ 759 ptr = strstr(target->name, suff->name); 760 if (ptr == NULL) 761 return false; 762 763 /* 764 * XXX: In suff-rebuild.mk, in the line '.SUFFIXES: .c .b .a', this 765 * condition prevents the rule '.b.c' from being added again during 766 * Suff_AddSuffix(".b"). 767 * 768 * XXX: Removing this paragraph makes suff-add-later.mk use massive 769 * amounts of memory. 770 */ 771 if (ptr == target->name) 772 return false; 773 774 if (ParseTransform(target->name, &srcSuff, &targSuff)) { 775 if (*inout_main == target) { 776 DEBUG1(MAKE, 777 "Setting main node from \"%s\" back to null\n", 778 target->name); 779 *inout_removedMain = true; 780 *inout_main = NULL; 781 Targ_SetMain(NULL); 782 } 783 Lst_Done(&target->children); 784 Lst_Init(&target->children); 785 target->type = OP_TRANSFORM; 786 787 /* 788 * Link the two together in the proper relationship and order. 789 */ 790 DEBUG2(SUFF, "defining transformation from `%s' to `%s'\n", 791 srcSuff->name, targSuff->name); 792 Relate(srcSuff, targSuff); 793 } 794 return false; 795 } 796 797 /* 798 * Look at all existing targets to see if adding this suffix will make one 799 * of the current targets mutate into a suffix rule. 800 * 801 * This is ugly, but other makes treat all targets that start with a '.' as 802 * suffix rules. 803 */ 804 static void 805 UpdateTargets(GNode **inout_main, Suffix *suff) 806 { 807 bool removedMain = false; 808 GNodeListNode *ln; 809 810 for (ln = Targ_List()->first; ln != NULL; ln = ln->next) { 811 GNode *gn = ln->datum; 812 if (UpdateTarget(gn, inout_main, suff, &removedMain)) 813 break; 814 } 815 } 816 817 /* 818 * Add the suffix to the end of the list of known suffixes. 819 * Should we restructure the suffix graph? Make doesn't. 820 * 821 * A GNode is created for the suffix (XXX: this sounds completely wrong) and 822 * a Suffix structure is created and added to the suffixes list unless the 823 * suffix was already known. 824 * The mainNode passed can be modified if a target mutated into a 825 * transform and that target happened to be the main target. 826 * 827 * Input: 828 * name the name of the suffix to add 829 */ 830 void 831 Suff_AddSuffix(const char *name, GNode **inout_main) 832 { 833 GNodeListNode *ln; 834 835 Suffix *suff = FindSuffixByName(name); 836 if (suff != NULL) 837 return; 838 839 suff = Suffix_New(name); 840 Lst_Append(&sufflist, suff); 841 DEBUG1(SUFF, "Adding suffix \"%s\"\n", suff->name); 842 843 UpdateTargets(inout_main, suff); 844 845 /* 846 * Look for any existing transformations from or to this suffix. 847 * XXX: Only do this after a Suff_ClearSuffixes? 848 */ 849 for (ln = transforms.first; ln != NULL; ln = ln->next) 850 RebuildGraph(ln->datum, suff); 851 } 852 853 /* Return the search path for the given suffix, or NULL. */ 854 SearchPath * 855 Suff_GetPath(const char *sname) 856 { 857 Suffix *suff = FindSuffixByName(sname); 858 return suff != NULL ? suff->searchPath : NULL; 859 } 860 861 /* 862 * Extend the search paths for all suffixes to include the default search 863 * path (dirSearchPath). 864 * 865 * The default search path can be defined using the special target '.PATH'. 866 * The search path of each suffix can be defined using the special target 867 * '.PATH<suffix>'. 868 * 869 * If paths were specified for the ".h" suffix, the directories are stuffed 870 * into a global variable called ".INCLUDES" with each directory preceded by 871 * '-I'. The same is done for the ".a" suffix, except the variable is called 872 * ".LIBS" and the flag is '-L'. 873 */ 874 void 875 Suff_ExtendPaths(void) 876 { 877 SuffixListNode *ln; 878 char *flags; 879 SearchPath *includesPath = SearchPath_New(); 880 SearchPath *libsPath = SearchPath_New(); 881 882 for (ln = sufflist.first; ln != NULL; ln = ln->next) { 883 Suffix *suff = ln->datum; 884 if (!Lst_IsEmpty(&suff->searchPath->dirs)) { 885 #ifdef INCLUDES 886 if (suff->include) 887 SearchPath_AddAll(includesPath, 888 suff->searchPath); 889 #endif 890 #ifdef LIBRARIES 891 if (suff->library) 892 SearchPath_AddAll(libsPath, suff->searchPath); 893 #endif 894 SearchPath_AddAll(suff->searchPath, &dirSearchPath); 895 } else { 896 SearchPath_Free(suff->searchPath); 897 suff->searchPath = Dir_CopyDirSearchPath(); 898 } 899 } 900 901 flags = SearchPath_ToFlags(includesPath, "-I"); 902 Global_Set(".INCLUDES", flags); 903 free(flags); 904 905 flags = SearchPath_ToFlags(libsPath, "-L"); 906 Global_Set(".LIBS", flags); 907 free(flags); 908 909 SearchPath_Free(includesPath); 910 SearchPath_Free(libsPath); 911 } 912 913 /* 914 * Add the given suffix as a type of file which gets included. 915 * Called when a '.INCLUDES: .h' line is parsed. 916 * To have an effect, the suffix must already exist. 917 * This affects the magic variable '.INCLUDES'. 918 */ 919 void 920 Suff_AddInclude(const char *suffName) 921 { 922 Suffix *suff = FindSuffixByName(suffName); 923 if (suff != NULL) 924 suff->include = true; 925 } 926 927 /* 928 * Add the given suffix as a type of file which is a library. 929 * Called when a '.LIBS: .a' line is parsed. 930 * To have an effect, the suffix must already exist. 931 * This affects the magic variable '.LIBS'. 932 */ 933 void 934 Suff_AddLib(const char *suffName) 935 { 936 Suffix *suff = FindSuffixByName(suffName); 937 if (suff != NULL) 938 suff->library = true; 939 } 940 941 /********** Implicit Source Search Functions *********/ 942 943 static void 944 CandidateSearcher_Init(CandidateSearcher *cs) 945 { 946 Lst_Init(&cs->list); 947 } 948 949 static void 950 CandidateSearcher_Done(CandidateSearcher *cs) 951 { 952 Lst_Done(&cs->list); 953 } 954 955 static void 956 CandidateSearcher_Add(CandidateSearcher *cs, Candidate *cand) 957 { 958 /* TODO: filter duplicates */ 959 Lst_Append(&cs->list, cand); 960 } 961 962 static void 963 CandidateSearcher_AddIfNew(CandidateSearcher *cs, Candidate *cand) 964 { 965 /* TODO: filter duplicates */ 966 if (Lst_FindDatum(&cs->list, cand) == NULL) 967 Lst_Append(&cs->list, cand); 968 } 969 970 static void 971 CandidateSearcher_MoveAll(CandidateSearcher *cs, CandidateList *list) 972 { 973 /* TODO: filter duplicates */ 974 Lst_MoveAll(&cs->list, list); 975 } 976 977 978 #ifdef DEBUG_SRC 979 static void 980 CandidateList_PrintAddrs(CandidateList *list) 981 { 982 CandidateListNode *ln; 983 984 for (ln = list->first; ln != NULL; ln = ln->next) { 985 Candidate *cand = ln->datum; 986 debug_printf(" %p:%s", cand, cand->file); 987 } 988 debug_printf("\n"); 989 } 990 #endif 991 992 static Candidate * 993 Candidate_New(char *name, char *prefix, Suffix *suff, Candidate *parent, 994 GNode *gn) 995 { 996 Candidate *cand = bmake_malloc(sizeof *cand); 997 998 cand->file = name; 999 cand->prefix = prefix; 1000 cand->suff = Suffix_Ref(suff); 1001 cand->parent = parent; 1002 cand->node = gn; 1003 cand->numChildren = 0; 1004 #ifdef DEBUG_SRC 1005 Lst_Init(&cand->childrenList); 1006 #endif 1007 1008 return cand; 1009 } 1010 1011 /* Add a new candidate to the list. */ 1012 /*ARGSUSED*/ 1013 static void 1014 CandidateList_Add(CandidateList *list, char *srcName, Candidate *targ, 1015 Suffix *suff, const char *debug_tag) 1016 { 1017 Candidate *cand = Candidate_New(srcName, targ->prefix, suff, targ, 1018 NULL); 1019 targ->numChildren++; 1020 Lst_Append(list, cand); 1021 1022 #ifdef DEBUG_SRC 1023 Lst_Append(&targ->childrenList, cand); 1024 debug_printf("%s add suff %p:%s candidate %p:%s to list %p:", 1025 debug_tag, targ, targ->file, cand, cand->file, list); 1026 CandidateList_PrintAddrs(list); 1027 #endif 1028 } 1029 1030 /* 1031 * Add all candidates to the list that can be formed by applying a suffix to 1032 * the candidate. 1033 */ 1034 static void 1035 CandidateList_AddCandidatesFor(CandidateList *list, Candidate *cand) 1036 { 1037 SuffixListNode *ln; 1038 for (ln = cand->suff->children.first; ln != NULL; ln = ln->next) { 1039 Suffix *suff = ln->datum; 1040 1041 if (suff->isNull && suff->name[0] != '\0') { 1042 /* 1043 * If the suffix has been marked as the NULL suffix, 1044 * also create a candidate for a file with no suffix 1045 * attached. 1046 */ 1047 CandidateList_Add(list, bmake_strdup(cand->prefix), 1048 cand, suff, "1"); 1049 } 1050 1051 CandidateList_Add(list, str_concat2(cand->prefix, suff->name), 1052 cand, suff, "2"); 1053 } 1054 } 1055 1056 /* 1057 * Free the first candidate in the list that is not referenced anymore. 1058 * Return whether a candidate was removed. 1059 */ 1060 static bool 1061 RemoveCandidate(CandidateList *srcs) 1062 { 1063 CandidateListNode *ln; 1064 1065 #ifdef DEBUG_SRC 1066 debug_printf("cleaning list %p:", srcs); 1067 CandidateList_PrintAddrs(srcs); 1068 #endif 1069 1070 for (ln = srcs->first; ln != NULL; ln = ln->next) { 1071 Candidate *src = ln->datum; 1072 1073 if (src->numChildren == 0) { 1074 if (src->parent == NULL) 1075 free(src->prefix); 1076 else { 1077 #ifdef DEBUG_SRC 1078 /* XXX: Lst_RemoveDatum */ 1079 CandidateListNode *ln2; 1080 ln2 = Lst_FindDatum(&src->parent->childrenList, 1081 src); 1082 if (ln2 != NULL) 1083 Lst_Remove(&src->parent->childrenList, 1084 ln2); 1085 #endif 1086 src->parent->numChildren--; 1087 } 1088 #ifdef DEBUG_SRC 1089 debug_printf("free: list %p src %p:%s children %d\n", 1090 srcs, src, src->file, src->numChildren); 1091 Lst_Done(&src->childrenList); 1092 #endif 1093 Lst_Remove(srcs, ln); 1094 free(src->file); 1095 free(src); 1096 return true; 1097 } 1098 #ifdef DEBUG_SRC 1099 else { 1100 debug_printf("keep: list %p src %p:%s children %d:", 1101 srcs, src, src->file, src->numChildren); 1102 CandidateList_PrintAddrs(&src->childrenList); 1103 } 1104 #endif 1105 } 1106 1107 return false; 1108 } 1109 1110 /* Find the first existing file/target in srcs. */ 1111 static Candidate * 1112 FindThem(CandidateList *srcs, CandidateSearcher *cs) 1113 { 1114 HashSet seen; 1115 1116 HashSet_Init(&seen); 1117 1118 while (!Lst_IsEmpty(srcs)) { 1119 Candidate *src = Lst_Dequeue(srcs); 1120 1121 #ifdef DEBUG_SRC 1122 debug_printf("remove from list %p src %p:%s\n", 1123 srcs, src, src->file); 1124 #endif 1125 DEBUG1(SUFF, "\ttrying %s...", src->file); 1126 1127 /* 1128 * A file is considered to exist if either a node exists in the 1129 * graph for it or the file actually exists. 1130 */ 1131 if (Targ_FindNode(src->file) != NULL) { 1132 found: 1133 HashSet_Done(&seen); 1134 DEBUG0(SUFF, "got it\n"); 1135 return src; 1136 } 1137 1138 { 1139 char *file = Dir_FindFile(src->file, 1140 src->suff->searchPath); 1141 if (file != NULL) { 1142 free(file); 1143 goto found; 1144 } 1145 } 1146 1147 DEBUG0(SUFF, "not there\n"); 1148 1149 if (HashSet_Add(&seen, src->file)) 1150 CandidateList_AddCandidatesFor(srcs, src); 1151 else { 1152 DEBUG1(SUFF, "FindThem: skipping duplicate \"%s\"\n", 1153 src->file); 1154 } 1155 1156 CandidateSearcher_Add(cs, src); 1157 } 1158 1159 HashSet_Done(&seen); 1160 return NULL; 1161 } 1162 1163 /* 1164 * See if any of the children of the candidate's GNode is one from which the 1165 * target can be transformed. If there is one, a candidate is put together 1166 * for it and returned. 1167 */ 1168 static Candidate * 1169 FindCmds(Candidate *targ, CandidateSearcher *cs) 1170 { 1171 GNodeListNode *gln; 1172 GNode *tgn; /* Target GNode */ 1173 GNode *sgn; /* Source GNode */ 1174 size_t prefLen; /* The length of the defined prefix */ 1175 Suffix *suff; /* Suffix of the matching candidate */ 1176 Candidate *ret; /* Return value */ 1177 1178 tgn = targ->node; 1179 prefLen = strlen(targ->prefix); 1180 1181 for (gln = tgn->children.first; gln != NULL; gln = gln->next) { 1182 const char *base; 1183 1184 sgn = gln->datum; 1185 1186 if (sgn->type & OP_OPTIONAL && Lst_IsEmpty(&tgn->commands)) { 1187 /* 1188 * We haven't looked to see if .OPTIONAL files exist 1189 * yet, so don't use one as the implicit source. 1190 * This allows us to use .OPTIONAL in .depend files so 1191 * make won't complain "don't know how to make xxx.h" 1192 * when a dependent file has been moved/deleted. 1193 */ 1194 continue; 1195 } 1196 1197 base = str_basename(sgn->name); 1198 if (strncmp(base, targ->prefix, prefLen) != 0) 1199 continue; 1200 /* The node matches the prefix, see if it has a known suffix. */ 1201 suff = FindSuffixByName(base + prefLen); 1202 if (suff == NULL) 1203 continue; 1204 1205 /* 1206 * It even has a known suffix, see if there's a transformation 1207 * defined between the node's suffix and the target's suffix. 1208 * 1209 * XXX: Handle multi-stage transformations here, too. 1210 */ 1211 1212 if (Lst_FindDatum(&suff->parents, targ->suff) != NULL) 1213 break; 1214 } 1215 1216 if (gln == NULL) 1217 return NULL; 1218 1219 ret = Candidate_New(bmake_strdup(sgn->name), targ->prefix, suff, targ, 1220 sgn); 1221 targ->numChildren++; 1222 #ifdef DEBUG_SRC 1223 debug_printf("3 add targ %p:%s ret %p:%s\n", 1224 targ, targ->file, ret, ret->file); 1225 Lst_Append(&targ->childrenList, ret); 1226 #endif 1227 CandidateSearcher_Add(cs, ret); 1228 DEBUG1(SUFF, "\tusing existing source %s\n", sgn->name); 1229 return ret; 1230 } 1231 1232 static void 1233 ExpandWildcards(GNodeListNode *cln, GNode *pgn) 1234 { 1235 GNode *cgn = cln->datum; 1236 StringList expansions; 1237 1238 if (!Dir_HasWildcards(cgn->name)) 1239 return; 1240 1241 /* 1242 * Expand the word along the chosen path 1243 */ 1244 Lst_Init(&expansions); 1245 SearchPath_Expand(Suff_FindPath(cgn), cgn->name, &expansions); 1246 1247 while (!Lst_IsEmpty(&expansions)) { 1248 GNode *gn; 1249 /* 1250 * Fetch next expansion off the list and find its GNode 1251 */ 1252 char *cp = Lst_Dequeue(&expansions); 1253 1254 DEBUG1(SUFF, "%s...", cp); 1255 gn = Targ_GetNode(cp); 1256 1257 /* Add gn to the parents child list before the original child */ 1258 Lst_InsertBefore(&pgn->children, cln, gn); 1259 Lst_Append(&gn->parents, pgn); 1260 pgn->unmade++; 1261 } 1262 1263 Lst_Done(&expansions); 1264 1265 DEBUG0(SUFF, "\n"); 1266 1267 /* 1268 * Now the source is expanded, remove it from the list of children to 1269 * keep it from being processed. 1270 */ 1271 pgn->unmade--; 1272 Lst_Remove(&pgn->children, cln); 1273 Lst_Remove(&cgn->parents, Lst_FindDatum(&cgn->parents, pgn)); 1274 } 1275 1276 /* 1277 * Break the result into a vector of strings whose nodes we can find, then 1278 * add those nodes to the members list. 1279 * 1280 * Unfortunately, we can't use Str_Words because it doesn't understand about 1281 * variable expressions with spaces in them. 1282 */ 1283 static void 1284 ExpandChildrenRegular(char *cp, GNode *pgn, GNodeList *members) 1285 { 1286 char *start; 1287 1288 pp_skip_hspace(&cp); 1289 start = cp; 1290 while (*cp != '\0') { 1291 if (*cp == ' ' || *cp == '\t') { 1292 GNode *gn; 1293 /* 1294 * White-space -- terminate element, find the node, 1295 * add it, skip any further spaces. 1296 */ 1297 *cp++ = '\0'; 1298 gn = Targ_GetNode(start); 1299 Lst_Append(members, gn); 1300 pp_skip_hspace(&cp); 1301 /* Continue at the next non-space. */ 1302 start = cp; 1303 } else if (*cp == '$') { 1304 /* Skip over the variable expression. */ 1305 const char *nested_p = cp; 1306 FStr junk; 1307 1308 (void)Var_Parse(&nested_p, pgn, VARE_PARSE_ONLY, &junk); 1309 /* TODO: handle errors */ 1310 if (junk.str == var_Error) { 1311 Parse_Error(PARSE_FATAL, 1312 "Malformed variable expression at \"%s\"", 1313 cp); 1314 cp++; 1315 } else { 1316 cp += nested_p - cp; 1317 } 1318 1319 FStr_Done(&junk); 1320 } else if (cp[0] == '\\' && cp[1] != '\0') { 1321 /* Escaped something -- skip over it. */ 1322 /* 1323 * XXX: In other places, escaping at this syntactical 1324 * position is done by a '$', not a '\'. The '\' is 1325 * only used in variable modifiers. 1326 */ 1327 cp += 2; 1328 } else { 1329 cp++; 1330 } 1331 } 1332 1333 if (cp != start) { 1334 /* 1335 * Stuff left over -- add it to the list too 1336 */ 1337 GNode *gn = Targ_GetNode(start); 1338 Lst_Append(members, gn); 1339 } 1340 } 1341 1342 /* 1343 * Expand the names of any children of a given node that contain variable 1344 * expressions or file wildcards into actual targets. 1345 * 1346 * The expanded node is removed from the parent's list of children, and the 1347 * parent's unmade counter is decremented, but other nodes may be added. 1348 * 1349 * Input: 1350 * cln Child to examine 1351 * pgn Parent node being processed 1352 */ 1353 static void 1354 ExpandChildren(GNodeListNode *cln, GNode *pgn) 1355 { 1356 GNode *cgn = cln->datum; 1357 char *cp; /* Expanded value */ 1358 1359 if (!Lst_IsEmpty(&cgn->order_pred) || !Lst_IsEmpty(&cgn->order_succ)) 1360 /* It is all too hard to process the result of .ORDER */ 1361 return; 1362 1363 if (cgn->type & OP_WAIT) 1364 /* Ignore these (& OP_PHONY ?) */ 1365 return; 1366 1367 /* 1368 * First do variable expansion -- this takes precedence over wildcard 1369 * expansion. If the result contains wildcards, they'll be gotten to 1370 * later since the resulting words are tacked on to the end of the 1371 * children list. 1372 */ 1373 if (strchr(cgn->name, '$') == NULL) { 1374 ExpandWildcards(cln, pgn); 1375 return; 1376 } 1377 1378 DEBUG1(SUFF, "Expanding \"%s\"...", cgn->name); 1379 (void)Var_Subst(cgn->name, pgn, VARE_UNDEFERR, &cp); 1380 /* TODO: handle errors */ 1381 1382 { 1383 GNodeList members = LST_INIT; 1384 1385 if (cgn->type & OP_ARCHV) { 1386 /* 1387 * Node was an 'archive(member)' target, so 1388 * call on the Arch module to find the nodes for us, 1389 * expanding variables in the parent's scope. 1390 */ 1391 char *p = cp; 1392 (void)Arch_ParseArchive(&p, &members, pgn); 1393 } else { 1394 ExpandChildrenRegular(cp, pgn, &members); 1395 } 1396 1397 /* 1398 * Add all elements of the members list to the parent node. 1399 */ 1400 while (!Lst_IsEmpty(&members)) { 1401 GNode *gn = Lst_Dequeue(&members); 1402 1403 DEBUG1(SUFF, "%s...", gn->name); 1404 /* 1405 * Add gn to the parents child list before the 1406 * original child. 1407 */ 1408 Lst_InsertBefore(&pgn->children, cln, gn); 1409 Lst_Append(&gn->parents, pgn); 1410 pgn->unmade++; 1411 /* Expand wildcards on new node */ 1412 ExpandWildcards(cln->prev, pgn); 1413 } 1414 Lst_Done(&members); 1415 1416 free(cp); 1417 } 1418 1419 DEBUG0(SUFF, "\n"); 1420 1421 /* 1422 * Now the source is expanded, remove it from the list of children to 1423 * keep it from being processed. 1424 */ 1425 pgn->unmade--; 1426 Lst_Remove(&pgn->children, cln); 1427 Lst_Remove(&cgn->parents, Lst_FindDatum(&cgn->parents, pgn)); 1428 } 1429 1430 static void 1431 ExpandAllChildren(GNode *gn) 1432 { 1433 GNodeListNode *ln, *nln; 1434 1435 for (ln = gn->children.first; ln != NULL; ln = nln) { 1436 nln = ln->next; 1437 ExpandChildren(ln, gn); 1438 } 1439 } 1440 1441 /* 1442 * Find a path along which to expand the node. 1443 * 1444 * If the node has a known suffix, use that path. 1445 * If it has no known suffix, use the default system search path. 1446 * 1447 * Input: 1448 * gn Node being examined 1449 * 1450 * Results: 1451 * The appropriate path to search for the GNode. 1452 */ 1453 SearchPath * 1454 Suff_FindPath(GNode *gn) 1455 { 1456 Suffix *suff = gn->suffix; 1457 1458 if (suff == NULL) { 1459 char *name = gn->name; 1460 size_t nameLen = strlen(gn->name); 1461 SuffixListNode *ln; 1462 for (ln = sufflist.first; ln != NULL; ln = ln->next) 1463 if (Suffix_IsSuffix(ln->datum, nameLen, name + nameLen)) 1464 break; 1465 1466 DEBUG1(SUFF, "Wildcard expanding \"%s\"...", gn->name); 1467 if (ln != NULL) 1468 suff = ln->datum; 1469 /* 1470 * XXX: Here we can save the suffix so we don't have to do 1471 * this again. 1472 */ 1473 } 1474 1475 if (suff != NULL) { 1476 DEBUG1(SUFF, "suffix is \"%s\"...\n", suff->name); 1477 return suff->searchPath; 1478 } else { 1479 DEBUG0(SUFF, "\n"); 1480 return &dirSearchPath; /* Use default search path */ 1481 } 1482 } 1483 1484 /* 1485 * Apply a transformation rule, given the source and target nodes and 1486 * suffixes. 1487 * 1488 * The source and target are linked and the commands from the transformation 1489 * are added to the target node's commands list. The target also inherits all 1490 * the sources for the transformation rule. 1491 * 1492 * Results: 1493 * true if successful, false if not. 1494 */ 1495 static bool 1496 ApplyTransform(GNode *tgn, GNode *sgn, Suffix *tsuff, Suffix *ssuff) 1497 { 1498 GNodeListNode *ln; 1499 char *tname; /* Name of transformation rule */ 1500 GNode *gn; /* Node for the transformation rule */ 1501 1502 /* Form the proper links between the target and source. */ 1503 Lst_Append(&tgn->children, sgn); 1504 Lst_Append(&sgn->parents, tgn); 1505 tgn->unmade++; 1506 1507 /* Locate the transformation rule itself. */ 1508 tname = str_concat2(ssuff->name, tsuff->name); 1509 gn = FindTransformByName(tname); 1510 free(tname); 1511 1512 /* This can happen when linking an OP_MEMBER and OP_ARCHV node. */ 1513 if (gn == NULL) 1514 return false; 1515 1516 DEBUG3(SUFF, "\tapplying %s -> %s to \"%s\"\n", 1517 ssuff->name, tsuff->name, tgn->name); 1518 1519 /* Record last child; Make_HandleUse may add child nodes. */ 1520 ln = tgn->children.last; 1521 1522 /* Apply the rule. */ 1523 Make_HandleUse(gn, tgn); 1524 1525 /* Deal with wildcards and variables in any acquired sources. */ 1526 ln = ln != NULL ? ln->next : NULL; 1527 while (ln != NULL) { 1528 GNodeListNode *nln = ln->next; 1529 ExpandChildren(ln, tgn); 1530 ln = nln; 1531 } 1532 1533 /* 1534 * Keep track of another parent to which this node is transformed so 1535 * the .IMPSRC variable can be set correctly for the parent. 1536 */ 1537 Lst_Append(&sgn->implicitParents, tgn); 1538 1539 return true; 1540 } 1541 1542 /* 1543 * Member has a known suffix, so look for a transformation rule from 1544 * it to a possible suffix of the archive. 1545 * 1546 * Rather than searching through the entire list, we just look at 1547 * suffixes to which the member's suffix may be transformed. 1548 */ 1549 static void 1550 ExpandMember(GNode *gn, const char *eoarch, GNode *mem, Suffix *memSuff) 1551 { 1552 GNodeListNode *ln; 1553 size_t nameLen = (size_t)(eoarch - gn->name); 1554 1555 /* Use first matching suffix... */ 1556 for (ln = memSuff->parents.first; ln != NULL; ln = ln->next) 1557 if (Suffix_IsSuffix(ln->datum, nameLen, eoarch)) 1558 break; 1559 1560 if (ln != NULL) { 1561 /* Got one -- apply it */ 1562 Suffix *suff = ln->datum; 1563 if (!ApplyTransform(gn, mem, suff, memSuff)) { 1564 DEBUG2(SUFF, "\tNo transformation from %s -> %s\n", 1565 memSuff->name, suff->name); 1566 } 1567 } 1568 } 1569 1570 static void FindDeps(GNode *, CandidateSearcher *); 1571 1572 /* 1573 * Locate dependencies for an OP_ARCHV node. 1574 * 1575 * Input: 1576 * gn Node for which to locate dependencies 1577 * 1578 * Side Effects: 1579 * Same as Suff_FindDeps 1580 */ 1581 static void 1582 FindDepsArchive(GNode *gn, CandidateSearcher *cs) 1583 { 1584 char *eoarch; /* End of archive portion */ 1585 char *eoname; /* End of member portion */ 1586 GNode *mem; /* Node for member */ 1587 Suffix *memSuff; 1588 const char *name; /* Start of member's name */ 1589 1590 /* 1591 * The node is an archive(member) pair. so we must find a 1592 * suffix for both of them. 1593 */ 1594 eoarch = strchr(gn->name, '('); 1595 eoname = strchr(eoarch, ')'); 1596 1597 /* 1598 * Caller guarantees the format `libname(member)', via 1599 * Arch_ParseArchive. 1600 */ 1601 assert(eoarch != NULL); 1602 assert(eoname != NULL); 1603 1604 *eoname = '\0'; /* Nuke parentheses during suffix search */ 1605 *eoarch = '\0'; /* So a suffix can be found */ 1606 1607 name = eoarch + 1; 1608 1609 /* 1610 * To simplify things, call Suff_FindDeps recursively on the member 1611 * now, so we can simply compare the member's .PREFIX and .TARGET 1612 * variables to locate its suffix. This allows us to figure out the 1613 * suffix to use for the archive without having to do a quadratic 1614 * search over the suffix list, backtracking for each one. 1615 */ 1616 mem = Targ_GetNode(name); 1617 FindDeps(mem, cs); 1618 1619 /* Create the link between the two nodes right off. */ 1620 Lst_Append(&gn->children, mem); 1621 Lst_Append(&mem->parents, gn); 1622 gn->unmade++; 1623 1624 /* Copy in the variables from the member node to this one. */ 1625 Var_Set(gn, PREFIX, GNode_VarPrefix(mem)); 1626 Var_Set(gn, TARGET, GNode_VarTarget(mem)); 1627 1628 memSuff = mem->suffix; 1629 if (memSuff == NULL) { /* Didn't know what it was. */ 1630 DEBUG0(SUFF, "using null suffix\n"); 1631 memSuff = nullSuff; 1632 } 1633 1634 1635 /* Set the other two local variables required for this target. */ 1636 Var_Set(gn, MEMBER, name); 1637 Var_Set(gn, ARCHIVE, gn->name); 1638 /* Set $@ for compatibility with other makes. */ 1639 Var_Set(gn, TARGET, gn->name); 1640 1641 /* 1642 * Now we've got the important local variables set, expand any sources 1643 * that still contain variables or wildcards in their names. 1644 */ 1645 ExpandAllChildren(gn); 1646 1647 if (memSuff != NULL) 1648 ExpandMember(gn, eoarch, mem, memSuff); 1649 1650 /* 1651 * Replace the opening and closing parens now we've no need of the 1652 * separate pieces. 1653 */ 1654 *eoarch = '('; 1655 *eoname = ')'; 1656 1657 /* 1658 * Pretend gn appeared to the left of a dependency operator so the 1659 * user needn't provide a transformation from the member to the 1660 * archive. 1661 */ 1662 if (!GNode_IsTarget(gn)) 1663 gn->type |= OP_DEPENDS; 1664 1665 /* 1666 * Flag the member as such so we remember to look in the archive for 1667 * its modification time. The OP_JOIN | OP_MADE is needed because 1668 * this target should never get made. 1669 */ 1670 mem->type |= OP_MEMBER | OP_JOIN | OP_MADE; 1671 } 1672 1673 /* 1674 * If the node is a library, it is the arch module's job to find it 1675 * and set the TARGET variable accordingly. We merely provide the 1676 * search path, assuming all libraries end in ".a" (if the suffix 1677 * hasn't been defined, there's nothing we can do for it, so we just 1678 * set the TARGET variable to the node's name in order to give it a 1679 * value). 1680 */ 1681 static void 1682 FindDepsLib(GNode *gn) 1683 { 1684 Suffix *suff = FindSuffixByName(LIBSUFF); 1685 if (suff != NULL) { 1686 Suffix_Reassign(&gn->suffix, suff); 1687 Arch_FindLib(gn, suff->searchPath); 1688 } else { 1689 Suffix_Unassign(&gn->suffix); 1690 Var_Set(gn, TARGET, gn->name); 1691 } 1692 1693 /* 1694 * Because a library (-lfoo) target doesn't follow the standard 1695 * filesystem conventions, we don't set the regular variables for 1696 * the thing. .PREFIX is simply made empty. 1697 */ 1698 Var_Set(gn, PREFIX, ""); 1699 } 1700 1701 static void 1702 FindDepsRegularKnown(const char *name, size_t nameLen, GNode *gn, 1703 CandidateList *srcs, CandidateList *targs) 1704 { 1705 SuffixListNode *ln; 1706 Candidate *targ; 1707 char *pref; 1708 1709 for (ln = sufflist.first; ln != NULL; ln = ln->next) { 1710 Suffix *suff = ln->datum; 1711 if (!Suffix_IsSuffix(suff, nameLen, name + nameLen)) 1712 continue; 1713 1714 pref = bmake_strldup(name, (size_t)(nameLen - suff->nameLen)); 1715 targ = Candidate_New(bmake_strdup(gn->name), pref, suff, NULL, 1716 gn); 1717 1718 CandidateList_AddCandidatesFor(srcs, targ); 1719 1720 /* Record the target so we can nuke it. */ 1721 Lst_Append(targs, targ); 1722 } 1723 } 1724 1725 static void 1726 FindDepsRegularUnknown(GNode *gn, const char *sopref, 1727 CandidateList *srcs, CandidateList *targs) 1728 { 1729 Candidate *targ; 1730 1731 if (!Lst_IsEmpty(targs) || nullSuff == NULL) 1732 return; 1733 1734 DEBUG1(SUFF, "\tNo known suffix on %s. Using .NULL suffix\n", gn->name); 1735 1736 targ = Candidate_New(bmake_strdup(gn->name), bmake_strdup(sopref), 1737 nullSuff, NULL, gn); 1738 1739 /* 1740 * Only use the default suffix rules if we don't have commands 1741 * defined for this gnode; traditional make programs used to not 1742 * define suffix rules if the gnode had children but we don't do 1743 * this anymore. 1744 */ 1745 if (Lst_IsEmpty(&gn->commands)) 1746 CandidateList_AddCandidatesFor(srcs, targ); 1747 else { 1748 DEBUG0(SUFF, "not "); 1749 } 1750 1751 DEBUG0(SUFF, "adding suffix rules\n"); 1752 1753 Lst_Append(targs, targ); 1754 } 1755 1756 /* 1757 * Deal with finding the thing on the default search path. We always do 1758 * that, not only if the node is only a source (not on the lhs of a 1759 * dependency operator or [XXX] it has neither children or commands) as 1760 * the old pmake did. 1761 */ 1762 static void 1763 FindDepsRegularPath(GNode *gn, Candidate *targ) 1764 { 1765 if (gn->type & (OP_PHONY | OP_NOPATH)) 1766 return; 1767 1768 free(gn->path); 1769 gn->path = Dir_FindFile(gn->name, 1770 (targ == NULL ? &dirSearchPath : 1771 targ->suff->searchPath)); 1772 if (gn->path == NULL) 1773 return; 1774 1775 Var_Set(gn, TARGET, gn->path); 1776 1777 if (targ != NULL) { 1778 /* 1779 * Suffix known for the thing -- trim the suffix off 1780 * the path to form the proper .PREFIX variable. 1781 */ 1782 size_t savep = strlen(gn->path) - targ->suff->nameLen; 1783 char savec; 1784 1785 Suffix_Reassign(&gn->suffix, targ->suff); 1786 1787 savec = gn->path[savep]; 1788 gn->path[savep] = '\0'; 1789 1790 Var_Set(gn, PREFIX, str_basename(gn->path)); 1791 1792 gn->path[savep] = savec; 1793 } else { 1794 /* 1795 * The .PREFIX gets the full path if the target has no 1796 * known suffix. 1797 */ 1798 Suffix_Unassign(&gn->suffix); 1799 Var_Set(gn, PREFIX, str_basename(gn->path)); 1800 } 1801 } 1802 1803 /* 1804 * Locate implicit dependencies for regular targets. 1805 * 1806 * Input: 1807 * gn Node for which to find sources 1808 * 1809 * Side Effects: 1810 * Same as Suff_FindDeps 1811 */ 1812 static void 1813 FindDepsRegular(GNode *gn, CandidateSearcher *cs) 1814 { 1815 /* List of sources at which to look */ 1816 CandidateList srcs = LST_INIT; 1817 /* 1818 * List of targets to which things can be transformed. 1819 * They all have the same file, but different suff and prefix fields. 1820 */ 1821 CandidateList targs = LST_INIT; 1822 Candidate *bottom; /* Start of found transformation path */ 1823 Candidate *src; 1824 Candidate *targ; 1825 1826 const char *name = gn->name; 1827 size_t nameLen = strlen(name); 1828 1829 #ifdef DEBUG_SRC 1830 DEBUG1(SUFF, "FindDepsRegular \"%s\"\n", gn->name); 1831 #endif 1832 1833 /* 1834 * We're caught in a catch-22 here. On the one hand, we want to use 1835 * any transformation implied by the target's sources, but we can't 1836 * examine the sources until we've expanded any variables/wildcards 1837 * they may hold, and we can't do that until we've set up the 1838 * target's local variables and we can't do that until we know what 1839 * the proper suffix for the target is (in case there are two 1840 * suffixes one of which is a suffix of the other) and we can't know 1841 * that until we've found its implied source, which we may not want 1842 * to use if there's an existing source that implies a different 1843 * transformation. 1844 * 1845 * In an attempt to get around this, which may not work all the time, 1846 * but should work most of the time, we look for implied sources 1847 * first, checking transformations to all possible suffixes of the 1848 * target, use what we find to set the target's local variables, 1849 * expand the children, then look for any overriding transformations 1850 * they imply. Should we find one, we discard the one we found before. 1851 */ 1852 bottom = NULL; 1853 targ = NULL; 1854 1855 if (!(gn->type & OP_PHONY)) { 1856 1857 FindDepsRegularKnown(name, nameLen, gn, &srcs, &targs); 1858 1859 /* Handle target of unknown suffix... */ 1860 FindDepsRegularUnknown(gn, name, &srcs, &targs); 1861 1862 /* 1863 * Using the list of possible sources built up from the target 1864 * suffix(es), try and find an existing file/target that 1865 * matches. 1866 */ 1867 bottom = FindThem(&srcs, cs); 1868 1869 if (bottom == NULL) { 1870 /* 1871 * No known transformations -- use the first suffix 1872 * found for setting the local variables. 1873 */ 1874 if (targs.first != NULL) 1875 targ = targs.first->datum; 1876 else 1877 targ = NULL; 1878 } else { 1879 /* 1880 * Work up the transformation path to find the suffix 1881 * of the target to which the transformation was made. 1882 */ 1883 for (targ = bottom; 1884 targ->parent != NULL; targ = targ->parent) 1885 continue; 1886 } 1887 } 1888 1889 Var_Set(gn, TARGET, GNode_Path(gn)); 1890 Var_Set(gn, PREFIX, targ != NULL ? targ->prefix : gn->name); 1891 1892 /* 1893 * Now we've got the important local variables set, expand any sources 1894 * that still contain variables or wildcards in their names. 1895 */ 1896 { 1897 GNodeListNode *ln, *nln; 1898 for (ln = gn->children.first; ln != NULL; ln = nln) { 1899 nln = ln->next; 1900 ExpandChildren(ln, gn); 1901 } 1902 } 1903 1904 if (targ == NULL) { 1905 DEBUG1(SUFF, "\tNo valid suffix on %s\n", gn->name); 1906 1907 sfnd_abort: 1908 FindDepsRegularPath(gn, targ); 1909 goto sfnd_return; 1910 } 1911 1912 /* 1913 * If the suffix indicates that the target is a library, mark that in 1914 * the node's type field. 1915 */ 1916 if (targ->suff->library) 1917 gn->type |= OP_LIB; 1918 1919 /* 1920 * Check for overriding transformation rule implied by sources 1921 */ 1922 if (!Lst_IsEmpty(&gn->children)) { 1923 src = FindCmds(targ, cs); 1924 1925 if (src != NULL) { 1926 /* 1927 * Free up all the candidates in the transformation 1928 * path, up to but not including the parent node. 1929 */ 1930 while (bottom != NULL && bottom->parent != NULL) { 1931 CandidateSearcher_AddIfNew(cs, bottom); 1932 bottom = bottom->parent; 1933 } 1934 bottom = src; 1935 } 1936 } 1937 1938 if (bottom == NULL) { 1939 /* No idea from where it can come -- return now. */ 1940 goto sfnd_abort; 1941 } 1942 1943 /* 1944 * We now have a list of candidates headed by 'bottom' and linked via 1945 * their 'parent' pointers. What we do next is create links between 1946 * source and target nodes (which may or may not have been created) 1947 * and set the necessary local variables in each target. 1948 * 1949 * The commands for each target are set from the commands of the 1950 * transformation rule used to get from the src suffix to the targ 1951 * suffix. Note that this causes the commands list of the original 1952 * node, gn, to be replaced with the commands of the final 1953 * transformation rule. 1954 */ 1955 if (bottom->node == NULL) 1956 bottom->node = Targ_GetNode(bottom->file); 1957 1958 for (src = bottom; src->parent != NULL; src = src->parent) { 1959 targ = src->parent; 1960 1961 Suffix_Reassign(&src->node->suffix, src->suff); 1962 1963 if (targ->node == NULL) 1964 targ->node = Targ_GetNode(targ->file); 1965 1966 ApplyTransform(targ->node, src->node, 1967 targ->suff, src->suff); 1968 1969 if (targ->node != gn) { 1970 /* 1971 * Finish off the dependency-search process for any 1972 * nodes between bottom and gn (no point in questing 1973 * around the filesystem for their implicit source 1974 * when it's already known). Note that the node 1975 * can't have any sources that need expanding, since 1976 * SuffFindThem will stop on an existing node, so all 1977 * we need to do is set the standard variables. 1978 */ 1979 targ->node->type |= OP_DEPS_FOUND; 1980 Var_Set(targ->node, PREFIX, targ->prefix); 1981 Var_Set(targ->node, TARGET, targ->node->name); 1982 } 1983 } 1984 1985 Suffix_Reassign(&gn->suffix, src->suff); 1986 1987 /* 1988 * Nuke the transformation path and the candidates left over in the 1989 * two lists. 1990 */ 1991 sfnd_return: 1992 if (bottom != NULL) 1993 CandidateSearcher_AddIfNew(cs, bottom); 1994 1995 while (RemoveCandidate(&srcs) || RemoveCandidate(&targs)) 1996 continue; 1997 1998 CandidateSearcher_MoveAll(cs, &srcs); 1999 CandidateSearcher_MoveAll(cs, &targs); 2000 } 2001 2002 static void 2003 CandidateSearcher_CleanUp(CandidateSearcher *cs) 2004 { 2005 while (RemoveCandidate(&cs->list)) 2006 continue; 2007 assert(Lst_IsEmpty(&cs->list)); 2008 } 2009 2010 2011 /* 2012 * Find implicit sources for the target. 2013 * 2014 * Nodes are added to the graph as children of the passed-in node. The nodes 2015 * are marked to have their IMPSRC variable filled in. The PREFIX variable 2016 * is set for the given node and all its implied children. 2017 * 2018 * The path found by this target is the shortest path in the transformation 2019 * graph, which may pass through nonexistent targets, to an existing target. 2020 * The search continues on all paths from the root suffix until a file is 2021 * found. I.e. if there's a path .o -> .c -> .l -> .l,v from the root and the 2022 * .l,v file exists but the .c and .l files don't, the search will branch out 2023 * in all directions from .o and again from all the nodes on the next level 2024 * until the .l,v node is encountered. 2025 */ 2026 void 2027 Suff_FindDeps(GNode *gn) 2028 { 2029 CandidateSearcher cs; 2030 2031 CandidateSearcher_Init(&cs); 2032 2033 FindDeps(gn, &cs); 2034 2035 CandidateSearcher_CleanUp(&cs); 2036 CandidateSearcher_Done(&cs); 2037 } 2038 2039 static void 2040 FindDeps(GNode *gn, CandidateSearcher *cs) 2041 { 2042 if (gn->type & OP_DEPS_FOUND) 2043 return; 2044 gn->type |= OP_DEPS_FOUND; 2045 2046 /* Make sure we have these set, may get revised below. */ 2047 Var_Set(gn, TARGET, GNode_Path(gn)); 2048 Var_Set(gn, PREFIX, gn->name); 2049 2050 DEBUG1(SUFF, "SuffFindDeps \"%s\"\n", gn->name); 2051 2052 if (gn->type & OP_ARCHV) 2053 FindDepsArchive(gn, cs); 2054 else if (gn->type & OP_LIB) 2055 FindDepsLib(gn); 2056 else 2057 FindDepsRegular(gn, cs); 2058 } 2059 2060 /* 2061 * Define which suffix is the null suffix. 2062 * 2063 * Need to handle the changing of the null suffix gracefully so the old 2064 * transformation rules don't just go away. 2065 * 2066 * Input: 2067 * name Name of null suffix 2068 */ 2069 void 2070 Suff_SetNull(const char *name) 2071 { 2072 Suffix *suff = FindSuffixByName(name); 2073 if (suff == NULL) { 2074 Parse_Error(PARSE_WARNING, 2075 "Desired null suffix %s not defined", 2076 name); 2077 return; 2078 } 2079 2080 if (nullSuff != NULL) 2081 nullSuff->isNull = false; 2082 suff->isNull = true; 2083 /* XXX: Here's where the transformation mangling would take place. */ 2084 nullSuff = suff; 2085 } 2086 2087 /* Initialize the suffixes module. */ 2088 void 2089 Suff_Init(void) 2090 { 2091 /* 2092 * Create null suffix for single-suffix rules (POSIX). The thing 2093 * doesn't actually go on the suffix list or everyone will think 2094 * that's its suffix. 2095 */ 2096 Suff_ClearSuffixes(); 2097 } 2098 2099 2100 /* Clean up the suffixes module. */ 2101 void 2102 Suff_End(void) 2103 { 2104 #ifdef CLEANUP 2105 Lst_DoneCall(&sufflist, SuffFree); 2106 Lst_DoneCall(&suffClean, SuffFree); 2107 if (nullSuff != NULL) 2108 SuffFree(nullSuff); 2109 Lst_Done(&transforms); 2110 #endif 2111 } 2112 2113 2114 static void 2115 PrintSuffNames(const char *prefix, const SuffixList *suffs) 2116 { 2117 SuffixListNode *ln; 2118 2119 debug_printf("#\t%s: ", prefix); 2120 for (ln = suffs->first; ln != NULL; ln = ln->next) { 2121 const Suffix *suff = ln->datum; 2122 debug_printf("%s ", suff->name); 2123 } 2124 debug_printf("\n"); 2125 } 2126 2127 static void 2128 Suffix_Print(const Suffix *suff) 2129 { 2130 Buffer buf; 2131 2132 Buf_InitSize(&buf, 16); 2133 Buf_AddFlag(&buf, suff->include, "SUFF_INCLUDE"); 2134 Buf_AddFlag(&buf, suff->library, "SUFF_LIBRARY"); 2135 Buf_AddFlag(&buf, suff->isNull, "SUFF_NULL"); 2136 2137 debug_printf("# \"%s\" (num %d, ref %d)", 2138 suff->name, suff->sNum, suff->refCount); 2139 if (buf.len > 0) 2140 debug_printf(" (%s)", buf.data); 2141 debug_printf("\n"); 2142 2143 Buf_Done(&buf); 2144 2145 PrintSuffNames("To", &suff->parents); 2146 PrintSuffNames("From", &suff->children); 2147 2148 debug_printf("#\tSearch Path: "); 2149 SearchPath_Print(suff->searchPath); 2150 debug_printf("\n"); 2151 } 2152 2153 static void 2154 PrintTransformation(GNode *t) 2155 { 2156 debug_printf("%-16s:", t->name); 2157 Targ_PrintType(t->type); 2158 debug_printf("\n"); 2159 Targ_PrintCmds(t); 2160 debug_printf("\n"); 2161 } 2162 2163 void 2164 Suff_PrintAll(void) 2165 { 2166 debug_printf("#*** Suffixes:\n"); 2167 { 2168 SuffixListNode *ln; 2169 for (ln = sufflist.first; ln != NULL; ln = ln->next) 2170 Suffix_Print(ln->datum); 2171 } 2172 2173 debug_printf("#*** Transformations:\n"); 2174 { 2175 GNodeListNode *ln; 2176 for (ln = transforms.first; ln != NULL; ln = ln->next) 2177 PrintTransformation(ln->datum); 2178 } 2179 } 2180 2181 const char * 2182 Suff_NamesStr(void) 2183 { 2184 Buffer buf; 2185 SuffixListNode *ln; 2186 Suffix *suff; 2187 2188 Buf_InitSize(&buf, 16); 2189 for (ln = sufflist.first; ln != NULL; ln = ln->next) { 2190 suff = ln->datum; 2191 if (ln != sufflist.first) 2192 Buf_AddByte(&buf, ' '); 2193 Buf_AddStr(&buf, suff->name); 2194 } 2195 return Buf_DoneData(&buf); 2196 } 2197