Commit | Line | Data |
---|---|---|
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 | |
40 | static 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 | ||
96 | static Lst sufflist; /* Lst of suffixes */ | |
97 | static Lst transforms; /* Lst of transformation rules */ | |
98 | ||
99 | static int sNum = 0; /* Counter for assigning suffix numbers */ | |
100 | ||
101 | /* | |
102 | * Structure describing an individual suffix. | |
103 | */ | |
104 | typedef 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 | */ | |
121 | typedef 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 | ||
131 | static Suff *suffNull; /* The NULL suffix for this run */ | |
132 | static 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 | */ | |
148 | static char * | |
149 | SuffStrIsPrefix (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 | */ | |
175 | static char * | |
176 | SuffSuffIsSuffix (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 | */ | |
208 | SuffSuffIsSuffixP(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 | */ | |
228 | static int | |
229 | SuffSuffHasNameP (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 | */ | |
251 | static int | |
252 | SuffSuffIsPrefix (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 | */ | |
271 | static int | |
272 | SuffGNHasNameP (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 | */ | |
292 | static void | |
293 | SuffFree (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 | */ | |
316 | static void | |
317 | SuffInsert (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 | */ | |
370 | void | |
371 | Suff_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 | */ | |
393 | static Boolean | |
394 | SuffParseTransform(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 | */ | |
474 | Boolean | |
475 | Suff_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 | */ | |
497 | GNode * | |
498 | Suff_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 | */ | |
562 | int | |
563 | Suff_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 | */ | |
625 | static int | |
626 | SuffRebuildGraph(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 | */ | |
692 | void | |
693 | Suff_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 | */ | |
733 | Lst | |
734 | Suff_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 | */ | |
767 | void | |
768 | Suff_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 | */ | |
826 | void | |
827 | Suff_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 | */ | |
856 | void | |
857 | Suff_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 | */ | |
875 | typedef 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 | */ | |
894 | static int | |
895 | SuffAddSrc (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 | */ | |
945 | static void | |
946 | SuffAddLevel (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 | */ | |
970 | static void | |
971 | SuffFreeSrc (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 | */ | |
999 | static Src * | |
1000 | SuffFindThem (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 | */ | |
1051 | static Src * | |
1052 | SuffFindCmds (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 | */ | |
1137 | static int | |
1138 | SuffExpandChildren(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 | */ | |
1378 | static Boolean | |
1379 | SuffApplyTransform(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 | */ | |
1484 | static void | |
1485 | SuffFindArchiveDeps(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 | */ | |
1620 | static void | |
1621 | SuffFindNormalDeps(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 | ||
1779 | sfnd_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 | ||
1928 | sfnd_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 | */ | |
1964 | void | |
1965 | Suff_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 | */ | |
2031 | void | |
2032 | Suff_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 | */ | |
2067 | void | |
2068 | Suff_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 | ||
2093 | static int SuffPrintName(s) Suff *s; {printf ("%s ", s->name); return (0);} | |
2094 | ||
2095 | static int | |
2096 | SuffPrintSuff (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 | ||
2137 | static int | |
2138 | SuffPrintTrans (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 | ||
2151 | Suff_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 |