Annotation of 43BSDReno/usr.bin/make/suff.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.