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