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