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