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