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