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