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