suff.c revision 1.72 1 1.72 christos /* $NetBSD: suff.c,v 1.72 2014/08/27 08:50:38 christos Exp $ */
2 1.8 christos
3 1.1 cgd /*
4 1.13 christos * Copyright (c) 1988, 1989, 1990, 1993
5 1.13 christos * The Regents of the University of California. All rights reserved.
6 1.42 agc *
7 1.42 agc * This code is derived from software contributed to Berkeley by
8 1.42 agc * Adam de Boor.
9 1.42 agc *
10 1.42 agc * Redistribution and use in source and binary forms, with or without
11 1.42 agc * modification, are permitted provided that the following conditions
12 1.42 agc * are met:
13 1.42 agc * 1. Redistributions of source code must retain the above copyright
14 1.42 agc * notice, this list of conditions and the following disclaimer.
15 1.42 agc * 2. Redistributions in binary form must reproduce the above copyright
16 1.42 agc * notice, this list of conditions and the following disclaimer in the
17 1.42 agc * documentation and/or other materials provided with the distribution.
18 1.42 agc * 3. Neither the name of the University nor the names of its contributors
19 1.42 agc * may be used to endorse or promote products derived from this software
20 1.42 agc * without specific prior written permission.
21 1.42 agc *
22 1.42 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 1.42 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 1.42 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 1.42 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 1.42 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 1.42 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 1.42 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 1.42 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 1.42 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 1.42 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 1.42 agc * SUCH DAMAGE.
33 1.42 agc */
34 1.42 agc
35 1.42 agc /*
36 1.1 cgd * Copyright (c) 1989 by Berkeley Softworks
37 1.1 cgd * All rights reserved.
38 1.1 cgd *
39 1.1 cgd * This code is derived from software contributed to Berkeley by
40 1.1 cgd * Adam de Boor.
41 1.1 cgd *
42 1.1 cgd * Redistribution and use in source and binary forms, with or without
43 1.1 cgd * modification, are permitted provided that the following conditions
44 1.1 cgd * are met:
45 1.1 cgd * 1. Redistributions of source code must retain the above copyright
46 1.1 cgd * notice, this list of conditions and the following disclaimer.
47 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
48 1.1 cgd * notice, this list of conditions and the following disclaimer in the
49 1.1 cgd * documentation and/or other materials provided with the distribution.
50 1.1 cgd * 3. All advertising materials mentioning features or use of this software
51 1.1 cgd * must display the following acknowledgement:
52 1.1 cgd * This product includes software developed by the University of
53 1.1 cgd * California, Berkeley and its contributors.
54 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
55 1.1 cgd * may be used to endorse or promote products derived from this software
56 1.1 cgd * without specific prior written permission.
57 1.1 cgd *
58 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 1.1 cgd * SUCH DAMAGE.
69 1.1 cgd */
70 1.1 cgd
71 1.45 ross #ifndef MAKE_NATIVE
72 1.72 christos static char rcsid[] = "$NetBSD: suff.c,v 1.72 2014/08/27 08:50:38 christos Exp $";
73 1.18 lukem #else
74 1.17 christos #include <sys/cdefs.h>
75 1.1 cgd #ifndef lint
76 1.8 christos #if 0
77 1.13 christos static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";
78 1.8 christos #else
79 1.72 christos __RCSID("$NetBSD: suff.c,v 1.72 2014/08/27 08:50:38 christos Exp $");
80 1.8 christos #endif
81 1.1 cgd #endif /* not lint */
82 1.18 lukem #endif
83 1.1 cgd
84 1.1 cgd /*-
85 1.1 cgd * suff.c --
86 1.1 cgd * Functions to maintain suffix lists and find implicit dependents
87 1.1 cgd * using suffix transformation rules
88 1.1 cgd *
89 1.1 cgd * Interface:
90 1.1 cgd * Suff_Init Initialize all things to do with suffixes.
91 1.1 cgd *
92 1.71 christos * Suff_End Clean up the module. Must be called after
93 1.71 christos * Targ_End() so suffix references in nodes
94 1.71 christos * have been dealt with.
95 1.71 christos *
96 1.71 christos * Suff_UnsetSuffix Helper for Targ_End() to unset node's suffix
97 1.71 christos * so as to not mess up reference counting.
98 1.6 jtc *
99 1.1 cgd * Suff_DoPaths This function is used to make life easier
100 1.1 cgd * when searching for a file according to its
101 1.1 cgd * suffix. It takes the global search path,
102 1.1 cgd * as defined using the .PATH: target, and appends
103 1.1 cgd * its directories to the path of each of the
104 1.1 cgd * defined suffixes, as specified using
105 1.1 cgd * .PATH<suffix>: targets. In addition, all
106 1.1 cgd * directories given for suffixes labeled as
107 1.1 cgd * include files or libraries, using the .INCLUDES
108 1.1 cgd * or .LIBS targets, are played with using
109 1.1 cgd * Dir_MakeFlags to create the .INCLUDES and
110 1.1 cgd * .LIBS global variables.
111 1.1 cgd *
112 1.1 cgd * Suff_ClearSuffixes Clear out all the suffixes and defined
113 1.1 cgd * transformations.
114 1.1 cgd *
115 1.1 cgd * Suff_IsTransform Return TRUE if the passed string is the lhs
116 1.1 cgd * of a transformation rule.
117 1.1 cgd *
118 1.1 cgd * Suff_AddSuffix Add the passed string as another known suffix.
119 1.1 cgd *
120 1.1 cgd * Suff_GetPath Return the search path for the given suffix.
121 1.1 cgd *
122 1.1 cgd * Suff_AddInclude Mark the given suffix as denoting an include
123 1.1 cgd * file.
124 1.1 cgd *
125 1.1 cgd * Suff_AddLib Mark the given suffix as denoting a library.
126 1.1 cgd *
127 1.1 cgd * Suff_AddTransform Add another transformation to the suffix
128 1.1 cgd * graph. Returns GNode suitable for framing, I
129 1.1 cgd * mean, tacking commands, attributes, etc. on.
130 1.1 cgd *
131 1.1 cgd * Suff_FindDeps Find implicit sources for and the location of
132 1.1 cgd * a target based on its suffix. Returns the
133 1.65 dsl * bottom-most node added to the graph or NULL
134 1.1 cgd * if the target had no implicit sources.
135 1.47 christos *
136 1.47 christos * Suff_FindPath Return the appropriate path to search in
137 1.47 christos * order to find the node.
138 1.1 cgd */
139 1.1 cgd
140 1.71 christos #include <assert.h>
141 1.71 christos #include <limits.h>
142 1.71 christos #include <stdarg.h>
143 1.1 cgd #include <stdio.h>
144 1.1 cgd #include "make.h"
145 1.4 cgd #include "hash.h"
146 1.4 cgd #include "dir.h"
147 1.1 cgd
148 1.71 christos /*
149 1.71 christos * Currently known suffixes:
150 1.71 christos * All currently known suffixes are stored in sufflist (data: Suff *) and
151 1.71 christos * the next suffix added will get sNum as its suffix number (incremented
152 1.71 christos * after each use). Lookup is used as a lookup table for quick rejection,
153 1.71 christos * when it needs to be known if a string matches a known suffix. All indexes
154 1.71 christos * corresponding to the first character of a suffix in sufflist are true
155 1.71 christos * and others are false.
156 1.71 christos */
157 1.71 christos static int sNum = 0;
158 1.71 christos static Lst sufflist;
159 1.71 christos #define LOOKUP_SIZE 256
160 1.71 christos static int lookup[LOOKUP_SIZE] = { 0 };
161 1.1 cgd
162 1.71 christos /*
163 1.71 christos * Currently known transformations:
164 1.71 christos * References to nodes of currently active transformation rules (i.e. all
165 1.71 christos * which have OP_TRANSFORM set). It is used to remove the need to iterate
166 1.71 christos * through all targets when a transformation node needs to be accessed.
167 1.71 christos * (data: GNode *)
168 1.71 christos */
169 1.71 christos static Lst transforms;
170 1.1 cgd
171 1.1 cgd /*
172 1.1 cgd * Structure describing an individual suffix.
173 1.71 christos *
174 1.71 christos * When a target has a known suffix, a reference is stored in the suffix
175 1.71 christos * field of its node. The same field is also used in OP_TRANSFORM nodes to
176 1.71 christos * store the /target/ of the transformation. This enables SuffScanTargets()
177 1.71 christos * to recognize single suffix transformations by the fact that the field
178 1.71 christos * references emptySuff. This also happens to be the known suffix of
179 1.71 christos * the field if the node is used as a regular target.
180 1.71 christos *
181 1.71 christos * Use the provided maintenance functions for creating, destroying and moving
182 1.71 christos * these around to keep the reference counts in order. The suffix will be
183 1.71 christos * free'd when the count reaches zero.
184 1.71 christos *
185 1.71 christos * The SUFF_NULL type flag is required for SuffAddLevelForSuffix() to
186 1.71 christos * detect when a suffix is used as a regular suffix and when as the .NULL
187 1.71 christos * suffix. This is achieved by only setting it for the duration of
188 1.71 christos * the call when the "remove a suffix" aspect of .NULL is used. When
189 1.71 christos * the .NULL feature is used in its "add a suffix" aspect, the transformation
190 1.71 christos * from a suffixless file is added after the regular transformation by
191 1.71 christos * SuffNewChildSrc() when a suffix == nullSuff is used.
192 1.1 cgd */
193 1.1 cgd typedef struct _Suff {
194 1.71 christos char *name; /* The suffix itself (e.g. ".c") */
195 1.71 christos size_t nameLen; /* Length of the suffix */
196 1.71 christos
197 1.71 christos short flags; /* Filetype implied by the suffix (bitfield) */
198 1.71 christos #define SUFF_INCLUDE 0x01 /* One which is #include'd.
199 1.71 christos * XXX: Not used? Remove? */
200 1.71 christos #define SUFF_LIBRARY 0x02 /* ar(1) archive */
201 1.71 christos #define SUFF_NULL 0x04 /* The .NULL suffix */
202 1.71 christos
203 1.71 christos Lst searchPath; /* The path along which files of this suffix
204 1.1 cgd * may be found */
205 1.71 christos
206 1.71 christos /*
207 1.71 christos * The suffix number. Unique for each suffix. Doubles as suffix
208 1.71 christos * priority, i.e. shows the relative .SUFFIXES ordering of suffixes:
209 1.71 christos * smaller sNums are earlier in the list.
210 1.71 christos */
211 1.71 christos int sNum;
212 1.71 christos
213 1.71 christos /*
214 1.71 christos * Reference count. Counted references are: membership in sufflist,
215 1.71 christos * membership in parents or children list of another suffix, assignment
216 1.71 christos * to GNode->suffix, assignment as emptySuff, and assignment as nullSuff.
217 1.71 christos */
218 1.71 christos int refCount;
219 1.71 christos
220 1.71 christos /*
221 1.71 christos * Suffixes we have a transformation to (parents) and from (children).
222 1.71 christos * Kept in .SUFFIXES order, as implied by sNum (data: Suff *)
223 1.71 christos * XXX: renaming these to "to" and "from" or "targets" and "sources"
224 1.71 christos * could make sense as parents and children on a suffix are not very
225 1.71 christos * intuitive.
226 1.71 christos */
227 1.71 christos Lst parents;
228 1.71 christos Lst children;
229 1.71 christos
230 1.71 christos #ifdef DEBUG_SRC
231 1.71 christos /*
232 1.71 christos * Lists this suffix is referenced in. Contains sufflist for all but
233 1.71 christos * emptySuff, parents list of all suffixes referenced in own children
234 1.71 christos * list, and children list of all suffixes referenced in own parents
235 1.71 christos * list. (data: Lst)
236 1.71 christos */
237 1.71 christos Lst ref;
238 1.71 christos #endif
239 1.1 cgd } Suff;
240 1.1 cgd
241 1.1 cgd /*
242 1.22 itohy * for SuffSuffIsSuffix
243 1.22 itohy */
244 1.22 itohy typedef struct {
245 1.71 christos char *ename; /* The end of the name (the final '\0') */
246 1.71 christos size_t len; /* The length of the name */
247 1.22 itohy } SuffixCmpData;
248 1.22 itohy
249 1.22 itohy /*
250 1.1 cgd * Structure used in the search for implied sources.
251 1.1 cgd */
252 1.1 cgd typedef struct _Src {
253 1.1 cgd char *file; /* The file to look for */
254 1.71 christos
255 1.71 christos /*
256 1.71 christos * Prefix from which file was formed. In an effort to reduce
257 1.71 christos * unnecessary memory allocations, only those with parent != NULL
258 1.71 christos * own their pref, others refer to their parents'.
259 1.71 christos */
260 1.71 christos char *pref;
261 1.71 christos
262 1.1 cgd Suff *suff; /* The suffix on the file */
263 1.1 cgd struct _Src *parent; /* The Src for which this is a source */
264 1.1 cgd GNode *node; /* The node describing the file */
265 1.71 christos
266 1.71 christos /*
267 1.71 christos * Steps to top of chain. Used in debug prints to show chain length
268 1.71 christos * with indentation so multi-stage transformations are more readable.
269 1.71 christos */
270 1.71 christos int depth;
271 1.1 cgd } Src;
272 1.1 cgd
273 1.71 christos /* Extra arguments to SuffAddSrc() via Lst_ForEach(). */
274 1.71 christos typedef struct {
275 1.71 christos Src *target; /* get possible transformations for this target */
276 1.71 christos Lst possible; /* list of possible transformation not yet tried */
277 1.71 christos Lst cleanup; /* list of all transformations created (for freeing) */
278 1.71 christos } LstSrc;
279 1.71 christos
280 1.4 cgd /*
281 1.71 christos * Empty suffix for implementing POSIX single-suffix transformation rules.
282 1.71 christos * It won't go in sufflist lest all targets consider it as their suffix.
283 1.71 christos * Also, single suffix rules must only be checked if the target does not
284 1.71 christos * have a known suffix. This suffix is always the first one created, but
285 1.71 christos * its sNum field is forced to INT_MAX to keep it in its proper place
286 1.71 christos * at the end of the parents list of any of its children. (Hopefully no one
287 1.71 christos * will create that many suffixes)
288 1.4 cgd */
289 1.71 christos static Suff *emptySuff = NULL;
290 1.71 christos
291 1.71 christos /*
292 1.71 christos * XXX: replace this ugly hack of a feature with pattern rules!
293 1.71 christos */
294 1.71 christos static Suff *nullSuff = NULL;
295 1.4 cgd
296 1.71 christos /* Flags for SuffCleanUp() */
297 1.71 christos #define SCU_CLEAR (1 << 1) /* called from Suff_ClearSuffixes() */
298 1.71 christos #define SCU_END (1 << 2) /* called from Suff_End() */
299 1.71 christos /* Flags for SuffApplyTransformation*() */
300 1.71 christos #define SAT_REGULAR (1 << 0) /* Standard behavior */
301 1.71 christos #define SAT_NO_EXPAND (1 << 1) /* Don't expand children of top node */
302 1.1 cgd
303 1.71 christos /* Definitions (and map) for local functions. */
304 1.4 cgd
305 1.71 christos /* Lst Predicates */
306 1.67 dsl static const char *SuffStrIsPrefix(const char *, const char *);
307 1.67 dsl static char *SuffSuffIsSuffix(const Suff *, const SuffixCmpData *);
308 1.67 dsl static int SuffSuffIsSuffixP(const void *, const void *);
309 1.67 dsl static int SuffSuffHasNameP(const void *, const void *);
310 1.71 christos static int SuffSuffIsPrefixP(const void *, const void *);
311 1.67 dsl static int SuffGNHasNameP(const void *, const void *);
312 1.71 christos static int SuffSuffHasPriorityLEP(const void *, const void *);
313 1.71 christos
314 1.71 christos /* Maintenance Functions */
315 1.71 christos static Suff *SuffNewSuff(const char *);
316 1.71 christos static void SuffFreeSuff(Suff *);
317 1.71 christos static Src *SuffNewSrc(char *, char *, Suff *, GNode *, Src *);
318 1.71 christos static Src *SuffNewTopSrc(GNode *, Suff *);
319 1.71 christos static Src *SuffNewChildSrc(Src *, Suff *, Src **);
320 1.71 christos static void SuffFreeSrc(void *);
321 1.71 christos static void SuffLinkSuffixes(Suff *, Suff *);
322 1.71 christos static int SuffUnlinkSuffixes(void *f, void *t);
323 1.71 christos static void SuffSetSuffix(GNode *, Suff *);
324 1.71 christos static void Suff_UnsetSuffix(GNode *);
325 1.71 christos static void SuffAddToList(Suff *, Lst, LstNode);
326 1.71 christos static void SuffRemoveFromList(Suff *, Lst);
327 1.71 christos static void SuffInsertIntoList(Suff *, Lst);
328 1.71 christos static void SuffUnsetOpTransform(void *);
329 1.71 christos static int SuffUnlinkChildren(void *, void *);
330 1.71 christos static void SuffFreeSuffSufflist(void *);
331 1.71 christos static void SuffCleanUp(int);
332 1.71 christos
333 1.71 christos /* Parsing Helpers */
334 1.71 christos /* Suff_ClearSuffixes */
335 1.39 wiz static Boolean SuffParseTransform(char *, Suff **, Suff **);
336 1.71 christos /* Suff_IsTransform */
337 1.71 christos /* Suff_AddTransform */
338 1.71 christos /* Suff_EndTransform */
339 1.66 dsl static int SuffScanTargets(void *, void *);
340 1.71 christos /* Suff_AddSuffix */
341 1.71 christos /* Suff_GetPath */
342 1.71 christos /* Suff_DoPaths */
343 1.71 christos /* Suff_AddInclude */
344 1.71 christos /* Suff_AddLib */
345 1.71 christos
346 1.71 christos /* Implicit Source Search Functions */
347 1.66 dsl static int SuffAddSrc(void *, void *);
348 1.71 christos static void SuffAddLevel(Lst, Src *, Lst);
349 1.39 wiz static Src *SuffFindThem(Lst, Lst);
350 1.71 christos static void SuffExpandChildren(GNode *, LstNode);
351 1.71 christos static void SuffExpandChild(LstNode, GNode *);
352 1.56 dsl static void SuffExpandWildcards(LstNode, GNode *);
353 1.71 christos /* Suff_FindPath */
354 1.71 christos static Suff *SuffApplyTransformations(Src *, GNode *);
355 1.71 christos static Boolean SuffApplyTransformation(GNode *, GNode *, Suff *, Suff *, int);
356 1.71 christos static Suff *SuffFirstKnownSuffix(char* name);
357 1.71 christos static void SuffSetPrefixLocalVar(Suff *suffix, char *name, GNode *node);
358 1.39 wiz static void SuffFindArchiveDeps(GNode *, Lst);
359 1.39 wiz static void SuffFindNormalDeps(GNode *, Lst);
360 1.71 christos /* Suff_FindDeps */
361 1.71 christos /* Suff_SetNull */
362 1.71 christos /* Suff_Init */
363 1.71 christos /* Suff_End */
364 1.71 christos
365 1.71 christos /* Debugging Functions */
366 1.71 christos static int SuffDebug(const char *,...) MAKE_ATTR_PRINTFLIKE(1, 2);
367 1.71 christos static void SuffDebugChain(Src *);
368 1.66 dsl static int SuffPrintName(void *, void *);
369 1.66 dsl static int SuffPrintSuff(void *, void *);
370 1.66 dsl static int SuffPrintTrans(void *, void *);
371 1.4 cgd
372 1.71 christos
373 1.71 christos /*
374 1.71 christos ******************************************************************************
375 1.71 christos * Lst Predicates
376 1.71 christos ******************************************************************************
377 1.71 christos */
378 1.71 christos
379 1.1 cgd /*-
380 1.1 cgd *-----------------------------------------------------------------------
381 1.1 cgd * SuffStrIsPrefix --
382 1.1 cgd * See if pref is a prefix of str.
383 1.1 cgd *
384 1.39 wiz * Input:
385 1.39 wiz * pref possible prefix
386 1.39 wiz * str string to check
387 1.39 wiz *
388 1.1 cgd * Results:
389 1.1 cgd * NULL if it ain't, pointer to character in str after prefix if so
390 1.1 cgd *
391 1.1 cgd * Side Effects:
392 1.1 cgd * None
393 1.1 cgd *-----------------------------------------------------------------------
394 1.1 cgd */
395 1.67 dsl static const char *
396 1.67 dsl SuffStrIsPrefix(const char *pref, const char *str)
397 1.1 cgd {
398 1.1 cgd while (*str && *pref == *str) {
399 1.1 cgd pref++;
400 1.1 cgd str++;
401 1.1 cgd }
402 1.1 cgd
403 1.1 cgd return (*pref ? NULL : str);
404 1.1 cgd }
405 1.1 cgd
406 1.1 cgd /*-
407 1.1 cgd *-----------------------------------------------------------------------
408 1.1 cgd * SuffSuffIsSuffix --
409 1.22 itohy * See if suff is a suffix of str. sd->ename should point to THE END
410 1.22 itohy * of the string to check. (THE END == the null byte)
411 1.1 cgd *
412 1.39 wiz * Input:
413 1.39 wiz * s possible suffix
414 1.39 wiz * sd string to examine
415 1.39 wiz *
416 1.1 cgd * Results:
417 1.1 cgd * NULL if it ain't, pointer to character in str before suffix if
418 1.1 cgd * it is.
419 1.1 cgd *
420 1.1 cgd * Side Effects:
421 1.1 cgd * None
422 1.1 cgd *-----------------------------------------------------------------------
423 1.1 cgd */
424 1.1 cgd static char *
425 1.67 dsl SuffSuffIsSuffix(const Suff *s, const SuffixCmpData *sd)
426 1.1 cgd {
427 1.39 wiz char *p1; /* Pointer into suffix name */
428 1.39 wiz char *p2; /* Pointer into string being examined */
429 1.1 cgd
430 1.22 itohy if (sd->len < s->nameLen)
431 1.22 itohy return NULL; /* this string is shorter than the suffix */
432 1.22 itohy
433 1.1 cgd p1 = s->name + s->nameLen;
434 1.22 itohy p2 = sd->ename;
435 1.1 cgd
436 1.1 cgd while (p1 >= s->name && *p1 == *p2) {
437 1.1 cgd p1--;
438 1.1 cgd p2--;
439 1.1 cgd }
440 1.1 cgd
441 1.1 cgd return (p1 == s->name - 1 ? p2 : NULL);
442 1.1 cgd }
443 1.1 cgd
444 1.1 cgd /*-
445 1.1 cgd *-----------------------------------------------------------------------
446 1.1 cgd * SuffSuffIsSuffixP --
447 1.1 cgd * Predicate form of SuffSuffIsSuffix. Passed as the callback function
448 1.1 cgd * to Lst_Find.
449 1.1 cgd *
450 1.1 cgd * Results:
451 1.1 cgd * 0 if the suffix is the one desired, non-zero if not.
452 1.1 cgd *
453 1.1 cgd * Side Effects:
454 1.1 cgd * None.
455 1.1 cgd *
456 1.1 cgd *-----------------------------------------------------------------------
457 1.1 cgd */
458 1.4 cgd static int
459 1.67 dsl SuffSuffIsSuffixP(const void *s, const void *sd)
460 1.1 cgd {
461 1.67 dsl return(!SuffSuffIsSuffix(s, sd));
462 1.1 cgd }
463 1.1 cgd
464 1.1 cgd /*-
465 1.1 cgd *-----------------------------------------------------------------------
466 1.1 cgd * SuffSuffHasNameP --
467 1.1 cgd * Callback procedure for finding a suffix based on its name. Used by
468 1.1 cgd * Suff_GetPath.
469 1.1 cgd *
470 1.39 wiz * Input:
471 1.39 wiz * s Suffix to check
472 1.39 wiz * sd Desired name
473 1.39 wiz *
474 1.1 cgd * Results:
475 1.1 cgd * 0 if the suffix is of the given name. non-zero otherwise.
476 1.1 cgd *
477 1.1 cgd * Side Effects:
478 1.1 cgd * None
479 1.1 cgd *-----------------------------------------------------------------------
480 1.1 cgd */
481 1.1 cgd static int
482 1.67 dsl SuffSuffHasNameP(const void *s, const void *sname)
483 1.1 cgd {
484 1.67 dsl return (strcmp(sname, ((const Suff *)s)->name));
485 1.1 cgd }
486 1.1 cgd
487 1.1 cgd /*-
488 1.1 cgd *-----------------------------------------------------------------------
489 1.71 christos * SuffSuffIsPrefixP -- see if str starts with s->name.
490 1.71 christos *
491 1.71 christos * Care must be taken when using this to search for transformations and
492 1.1 cgd * what-not, since there could well be two suffixes, one of which
493 1.1 cgd * is a prefix of the other...
494 1.1 cgd *
495 1.39 wiz * Input:
496 1.39 wiz * s suffix to compare
497 1.39 wiz * str string to examine
498 1.39 wiz *
499 1.1 cgd * Results:
500 1.1 cgd * 0 if s is a prefix of str. non-zero otherwise
501 1.1 cgd *
502 1.1 cgd * Side Effects:
503 1.1 cgd * None
504 1.1 cgd *-----------------------------------------------------------------------
505 1.1 cgd */
506 1.1 cgd static int
507 1.71 christos SuffSuffIsPrefixP(const void *s, const void *str)
508 1.1 cgd {
509 1.67 dsl return SuffStrIsPrefix(((const Suff *)s)->name, str) == NULL;
510 1.1 cgd }
511 1.1 cgd
512 1.1 cgd /*-
513 1.1 cgd *-----------------------------------------------------------------------
514 1.1 cgd * SuffGNHasNameP --
515 1.1 cgd * See if the graph node has the desired name
516 1.1 cgd *
517 1.39 wiz * Input:
518 1.39 wiz * gn current node we're looking at
519 1.39 wiz * name name we're looking for
520 1.39 wiz *
521 1.1 cgd * Results:
522 1.1 cgd * 0 if it does. non-zero if it doesn't
523 1.1 cgd *
524 1.1 cgd * Side Effects:
525 1.1 cgd * None
526 1.1 cgd *-----------------------------------------------------------------------
527 1.1 cgd */
528 1.1 cgd static int
529 1.67 dsl SuffGNHasNameP(const void *gn, const void *name)
530 1.1 cgd {
531 1.67 dsl return (strcmp(name, ((const GNode *)gn)->name));
532 1.1 cgd }
533 1.1 cgd
534 1.71 christos /*-
535 1.71 christos *-----------------------------------------------------------------------
536 1.71 christos * SuffSuffHasPriorityLEP -- (Less Than or Equal To [Predicate])
537 1.71 christos *
538 1.71 christos * Check if the second suffix should preceed the first one. This is
539 1.71 christos * a predicate function for Lst_Find(), used by SuffInsertIntoList()
540 1.71 christos * for finding the insertion position of the new suffix.
541 1.71 christos *
542 1.71 christos * Input:
543 1.71 christos * first The first suffix. (Suff *)
544 1.71 christos * second The second suffix. (Suff *)
545 1.71 christos *
546 1.71 christos * Returns:
547 1.71 christos * Return 0 if the first suffix has a priority less than or
548 1.71 christos * equal to the second one, i.e. the second one preceeds the first
549 1.71 christos * one in the .SUFFIXES list or they are in fact the same suffix.
550 1.71 christos * Otherwise non-zero is returned.
551 1.71 christos *-----------------------------------------------------------------------
552 1.71 christos */
553 1.71 christos static int
554 1.71 christos SuffSuffHasPriorityLEP(const void *first, const void* second)
555 1.71 christos {
556 1.71 christos return !(((const Suff *)first)->sNum >= ((const Suff *)second)->sNum);
557 1.71 christos }
558 1.6 jtc
559 1.6 jtc
560 1.71 christos /*
561 1.71 christos ******************************************************************************
562 1.71 christos * Maintenance Functions
563 1.71 christos ******************************************************************************
564 1.71 christos */
565 1.6 jtc
566 1.71 christos /*
567 1.1 cgd *-----------------------------------------------------------------------
568 1.71 christos * SuffNewSuff -- allocate and initialize a Suff structure.
569 1.71 christos *
570 1.71 christos * The contained lists are initialized and empty. No flags are set and
571 1.71 christos * the reference count is zero. The next serial number is allocated
572 1.71 christos * for this struct.
573 1.71 christos *
574 1.71 christos * Input:
575 1.71 christos * name The suffix this structure describes (e.g. ".c"). A copy
576 1.71 christos * is made of this string.
577 1.1 cgd *
578 1.1 cgd * Results:
579 1.71 christos * The allocated and initialized structure.
580 1.1 cgd *-----------------------------------------------------------------------
581 1.1 cgd */
582 1.71 christos static Suff*
583 1.71 christos SuffNewSuff(const char* name)
584 1.1 cgd {
585 1.71 christos Suff *s = bmake_malloc(sizeof(Suff));
586 1.6 jtc
587 1.71 christos s->name = bmake_strdup(name);
588 1.71 christos s->nameLen = strlen(name);
589 1.71 christos s->flags = (strcmp(name, LIBSUFF) == 0 ? SUFF_LIBRARY : 0);
590 1.71 christos s->searchPath = Lst_Init(FALSE);
591 1.71 christos s->sNum = sNum++;
592 1.71 christos s->refCount = 0;
593 1.71 christos s->children = Lst_Init(FALSE);
594 1.71 christos s->parents = Lst_Init(FALSE);
595 1.71 christos #ifdef DEBUG_SRC
596 1.71 christos s->ref = Lst_Init(FALSE);
597 1.19 christos #endif
598 1.19 christos
599 1.71 christos return s;
600 1.1 cgd }
601 1.1 cgd
602 1.71 christos /*
603 1.1 cgd *-----------------------------------------------------------------------
604 1.71 christos * SuffFreeSuff -- release resources held by a Suff structure.
605 1.6 jtc *
606 1.71 christos * There are no other resources than memory, which is free'd.
607 1.6 jtc *
608 1.71 christos * Input:
609 1.71 christos * s the struct to free
610 1.6 jtc *-----------------------------------------------------------------------
611 1.6 jtc */
612 1.6 jtc static void
613 1.71 christos SuffFreeSuff(Suff *s)
614 1.6 jtc {
615 1.71 christos /* Make reference counting bugs unpleasantly obvious. */
616 1.71 christos if (s->refCount != 0)
617 1.71 christos Punt("Internal error deleting suffix `%s' with reference count %d",
618 1.71 christos s->name, s->refCount);
619 1.71 christos
620 1.71 christos free(s->name);
621 1.71 christos Lst_Destroy(s->searchPath, Dir_Destroy);
622 1.71 christos Lst_Destroy(s->parents, NULL);
623 1.71 christos Lst_Destroy(s->children, NULL);
624 1.71 christos #ifdef DEBUG_SRC
625 1.71 christos Lst_Destroy(s->ref, NULL);
626 1.71 christos #endif
627 1.71 christos free(s);
628 1.6 jtc }
629 1.71 christos
630 1.6 jtc /*-
631 1.6 jtc *-----------------------------------------------------------------------
632 1.71 christos * SuffNewSrc -- allocate and initialize a new Src structure.
633 1.71 christos *
634 1.71 christos * The depth field is set to 0 if parent is NULL and to parent->depth + 1
635 1.71 christos * otherwise.
636 1.71 christos *
637 1.71 christos * You probably want to use the convenience functions SuffNewTopSrc() and
638 1.71 christos * SuffNewChildSrc(). These convenience functions take the relevant
639 1.71 christos * information from their parameters, making copies as needed.
640 1.1 cgd *
641 1.39 wiz * Input:
642 1.71 christos * file, pref, suffix, node, parent
643 1.71 christos * Contents of the corresponding fields. No copies are
644 1.71 christos * made, they are used as they are!
645 1.39 wiz *
646 1.1 cgd * Results:
647 1.71 christos * The allocated and initialized structure.
648 1.1 cgd *-----------------------------------------------------------------------
649 1.1 cgd */
650 1.71 christos static Src*
651 1.71 christos SuffNewSrc(char* file, char* pref, Suff *suffix, GNode *node, Src *parent)
652 1.1 cgd {
653 1.71 christos Src *s = bmake_malloc(sizeof(Src));
654 1.71 christos
655 1.71 christos s->file = file;
656 1.71 christos s->pref = pref;
657 1.71 christos
658 1.71 christos s->suff = suffix;
659 1.71 christos
660 1.71 christos s->parent = parent;
661 1.71 christos s->depth = 0;
662 1.71 christos if (parent != NULL)
663 1.71 christos s->depth = parent->depth + 1;
664 1.1 cgd
665 1.71 christos s->node = node;
666 1.71 christos
667 1.71 christos return s;
668 1.71 christos }
669 1.1 cgd
670 1.71 christos /*-
671 1.71 christos *-----------------------------------------------------------------------
672 1.71 christos * SuffNewTopSrc -- create a new Src for node->name, using suffix.
673 1.71 christos *-----------------------------------------------------------------------
674 1.71 christos */
675 1.71 christos static Src*
676 1.71 christos SuffNewTopSrc(GNode *node, Suff *suffix)
677 1.71 christos {
678 1.71 christos return SuffNewSrc(
679 1.71 christos bmake_strdup(node->name),
680 1.71 christos bmake_strndup(node->name, strlen(node->name) - suffix->nameLen),
681 1.71 christos suffix,
682 1.71 christos node,
683 1.71 christos NULL);
684 1.1 cgd }
685 1.1 cgd
686 1.1 cgd /*-
687 1.1 cgd *-----------------------------------------------------------------------
688 1.71 christos * SuffNewTopSrc -- create a new Src for node->name, faking suffix as "".
689 1.1 cgd *-----------------------------------------------------------------------
690 1.1 cgd */
691 1.71 christos static Src*
692 1.71 christos SuffNewTopSrcNull(GNode *node, Suff *suffix)
693 1.1 cgd {
694 1.71 christos return SuffNewSrc(
695 1.71 christos bmake_strdup(node->name),
696 1.71 christos bmake_strdup(node->name),
697 1.71 christos suffix,
698 1.71 christos node,
699 1.71 christos NULL);
700 1.1 cgd }
701 1.1 cgd
702 1.1 cgd /*-
703 1.1 cgd *-----------------------------------------------------------------------
704 1.71 christos * SuffNewChildSrc -- create a new Src for (parent->pref + suffix->name).
705 1.1 cgd *
706 1.39 wiz * Input:
707 1.71 christos * nullChild for storing the .NULL child
708 1.1 cgd *
709 1.1 cgd * Side Effects:
710 1.71 christos * If suffix == nullSuff, a possible source is created for parent->pref
711 1.71 christos * also and stored into nullChild. Otherwise nullChild is set to NULL.
712 1.1 cgd *-----------------------------------------------------------------------
713 1.1 cgd */
714 1.71 christos static Src*
715 1.71 christos SuffNewChildSrc(Src *parent, Suff *suffix, Src **nullChild)
716 1.39 wiz {
717 1.71 christos if (suffix == nullSuff)
718 1.71 christos *nullChild = SuffNewSrc(
719 1.71 christos bmake_strdup(parent->pref),
720 1.71 christos parent->pref,
721 1.71 christos suffix,
722 1.71 christos NULL,
723 1.71 christos parent);
724 1.71 christos else
725 1.71 christos *nullChild = NULL;
726 1.71 christos
727 1.71 christos return SuffNewSrc(
728 1.71 christos str_concat(parent->pref, suffix->name, 0),
729 1.71 christos parent->pref,
730 1.71 christos suffix,
731 1.71 christos NULL,
732 1.71 christos parent);
733 1.1 cgd }
734 1.1 cgd
735 1.71 christos /*
736 1.1 cgd *-----------------------------------------------------------------------
737 1.71 christos * SuffFreeSrc -- release resources held by an Src structure.
738 1.1 cgd *
739 1.71 christos * There are no other resources than memory, which is free'd. The signature
740 1.71 christos * is chosen so as to be able to call this from Lst_Destroy().
741 1.1 cgd *
742 1.39 wiz * Input:
743 1.71 christos * sp the struct to free
744 1.1 cgd *-----------------------------------------------------------------------
745 1.1 cgd */
746 1.71 christos static void
747 1.71 christos SuffFreeSrc(void *sp)
748 1.1 cgd {
749 1.71 christos Src *s = (Src *)sp;
750 1.1 cgd
751 1.71 christos free(s->file);
752 1.71 christos if (s->parent == NULL)
753 1.71 christos free(s->pref);
754 1.71 christos free(s);
755 1.1 cgd }
756 1.1 cgd
757 1.1 cgd /*-
758 1.1 cgd *-----------------------------------------------------------------------
759 1.71 christos * SuffLinkSuffixes -- relate two suffixes.
760 1.1 cgd *
761 1.71 christos * Makes "from" aware that "to" is a possible target and "to" aware that
762 1.71 christos * "from" is a possible source. Proper .SUFFIXES ordering is maintained.
763 1.39 wiz *
764 1.71 christos * Pre-condition:
765 1.71 christos * The suffixes are not already linked.
766 1.1 cgd *
767 1.71 christos * Input:
768 1.71 christos * from source file suffix
769 1.71 christos * to target file suffix
770 1.1 cgd *-----------------------------------------------------------------------
771 1.1 cgd */
772 1.71 christos static void
773 1.71 christos SuffLinkSuffixes(Suff *from, Suff *to)
774 1.1 cgd {
775 1.71 christos SuffDebug("Defining a transformation from `%s' to `%s'.\n",
776 1.71 christos from->name, to->name);
777 1.1 cgd
778 1.71 christos SuffInsertIntoList(to, from->parents);
779 1.71 christos SuffInsertIntoList(from, to->children);
780 1.71 christos }
781 1.1 cgd
782 1.71 christos /*-
783 1.71 christos *-----------------------------------------------------------------------
784 1.71 christos * SuffUnlinkSuffixes -- undo what SuffLinkSuffixes() did.
785 1.71 christos *-----------------------------------------------------------------------
786 1.71 christos */
787 1.71 christos static int
788 1.71 christos SuffUnlinkSuffixes(void *f, void *t)
789 1.71 christos {
790 1.71 christos Suff *from = (Suff *)f;
791 1.71 christos Suff *to = (Suff *)t;
792 1.1 cgd
793 1.71 christos SuffDebug("Undefining a transformation from `%s' to `%s'.\n",
794 1.71 christos from->name, to->name);
795 1.1 cgd
796 1.71 christos SuffRemoveFromList(to, from->parents);
797 1.71 christos SuffRemoveFromList(from, to->children);
798 1.71 christos /* The suffixes are still in sufflist, refCount must be > 0. */
799 1.71 christos assert(to->refCount > 0);
800 1.71 christos assert(from->refCount > 0);
801 1.1 cgd
802 1.71 christos return 0;
803 1.1 cgd }
804 1.1 cgd
805 1.1 cgd /*-
806 1.1 cgd *-----------------------------------------------------------------------
807 1.71 christos * SuffSetSuffix -- set a new suffix for node.
808 1.71 christos *
809 1.71 christos * The old suffix, if any, is removed by calling Suff_UnsetSuffix().
810 1.1 cgd *
811 1.39 wiz * Input:
812 1.71 christos * node node to set the suffix for
813 1.71 christos * suffix new suffix for the node
814 1.1 cgd *
815 1.1 cgd * Side Effects:
816 1.71 christos * OP_LIB is set / unset on node if SUFF_LIBRARY is set / unset on
817 1.71 christos * suffix.
818 1.1 cgd *-----------------------------------------------------------------------
819 1.1 cgd */
820 1.71 christos static void
821 1.71 christos SuffSetSuffix(GNode *node, Suff *suffix)
822 1.1 cgd {
823 1.71 christos Suff_UnsetSuffix(node);
824 1.20 christos
825 1.71 christos node->suffix = suffix;
826 1.1 cgd
827 1.71 christos if (suffix != NULL) {
828 1.71 christos suffix->refCount++;
829 1.71 christos if (suffix->flags & SUFF_LIBRARY)
830 1.71 christos node->type |= OP_LIB;
831 1.1 cgd }
832 1.1 cgd }
833 1.1 cgd
834 1.1 cgd /*-
835 1.1 cgd *-----------------------------------------------------------------------
836 1.71 christos * Suff_UnsetSuffix -- remove the current suffix of a node.
837 1.1 cgd *
838 1.39 wiz * Input:
839 1.71 christos * node Node whose suffix is to be cleared.
840 1.1 cgd *
841 1.1 cgd * Side Effects:
842 1.71 christos * OP_LIB is cleared from node if it was set. The library status
843 1.71 christos * of nodes stems from their suffixes, so it can't be a library
844 1.71 christos * if it has no suffix.
845 1.1 cgd *-----------------------------------------------------------------------
846 1.1 cgd */
847 1.71 christos static void
848 1.71 christos Suff_UnsetSuffix(GNode *node)
849 1.6 jtc {
850 1.71 christos if (node->suffix != NULL) {
851 1.71 christos --node->suffix->refCount;
852 1.71 christos /* Suffix is still in sufflist, so refCount must be > 0 */
853 1.71 christos assert(node->suffix->refCount > 0);
854 1.1 cgd
855 1.71 christos node->type &= ~OP_LIB;
856 1.71 christos node->suffix = NULL;
857 1.1 cgd }
858 1.71 christos }
859 1.71 christos
860 1.71 christos /*-
861 1.71 christos *-----------------------------------------------------------------------
862 1.71 christos * SuffAddToList -- add a suffix to a suffix list.
863 1.71 christos *
864 1.71 christos * Input:
865 1.71 christos * suffix suffix to add
866 1.71 christos * list list to receive the suffix
867 1.71 christos * succ The intended successor of the suffix in the list.
868 1.71 christos * NULL means no successor, i.e. append.
869 1.71 christos *-----------------------------------------------------------------------
870 1.71 christos */
871 1.71 christos static void
872 1.71 christos SuffAddToList(Suff *suffix, Lst list, LstNode succ)
873 1.71 christos {
874 1.71 christos if (list != sufflist)
875 1.71 christos SuffDebug("\t`%s'(%d) ", suffix->name, suffix->sNum);
876 1.71 christos
877 1.71 christos if (succ == NULL) {
878 1.71 christos (void)Lst_AtEnd(list, suffix);
879 1.71 christos if (list != sufflist)
880 1.71 christos SuffDebug("inserted at the end of the list.\n");
881 1.71 christos } else {
882 1.71 christos Suff *s = (Suff *)Lst_Datum(succ);
883 1.71 christos (void)Lst_InsertBefore(list, succ, suffix);
884 1.71 christos if (list != sufflist)
885 1.71 christos SuffDebug("inserted before `%s'(%d).\n", s->name, s->sNum);
886 1.71 christos }
887 1.71 christos ++suffix->refCount;
888 1.71 christos
889 1.71 christos #ifdef DEBUG_SRC
890 1.71 christos (void)Lst_AtEnd(suffix->ref, list);
891 1.71 christos #endif
892 1.71 christos }
893 1.71 christos
894 1.71 christos /*-
895 1.71 christos *-----------------------------------------------------------------------
896 1.71 christos * SuffRemoveFromList -- remove a suffix from a suffix list.
897 1.71 christos *
898 1.71 christos * The reference count of the suffix might be zero afterwards. It is
899 1.71 christos * the responsibility of the caller to handle this.
900 1.71 christos *
901 1.71 christos * Input:
902 1.71 christos * suffix suffix to remove
903 1.71 christos * list list to remove the suffix from
904 1.71 christos *-----------------------------------------------------------------------
905 1.71 christos */
906 1.71 christos static void
907 1.71 christos SuffRemoveFromList(Suff *suffix, Lst list)
908 1.71 christos {
909 1.71 christos if (Lst_Remove(list, Lst_Member(list, suffix)) == SUCCESS) {
910 1.71 christos suffix->refCount--;
911 1.71 christos
912 1.71 christos #ifdef DEBUG_SRC
913 1.71 christos Lst_Remove(suffix->ref, Lst_Member(suffix->ref, list));
914 1.71 christos #endif
915 1.71 christos }
916 1.71 christos }
917 1.71 christos
918 1.71 christos /*-
919 1.71 christos *-----------------------------------------------------------------------
920 1.71 christos * SuffInsertIntoList -- insert a suffix into its proper place in a list.
921 1.71 christos *
922 1.71 christos * The suffixes in the list are kept ordered by suffix numbers (sNum).
923 1.71 christos *
924 1.71 christos * Pre-condition:
925 1.71 christos * suffix is not already in the list.
926 1.71 christos *
927 1.71 christos * Input:
928 1.71 christos * suffix suffix to add
929 1.71 christos * list list to receive the suffix
930 1.71 christos *-----------------------------------------------------------------------
931 1.71 christos */
932 1.71 christos static void
933 1.71 christos SuffInsertIntoList(Suff *suffix, Lst list)
934 1.71 christos {
935 1.71 christos LstNode successor;
936 1.71 christos
937 1.71 christos successor = Lst_Find(list, suffix, SuffSuffHasPriorityLEP);
938 1.71 christos
939 1.71 christos if (successor == NULL || ((Suff *)Lst_Datum(successor)) != suffix)
940 1.71 christos SuffAddToList(suffix, list, successor);
941 1.71 christos else
942 1.71 christos /*
943 1.71 christos * This function is only used by SuffLinkSuffixes(), which in turn
944 1.71 christos * should only be called to link previously unlinked suffixes.
945 1.71 christos */
946 1.71 christos Punt("Internal error: tried to insert duplicate suffix `%s'(%d) "
947 1.71 christos "into a list.\n", suffix->name, suffix->sNum);
948 1.71 christos }
949 1.71 christos
950 1.71 christos /*
951 1.71 christos *-----------------------------------------------------------------------
952 1.71 christos * SuffUnsetOpTransform -- clear the OP_TRANSFORM flag from a target.
953 1.71 christos *
954 1.71 christos * Input:
955 1.71 christos * target The target node whose type is modified. (GNode *)
956 1.71 christos *
957 1.71 christos * Side Effects:
958 1.71 christos * The suffix of the node is unset.
959 1.71 christos *-----------------------------------------------------------------------
960 1.71 christos */
961 1.71 christos static void
962 1.71 christos SuffUnsetOpTransform(void *tp)
963 1.71 christos {
964 1.71 christos GNode *target = (GNode *)tp;
965 1.71 christos Suff_UnsetSuffix(target);
966 1.71 christos target->type &= ~OP_TRANSFORM;
967 1.71 christos }
968 1.71 christos
969 1.71 christos /*
970 1.71 christos *-----------------------------------------------------------------------
971 1.71 christos * SuffUnlinkChildren -- SuffUnlinkSuffixes(child, suffix) with all chidren.
972 1.71 christos *
973 1.71 christos * Calling this function for all suffixes undoes all links between suffixes
974 1.71 christos * and this is what Suff_ClearSuffixes() uses it for.
975 1.71 christos *
976 1.71 christos * Input:
977 1.71 christos * suff undo links to children for this suffix (Suff *)
978 1.71 christos *-----------------------------------------------------------------------
979 1.71 christos */
980 1.71 christos static int
981 1.71 christos SuffUnlinkChildren(void *suff, void *unused)
982 1.71 christos {
983 1.71 christos Suff *suffix = (Suff *)suff;
984 1.71 christos (void)unused;
985 1.71 christos Lst_ForEach(suffix->children, SuffUnlinkSuffixes, suffix);
986 1.71 christos
987 1.71 christos return 0;
988 1.71 christos }
989 1.71 christos
990 1.71 christos /*
991 1.71 christos *-----------------------------------------------------------------------
992 1.71 christos * SuffFreeSuffSufflist -- frontend to SuffFreeSuff() for destroying sufflist.
993 1.71 christos *
994 1.71 christos * Reduce the reference count of the suffix by one because it is
995 1.71 christos * no longer in sufflist, preventing SuffFreeSuff() from throwing a fit.
996 1.71 christos *
997 1.71 christos * Input:
998 1.71 christos * suff suffix to free
999 1.71 christos *-----------------------------------------------------------------------
1000 1.71 christos */
1001 1.71 christos static void
1002 1.71 christos SuffFreeSuffSufflist(void *suff)
1003 1.71 christos {
1004 1.71 christos Suff *suffix = (Suff *)suff;
1005 1.71 christos --suffix->refCount;
1006 1.71 christos SuffFreeSuff(suffix);
1007 1.71 christos }
1008 1.71 christos
1009 1.71 christos /*
1010 1.71 christos *-----------------------------------------------------------------------
1011 1.71 christos * SuffCleanUp -- uninitialize the module.
1012 1.71 christos *
1013 1.71 christos * Clears OP_TRANSFORM from transformation rules and deletes all suffixes.
1014 1.71 christos *
1015 1.71 christos * This is a separate function instead of being built in to Suff_End()
1016 1.71 christos * because coincidentally this exact same functionality is needed
1017 1.71 christos * by Suff_ClearSuffixes().
1018 1.71 christos *
1019 1.71 christos * Input:
1020 1.71 christos * flags tweak behavior
1021 1.71 christos * SCU_CLEAR
1022 1.71 christos * regular behavior
1023 1.71 christos * SCU_END
1024 1.71 christos * do not clear transforms, they've been deleted
1025 1.71 christos * already by Targ_End()
1026 1.71 christos *-----------------------------------------------------------------------
1027 1.71 christos */
1028 1.71 christos static void
1029 1.71 christos SuffCleanUp(int flags)
1030 1.71 christos {
1031 1.71 christos /*
1032 1.71 christos * Undo all references between the suffixes before deleting them
1033 1.71 christos * so SuffFreeSuff() can catch any bugs we might have with reference
1034 1.71 christos * counting.
1035 1.71 christos */
1036 1.71 christos
1037 1.71 christos Lst_Destroy(transforms,
1038 1.71 christos ((flags & SCU_CLEAR) ? SuffUnsetOpTransform : NULL));
1039 1.71 christos
1040 1.71 christos if (nullSuff != NULL) {
1041 1.71 christos --nullSuff->refCount;
1042 1.71 christos nullSuff = NULL;
1043 1.71 christos }
1044 1.71 christos
1045 1.71 christos SuffUnlinkChildren(emptySuff, NULL);
1046 1.71 christos --emptySuff->refCount;
1047 1.71 christos SuffFreeSuff(emptySuff);
1048 1.71 christos
1049 1.71 christos Lst_ForEach(sufflist, SuffUnlinkChildren, NULL);
1050 1.71 christos Lst_Destroy(sufflist, SuffFreeSuffSufflist);
1051 1.71 christos }
1052 1.71 christos
1053 1.71 christos
1054 1.71 christos /*
1055 1.71 christos ******************************************************************************
1056 1.71 christos * Parsing Helpers
1057 1.71 christos ******************************************************************************
1058 1.71 christos */
1059 1.71 christos
1060 1.71 christos /*-
1061 1.71 christos *-----------------------------------------------------------------------
1062 1.71 christos * Suff_ClearSuffixes -- remove all known suffixes.
1063 1.71 christos *
1064 1.71 christos * Effectively, the module is re-initialized.
1065 1.71 christos *
1066 1.71 christos * Side Effects:
1067 1.71 christos * All OP_TRANSFORM nodes in the graph are reset to regular nodes.
1068 1.71 christos *-----------------------------------------------------------------------
1069 1.71 christos */
1070 1.71 christos void
1071 1.71 christos Suff_ClearSuffixes(void)
1072 1.71 christos {
1073 1.71 christos SuffCleanUp(SCU_CLEAR);
1074 1.71 christos Suff_Init();
1075 1.71 christos }
1076 1.71 christos
1077 1.71 christos /*-
1078 1.71 christos *-----------------------------------------------------------------------
1079 1.71 christos * SuffParseTransform -- get component suffixes from transformation name.
1080 1.71 christos *
1081 1.71 christos * Double suffix rules are preferred over single suffix ones (i.e.
1082 1.71 christos * transformations to the empty suffix). This only matters if any suffix
1083 1.71 christos * is a catenation of two others: if .tar.gz, .tar, and .gz are known, then
1084 1.71 christos * ".tar.gz" is double suffix transformation from .tar to .gz, not a single
1085 1.71 christos * suffix one from .tar.gz.
1086 1.71 christos *
1087 1.71 christos * Input:
1088 1.71 christos * name transformation name
1089 1.71 christos * sourceSuff place to store the source suffix
1090 1.71 christos * targetSuff place to store the target suffix
1091 1.71 christos *
1092 1.71 christos * Results:
1093 1.71 christos * TRUE if the string is a valid transformation and FALSE otherwise.
1094 1.71 christos *
1095 1.71 christos * Side Effects:
1096 1.71 christos * The passed pointers are overwritten: by the actual suffixes when
1097 1.71 christos * TRUE is returned, with NULLs otherwise.
1098 1.71 christos *
1099 1.71 christos *-----------------------------------------------------------------------
1100 1.71 christos */
1101 1.71 christos static Boolean
1102 1.71 christos SuffParseTransform(char *name, Suff **sourceSuff, Suff **targetSuff)
1103 1.71 christos {
1104 1.71 christos LstNode s; /* sufflist iterator for source */
1105 1.71 christos Suff *from, *to; /* source and target suffixes */
1106 1.71 christos Suff *single; /* the suffix that matches the whole name */
1107 1.71 christos
1108 1.71 christos s = NULL;
1109 1.71 christos from = to = single = NULL;
1110 1.71 christos
1111 1.71 christos /* Don't bother with obviously invalid names. */
1112 1.71 christos if (!lookup[(unsigned char)name[0]])
1113 1.71 christos goto end;
1114 1.71 christos
1115 1.71 christos /*
1116 1.71 christos * Is it a double suffix transformation? For each suffix that matches
1117 1.71 christos * the start of the name, see if another one matches the rest of it.
1118 1.71 christos * The first valid pair is chosen. The first suffix that matches
1119 1.71 christos * the whole name is remembered, so the suffixes need not to be checked
1120 1.71 christos * again for a single suffix transformation. from and to stay as
1121 1.71 christos * NULLs if no valid transformation is found.
1122 1.71 christos */
1123 1.71 christos for (s = Lst_Find(sufflist, name, SuffSuffIsPrefixP); s != NULL;
1124 1.71 christos s = Lst_FindFrom(sufflist, Lst_Succ(s), name, SuffSuffIsPrefixP))
1125 1.71 christos {
1126 1.71 christos from = (Suff *)Lst_Datum(s);
1127 1.71 christos char *targetName = name + from->nameLen;
1128 1.71 christos
1129 1.71 christos if (*targetName == '\0') {
1130 1.71 christos single = from;
1131 1.71 christos } else {
1132 1.71 christos LstNode t = Lst_Find(sufflist, targetName, SuffSuffHasNameP);
1133 1.71 christos if (t != NULL) {
1134 1.71 christos to = (Suff *)Lst_Datum(t);
1135 1.71 christos break;
1136 1.71 christos }
1137 1.71 christos }
1138 1.71 christos from = NULL;
1139 1.71 christos }
1140 1.71 christos
1141 1.71 christos /* Use the full match for a single if it wasn't a double. */
1142 1.71 christos if (from == NULL && single != NULL) {
1143 1.71 christos from = single;
1144 1.71 christos to = emptySuff;
1145 1.71 christos }
1146 1.71 christos
1147 1.71 christos end:
1148 1.71 christos if (sourceSuff != NULL && targetSuff != NULL) {
1149 1.71 christos *sourceSuff = from;
1150 1.71 christos *targetSuff = to;
1151 1.71 christos }
1152 1.71 christos
1153 1.71 christos return from != NULL;
1154 1.71 christos }
1155 1.71 christos
1156 1.71 christos /*-
1157 1.71 christos *-----------------------------------------------------------------------
1158 1.71 christos * Suff_IsTransform -- check if the given string is a transformation rule.
1159 1.71 christos *
1160 1.71 christos * Figuring out if the name is a transformation requires us to find
1161 1.71 christos * the suffixes which would make up the transformation. The same
1162 1.71 christos * information will be calculated if Suff_AddTransform() is then called
1163 1.71 christos * with the same name. The information from this call can be cached by
1164 1.71 christos * providing non-NULL values for fromCache and toCache and passing all
1165 1.71 christos * the same parameters to Suff_AddTransform() if this function returns
1166 1.71 christos * true..
1167 1.71 christos *
1168 1.71 christos * Input:
1169 1.71 christos * str string to check
1170 1.71 christos * fromCache opaque cache pointer
1171 1.71 christos * toCache opaque cache pointer
1172 1.71 christos *
1173 1.71 christos * Results:
1174 1.71 christos * TRUE if the string is a catenation of two known suffixes or
1175 1.71 christos * matches one suffix exactly, FALSE otherwise
1176 1.71 christos *-----------------------------------------------------------------------
1177 1.71 christos */
1178 1.71 christos Boolean
1179 1.71 christos Suff_IsTransform(char *str, void **fromCache, void **toCache)
1180 1.71 christos {
1181 1.71 christos return SuffParseTransform(str, (Suff **)fromCache, (Suff **)toCache);
1182 1.71 christos }
1183 1.71 christos
1184 1.71 christos /*-
1185 1.71 christos *-----------------------------------------------------------------------
1186 1.71 christos * Suff_AddTransform -- record the transformation defined by name.
1187 1.71 christos *
1188 1.71 christos * A node is created into the graph to store the transformation, if one
1189 1.71 christos * does not already exist.
1190 1.71 christos *
1191 1.71 christos * Pre-condition:
1192 1.71 christos * If src and targ are non-NULL, they must have been parameters
1193 1.71 christos * of a call to Suff_IsTransform() that returned true for the same
1194 1.71 christos * set of parameters.
1195 1.71 christos *
1196 1.71 christos * Input:
1197 1.71 christos * name name of new transformation
1198 1.71 christos * fromCache opaque cache pointer
1199 1.71 christos * toCache opaque cache pointer
1200 1.71 christos *
1201 1.71 christos * Results:
1202 1.71 christos * The node of the transformation.
1203 1.71 christos *-----------------------------------------------------------------------
1204 1.71 christos */
1205 1.71 christos GNode *
1206 1.71 christos Suff_AddTransform(char *name, void **fromCache, void **toCache)
1207 1.71 christos {
1208 1.71 christos GNode *node;
1209 1.71 christos Suff *from, *to;
1210 1.71 christos if (fromCache != NULL && toCache != NULL) {
1211 1.71 christos from = (Suff *)*fromCache;
1212 1.71 christos to = (Suff *)*toCache;
1213 1.71 christos } else
1214 1.71 christos from = to = NULL;
1215 1.71 christos
1216 1.71 christos node = Targ_FindNode(name, TARG_CREATE);
1217 1.71 christos
1218 1.71 christos if ((from != NULL || SuffParseTransform(name, &from, &to))
1219 1.71 christos && !(node->type & OP_TRANSFORM))
1220 1.71 christos {
1221 1.71 christos node->type |= OP_TRANSFORM;
1222 1.71 christos Lst_AtEnd(transforms, node);
1223 1.71 christos SuffSetSuffix(node, to);
1224 1.71 christos
1225 1.71 christos /* Pre-cond: this did not exist before, can't be linked yet. */
1226 1.71 christos SuffLinkSuffixes(from, to);
1227 1.71 christos }
1228 1.71 christos
1229 1.71 christos return node;
1230 1.71 christos }
1231 1.71 christos
1232 1.71 christos /*-
1233 1.71 christos *-----------------------------------------------------------------------
1234 1.71 christos * Suff_EndTransform --
1235 1.71 christos * Handle the finish of a transformation definition, removing the
1236 1.71 christos * transformation from the graph if it has neither commands nor
1237 1.71 christos * sources. This is a callback procedure for the Parse module via
1238 1.71 christos * Lst_ForEach
1239 1.71 christos *
1240 1.71 christos * Input:
1241 1.71 christos * gnp Node for transformation
1242 1.71 christos *
1243 1.71 christos * Results:
1244 1.71 christos * === 0
1245 1.71 christos *
1246 1.71 christos * Side Effects:
1247 1.71 christos * If the node has no commands or children, the children and parents
1248 1.71 christos * lists of the affected suffixes are altered.
1249 1.71 christos *
1250 1.71 christos *-----------------------------------------------------------------------
1251 1.71 christos */
1252 1.71 christos int
1253 1.71 christos Suff_EndTransform(void *gnp, void *unused)
1254 1.71 christos {
1255 1.71 christos GNode *gn = (GNode *)gnp;
1256 1.71 christos
1257 1.71 christos (void)unused;
1258 1.71 christos
1259 1.71 christos if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts))
1260 1.71 christos gn = (GNode *)Lst_Datum(Lst_Last(gn->cohorts));
1261 1.71 christos if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(gn->commands) &&
1262 1.71 christos Lst_IsEmpty(gn->children))
1263 1.71 christos {
1264 1.71 christos /* So it is an empty target. */
1265 1.71 christos Suff *s, *t;
1266 1.71 christos
1267 1.71 christos /* But is it a transformation? (.DEFAULT is also OP_TRANSFORM) */
1268 1.71 christos if (SuffParseTransform(gn->name, &s, &t)) {
1269 1.71 christos SuffDebug("Deleting a transformation with no commands.\n");
1270 1.71 christos SuffUnlinkSuffixes(s, t);
1271 1.71 christos gn->type |= ~OP_TRANSFORM;
1272 1.71 christos }
1273 1.71 christos } else if ((gn->type & OP_TRANSFORM))
1274 1.71 christos SuffDebug("Transformation %s completed.\n", gn->name);
1275 1.71 christos
1276 1.71 christos return 0;
1277 1.1 cgd }
1278 1.1 cgd
1279 1.1 cgd /*-
1280 1.1 cgd *-----------------------------------------------------------------------
1281 1.14 christos * SuffScanTargets --
1282 1.14 christos * Called from Suff_AddSuffix via Lst_ForEach to search through the
1283 1.71 christos * list of existing targets for necessary changes.
1284 1.71 christos *
1285 1.71 christos * Any target that was not already a transformation and according to
1286 1.71 christos * SuffParseTransform() now is, is made into one. Existing
1287 1.71 christos * single suffix transformations, that are now valid two suffix ones,
1288 1.71 christos * are converted. There's no change in double prefix rules.
1289 1.71 christos * The single suffix conversion could not happen if we were to accept
1290 1.71 christos * only POSIX suffixes, but we accept everything.
1291 1.71 christos *
1292 1.71 christos * What is so special about single suffix transformations? Consider
1293 1.71 christos * the case in which suffixes s1, s2, ..., and sN are given. Then
1294 1.71 christos * any double prefix rule is sXsY such that sX is the first suffix
1295 1.71 christos * in the list for which the remainder sY is also in the list.
1296 1.71 christos * Thus X and Y are both at most N. No matter what suffix we add
1297 1.71 christos * to the list, X and Y cannot change.
1298 1.71 christos *
1299 1.71 christos * For a single suffix rule the case is different. Given suffixes
1300 1.71 christos * .a.b and .a, the transformation ".a.b" is a single prefix rule.
1301 1.71 christos * We always give precedence for double prefix rules, so when
1302 1.71 christos * .b is added as a suffix, the transformation should now be
1303 1.71 christos * a double suffix rule .a -> .b.
1304 1.71 christos *
1305 1.71 christos * Input:
1306 1.71 christos * targetNode Current target to check.
1307 1.71 christos * newSuffix The newly added suffix.
1308 1.14 christos *
1309 1.14 christos * Results:
1310 1.71 christos * Always 0, so Lst_ForEach() won't stop prematurely.
1311 1.14 christos *
1312 1.14 christos * Side Effects:
1313 1.14 christos *
1314 1.14 christos *-----------------------------------------------------------------------
1315 1.14 christos */
1316 1.14 christos static int
1317 1.71 christos SuffScanTargets(void *targetGNode, void *newSuffix)
1318 1.14 christos {
1319 1.71 christos GNode *target = (GNode *)targetGNode;
1320 1.71 christos Suff *from, *to;
1321 1.71 christos Suff *suffix = (Suff *)newSuffix;
1322 1.71 christos
1323 1.71 christos from = to = NULL;
1324 1.71 christos
1325 1.71 christos /* Reject obviously irrelevant targets. */
1326 1.71 christos if (!(lookup[(unsigned char)target->name[0]]
1327 1.71 christos && strstr(target->name, suffix->name) != NULL))
1328 1.71 christos {
1329 1.71 christos goto out;
1330 1.71 christos }
1331 1.71 christos
1332 1.71 christos if (SuffParseTransform(target->name, &from, &to)) {
1333 1.71 christos if (target->type & OP_TRANSFORM) {
1334 1.71 christos if (target->suffix == emptySuff && to != emptySuff)
1335 1.71 christos SuffUnlinkSuffixes(from, to); /* single to double */
1336 1.71 christos else
1337 1.71 christos from = to = NULL; /* still a single, or was double */
1338 1.71 christos } else
1339 1.71 christos target->type |= OP_TRANSFORM; /* regular to transformation */
1340 1.71 christos
1341 1.71 christos if (from != NULL && to != NULL) {
1342 1.71 christos /* Pre-cond: new double or completely new, can't be linked yet. */
1343 1.71 christos SuffLinkSuffixes(from, to);
1344 1.71 christos Lst_AtEnd(transforms, target);
1345 1.71 christos }
1346 1.14 christos }
1347 1.71 christos
1348 1.71 christos out:
1349 1.14 christos return 0;
1350 1.14 christos }
1351 1.14 christos
1352 1.14 christos /*-
1353 1.14 christos *-----------------------------------------------------------------------
1354 1.1 cgd * Suff_AddSuffix --
1355 1.71 christos * Add the named suffix to the end of the list of known suffixes.
1356 1.71 christos * Existing targets are checked to see if any of them becomes
1357 1.71 christos * a transformation.
1358 1.71 christos *
1359 1.71 christos * If the suffix is already in the list of known suffixes, nothing
1360 1.71 christos * is done.
1361 1.71 christos *
1362 1.71 christos * After this function is called, the target list should be re-scanned
1363 1.71 christos * in case the current main target was made into a transformation rule.
1364 1.1 cgd *
1365 1.39 wiz * Input:
1366 1.71 christos * name the name of the suffix to add
1367 1.39 wiz *
1368 1.1 cgd * Results:
1369 1.71 christos * TRUE if a new suffix was added, FALSE otherwise.
1370 1.1 cgd *
1371 1.1 cgd * Side Effects:
1372 1.1 cgd * A GNode is created for the suffix and a Suff structure is created and
1373 1.71 christos * appended to the suffixes list unless the suffix was already known.
1374 1.1 cgd *-----------------------------------------------------------------------
1375 1.1 cgd */
1376 1.1 cgd void
1377 1.71 christos Suff_AddSuffix(char *name)
1378 1.1 cgd {
1379 1.71 christos Suff *s; /* New one for adding */
1380 1.71 christos LstNode old;
1381 1.71 christos
1382 1.71 christos old = Lst_Find(sufflist, name, SuffSuffHasNameP);
1383 1.71 christos if (old == NULL) {
1384 1.71 christos s = SuffNewSuff(name);
1385 1.71 christos SuffAddToList(s, sufflist, NULL);
1386 1.71 christos
1387 1.71 christos lookup[(unsigned char)s->name[0]] = 1;
1388 1.1 cgd
1389 1.71 christos Lst_ForEach(Targ_List(), SuffScanTargets, s);
1390 1.13 christos }
1391 1.1 cgd }
1392 1.1 cgd
1393 1.1 cgd /*-
1394 1.1 cgd *-----------------------------------------------------------------------
1395 1.1 cgd * Suff_GetPath --
1396 1.1 cgd * Return the search path for the given suffix, if it's defined.
1397 1.1 cgd *
1398 1.1 cgd * Results:
1399 1.65 dsl * The searchPath for the desired suffix or NULL if the suffix isn't
1400 1.1 cgd * defined.
1401 1.1 cgd *
1402 1.1 cgd * Side Effects:
1403 1.1 cgd * None
1404 1.1 cgd *-----------------------------------------------------------------------
1405 1.1 cgd */
1406 1.1 cgd Lst
1407 1.39 wiz Suff_GetPath(char *sname)
1408 1.1 cgd {
1409 1.1 cgd LstNode ln;
1410 1.1 cgd Suff *s;
1411 1.1 cgd
1412 1.59 dsl ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
1413 1.71 christos if (ln != NULL)
1414 1.49 christos s = (Suff *)Lst_Datum(ln);
1415 1.71 christos
1416 1.71 christos return (ln == NULL ? NULL : s->searchPath);
1417 1.1 cgd }
1418 1.1 cgd
1419 1.1 cgd /*-
1420 1.1 cgd *-----------------------------------------------------------------------
1421 1.1 cgd * Suff_DoPaths --
1422 1.1 cgd * Extend the search paths for all suffixes to include the default
1423 1.1 cgd * search path.
1424 1.1 cgd *
1425 1.1 cgd * Results:
1426 1.1 cgd * None.
1427 1.1 cgd *
1428 1.1 cgd * Side Effects:
1429 1.1 cgd * The searchPath field of all the suffixes is extended by the
1430 1.1 cgd * directories in dirSearchPath. If paths were specified for the
1431 1.1 cgd * ".h" suffix, the directories are stuffed into a global variable
1432 1.34 wiz * called ".INCLUDES" with each directory preceded by a -I. The same
1433 1.1 cgd * is done for the ".a" suffix, except the variable is called
1434 1.1 cgd * ".LIBS" and the flag is -L.
1435 1.1 cgd *-----------------------------------------------------------------------
1436 1.1 cgd */
1437 1.1 cgd void
1438 1.39 wiz Suff_DoPaths(void)
1439 1.1 cgd {
1440 1.39 wiz Suff *s;
1441 1.39 wiz LstNode ln;
1442 1.6 jtc char *ptr;
1443 1.1 cgd Lst inIncludes; /* Cumulative .INCLUDES path */
1444 1.1 cgd Lst inLibs; /* Cumulative .LIBS path */
1445 1.1 cgd
1446 1.48 christos if (Lst_Open(sufflist) == FAILURE) {
1447 1.1 cgd return;
1448 1.1 cgd }
1449 1.1 cgd
1450 1.1 cgd inIncludes = Lst_Init(FALSE);
1451 1.1 cgd inLibs = Lst_Init(FALSE);
1452 1.1 cgd
1453 1.65 dsl while ((ln = Lst_Next(sufflist)) != NULL) {
1454 1.49 christos s = (Suff *)Lst_Datum(ln);
1455 1.1 cgd if (!Lst_IsEmpty (s->searchPath)) {
1456 1.1 cgd #ifdef INCLUDES
1457 1.1 cgd if (s->flags & SUFF_INCLUDE) {
1458 1.1 cgd Dir_Concat(inIncludes, s->searchPath);
1459 1.1 cgd }
1460 1.1 cgd #endif /* INCLUDES */
1461 1.1 cgd #ifdef LIBRARIES
1462 1.1 cgd if (s->flags & SUFF_LIBRARY) {
1463 1.1 cgd Dir_Concat(inLibs, s->searchPath);
1464 1.1 cgd }
1465 1.1 cgd #endif /* LIBRARIES */
1466 1.1 cgd Dir_Concat(s->searchPath, dirSearchPath);
1467 1.1 cgd } else {
1468 1.48 christos Lst_Destroy(s->searchPath, Dir_Destroy);
1469 1.1 cgd s->searchPath = Lst_Duplicate(dirSearchPath, Dir_CopyDir);
1470 1.1 cgd }
1471 1.1 cgd }
1472 1.1 cgd
1473 1.33 sjg Var_Set(".INCLUDES", ptr = Dir_MakeFlags("-I", inIncludes), VAR_GLOBAL, 0);
1474 1.6 jtc free(ptr);
1475 1.33 sjg Var_Set(".LIBS", ptr = Dir_MakeFlags("-L", inLibs), VAR_GLOBAL, 0);
1476 1.6 jtc free(ptr);
1477 1.1 cgd
1478 1.1 cgd Lst_Destroy(inIncludes, Dir_Destroy);
1479 1.1 cgd Lst_Destroy(inLibs, Dir_Destroy);
1480 1.1 cgd
1481 1.48 christos Lst_Close(sufflist);
1482 1.1 cgd }
1483 1.1 cgd
1484 1.1 cgd /*-
1485 1.1 cgd *-----------------------------------------------------------------------
1486 1.1 cgd * Suff_AddInclude --
1487 1.1 cgd * Add the given suffix as a type of file which gets included.
1488 1.1 cgd * Called from the parse module when a .INCLUDES line is parsed.
1489 1.1 cgd * The suffix must have already been defined.
1490 1.1 cgd *
1491 1.39 wiz * Input:
1492 1.39 wiz * sname Name of the suffix to mark
1493 1.39 wiz *
1494 1.1 cgd * Results:
1495 1.1 cgd * None.
1496 1.1 cgd *
1497 1.1 cgd * Side Effects:
1498 1.1 cgd * The SUFF_INCLUDE bit is set in the suffix's flags field
1499 1.1 cgd *
1500 1.1 cgd *-----------------------------------------------------------------------
1501 1.1 cgd */
1502 1.1 cgd void
1503 1.39 wiz Suff_AddInclude(char *sname)
1504 1.1 cgd {
1505 1.1 cgd LstNode ln;
1506 1.1 cgd Suff *s;
1507 1.1 cgd
1508 1.59 dsl ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
1509 1.65 dsl if (ln != NULL) {
1510 1.49 christos s = (Suff *)Lst_Datum(ln);
1511 1.1 cgd s->flags |= SUFF_INCLUDE;
1512 1.1 cgd }
1513 1.1 cgd }
1514 1.1 cgd
1515 1.1 cgd /*-
1516 1.1 cgd *-----------------------------------------------------------------------
1517 1.1 cgd * Suff_AddLib --
1518 1.1 cgd * Add the given suffix as a type of file which is a library.
1519 1.1 cgd * Called from the parse module when parsing a .LIBS line. The
1520 1.1 cgd * suffix must have been defined via .SUFFIXES before this is
1521 1.1 cgd * called.
1522 1.1 cgd *
1523 1.39 wiz * Input:
1524 1.39 wiz * sname Name of the suffix to mark
1525 1.39 wiz *
1526 1.1 cgd * Results:
1527 1.1 cgd * None.
1528 1.1 cgd *
1529 1.1 cgd * Side Effects:
1530 1.1 cgd * The SUFF_LIBRARY bit is set in the suffix's flags field
1531 1.1 cgd *
1532 1.1 cgd *-----------------------------------------------------------------------
1533 1.1 cgd */
1534 1.1 cgd void
1535 1.39 wiz Suff_AddLib(char *sname)
1536 1.1 cgd {
1537 1.1 cgd LstNode ln;
1538 1.1 cgd Suff *s;
1539 1.1 cgd
1540 1.59 dsl ln = Lst_Find(sufflist, sname, SuffSuffHasNameP);
1541 1.65 dsl if (ln != NULL) {
1542 1.49 christos s = (Suff *)Lst_Datum(ln);
1543 1.1 cgd s->flags |= SUFF_LIBRARY;
1544 1.1 cgd }
1545 1.1 cgd }
1546 1.1 cgd
1547 1.71 christos
1548 1.71 christos /*
1549 1.71 christos ******************************************************************************
1550 1.71 christos * Implicit Source Search Functions
1551 1.71 christos ******************************************************************************
1552 1.71 christos */
1553 1.1 cgd
1554 1.1 cgd /*-
1555 1.1 cgd *-----------------------------------------------------------------------
1556 1.71 christos * SuffAddSrc -- add transformation possibility.
1557 1.71 christos *
1558 1.71 christos * Create an Src structure describing a transformation from a file with
1559 1.71 christos * the given suffix to the given target (target.from -> target.to).
1560 1.71 christos * If the suffix happens to be the .NULL suffix, create a transformation
1561 1.71 christos * from target's prefix also (target -> target.to).
1562 1.71 christos *
1563 1.71 christos * This is callback function for Lst_ForEach().
1564 1.1 cgd *
1565 1.39 wiz * Input:
1566 1.71 christos * suffix the source's suffix
1567 1.71 christos * arguments more arguments: target, transformations not yet tried,
1568 1.71 christos * cleanup list.
1569 1.39 wiz *
1570 1.1 cgd * Results:
1571 1.71 christos * Always return 0 to prevent Lst_ForEach() from exiting prematurely.
1572 1.1 cgd *-----------------------------------------------------------------------
1573 1.1 cgd */
1574 1.1 cgd static int
1575 1.71 christos SuffAddSrc(void *suffix, void *arguments)
1576 1.1 cgd {
1577 1.71 christos Suff *fromSuffix;
1578 1.71 christos LstSrc *args;
1579 1.71 christos Src *from, *nullChild, *to;
1580 1.1 cgd
1581 1.71 christos fromSuffix = (Suff *)suffix;
1582 1.71 christos args = (LstSrc *)arguments;
1583 1.71 christos to = args->target;
1584 1.13 christos
1585 1.71 christos /*
1586 1.71 christos * Don't add a transformation that is already in the chain or we
1587 1.71 christos * might get stuck in an infinite loop.
1588 1.71 christos */
1589 1.71 christos for (to = args->target; to != NULL; to = to->parent) {
1590 1.71 christos if (to->suff == fromSuffix) {
1591 1.71 christos SuffDebug("\t%*.s%s%s: ignored (already tried in this chain)\n",
1592 1.71 christos args->target->depth + 1, " ", to->pref, fromSuffix->name);
1593 1.71 christos goto end;
1594 1.71 christos }
1595 1.1 cgd }
1596 1.71 christos to = args->target;
1597 1.71 christos
1598 1.71 christos from = SuffNewChildSrc(to, fromSuffix, &nullChild);
1599 1.6 jtc #ifdef DEBUG_SRC
1600 1.71 christos fprintf(debug_file, "1 add %x %x to %x:", to, from, args->possible);
1601 1.71 christos if (nullChild != NULL)
1602 1.71 christos fprintf(debug_file, "2 add %x %x to %x:", to, nullChild,
1603 1.71 christos args->possible);
1604 1.71 christos Lst_ForEach(args->possible, PrintAddr, NULL);
1605 1.55 dsl fprintf(debug_file, "\n");
1606 1.6 jtc #endif
1607 1.71 christos Lst_AtEnd(args->possible, from);
1608 1.71 christos Lst_AtEnd(args->cleanup, from);
1609 1.71 christos if (nullChild != NULL) {
1610 1.71 christos Lst_AtEnd(args->possible, nullChild);
1611 1.71 christos Lst_AtEnd(args->cleanup, nullChild);
1612 1.71 christos }
1613 1.1 cgd
1614 1.71 christos end:
1615 1.71 christos return 0;
1616 1.1 cgd }
1617 1.1 cgd
1618 1.1 cgd /*-
1619 1.1 cgd *-----------------------------------------------------------------------
1620 1.71 christos * SuffAddLevelForSuffix -- get possible transformations to target node.
1621 1.1 cgd *
1622 1.71 christos * A new top level Src structure (parent == NULL) is created for target
1623 1.71 christos * using the provided suffix. Then Src structures describing all
1624 1.71 christos * the possible ways to create the target node are appended into the list
1625 1.71 christos * possible. If the target node has multiple known suffixes, this function
1626 1.71 christos * should be called for each suffix separately to get all the possible ways
1627 1.71 christos * to create the node.
1628 1.71 christos *
1629 1.71 christos * The top level Src and the possible transformations are added into
1630 1.71 christos * cleanup.
1631 1.71 christos *
1632 1.71 christos * Input:
1633 1.71 christos * suffix target node's suffix
1634 1.71 christos * possible list to add the possible transformations into
1635 1.71 christos * (data: Src *)
1636 1.71 christos * end desired transformation target
1637 1.71 christos * cleanup list of all Srcs for eventual cleanup (data: Src *)
1638 1.1 cgd *-----------------------------------------------------------------------
1639 1.1 cgd */
1640 1.1 cgd static void
1641 1.71 christos SuffAddLevelForSuffix(Suff *suffix, Lst possible, GNode *end, Lst cleanup)
1642 1.1 cgd {
1643 1.71 christos Src *s;
1644 1.71 christos if (suffix != NULL) {
1645 1.71 christos if (suffix->flags & SUFF_NULL)
1646 1.71 christos /* Only set when "remove a suffix" aspect of .NULL is used. */
1647 1.71 christos s = SuffNewTopSrcNull(end, suffix);
1648 1.71 christos else
1649 1.71 christos s = SuffNewTopSrc(end, suffix);
1650 1.71 christos Lst_AtEnd(cleanup, s);
1651 1.1 cgd
1652 1.71 christos SuffAddLevel(possible, s, cleanup);
1653 1.71 christos }
1654 1.1 cgd }
1655 1.1 cgd
1656 1.1 cgd /*-
1657 1.71 christos *-----------------------------------------------------------------------
1658 1.71 christos * SuffAddLevel -- get possible transformations to target Src.
1659 1.71 christos *
1660 1.71 christos * Src structures describing all the possible ways to create target are
1661 1.71 christos * appended into the list possible.
1662 1.1 cgd *
1663 1.71 christos * The possible transformations are also added into cleanup.
1664 1.1 cgd *
1665 1.71 christos * Input:
1666 1.71 christos * possible list to add the possible transformations to
1667 1.71 christos * (data: Src *)
1668 1.71 christos * target desired transformation target
1669 1.71 christos * cleanup list of all Srcs for eventual clean-up (data: Src *)
1670 1.71 christos *-----------------------------------------------------------------------
1671 1.1 cgd */
1672 1.71 christos static void
1673 1.71 christos SuffAddLevel(Lst possible, Src *target, Lst cleanup) {
1674 1.71 christos LstSrc ls;
1675 1.6 jtc
1676 1.71 christos ls.target = target;
1677 1.71 christos ls.possible = possible;
1678 1.71 christos ls.cleanup = cleanup;
1679 1.6 jtc
1680 1.71 christos Lst_ForEach(target->suff->children, SuffAddSrc, &ls);
1681 1.1 cgd }
1682 1.1 cgd
1683 1.1 cgd /*-
1684 1.1 cgd *-----------------------------------------------------------------------
1685 1.71 christos * SuffFindThem -- find a transformation chain from a list of possibilities.
1686 1.71 christos *
1687 1.71 christos * A valid transformation chain is one which starts from an existing
1688 1.71 christos * target node or file and can be converted into the desired target by
1689 1.71 christos * repeated application of transformation rules. If any such chain
1690 1.71 christos * can be found, this function will return the one which is the shortest.
1691 1.71 christos * If there are multiple equally short chains, the steps required are
1692 1.71 christos * compared, starting from the /last/ one, and on the first differing
1693 1.71 christos * step the one whose target suffix occurs first in .SUFFIXES is chosen.
1694 1.1 cgd *
1695 1.39 wiz * Input:
1696 1.71 christos * possible all possible last steps in the transformation,
1697 1.71 christos * in the proper .SUFFIXES order
1698 1.71 christos * chain (data: Src *)
1699 1.71 christos * cleanup list of all Srcs for eventual clean-up (data: Src *)
1700 1.39 wiz *
1701 1.1 cgd * Results:
1702 1.71 christos * The starting point of the shortest, highest priority transformation
1703 1.71 christos * chain. Taking the node described by the returned value and
1704 1.71 christos * applying to it the transformations defined by the parent pointers
1705 1.71 christos * will result in the initially desired target.
1706 1.1 cgd *
1707 1.71 christos * If no chain terminates at an existing target or file, NULL is
1708 1.71 christos * returned.
1709 1.1 cgd *-----------------------------------------------------------------------
1710 1.1 cgd */
1711 1.1 cgd static Src *
1712 1.71 christos SuffFindThem(Lst possible, Lst cleanup)
1713 1.1 cgd {
1714 1.71 christos Src *i, *result, *parent;
1715 1.72 christos char *tf;
1716 1.1 cgd
1717 1.71 christos result = NULL;
1718 1.71 christos /*
1719 1.71 christos * Parent of the current candidate. When it changes, debug print
1720 1.71 christos * the chain of transformations so far.
1721 1.71 christos */
1722 1.71 christos parent = NULL;
1723 1.1 cgd
1724 1.71 christos /*
1725 1.71 christos * You've been lied to. There wont be any step priority comparisons.
1726 1.71 christos * Because the list initially contains the possible transformations
1727 1.71 christos * in the correct order, the first existing one is the correct result.
1728 1.71 christos * Each possible transformation is removed from the front of the list
1729 1.71 christos * as it is checked and if it does not exist, all the ways to create
1730 1.71 christos * it are appended to the list. This way the one step longer chains
1731 1.71 christos * are also in the correct priority order and the item at the front
1732 1.71 christos * of the list is always the correct result, should it exist. It is
1733 1.71 christos * then easy to keep popping the list until the result is found or all
1734 1.71 christos * possibilities are exhausted.
1735 1.71 christos */
1736 1.71 christos while ((i = (Src *)Lst_DeQueue(possible)) != NULL) {
1737 1.72 christos GNode *n;
1738 1.71 christos if (parent != i->parent) {
1739 1.71 christos SuffDebugChain(i->parent);
1740 1.71 christos parent = i->parent;
1741 1.1 cgd }
1742 1.71 christos SuffDebug ("\t%*.s%s: ", i->depth, " ", i->file);
1743 1.6 jtc
1744 1.1 cgd /*
1745 1.71 christos * XXX: should only targets with commands be accepted? The node
1746 1.71 christos * exists even if it only has had extra dependencies added.
1747 1.1 cgd */
1748 1.72 christos if ((n = Targ_FindNode(i->file, TARG_NOCREATE)) != NULL) {
1749 1.6 jtc #ifdef DEBUG_SRC
1750 1.71 christos fprintf(debug_file, "remove %x from %x\n", i, possible);
1751 1.6 jtc #endif
1752 1.72 christos SuffDebug(": Node %s %x: ", i->file, n->type);
1753 1.72 christos if ((n->type & OP_INVISIBLE) == 0) {
1754 1.72 christos result = i;
1755 1.72 christos break;
1756 1.72 christos }
1757 1.72 christos } else if ((tf = Dir_FindFile(i->file, i->suff->searchPath)) != NULL) {
1758 1.71 christos result = i;
1759 1.6 jtc #ifdef DEBUG_SRC
1760 1.71 christos fprintf(debug_file, "remove %x from %x\n", i, possible);
1761 1.6 jtc #endif
1762 1.72 christos SuffDebug(": File %s %s: ", i->file, tf);
1763 1.72 christos free(tf);
1764 1.1 cgd break;
1765 1.1 cgd }
1766 1.6 jtc
1767 1.71 christos SuffDebug("not there.\n");
1768 1.6 jtc
1769 1.71 christos SuffAddLevel(possible, i, cleanup);
1770 1.6 jtc }
1771 1.6 jtc
1772 1.71 christos if (result)
1773 1.71 christos SuffDebug("got it.\n");
1774 1.71 christos
1775 1.71 christos return result;
1776 1.1 cgd }
1777 1.1 cgd
1778 1.1 cgd /*-
1779 1.1 cgd *-----------------------------------------------------------------------
1780 1.71 christos * SuffExpandChildren -- call SuffExpandChild() on node's children.
1781 1.1 cgd *
1782 1.39 wiz * Input:
1783 1.71 christos * parent parent node
1784 1.71 christos * first child to start from
1785 1.1 cgd *-----------------------------------------------------------------------
1786 1.1 cgd */
1787 1.71 christos static void
1788 1.71 christos SuffExpandChildren(GNode *parent, LstNode first)
1789 1.1 cgd {
1790 1.71 christos LstNode i, next;
1791 1.1 cgd
1792 1.43 dsl /*
1793 1.71 christos * SuffExpandChild() replaces the curren node with the expanded values,
1794 1.71 christos * so we won't try to expand the already expanded values
1795 1.71 christos */
1796 1.71 christos for (i = first; i != NULL; i = next) {
1797 1.71 christos /* SuffExpandChild() might remove i, so get the successor now. */
1798 1.71 christos next = Lst_Succ(i);
1799 1.71 christos SuffExpandChild(i, parent);
1800 1.1 cgd }
1801 1.1 cgd }
1802 1.1 cgd
1803 1.1 cgd /*-
1804 1.1 cgd *-----------------------------------------------------------------------
1805 1.71 christos * SuffExpandChild -- expand variables and wildcards in a child name.
1806 1.71 christos *
1807 1.71 christos * Expand variables and wildcards in a child's name and replace the child
1808 1.71 christos * with the results if an expansion happened. This means that when
1809 1.71 christos * expansion occurred, cln will point to free'd memory!
1810 1.1 cgd *
1811 1.39 wiz * Input:
1812 1.71 christos * cln child to expand.
1813 1.71 christos * pgn parent node being processed
1814 1.39 wiz *
1815 1.1 cgd * Results:
1816 1.1 cgd * === 0 (continue)
1817 1.1 cgd *-----------------------------------------------------------------------
1818 1.1 cgd */
1819 1.56 dsl static void
1820 1.71 christos SuffExpandChild(LstNode cln, GNode *pgn)
1821 1.1 cgd {
1822 1.56 dsl GNode *cgn = (GNode *)Lst_Datum(cln);
1823 1.71 christos GNode *gn; /* helper for adding expanded nodes */
1824 1.71 christos char *expanded; /* expanded child name */
1825 1.71 christos char *cp; /* current position in expanded value */
1826 1.1 cgd
1827 1.61 dsl if (!Lst_IsEmpty(cgn->order_pred) || !Lst_IsEmpty(cgn->order_succ))
1828 1.61 dsl /* It is all too hard to process the result of .ORDER */
1829 1.61 dsl return;
1830 1.61 dsl
1831 1.61 dsl if (cgn->type & OP_WAIT)
1832 1.61 dsl /* Ignore these (& OP_PHONY ?) */
1833 1.61 dsl return;
1834 1.61 dsl
1835 1.1 cgd /*
1836 1.1 cgd * First do variable expansion -- this takes precedence over
1837 1.1 cgd * wildcard expansion. If the result contains wildcards, they'll be gotten
1838 1.1 cgd * to later since the resulting words are tacked on to the end of
1839 1.1 cgd * the children list.
1840 1.1 cgd */
1841 1.56 dsl if (strchr(cgn->name, '$') == NULL) {
1842 1.56 dsl SuffExpandWildcards(cln, pgn);
1843 1.56 dsl return;
1844 1.56 dsl }
1845 1.56 dsl
1846 1.71 christos SuffDebug("\tVariable expanding dependency `%s'\n", cgn->name);
1847 1.71 christos cp = expanded = Var_Subst(NULL, cgn->name, pgn, TRUE);
1848 1.1 cgd
1849 1.56 dsl if (cp != NULL) {
1850 1.56 dsl Lst members = Lst_Init(FALSE);
1851 1.13 christos
1852 1.56 dsl if (cgn->type & OP_ARCHV) {
1853 1.56 dsl /*
1854 1.56 dsl * Node was an archive(member) target, so we want to call
1855 1.56 dsl * on the Arch module to find the nodes for us, expanding
1856 1.56 dsl * variables in the parent's context.
1857 1.56 dsl */
1858 1.56 dsl char *sacrifice = cp;
1859 1.1 cgd
1860 1.56 dsl (void)Arch_ParseArchive(&sacrifice, members, pgn);
1861 1.56 dsl } else {
1862 1.56 dsl /*
1863 1.56 dsl * Break the result into a vector of strings whose nodes
1864 1.56 dsl * we can find, then add those nodes to the members list.
1865 1.56 dsl * Unfortunately, we can't use brk_string b/c it
1866 1.56 dsl * doesn't understand about variable specifications with
1867 1.56 dsl * spaces in them...
1868 1.71 christos * XXX: what variable specs?! I thought we already expanded
1869 1.71 christos * all of the variables and there shouldn't be any variable
1870 1.71 christos * expansion stages left before the name is used as target!
1871 1.56 dsl */
1872 1.56 dsl char *start;
1873 1.1 cgd
1874 1.56 dsl for (start = cp; *start == ' ' || *start == '\t'; start++)
1875 1.56 dsl continue;
1876 1.56 dsl for (cp = start; *cp != '\0'; cp++) {
1877 1.56 dsl if (*cp == ' ' || *cp == '\t') {
1878 1.56 dsl /*
1879 1.56 dsl * White-space -- terminate element, find the node,
1880 1.56 dsl * add it, skip any further spaces.
1881 1.56 dsl */
1882 1.56 dsl *cp++ = '\0';
1883 1.56 dsl gn = Targ_FindNode(start, TARG_CREATE);
1884 1.59 dsl (void)Lst_AtEnd(members, gn);
1885 1.56 dsl while (*cp == ' ' || *cp == '\t') {
1886 1.1 cgd cp++;
1887 1.1 cgd }
1888 1.56 dsl /*
1889 1.56 dsl * Adjust cp for increment at start of loop, but
1890 1.56 dsl * set start to first non-space.
1891 1.56 dsl */
1892 1.56 dsl start = cp--;
1893 1.56 dsl } else if (*cp == '$') {
1894 1.56 dsl /*
1895 1.56 dsl * Start of a variable spec -- contact variable module
1896 1.56 dsl * to find the end so we can skip over it.
1897 1.56 dsl */
1898 1.56 dsl char *junk;
1899 1.63 christos int len;
1900 1.56 dsl void *freeIt;
1901 1.56 dsl
1902 1.56 dsl junk = Var_Parse(cp, pgn, TRUE, &len, &freeIt);
1903 1.56 dsl if (junk != var_Error) {
1904 1.56 dsl cp += len - 1;
1905 1.56 dsl }
1906 1.1 cgd
1907 1.56 dsl if (freeIt)
1908 1.56 dsl free(freeIt);
1909 1.56 dsl } else if (*cp == '\\' && *cp != '\0') {
1910 1.1 cgd /*
1911 1.56 dsl * Escaped something -- skip over it
1912 1.1 cgd */
1913 1.56 dsl cp++;
1914 1.1 cgd }
1915 1.56 dsl }
1916 1.56 dsl
1917 1.56 dsl if (cp != start) {
1918 1.1 cgd /*
1919 1.56 dsl * Stuff left over -- add it to the list too
1920 1.1 cgd */
1921 1.56 dsl gn = Targ_FindNode(start, TARG_CREATE);
1922 1.59 dsl (void)Lst_AtEnd(members, gn);
1923 1.1 cgd }
1924 1.56 dsl }
1925 1.1 cgd
1926 1.1 cgd /*
1927 1.56 dsl * Add all elements of the members list to the parent node.
1928 1.1 cgd */
1929 1.56 dsl while(!Lst_IsEmpty(members)) {
1930 1.56 dsl gn = (GNode *)Lst_DeQueue(members);
1931 1.56 dsl
1932 1.71 christos SuffDebug("\t\t%s\n", gn->name);
1933 1.56 dsl /* Add gn to the parents child list before the original child */
1934 1.59 dsl (void)Lst_InsertBefore(pgn->children, cln, gn);
1935 1.71 christos if ((GNode *)Lst_Datum(pgn->first_local_child) == cgn)
1936 1.71 christos pgn->first_local_child = Lst_Prev(cln);
1937 1.59 dsl (void)Lst_AtEnd(gn->parents, pgn);
1938 1.56 dsl pgn->unmade++;
1939 1.56 dsl /* Expand wildcards on new node */
1940 1.57 dsl SuffExpandWildcards(Lst_Prev(cln), pgn);
1941 1.1 cgd }
1942 1.65 dsl Lst_Destroy(members, NULL);
1943 1.1 cgd
1944 1.71 christos free(expanded);
1945 1.71 christos expanded = NULL;
1946 1.56 dsl }
1947 1.1 cgd
1948 1.56 dsl /*
1949 1.56 dsl * Now the source is expanded, remove it from the list of children to
1950 1.56 dsl * keep it from being processed.
1951 1.56 dsl */
1952 1.56 dsl pgn->unmade--;
1953 1.56 dsl Lst_Remove(pgn->children, cln);
1954 1.56 dsl Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn));
1955 1.56 dsl }
1956 1.56 dsl
1957 1.56 dsl static void
1958 1.56 dsl SuffExpandWildcards(LstNode cln, GNode *pgn)
1959 1.56 dsl {
1960 1.56 dsl GNode *cgn = (GNode *)Lst_Datum(cln);
1961 1.56 dsl GNode *gn; /* New source 8) */
1962 1.56 dsl char *cp; /* Expanded value */
1963 1.56 dsl Lst explist; /* List of expansions */
1964 1.1 cgd
1965 1.56 dsl if (!Dir_HasWildcards(cgn->name))
1966 1.56 dsl return;
1967 1.1 cgd
1968 1.56 dsl /*
1969 1.56 dsl * Expand the word along the chosen path
1970 1.56 dsl */
1971 1.71 christos SuffDebug("\tWildcard expanding dependency `%s'\n", cgn->name);
1972 1.56 dsl explist = Lst_Init(FALSE);
1973 1.56 dsl Dir_Expand(cgn->name, Suff_FindPath(cgn), explist);
1974 1.1 cgd
1975 1.56 dsl while (!Lst_IsEmpty(explist)) {
1976 1.1 cgd /*
1977 1.56 dsl * Fetch next expansion off the list and find its GNode
1978 1.1 cgd */
1979 1.56 dsl cp = (char *)Lst_DeQueue(explist);
1980 1.13 christos
1981 1.71 christos SuffDebug("\t\t%s\n", cp);
1982 1.56 dsl gn = Targ_FindNode(cp, TARG_CREATE);
1983 1.56 dsl
1984 1.56 dsl /* Add gn to the parents child list before the original child */
1985 1.59 dsl (void)Lst_InsertBefore(pgn->children, cln, gn);
1986 1.71 christos if ((GNode *)Lst_Datum(pgn->first_local_child) == cgn)
1987 1.71 christos pgn->first_local_child = Lst_Prev(cln);
1988 1.59 dsl (void)Lst_AtEnd(gn->parents, pgn);
1989 1.56 dsl pgn->unmade++;
1990 1.1 cgd }
1991 1.1 cgd
1992 1.56 dsl /*
1993 1.56 dsl * Nuke what's left of the list
1994 1.56 dsl */
1995 1.65 dsl Lst_Destroy(explist, NULL);
1996 1.56 dsl
1997 1.56 dsl /*
1998 1.56 dsl * Now the source is expanded, remove it from the list of children to
1999 1.56 dsl * keep it from being processed.
2000 1.56 dsl */
2001 1.56 dsl pgn->unmade--;
2002 1.56 dsl Lst_Remove(pgn->children, cln);
2003 1.56 dsl Lst_Remove(cgn->parents, Lst_Member(cgn->parents, pgn));
2004 1.1 cgd }
2005 1.1 cgd
2006 1.47 christos /*-
2007 1.47 christos *-----------------------------------------------------------------------
2008 1.47 christos * Suff_FindPath --
2009 1.47 christos * Find a path along which to expand the node.
2010 1.47 christos *
2011 1.47 christos * If the word has a known suffix, use that path.
2012 1.47 christos * If it has no known suffix, use the default system search path.
2013 1.47 christos *
2014 1.47 christos * Input:
2015 1.47 christos * gn Node being examined
2016 1.47 christos *
2017 1.47 christos * Results:
2018 1.47 christos * The appropriate path to search for the GNode.
2019 1.47 christos *
2020 1.47 christos * Side Effects:
2021 1.47 christos * XXX: We could set the suffix here so that we don't have to scan
2022 1.47 christos * again.
2023 1.46 christos *
2024 1.47 christos *-----------------------------------------------------------------------
2025 1.46 christos */
2026 1.46 christos Lst
2027 1.46 christos Suff_FindPath(GNode* gn)
2028 1.46 christos {
2029 1.46 christos Suff *suff = gn->suffix;
2030 1.46 christos
2031 1.46 christos if (suff == NULL) {
2032 1.46 christos SuffixCmpData sd; /* Search string data */
2033 1.46 christos LstNode ln;
2034 1.46 christos sd.len = strlen(gn->name);
2035 1.46 christos sd.ename = gn->name + sd.len;
2036 1.59 dsl ln = Lst_Find(sufflist, &sd, SuffSuffIsSuffixP);
2037 1.46 christos
2038 1.65 dsl if (ln != NULL)
2039 1.46 christos suff = (Suff *)Lst_Datum(ln);
2040 1.46 christos /* XXX: Here we can save the suffix so we don't have to do this again */
2041 1.46 christos }
2042 1.46 christos
2043 1.71 christos if (suff != NULL)
2044 1.46 christos return suff->searchPath;
2045 1.71 christos else
2046 1.46 christos return dirSearchPath;
2047 1.71 christos }
2048 1.71 christos
2049 1.71 christos
2050 1.71 christos /*-
2051 1.71 christos *-----------------------------------------------------------------------
2052 1.71 christos * SuffApplyTransformations -- apply a transformation chain.
2053 1.71 christos *
2054 1.71 christos * Apply transformations beginning at start, until the node end is
2055 1.71 christos * reached. A node is created for each intermediate target, if one does
2056 1.71 christos * not already exist and the relevant suffixes are set on the nodes.
2057 1.71 christos *
2058 1.71 christos * Each target except for the start and end of the chain gets TARGET
2059 1.71 christos * and PREFIX set and their children expanded. The start of the chain
2060 1.71 christos * cannot be expanded as it could turn out to be the result of another
2061 1.71 christos * transformation chain and have a different suffix as a part of that
2062 1.71 christos * chain. The end of the chain cannot be expanded because the node's
2063 1.71 christos * name might be a fake one (see SuffFindArchiveDeps()).
2064 1.71 christos *
2065 1.71 christos * Input:
2066 1.71 christos * start transformation chain's starting
2067 1.71 christos * end transformation chain's end, i.e. the node for which we were
2068 1.71 christos * initially looking dependencies for
2069 1.71 christos *
2070 1.71 christos * Results:
2071 1.71 christos * The suffix that was set on end.
2072 1.71 christos *-----------------------------------------------------------------------
2073 1.71 christos */
2074 1.71 christos static Suff *
2075 1.71 christos SuffApplyTransformations(Src *start, GNode *end)
2076 1.71 christos {
2077 1.71 christos Src *target, *source;
2078 1.71 christos
2079 1.71 christos if (start->node == NULL)
2080 1.71 christos start->node = Targ_FindNode(start->file, TARG_CREATE);
2081 1.71 christos
2082 1.71 christos for (source = start; source->parent != NULL; source = source->parent) {
2083 1.71 christos target = source->parent;
2084 1.71 christos
2085 1.71 christos SuffSetSuffix(source->node, source->suff);
2086 1.71 christos
2087 1.71 christos if (target->node == NULL)
2088 1.71 christos target->node = Targ_FindNode(target->file, TARG_CREATE);
2089 1.71 christos
2090 1.71 christos if (target->node != end) {
2091 1.71 christos /*
2092 1.71 christos * Dependency search for intermediate targets is finished:
2093 1.71 christos * if they had dependencies to check, they would have
2094 1.71 christos * a target or an existing file and therefore wouldn't be
2095 1.71 christos * intermediate targets.
2096 1.71 christos */
2097 1.71 christos target->node->type |= OP_DEPS_FOUND;
2098 1.71 christos Var_Set(TARGET, target->node->name, target->node, 0);
2099 1.71 christos Var_Set(PREFIX, target->pref, target->node, 0);
2100 1.71 christos }
2101 1.71 christos
2102 1.71 christos SuffApplyTransformation(target->node, source->node,
2103 1.71 christos target->suff, source->suff,
2104 1.71 christos (target->node == end ? SAT_NO_EXPAND : SAT_REGULAR));
2105 1.46 christos }
2106 1.71 christos
2107 1.71 christos SuffSetSuffix(end, source->suff);
2108 1.71 christos
2109 1.71 christos return end->suffix;
2110 1.46 christos }
2111 1.46 christos
2112 1.1 cgd /*-
2113 1.1 cgd *-----------------------------------------------------------------------
2114 1.71 christos * SuffApplyTransformation -- apply a transformation from source to target.
2115 1.1 cgd *
2116 1.39 wiz * Input:
2117 1.71 christos * tGn Target node
2118 1.71 christos * sGn Source node
2119 1.71 christos * t Target suffix
2120 1.71 christos * s Source suffix
2121 1.71 christos * flags Request modifications for standard behavior.
2122 1.71 christos * SAT_REGULAR:
2123 1.71 christos * Normal behavior.
2124 1.71 christos * SAT_NO_EXPAND:
2125 1.71 christos * Do not expand children.
2126 1.39 wiz *
2127 1.1 cgd * Results:
2128 1.1 cgd * TRUE if successful, FALSE if not.
2129 1.1 cgd *
2130 1.1 cgd * Side Effects:
2131 1.1 cgd * The source and target are linked and the commands from the
2132 1.1 cgd * transformation are added to the target node's commands list.
2133 1.1 cgd * All attributes but OP_DEPMASK and OP_TRANSFORM are applied
2134 1.1 cgd * to the target. The target also inherits all the sources for
2135 1.1 cgd * the transformation rule.
2136 1.1 cgd *
2137 1.1 cgd *-----------------------------------------------------------------------
2138 1.1 cgd */
2139 1.1 cgd static Boolean
2140 1.71 christos SuffApplyTransformation(GNode *tGn, GNode *sGn, Suff *t, Suff *s, int flags)
2141 1.1 cgd {
2142 1.71 christos LstNode ln; /* General node */
2143 1.1 cgd char *tname; /* Name of transformation rule */
2144 1.1 cgd GNode *gn; /* Node for same */
2145 1.1 cgd
2146 1.31 mycroft /*
2147 1.31 mycroft * Form the proper links between the target and source.
2148 1.31 mycroft */
2149 1.59 dsl (void)Lst_AtEnd(tGn->children, sGn);
2150 1.59 dsl (void)Lst_AtEnd(sGn->parents, tGn);
2151 1.31 mycroft tGn->unmade += 1;
2152 1.1 cgd
2153 1.1 cgd /*
2154 1.1 cgd * Locate the transformation rule itself
2155 1.1 cgd */
2156 1.1 cgd tname = str_concat(s->name, t->name, 0);
2157 1.59 dsl ln = Lst_Find(transforms, tname, SuffGNHasNameP);
2158 1.1 cgd free(tname);
2159 1.1 cgd
2160 1.1 cgd gn = (GNode *)Lst_Datum(ln);
2161 1.13 christos
2162 1.71 christos SuffDebug("\tApplying `%s' -> `%s' to `%s'\n", s->name, t->name,
2163 1.71 christos tGn->name);
2164 1.1 cgd
2165 1.71 christos /* Record last child so only the new children get expanded. */
2166 1.1 cgd ln = Lst_Last(tGn->children);
2167 1.13 christos
2168 1.1 cgd /*
2169 1.1 cgd * Pass the buck to Make_HandleUse to apply the rule
2170 1.1 cgd */
2171 1.1 cgd (void)Make_HandleUse(gn, tGn);
2172 1.1 cgd
2173 1.1 cgd /*
2174 1.71 christos * Deal with wildcards and variables in any acquired sources
2175 1.71 christos */
2176 1.71 christos if (!(flags & SAT_NO_EXPAND))
2177 1.71 christos SuffExpandChildren(tGn, Lst_Succ(ln));
2178 1.71 christos
2179 1.71 christos /*
2180 1.71 christos * Keep track of another parent to which this beast is transformed so
2181 1.71 christos * the .IMPSRC variable can be set correctly for the parent.
2182 1.71 christos */
2183 1.71 christos (void)Lst_AtEnd(sGn->iParents, tGn);
2184 1.71 christos
2185 1.71 christos return(TRUE);
2186 1.71 christos }
2187 1.71 christos
2188 1.71 christos
2189 1.71 christos /*-
2190 1.71 christos *-----------------------------------------------------------------------
2191 1.71 christos * SuffFirstKnownSuffix -- find the first suffix that fits name.
2192 1.71 christos *
2193 1.71 christos * Used by SuffFindArchiveDeps() and SuffFindNormalDeps() to figure
2194 1.71 christos * out suffixes for explicit rules.
2195 1.71 christos *
2196 1.71 christos * Input:
2197 1.71 christos * name The name to try the suffixes on.
2198 1.71 christos *
2199 1.71 christos * Results:
2200 1.71 christos * The first matching suffix structure or NULL if there isn't one.
2201 1.71 christos *-----------------------------------------------------------------------
2202 1.71 christos */
2203 1.71 christos static Suff*
2204 1.71 christos SuffFirstKnownSuffix(char* name)
2205 1.71 christos {
2206 1.71 christos LstNode ln;
2207 1.71 christos SuffixCmpData sd;
2208 1.1 cgd
2209 1.71 christos sd.len = strlen(name);
2210 1.71 christos sd.ename = name + sd.len;
2211 1.1 cgd
2212 1.71 christos ln = Lst_Find(sufflist, &sd, SuffSuffIsSuffixP);
2213 1.71 christos return (ln == NULL ? NULL : (Suff *)Lst_Datum(ln));
2214 1.1 cgd }
2215 1.1 cgd
2216 1.71 christos /*-
2217 1.71 christos *-----------------------------------------------------------------------
2218 1.71 christos * SuffSetPrefixLocalVar -- set .PREFIX properly on target.
2219 1.71 christos *
2220 1.71 christos * The value of the .PREFIX variable is the node's name less suffix->name.
2221 1.71 christos * Used by SuffFindArchiveDeps() and SuffFindNormalDeps().
2222 1.71 christos *
2223 1.71 christos * Input:
2224 1.71 christos * suffix The suffix structure to base the prefix on. If it is NULL,
2225 1.71 christos * the whole name is used.
2226 1.71 christos * name The name to get the prefix from, as it is not necessarily
2227 1.71 christos * the node's name.
2228 1.71 christos * node The context to set the variable in.
2229 1.71 christos *-----------------------------------------------------------------------
2230 1.71 christos */
2231 1.71 christos static void
2232 1.71 christos SuffSetPrefixLocalVar(Suff *suffix, char *name, GNode *node)
2233 1.71 christos {
2234 1.71 christos if (suffix != NULL) {
2235 1.71 christos char save, *save_pos;
2236 1.71 christos
2237 1.71 christos save_pos = name + (strlen(name) - suffix->nameLen);
2238 1.71 christos save = *save_pos;
2239 1.71 christos *save_pos = '\0';
2240 1.71 christos Var_Set(PREFIX, name, node, 0);
2241 1.71 christos *save_pos = save;
2242 1.71 christos }
2243 1.71 christos else
2244 1.71 christos Var_Set(PREFIX, name, node, 0);
2245 1.71 christos }
2246 1.1 cgd
2247 1.1 cgd /*-
2248 1.1 cgd *-----------------------------------------------------------------------
2249 1.1 cgd * SuffFindArchiveDeps --
2250 1.1 cgd * Locate dependencies for an OP_ARCHV node.
2251 1.1 cgd *
2252 1.39 wiz * Input:
2253 1.71 christos * target Node for which to locate dependencies
2254 1.71 christos * cleanup List to add all created Srcs into, so the caller can
2255 1.71 christos * destroy them.
2256 1.39 wiz *
2257 1.1 cgd * Results:
2258 1.1 cgd * None
2259 1.1 cgd *
2260 1.1 cgd * Side Effects:
2261 1.71 christos * Same as Suff_FindDeps. ARCHIVE and MEMBER variables are set as
2262 1.71 christos * well as gn->type is modified to include OP_MEMBER
2263 1.71 christos * on the relevant nodes and are so the modifications
2264 1.1 cgd *
2265 1.1 cgd *-----------------------------------------------------------------------
2266 1.1 cgd */
2267 1.1 cgd static void
2268 1.71 christos SuffFindArchiveDeps(GNode *target, Lst cleanup)
2269 1.1 cgd {
2270 1.71 christos Lst possible; /* Possible transformation starting points. */
2271 1.71 christos Src *start; /* The start of the chain of transformations that
2272 1.71 christos * results in this target being built. */
2273 1.71 christos Suff *suffix; /* Suffix of the member. */
2274 1.71 christos char *temp;
2275 1.71 christos
2276 1.71 christos char *lib, *member; /* Copies of lib and member parts, */
2277 1.71 christos char *libEnd, *memberEnd; /* their terminating NULs, and */
2278 1.71 christos size_t libLen, memberLen; /* their lengths. */
2279 1.13 christos
2280 1.71 christos possible = Lst_Init(FALSE);
2281 1.71 christos start = NULL;
2282 1.71 christos suffix = NULL;
2283 1.1 cgd
2284 1.71 christos lib = target->name;
2285 1.71 christos member = strchr(lib, '(') + 1;
2286 1.71 christos libLen = member - target->name - 1;
2287 1.71 christos memberLen = strchr(member, ')') - member;
2288 1.1 cgd
2289 1.71 christos lib = bmake_strndup(lib, libLen);
2290 1.71 christos member = bmake_strndup(member, memberLen);
2291 1.71 christos libEnd = lib + libLen;
2292 1.71 christos memberEnd = member + memberLen;
2293 1.13 christos
2294 1.1 cgd /*
2295 1.71 christos * Explicit rules always take precedence. Explicit <=> appeared as
2296 1.71 christos * a target in a rule with commands.
2297 1.1 cgd */
2298 1.71 christos if (!OP_NOP(target->type) && !Lst_IsEmpty(target->commands)) {
2299 1.71 christos SuffDebug("\tIt has an explicit rule.\n");
2300 1.1 cgd
2301 1.71 christos suffix = SuffFirstKnownSuffix(member);
2302 1.71 christos goto expand_children;
2303 1.71 christos }
2304 1.13 christos
2305 1.1 cgd /*
2306 1.71 christos * Try with POSIX semantics first, if applicable: library rules are only
2307 1.71 christos * supported for "lib(member.o)" and ".s2.a" is the transformation rule
2308 1.71 christos * from "member.s2" to "lib(member.o)", regardless of the suffix, if any,
2309 1.71 christos * "lib" might have. We pretend to be "member.a" and look for
2310 1.71 christos * transformations.
2311 1.1 cgd */
2312 1.71 christos if (memberLen > 2 && strcmp(memberEnd - 2, ".o") == 0) {
2313 1.71 christos LstNode ln;
2314 1.71 christos SuffDebug("\tTrying POSIX \".s2.a\" transformation.\n");
2315 1.6 jtc
2316 1.71 christos *(memberEnd - 1) = 'a';
2317 1.71 christos temp = target->name; target->name = member;
2318 1.71 christos ln = Lst_Find(sufflist, ".a", SuffSuffHasNameP);
2319 1.71 christos SuffAddLevelForSuffix((ln == NULL ? NULL : (Suff *)Lst_Datum(ln)),
2320 1.71 christos possible, target, cleanup);
2321 1.71 christos target->name = temp;
2322 1.71 christos *(memberEnd - 1) = 'o';
2323 1.1 cgd
2324 1.71 christos start = SuffFindThem(possible, cleanup);
2325 1.1 cgd }
2326 1.1 cgd
2327 1.1 cgd /*
2328 1.71 christos * Given lib.s2(member.s1), if a ".s1.s2" transformation exists, try
2329 1.71 christos * to find a way to make member.s1 so it could be added to lib.s2.
2330 1.71 christos * The problem is, all suffixes are accepted, not just POSIX ones
2331 1.71 christos * (\.[^./]+), so more than one may match either lib or member and
2332 1.71 christos * not all permutations are valid.
2333 1.71 christos *
2334 1.71 christos * Here are a couple of examples of what has to be taken into account.
2335 1.71 christos * Consider "lib.a.b(member.c)" in a case where "member.d" exists, and
2336 1.71 christos * with ".SUFFIXES: .b .a.b .c .d". The transformations are ".d.c" and
2337 1.71 christos * ".c.b". If one were to swap the longest suffixes and try with
2338 1.71 christos * "member.a.b", the transformation would not be found. Now consider
2339 1.71 christos * if the transformation ".d.a.b" also existed. If one were to try
2340 1.71 christos * in order each suffix of the lib against each suffix of the member
2341 1.71 christos * and take the first one that works, the chain ".d" -> ".c" -> ".b"
2342 1.71 christos * would be found but traditionally transformations choose the shortest
2343 1.71 christos * chain, which would be ".d" -> ".a.b".
2344 1.71 christos *
2345 1.71 christos * These issues mean that trying to shoehorn SuffFindNormalDeps()
2346 1.71 christos * to be useful here would be more trouble than it is worth. Gladly
2347 1.71 christos * that use would have mainly been as a frontend for SuffFindThem() and
2348 1.71 christos * SuffApplyTransformations() and things actually become cleaner if
2349 1.71 christos * they are used directly.
2350 1.71 christos *
2351 1.71 christos * Single suffix rules are not acceptable because they're usually used
2352 1.71 christos * to create executables.
2353 1.1 cgd */
2354 1.71 christos if (start == NULL) {
2355 1.71 christos /* One set for lib (l) and one for member (m). */
2356 1.71 christos LstNode l, m; /* Suffix list iterators. */
2357 1.71 christos SuffixCmpData ld, md; /* Parameters for predicates. */
2358 1.71 christos Suff *ls, *ms; /* Current suffix. */
2359 1.71 christos
2360 1.71 christos SuffDebug("\tTrying \".s1.s2\" transformation extension.\n");
2361 1.71 christos
2362 1.71 christos ld.len = libLen;
2363 1.71 christos ld.ename = libEnd;
2364 1.71 christos md.len = memberLen;
2365 1.71 christos md.ename = memberEnd;
2366 1.71 christos
2367 1.71 christos /* Get all possible transformations from member to lib. */
2368 1.71 christos for (l = Lst_Find(sufflist, &ld, SuffSuffIsSuffixP); l != NULL;
2369 1.71 christos l = Lst_FindFrom(sufflist, Lst_Succ(l), &ld, SuffSuffIsSuffixP))
2370 1.71 christos {
2371 1.71 christos ls = ((Suff *)Lst_Datum(l));
2372 1.71 christos
2373 1.71 christos for (m = Lst_Find(ls->children, &md, SuffSuffIsSuffixP);
2374 1.71 christos m != NULL;
2375 1.71 christos m = Lst_FindFrom(ls->children, Lst_Succ(m), &md,
2376 1.71 christos SuffSuffIsSuffixP))
2377 1.71 christos {
2378 1.71 christos char *fakename, save, *save_pos;
2379 1.1 cgd
2380 1.71 christos ms = (Suff *)Lst_Datum(m);
2381 1.71 christos save_pos = memberEnd - ms->nameLen;
2382 1.71 christos save = *save_pos;
2383 1.71 christos
2384 1.71 christos *save_pos = '\0';
2385 1.71 christos fakename = str_concat(member, ls->name, 0);
2386 1.71 christos *save_pos = save;
2387 1.71 christos
2388 1.71 christos temp = target->name; target->name = fakename;
2389 1.71 christos SuffAddLevelForSuffix(ms, possible, target, cleanup);
2390 1.71 christos target->name = temp;
2391 1.71 christos free(fakename);
2392 1.1 cgd }
2393 1.1 cgd }
2394 1.71 christos
2395 1.71 christos start = SuffFindThem(possible, cleanup);
2396 1.1 cgd }
2397 1.1 cgd
2398 1.71 christos if (start != NULL)
2399 1.71 christos suffix = SuffApplyTransformations(start, target);
2400 1.71 christos
2401 1.71 christos expand_children:
2402 1.1 cgd /*
2403 1.71 christos * POSIX: in a lib(member.o) and a .s2.a rule, the values for
2404 1.71 christos * the local variables are:
2405 1.71 christos * $* = member $@ = lib $? = member.s2 $% = member.o.
2406 1.71 christos * Additionally, for the .s2.a inference rule:
2407 1.71 christos * $< = member.s2
2408 1.71 christos *
2409 1.71 christos * ARCHIVE and MEMBER are used by Arch_MTime() to find the modification
2410 1.71 christos * time.
2411 1.1 cgd */
2412 1.71 christos Var_Set(ARCHIVE, lib, target, 0);
2413 1.71 christos Var_Set(MEMBER, member, target, 0);
2414 1.71 christos Var_Set(TARGET, lib, target, 0);
2415 1.71 christos
2416 1.71 christos if (suffix == NULL && memberLen > 2 && strcmp(memberEnd - 2, ".o") == 0)
2417 1.71 christos {
2418 1.71 christos /*
2419 1.71 christos * POSIX compatibility: in case ".o" was not a known suffix, force it.
2420 1.71 christos * The target is not POSIX compliant if a suffix other than ".o" was
2421 1.71 christos * already matched, so there's no need to try to force e.g. ".fo.o"
2422 1.71 christos * or "o" into ".o". (Compliant suffixes start with a period
2423 1.71 christos * and contain neither periods nor slashes.)
2424 1.71 christos */
2425 1.71 christos *(memberEnd - 2) = '\0';
2426 1.71 christos Var_Set(PREFIX, member, target, 0);
2427 1.71 christos *(memberEnd - 2) = '.';
2428 1.71 christos } else
2429 1.71 christos SuffSetPrefixLocalVar(suffix, member, target);
2430 1.1 cgd
2431 1.71 christos SuffExpandChildren(target, Lst_First(target->children));
2432 1.1 cgd
2433 1.71 christos free(lib);
2434 1.71 christos free(member);
2435 1.1 cgd }
2436 1.1 cgd
2437 1.1 cgd /*-
2438 1.1 cgd *-----------------------------------------------------------------------
2439 1.71 christos * SuffFindNormalDeps -- locate dependencies for regular targets.
2440 1.71 christos *
2441 1.71 christos * If the target does not have an explicit rule a suffix transformation
2442 1.71 christos * rule search is performed to see if it can be inferred.
2443 1.1 cgd *
2444 1.39 wiz * Input:
2445 1.71 christos * target Node for which to find sources.
2446 1.71 christos * cleanup List to add all created Srcs into, so the caller can
2447 1.71 christos * destroy them.
2448 1.39 wiz *
2449 1.1 cgd * Results:
2450 1.1 cgd * None.
2451 1.1 cgd *
2452 1.1 cgd * Side Effects:
2453 1.71 christos * Same as Suff_FindDeps.
2454 1.1 cgd *-----------------------------------------------------------------------
2455 1.1 cgd */
2456 1.71 christos
2457 1.1 cgd static void
2458 1.71 christos SuffFindNormalDeps(GNode *target, Lst cleanup)
2459 1.1 cgd {
2460 1.71 christos Lst possible; /* List of possible transformations (Src). */
2461 1.71 christos Suff *suffix; /* The suffix that applies to target. */
2462 1.71 christos Src *bottom; /* Start of found transformation chain. */
2463 1.71 christos
2464 1.71 christos possible = Lst_Init(FALSE);
2465 1.71 christos suffix = NULL;
2466 1.70 sjg bottom = NULL;
2467 1.1 cgd
2468 1.1 cgd /*
2469 1.71 christos * Explicit rules always take precedence. Explicit <=> appeared as
2470 1.71 christos * a target in a rule with commands.
2471 1.1 cgd */
2472 1.71 christos if (!OP_NOP(target->type) && !Lst_IsEmpty(target->commands)) {
2473 1.71 christos SuffDebug("\tIt has an explicit rule.\n");
2474 1.71 christos suffix = SuffFirstKnownSuffix(target->name);
2475 1.71 christos goto expand_children;
2476 1.1 cgd }
2477 1.1 cgd
2478 1.1 cgd /*
2479 1.71 christos * Try transformation rules. They're used to make files from other files,
2480 1.71 christos * so don't try them for .PHONY targets, which are not actual files.
2481 1.71 christos * All suffixes are accepted, not just POSIX ones (\.[^./]+), so more
2482 1.71 christos * than one may match. Matching ones are collected in .SUFFIXES order
2483 1.71 christos * and the one to give the shortest working chain is used for creating
2484 1.71 christos * the missing links and setting PREFIX. In the case that at least one
2485 1.71 christos * suffix matched but none resulted in a chain, use the first one to set
2486 1.71 christos * PREFIX.
2487 1.1 cgd */
2488 1.71 christos if (!(target->type & OP_PHONY)) {
2489 1.71 christos LstNode ln;
2490 1.71 christos SuffixCmpData sd;
2491 1.1 cgd
2492 1.71 christos sd.len = strlen(target->name);
2493 1.71 christos sd.ename = target->name + sd.len;
2494 1.1 cgd
2495 1.71 christos SuffDebug("\tTrying double suffix transformations.\n");
2496 1.71 christos for (ln = Lst_Find(sufflist, &sd, SuffSuffIsSuffixP); ln != NULL;
2497 1.71 christos ln = Lst_FindFrom(sufflist, Lst_Succ(ln), &sd, SuffSuffIsSuffixP))
2498 1.71 christos {
2499 1.71 christos if (suffix == NULL)
2500 1.71 christos suffix = (Suff *)Lst_Datum(ln);
2501 1.71 christos SuffAddLevelForSuffix((Suff *)Lst_Datum(ln), possible, target,
2502 1.71 christos cleanup);
2503 1.71 christos }
2504 1.71 christos
2505 1.71 christos if (suffix == NULL) {
2506 1.71 christos SuffDebug("\tNo known suffix, trying single suffix "
2507 1.71 christos "transformations.\n");
2508 1.71 christos SuffAddLevelForSuffix(emptySuff, possible, target, cleanup);
2509 1.71 christos
2510 1.71 christos if (nullSuff != NULL) {
2511 1.71 christos SuffDebug("\tTrying with .NULL too.\n");
2512 1.71 christos nullSuff->flags |= SUFF_NULL;
2513 1.71 christos SuffAddLevelForSuffix(nullSuff, possible, target, cleanup);
2514 1.71 christos nullSuff->flags &= ~SUFF_NULL;
2515 1.1 cgd }
2516 1.1 cgd }
2517 1.1 cgd
2518 1.71 christos bottom = SuffFindThem(possible, cleanup);
2519 1.1 cgd }
2520 1.1 cgd
2521 1.71 christos if (bottom != NULL) {
2522 1.71 christos suffix = SuffApplyTransformations(bottom, target);
2523 1.71 christos } else {
2524 1.71 christos /* If there's no transformation, try search paths. */
2525 1.71 christos SuffDebug("\tNo transformations, trying path search.\n");
2526 1.1 cgd
2527 1.71 christos if ((target->type & (OP_PHONY|OP_NOPATH)) == 0) {
2528 1.71 christos free(target->path);
2529 1.71 christos target->path = Dir_FindFile(target->name,
2530 1.71 christos (suffix == NULL ? dirSearchPath : suffix->searchPath));
2531 1.1 cgd }
2532 1.1 cgd }
2533 1.1 cgd
2534 1.71 christos expand_children:
2535 1.71 christos SuffSetSuffix(target, suffix);
2536 1.1 cgd
2537 1.71 christos Var_Set(TARGET, (target->path ? target->path : target->name), target, 0);
2538 1.71 christos if (bottom != NULL)
2539 1.71 christos /* Only because of nullSuff: use "" instead of the real suffix. */
2540 1.71 christos SuffSetPrefixLocalVar(NULL, bottom->pref, target);
2541 1.71 christos else
2542 1.71 christos SuffSetPrefixLocalVar(target->suffix, target->name, target);
2543 1.1 cgd
2544 1.71 christos SuffExpandChildren(target, Lst_First(target->children));
2545 1.1 cgd }
2546 1.13 christos
2547 1.13 christos
2548 1.1 cgd /*-
2549 1.1 cgd *-----------------------------------------------------------------------
2550 1.1 cgd * Suff_FindDeps --
2551 1.71 christos * Do suffix transformation rule search for the given target.
2552 1.71 christos * Explicit rules always take precedence, so the search will not be
2553 1.71 christos * done, if an explicit rule is detected.
2554 1.71 christos *
2555 1.71 christos * Input:
2556 1.71 christos * gn node to check inference rules for
2557 1.1 cgd *
2558 1.1 cgd * Results:
2559 1.1 cgd * Nothing.
2560 1.1 cgd *
2561 1.1 cgd * Side Effects:
2562 1.71 christos * Nodes may be added as dependencies to the target if implied so
2563 1.71 christos * by suffix search. Any newly created nodes are also added to
2564 1.71 christos * the graph. The implied sources are linked via their iParents
2565 1.71 christos * field to the target that uses them so the target will get its
2566 1.71 christos * IMPSRC variable filled in properly later.
2567 1.71 christos *
2568 1.71 christos * The TARGET, PREFIX, ARCHIVE and MEMBER variables get set on
2569 1.71 christos * the target and its children as needed.
2570 1.1 cgd *
2571 1.1 cgd * Notes:
2572 1.1 cgd * The path found by this target is the shortest path in the
2573 1.1 cgd * transformation graph, which may pass through non-existent targets,
2574 1.1 cgd * to an existing target. The search continues on all paths from the
2575 1.71 christos * root suffix until a file or an existing target node is found.
2576 1.71 christos * I.e. if there's a path .o -> .c -> .l -> .l,v from the root and
2577 1.71 christos * the .l,v file exists but the .c and .l files don't, the search
2578 1.71 christos * will branch out in all directions from .o and again from all
2579 1.71 christos * the nodes on the next level until the .l,v node is encountered.
2580 1.1 cgd *
2581 1.1 cgd *-----------------------------------------------------------------------
2582 1.1 cgd */
2583 1.6 jtc
2584 1.1 cgd void
2585 1.71 christos Suff_FindDeps(GNode *target)
2586 1.6 jtc {
2587 1.71 christos /*
2588 1.71 christos * Storage for all Src structures created during the search. This is
2589 1.71 christos * purely a convenience for the implementation of the helper functions.
2590 1.71 christos * This way there does not need to be logic for deciding what is safe
2591 1.71 christos * to remove and what is not. After the search is complete, they can
2592 1.71 christos * all be safely removed.
2593 1.71 christos */
2594 1.71 christos Lst cleanup = Lst_Init(FALSE);
2595 1.13 christos
2596 1.71 christos if (target->type & OP_DEPS_FOUND) {
2597 1.1 cgd /*
2598 1.1 cgd * If dependencies already found, no need to do it again...
2599 1.1 cgd */
2600 1.1 cgd return;
2601 1.1 cgd } else {
2602 1.71 christos target->type |= OP_DEPS_FOUND;
2603 1.1 cgd }
2604 1.69 sjg /*
2605 1.69 sjg * Make sure we have these set, may get revised below.
2606 1.69 sjg */
2607 1.71 christos Var_Set(TARGET, target->path ? target->path : target->name, target, 0);
2608 1.71 christos Var_Set(PREFIX, target->name, target, 0);
2609 1.70 sjg
2610 1.71 christos SuffDebug("SuffFindDeps (%s)\n", target->name);
2611 1.13 christos
2612 1.71 christos if (target->type & OP_ARCHV)
2613 1.71 christos SuffFindArchiveDeps(target, cleanup);
2614 1.71 christos else if (target->type & OP_LIB) {
2615 1.1 cgd /*
2616 1.1 cgd * If the node is a library, it is the arch module's job to find it
2617 1.1 cgd * and set the TARGET variable accordingly. We merely provide the
2618 1.1 cgd * search path, assuming all libraries end in ".a" (if the suffix
2619 1.1 cgd * hasn't been defined, there's nothing we can do for it, so we just
2620 1.1 cgd * set the TARGET variable to the node's name in order to give it a
2621 1.1 cgd * value).
2622 1.71 christos * XXX: try all suffixes with SUFF_LIBRARY set?
2623 1.1 cgd */
2624 1.1 cgd LstNode ln;
2625 1.1 cgd Suff *s;
2626 1.13 christos
2627 1.67 dsl ln = Lst_Find(sufflist, LIBSUFF, SuffSuffHasNameP);
2628 1.71 christos s = (ln == NULL ? NULL : (Suff *)Lst_Datum(ln));
2629 1.71 christos SuffSetSuffix(target, s);
2630 1.71 christos if (s != NULL)
2631 1.71 christos Arch_FindLib(target, s->searchPath);
2632 1.71 christos else
2633 1.71 christos Var_Set(TARGET, target->name, target, 0);
2634 1.1 cgd /*
2635 1.1 cgd * Because a library (-lfoo) target doesn't follow the standard
2636 1.1 cgd * filesystem conventions, we don't set the regular variables for
2637 1.1 cgd * the thing. .PREFIX is simply made empty...
2638 1.1 cgd */
2639 1.71 christos Var_Set(PREFIX, "", target, 0);
2640 1.71 christos } else
2641 1.71 christos SuffFindNormalDeps(target, cleanup);
2642 1.71 christos
2643 1.71 christos Lst_Destroy(cleanup, SuffFreeSrc);
2644 1.1 cgd }
2645 1.1 cgd /*-
2646 1.1 cgd *-----------------------------------------------------------------------
2647 1.71 christos * Suff_SetNull -- define which suffix is the .NULL suffix.
2648 1.1 cgd *
2649 1.39 wiz * Input:
2650 1.71 christos * name Name of null suffix
2651 1.1 cgd *-----------------------------------------------------------------------
2652 1.1 cgd */
2653 1.1 cgd void
2654 1.39 wiz Suff_SetNull(char *name)
2655 1.1 cgd {
2656 1.71 christos LstNode i;
2657 1.1 cgd
2658 1.71 christos i = Lst_Find(sufflist, name, SuffSuffHasNameP);
2659 1.71 christos if (i != NULL) {
2660 1.71 christos if (nullSuff != NULL)
2661 1.71 christos --nullSuff->refCount;
2662 1.71 christos nullSuff = (Suff *)Lst_Datum(i);
2663 1.71 christos ++nullSuff->refCount;
2664 1.71 christos }
2665 1.71 christos else
2666 1.71 christos Parse_Error(PARSE_WARNING,
2667 1.71 christos ".NULL not set because %s is not in .SUFFIXES.", name);
2668 1.1 cgd }
2669 1.1 cgd
2670 1.1 cgd /*-
2671 1.1 cgd *-----------------------------------------------------------------------
2672 1.1 cgd * Suff_Init --
2673 1.71 christos * Initialize suffixes module so all of its services can be used.
2674 1.1 cgd *-----------------------------------------------------------------------
2675 1.1 cgd */
2676 1.1 cgd void
2677 1.39 wiz Suff_Init(void)
2678 1.1 cgd {
2679 1.48 christos sufflist = Lst_Init(FALSE);
2680 1.71 christos /*
2681 1.71 christos * Do explicit initialization for .SUFFIXES related things with static
2682 1.71 christos * initialization because we get called by Suff_ClearSuffixes() too.
2683 1.71 christos */
2684 1.71 christos sNum = 0;
2685 1.71 christos memset(lookup, 0, sizeof(lookup[0]) * LOOKUP_SIZE);
2686 1.71 christos
2687 1.48 christos transforms = Lst_Init(FALSE);
2688 1.1 cgd
2689 1.71 christos emptySuff = SuffNewSuff("");
2690 1.71 christos emptySuff->sNum = INT_MAX;
2691 1.71 christos ++emptySuff->refCount;
2692 1.71 christos Dir_Concat(emptySuff->searchPath, dirSearchPath);
2693 1.1 cgd
2694 1.71 christos nullSuff = NULL;
2695 1.1 cgd }
2696 1.5 jtc
2697 1.5 jtc
2698 1.5 jtc /*-
2699 1.6 jtc *----------------------------------------------------------------------
2700 1.71 christos * Suff_End -- release resources used by the module.
2701 1.5 jtc *
2702 1.71 christos * It is not safe to call functions from this module after calling this.
2703 1.6 jtc *----------------------------------------------------------------------
2704 1.5 jtc */
2705 1.6 jtc void
2706 1.39 wiz Suff_End(void)
2707 1.5 jtc {
2708 1.25 mycroft #ifdef CLEANUP
2709 1.71 christos SuffCleanUp(SCU_END);
2710 1.25 mycroft #endif
2711 1.5 jtc }
2712 1.5 jtc
2713 1.1 cgd
2714 1.71 christos /*
2715 1.71 christos ******************************************************************************
2716 1.71 christos * Debugging Functions
2717 1.71 christos ******************************************************************************
2718 1.71 christos */
2719 1.71 christos
2720 1.71 christos /*
2721 1.71 christos *----------------------------------------------------------------------
2722 1.71 christos * SuffDebug -- print a message to debug_file if debugging is enabled.
2723 1.71 christos *
2724 1.71 christos * Input:
2725 1.71 christos * fmt printf format specification
2726 1.71 christos * ... print arguments
2727 1.71 christos *
2728 1.71 christos * Results:
2729 1.71 christos * See vfprintf().
2730 1.71 christos *----------------------------------------------------------------------
2731 1.71 christos */
2732 1.71 christos static int
2733 1.71 christos SuffDebug(const char * fmt, ...)
2734 1.71 christos {
2735 1.71 christos va_list ap;
2736 1.71 christos int rv;
2737 1.71 christos
2738 1.71 christos rv = 0;
2739 1.71 christos if (DEBUG(SUFF)) {
2740 1.71 christos va_start(ap, fmt);
2741 1.71 christos rv = vfprintf(debug_file, fmt, ap);
2742 1.71 christos va_end(ap);
2743 1.71 christos }
2744 1.71 christos return rv;
2745 1.71 christos }
2746 1.71 christos
2747 1.71 christos /*
2748 1.71 christos *----------------------------------------------------------------------
2749 1.71 christos * SuffDebugChain -- print transformation chain to debug_file.
2750 1.71 christos *
2751 1.71 christos * Print the transformation chain that begins with start in reverse
2752 1.71 christos * order (end result first). Each suffix in the chain is printed
2753 1.71 christos * on one line separated by " <- ".
2754 1.71 christos *
2755 1.71 christos * Input:
2756 1.71 christos * start chain's first transformation
2757 1.71 christos *----------------------------------------------------------------------
2758 1.71 christos */
2759 1.71 christos static void
2760 1.71 christos SuffDebugChain(Src *start)
2761 1.71 christos {
2762 1.71 christos if (DEBUG(SUFF)){
2763 1.71 christos Lst tmp = Lst_Init(FALSE);
2764 1.71 christos Src *i;
2765 1.71 christos LstNode j;
2766 1.71 christos
2767 1.71 christos for (i = start; i != NULL; i = i->parent)
2768 1.71 christos Lst_AtFront(tmp, i);
2769 1.71 christos fprintf(debug_file, "\t");
2770 1.71 christos for (j = Lst_First(tmp); j != NULL; j = Lst_Succ(j)) {
2771 1.71 christos i = (Src *)Lst_Datum(j);
2772 1.71 christos fprintf(debug_file, "`%s' <- ", i->suff->name);
2773 1.71 christos }
2774 1.71 christos fprintf(debug_file, "\n");
2775 1.71 christos
2776 1.71 christos Lst_Destroy(tmp, NULL);
2777 1.71 christos }
2778 1.71 christos }
2779 1.1 cgd
2780 1.71 christos static int SuffPrintName(void *s, void *unused)
2781 1.6 jtc {
2782 1.71 christos (void)unused;
2783 1.71 christos fprintf(debug_file, "`%s' ", ((Suff *)s)->name);
2784 1.71 christos return 0;
2785 1.6 jtc }
2786 1.1 cgd
2787 1.1 cgd static int
2788 1.71 christos SuffPrintSuff(void *sp, void *unused)
2789 1.1 cgd {
2790 1.51 christos Suff *s = (Suff *)sp;
2791 1.1 cgd int flags;
2792 1.1 cgd int flag;
2793 1.1 cgd
2794 1.71 christos (void)unused;
2795 1.71 christos
2796 1.63 christos fprintf(debug_file, "# `%s' [%d] ", s->name, s->refCount);
2797 1.13 christos
2798 1.1 cgd flags = s->flags;
2799 1.1 cgd if (flags) {
2800 1.63 christos fputs(" (", debug_file);
2801 1.1 cgd while (flags) {
2802 1.1 cgd flag = 1 << (ffs(flags) - 1);
2803 1.1 cgd flags &= ~flag;
2804 1.1 cgd switch (flag) {
2805 1.1 cgd case SUFF_INCLUDE:
2806 1.63 christos fprintf(debug_file, "INCLUDE");
2807 1.1 cgd break;
2808 1.1 cgd case SUFF_LIBRARY:
2809 1.63 christos fprintf(debug_file, "LIBRARY");
2810 1.1 cgd break;
2811 1.1 cgd }
2812 1.63 christos fputc(flags ? '|' : ')', debug_file);
2813 1.1 cgd }
2814 1.1 cgd }
2815 1.63 christos fputc('\n', debug_file);
2816 1.63 christos fprintf(debug_file, "#\tTo: ");
2817 1.59 dsl Lst_ForEach(s->parents, SuffPrintName, NULL);
2818 1.63 christos fputc('\n', debug_file);
2819 1.63 christos fprintf(debug_file, "#\tFrom: ");
2820 1.59 dsl Lst_ForEach(s->children, SuffPrintName, NULL);
2821 1.63 christos fputc('\n', debug_file);
2822 1.63 christos fprintf(debug_file, "#\tSearch Path: ");
2823 1.48 christos Dir_PrintPath(s->searchPath);
2824 1.63 christos fputc('\n', debug_file);
2825 1.71 christos return 0;
2826 1.1 cgd }
2827 1.1 cgd
2828 1.1 cgd static int
2829 1.71 christos SuffPrintTrans(void *tp, void *unused)
2830 1.1 cgd {
2831 1.51 christos GNode *t = (GNode *)tp;
2832 1.1 cgd
2833 1.71 christos (void)unused;
2834 1.71 christos
2835 1.63 christos fprintf(debug_file, "%-16s: ", t->name);
2836 1.48 christos Targ_PrintType(t->type);
2837 1.63 christos fputc('\n', debug_file);
2838 1.59 dsl Lst_ForEach(t->commands, Targ_PrintCmd, NULL);
2839 1.63 christos fputc('\n', debug_file);
2840 1.71 christos return 0;
2841 1.1 cgd }
2842 1.1 cgd
2843 1.4 cgd void
2844 1.39 wiz Suff_PrintAll(void)
2845 1.1 cgd {
2846 1.63 christos fprintf(debug_file, "#*** Suffixes:\n");
2847 1.59 dsl Lst_ForEach(sufflist, SuffPrintSuff, NULL);
2848 1.71 christos SuffPrintSuff(emptySuff, NULL);
2849 1.1 cgd
2850 1.63 christos fprintf(debug_file, "#*** Transformations:\n");
2851 1.59 dsl Lst_ForEach(transforms, SuffPrintTrans, NULL);
2852 1.1 cgd }
2853