[BACK]Return to suff.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Annotation of src/usr.bin/make/suff.c, Revision 1.1

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