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