Annotation of src/usr.bin/make/suff.c, Revision 1.83
1.83 ! espie 1: /* $OpenBSD: suff.c,v 1.82 2012/10/09 19:45:34 espie Exp $ */
1.5 millert 2: /* $NetBSD: suff.c,v 1.13 1996/11/06 17:59:25 christos Exp $ */
1.1 deraadt 3:
4: /*
1.5 millert 5: * Copyright (c) 1988, 1989, 1990, 1993
6: * The Regents of the University of California. All rights reserved.
1.1 deraadt 7: * Copyright (c) 1989 by Berkeley Softworks
8: * All rights reserved.
9: *
10: * This code is derived from software contributed to Berkeley by
11: * Adam de Boor.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
1.50 millert 21: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 22: * may be used to endorse or promote products derived from this software
23: * without specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35: * SUCH DAMAGE.
36: */
37:
38: /*-
39: * suff.c --
40: * Functions to maintain suffix lists and find implicit dependents
41: * using suffix transformation rules
42: *
43: * Interface:
1.41 espie 44: * Suff_Init Initialize all things to do with suffixes.
1.1 deraadt 45: *
1.81 espie 46: * Suff_ClearSuffixes Clear out all the suffixes.
1.1 deraadt 47: *
1.41 espie 48: * Suff_AddSuffix Add the passed string as another known suffix.
1.1 deraadt 49: *
1.70 espie 50: * Suff_ParseAsTransform Line might be a suffix line, check it.
51: * If it's not, return NULL. Otherwise, add
52: * another transformation to the suffix graph.
53: * Returns GNode suitable for framing, I mean,
54: * tacking commands, attributes, etc. on.
1.1 deraadt 55: *
1.41 espie 56: * Suff_FindDeps Find implicit sources for and the location of
57: * a target based on its suffix. Returns the
58: * bottom-most node added to the graph or NULL
59: * if the target had no implicit sources.
1.1 deraadt 60: */
61:
1.42 espie 62: #include <ctype.h>
63: #include <stdio.h>
1.43 espie 64: #include <stdlib.h>
1.70 espie 65: #include <stdint.h>
66: #include <stddef.h>
1.42 espie 67: #include <string.h>
1.73 espie 68: #include <signal.h>
1.70 espie 69: #include <ohash.h>
1.42 espie 70: #include "config.h"
71: #include "defines.h"
72: #include "dir.h"
1.63 espie 73: #include "direxpand.h"
1.70 espie 74: #include "engine.h"
1.42 espie 75: #include "arch.h"
76: #include "suff.h"
77: #include "var.h"
78: #include "targ.h"
79: #include "error.h"
80: #include "str.h"
81: #include "lst.h"
82: #include "memory.h"
83: #include "gnode.h"
1.70 espie 84: #include "make.h"
1.52 espie 85: #include "stats.h"
1.81 espie 86: #include "dump.h"
1.36 espie 87:
1.72 espie 88: /* XXX the suffixes hash is stored using a specific hash function, suitable
89: * for looking up suffixes in reverse.
90: */
91: static struct ohash suffixes;
92:
93: /* We remember the longest suffix, so we don't need to look beyond that. */
1.78 espie 94: size_t maxLen;
1.72 espie 95: static LIST srclist;
96:
97: /* Transforms (.c.o) are stored in another hash, independently from suffixes.
98: * When make sees a target, it checks whether it's currently parsable as a
99: * transform (according to the active suffixes). If yes, it's stored as a
100: * new transform.
101: *
102: * XXX
103: * But transforms DO NOT have a canonical decomposition as a set of suffixes,
104: * and will be used as necessary later, when looking up implicit rules for
105: * actual targets.
106: *
107: * For instance, a transform .a.b.c can be parsed as .a -> .b.c if suffixes
108: * .a and .b.c are active, and then LATER, reused as .a.b -> .c if suffixes
109: * .a.b and .c are active.
110: */
1.70 espie 111: static struct ohash transforms;
1.1 deraadt 112:
1.72 espie 113: /* conflicts between suffixes are solved by suffix declaration order. */
114: static int order = 0;
1.1 deraadt 115:
116: /*
117: * Structure describing an individual suffix.
118: */
1.82 espie 119: struct Suff_ {
1.72 espie 120: size_t nameLen; /* optimisation: strlen(name) */
121: short flags;
122: #define SUFF_ACTIVE 0x08 /* We never destroy suffixes and rules, */
123: /* we just deactivate them. */
1.70 espie 124: #define SUFF_PATH 0x10 /* False suffix: actually, the path keyword */
125: LIST searchPath; /* The path along which files of this suffix
126: * may be found */
1.78 espie 127: int order; /* order of declaration for conflict
1.72 espie 128: * resolution. */
129: LIST parents; /* List of Suff we have a transformation to */
130: LIST children; /* List of Suff we have a transformation from */
131: char name[1];
1.82 espie 132: };
1.1 deraadt 133:
1.70 espie 134: static struct ohash_info suff_info = {
1.78 espie 135: offsetof(struct Suff_, name), NULL,
1.72 espie 136: hash_alloc, hash_free, element_alloc
1.70 espie 137: };
138:
1.1 deraadt 139: /*
140: * Structure used in the search for implied sources.
141: */
1.40 espie 142: typedef struct Src_ {
1.70 espie 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
1.1 deraadt 149: * this thing too early or never nuke it) */
150: #ifdef DEBUG_SRC
1.70 espie 151: LIST cp; /* Debug; children list */
1.1 deraadt 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 {
1.70 espie 160: Lst l;
161: Src *s;
1.1 deraadt 162: } LstSrc;
163:
1.70 espie 164: static Suff *emptySuff; /* The empty suffix required for POSIX
165: * single-suffix transformation rules */
166:
167:
168: #define parse_transform(s, p, q) parse_transformi(s, s + strlen(s), p, q)
169: static bool parse_transformi(const char *, const char *, Suff **, Suff **);
170: #define new_suffix(s) new_suffixi(s, NULL)
171: static Suff *new_suffixi(const char *, const char *);
172: static void reverse_hash_add_char(uint32_t *, const char *);
173: static uint32_t reverse_hashi(const char *, const char **);
174: static unsigned int reverse_slot(struct ohash *, const char *, const char **);
175: static void clear_suffixes(void);
176: static void record_possible_suffix(Suff *, GNode *, char *, Lst, Lst);
177: static void record_possible_suffixes(GNode *, Lst, Lst);
178: static Suff *find_suffix_as_suffix(Lst, const char *, const char *);
179: static Suff *add_suffixi(const char *, const char *);
1.1 deraadt 180:
1.41 espie 181: static void SuffInsert(Lst, Suff *);
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);
1.77 espie 187: static void SuffExpandChildren(LstNode, GNode *);
1.41 espie 188: static void SuffExpandVarChildren(LstNode, GNode *, GNode *);
189: static void SuffExpandWildChildren(LstNode, GNode *, GNode *);
1.42 espie 190: static bool SuffApplyTransform(GNode *, GNode *, Suff *, Suff *);
1.41 espie 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 *);
1.70 espie 196: static void SuffPrintTrans(GNode *);
1.1 deraadt 197:
1.70 espie 198: #define find_suff(name) find_suffi(name, NULL)
199: static Suff *find_suffi(const char *, const char *);
200: static Suff *find_best_suffix(const char *, const char *);
201: static GNode *find_transform(const char *);
202: static GNode *find_or_create_transformi(const char *, const char *);
203: static void setup_paths(void);
204: static void build_suffixes_graph(void);
205: static void special_path_hack(void);
1.52 espie 206:
1.42 espie 207: #ifdef DEBUG_SRC
208: static void PrintAddr(void *);
209: #endif
1.70 espie 210:
1.72 espie 211: /* hash functions for the suffixes hash */
212: /* add one char to the hash */
1.70 espie 213: static void
214: reverse_hash_add_char(uint32_t *pk, const char *s)
215: {
216: *pk = ((*pk << 2) | (*pk >> 30)) ^ *s;
217: }
218:
1.72 espie 219: /* build a full hash from end to start */
1.70 espie 220: static uint32_t
221: reverse_hashi(const char *s, const char **e)
1.1 deraadt 222: {
1.70 espie 223: const char *p;
224: uint32_t k;
225:
226: if (*e == NULL)
227: *e = s + strlen(s);
228: p = *e;
229: if (p == s)
230: k = 0;
231: else
232: k = *--p;
233: while (p != s) {
234: reverse_hash_add_char(&k, --p);
1.66 espie 235: }
1.70 espie 236: return k;
237: }
238:
239: static unsigned int
240: reverse_slot(struct ohash *h, const char *s, const char **e)
241: {
242: uint32_t hv;
1.1 deraadt 243:
1.70 espie 244: hv = reverse_hashi(s, e);
245: return ohash_lookup_interval(h, s, *e, hv);
1.1 deraadt 246: }
247:
1.70 espie 248:
1.1 deraadt 249: static char *
1.70 espie 250: suffix_is_suffix(Suff *s, const char *str, const char *estr)
1.1 deraadt 251: {
1.70 espie 252: const char *p1; /* Pointer into suffix name */
253: const char *p2; /* Pointer into string being examined */
1.1 deraadt 254:
1.70 espie 255: if (estr - str < (ptrdiff_t) s->nameLen)
256: return NULL;
1.66 espie 257: p1 = s->name + s->nameLen;
1.70 espie 258: p2 = estr;
1.1 deraadt 259:
1.66 espie 260: while (p1 != s->name) {
261: p1--;
262: p2--;
263: if (*p1 != *p2)
264: return NULL;
265: }
1.1 deraadt 266:
1.66 espie 267: return (char *)p2;
1.1 deraadt 268: }
269:
1.70 espie 270: static Suff *
271: find_suffi(const char *name, const char *ename)
1.1 deraadt 272: {
1.70 espie 273: unsigned int slot;
274: #ifdef STATS_SUFF
275: STAT_SUFF_LOOKUP_NAME++;
276: #endif
277: slot = reverse_slot(&suffixes, name, &ename);
278: return ohash_find(&suffixes, slot);
1.1 deraadt 279: }
280:
1.70 espie 281: static GNode *
282: find_transform(const char *name)
1.1 deraadt 283: {
1.70 espie 284: unsigned int slot;
1.1 deraadt 285:
1.52 espie 286: #ifdef STATS_SUFF
1.70 espie 287: STAT_TRANSFORM_LOOKUP_NAME++;
1.52 espie 288: #endif
1.70 espie 289: slot = ohash_qlookup(&transforms, name);
290:
291: return ohash_find(&transforms, slot);
1.52 espie 292: }
293:
1.70 espie 294: static GNode *
295: find_or_create_transformi(const char *name, const char *end)
1.52 espie 296: {
1.70 espie 297: GNode *r;
298: unsigned int slot;
1.52 espie 299:
300: #ifdef STATS_SUFF
1.66 espie 301: STAT_TRANSFORM_LOOKUP_NAME++;
1.52 espie 302: #endif
1.70 espie 303: slot = ohash_qlookupi(&transforms, name, &end);
1.1 deraadt 304:
1.70 espie 305: r = ohash_find(&transforms, slot);
1.1 deraadt 306:
1.70 espie 307: if (r == NULL) {
308: r = Targ_NewGNi(name, end);
309: ohash_insert(&transforms, slot, r);
310: }
311: return r;
312: }
1.1 deraadt 313:
314: /*-
315: *-----------------------------------------------------------------------
316: * SuffInsert --
317: * Insert the suffix into the list keeping the list ordered by suffix
318: * numbers.
319: *
320: * Side Effects:
321: * The reference count of the suffix is incremented
322: *-----------------------------------------------------------------------
323: */
324: static void
1.51 espie 325: SuffInsert(Lst l, Suff *s)
1.1 deraadt 326: {
1.70 espie 327: LstNode ln; /* current element in l we're examining */
328: Suff *s2 = NULL; /* the suffix descriptor in this element */
1.1 deraadt 329:
1.66 espie 330: for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) {
331: s2 = (Suff *)Lst_Datum(ln);
1.72 espie 332: if (s2->order >= s->order)
1.66 espie 333: break;
334: }
1.1 deraadt 335:
1.70 espie 336: if (DEBUG(SUFF))
1.72 espie 337: printf("inserting %s(%d)...", s->name, s->order);
1.66 espie 338: if (ln == NULL) {
1.70 espie 339: if (DEBUG(SUFF))
1.66 espie 340: printf("at end of list\n");
341: Lst_AtEnd(l, s);
1.72 espie 342: } else if (s2->order != s->order) {
1.70 espie 343: if (DEBUG(SUFF))
1.72 espie 344: printf("before %s(%d)\n", s2->name, s2->order);
1.66 espie 345: Lst_Insert(l, ln, s);
346: } else if (DEBUG(SUFF)) {
347: printf("already there\n");
1.1 deraadt 348: }
349: }
350:
351: /*-
352: *-----------------------------------------------------------------------
353: * Suff_ClearSuffixes --
1.70 espie 354: * Nuke the list of suffixes but keep all transformation
355: * rules around.
1.1 deraadt 356: *
357: * Side Effects:
1.70 espie 358: * Current suffixes are reset
1.1 deraadt 359: *-----------------------------------------------------------------------
360: */
1.70 espie 361: static void
362: clear_suffixes(void)
363: {
364: unsigned int i;
365: Suff *s;
366:
367: for (s = ohash_first(&suffixes, &i); s != NULL;
368: s = ohash_next(&suffixes, &i))
1.72 espie 369: s->flags &= ~SUFF_ACTIVE;
1.70 espie 370:
1.72 espie 371: order = 0;
1.70 espie 372: maxLen = 0;
373: }
374:
1.1 deraadt 375: void
1.51 espie 376: Suff_ClearSuffixes(void)
1.1 deraadt 377: {
1.70 espie 378: clear_suffixes();
1.1 deraadt 379: }
380:
1.70 espie 381:
382: /* okay = parse_transform(str, &src, &targ);
383: * try parsing a string as a transformation rule, returns true if
384: * successful. Fills &src, &targ with the constituent suffixes.
385: * Special hack: source suffixes must exist OR be the special SUFF_PATH
386: * pseudo suffix (.PATH)
1.1 deraadt 387: */
1.42 espie 388: static bool
1.70 espie 389: parse_transformi(const char *str, const char *e, Suff **srcPtr, Suff **targPtr)
390: {
391: Suff *src, *target, *best_src, *best_target;
392: const char *p;
393:
394: size_t len;
395: uint32_t hv;
396: unsigned int slot;
397:
398: /* empty string -> no suffix */
399: if (e == str)
400: return false;
401:
402: len = e - str;
1.66 espie 403:
1.70 espie 404: if (len > 2 * maxLen)
405: return false;
406:
407: p = e;
408: best_src = best_target = NULL;
1.66 espie 409:
1.70 espie 410: hv = *--p;
411: while (p != str) {
412: slot = ohash_lookup_interval(&suffixes, p, e, hv);
413: /* no double suffix in there */
414: if (p - str <= (ptrdiff_t)maxLen) {
415: target = ohash_find(&suffixes, slot);
1.72 espie 416: if (target != NULL && (target->flags & SUFF_ACTIVE)) {
1.70 espie 417: src = find_suffi(str, p);
418: if (src != NULL &&
1.72 espie 419: (src->flags & (SUFF_ACTIVE | SUFF_PATH))) {
1.70 espie 420: /* XXX even if we find a set of suffixes, we
421: * have to keep going to find the best one,
422: * namely, the one whose src appears first in
423: * .SUFFIXES
1.66 espie 424: */
1.70 espie 425: if (best_src == NULL ||
1.72 espie 426: src->order < best_src->order) {
1.70 espie 427: best_src = src;
428: best_target = target;
429: }
430: }
1.66 espie 431: }
432: }
1.70 espie 433: /* can't be a suffix anyways */
434: if (e - p >= (ptrdiff_t)maxLen)
435: break;
436: reverse_hash_add_char(&hv, --p);
437: }
438:
439: if (p == str && best_src == NULL) {
440: /* no double suffix transformation, resort to single suffix if
441: * we find one. */
442: slot = ohash_lookup_interval(&suffixes, p, e, hv);
443: src = ohash_find(&suffixes, slot);
1.72 espie 444: if (src != NULL && (src->flags & (SUFF_ACTIVE | SUFF_PATH))) {
1.70 espie 445: best_src = src;
1.81 espie 446: best_target = emptySuff;
1.70 espie 447: }
448: }
449: if (best_src != NULL) {
450: *srcPtr = best_src;
451: *targPtr = best_target;
452: return true;
453: } else {
454: return false;
1.1 deraadt 455: }
456: }
457:
1.70 espie 458: static void
459: special_path_hack(void)
460: {
461: Suff *path = add_suffixi(".PATH", NULL);
462: path->flags |= SUFF_PATH;
463: }
464:
465: static Suff *
466: find_best_suffix(const char *s, const char *e)
1.1 deraadt 467: {
1.70 espie 468: const char *p;
469: uint32_t hv;
470: unsigned int slot;
471: Suff *best = NULL;
472: Suff *suff;
1.1 deraadt 473:
1.70 espie 474: if (e == s)
475: return NULL;
476: p = e;
477: hv = *--p;
478: while (p != s) {
479: slot = ohash_lookup_interval(&suffixes, p, e, hv);
480: suff = ohash_find(&suffixes, slot);
481: if (suff != NULL)
1.72 espie 482: if (best == NULL || suff->order < best->order)
1.70 espie 483: best = suff;
484: if (e - p >= (ptrdiff_t)maxLen)
485: break;
486: reverse_hash_add_char(&hv, --p);
487: }
488: return best;
1.1 deraadt 489: }
490:
491: /*-
492: *-----------------------------------------------------------------------
1.70 espie 493: * Suff_ParseAsTransform --
494: * Try parsing a target line as a transformation rule, depending on
495: * existing suffixes.
1.1 deraadt 496: *
1.82 espie 497: * Possibly create a new transform, or reset an existing one.
1.1 deraadt 498: *-----------------------------------------------------------------------
499: */
500: GNode *
1.70 espie 501: Suff_ParseAsTransform(const char *line, const char *end)
1.1 deraadt 502: {
1.70 espie 503: GNode *gn; /* GNode of transformation rule */
504: Suff *s; /* source suffix */
505: Suff *t; /* target suffix */
506:
507: if (!parse_transformi(line, end, &s, &t))
508: return NULL;
1.1 deraadt 509:
1.70 espie 510: gn = find_or_create_transformi(line, end);
511: /* In case the transform already exists, nuke old commands and children.
512: * Note we can't free them, since there might be stuff that references
513: * them elsewhere
514: */
515: if (!Lst_IsEmpty(&gn->commands)) {
1.66 espie 516: Lst_Destroy(&gn->commands, NOFREE);
517: Lst_Init(&gn->commands);
1.70 espie 518: }
519: if (!Lst_IsEmpty(&gn->children)) {
1.66 espie 520: Lst_Destroy(&gn->children, NOFREE);
521: Lst_Init(&gn->children);
522: }
1.1 deraadt 523:
1.66 espie 524: gn->type = OP_TRANSFORM;
1.70 espie 525: if (s->flags & SUFF_PATH) {
526: gn->special = SPECIAL_PATH | SPECIAL_TARGET;
527: gn->suffix = t;
528: }
1.1 deraadt 529:
1.70 espie 530: if (DEBUG(SUFF))
1.66 espie 531: printf("defining transformation from `%s' to `%s'\n",
532: s->name, t->name);
1.70 espie 533: return gn;
534: }
535:
536: static void
537: make_suffix_known(Suff *s)
538: {
1.72 espie 539: if ((s->flags & SUFF_ACTIVE) == 0) {
540: s->order = order++;
541: s->flags |= SUFF_ACTIVE;
1.70 espie 542: if (s->nameLen > maxLen)
543: maxLen = s->nameLen;
1.66 espie 544: }
1.70 espie 545: }
1.1 deraadt 546:
1.70 espie 547: static Suff *
548: new_suffixi(const char *str, const char *eptr)
549: {
550: Suff *s;
551:
552: s = ohash_create_entry(&suff_info, str, &eptr);
553: s->nameLen = eptr - str;
554: Lst_Init(&s->searchPath);
555: Lst_Init(&s->children);
556: Lst_Init(&s->parents);
557: s->flags = 0;
558: return s;
1.1 deraadt 559: }
560:
561: /*-
562: *-----------------------------------------------------------------------
1.70 espie 563: * Suff_AddSuffix --
564: * Add the suffix in string to the end of the list of known suffixes.
565: * Should we restructure the suffix graph? Make doesn't...
1.1 deraadt 566: *
567: * Side Effects:
1.70 espie 568: * A GNode is created for the suffix and a Suff structure is created and
569: * added to the known suffixes, unless it was already known.
1.1 deraadt 570: *-----------------------------------------------------------------------
571: */
1.27 espie 572: void
1.70 espie 573: Suff_AddSuffixi(const char *str, const char *end)
1.1 deraadt 574: {
1.70 espie 575: (void)add_suffixi(str, end);
576: }
1.5 millert 577:
1.70 espie 578: static Suff *
579: add_suffixi(const char *str, const char *end)
580: {
581: Suff *s; /* new suffix descriptor */
1.66 espie 582:
1.70 espie 583: unsigned int slot;
1.66 espie 584:
1.70 espie 585: slot = reverse_slot(&suffixes, str, &end);
586: s = ohash_find(&suffixes, slot);
587: if (s == NULL) {
588: s = new_suffixi(str, end);
589: ohash_insert(&suffixes, slot, s);
590: }
591: make_suffix_known(s);
592: return s;
593: }
1.1 deraadt 594:
1.70 espie 595: Lst
596: find_suffix_path(GNode *gn)
597: {
598: if (gn->suffix != NULL && gn->suffix != emptySuff)
599: return &(gn->suffix->searchPath);
600: else
601: return defaultPath;
602: }
1.1 deraadt 603:
1.70 espie 604: static void
605: build_suffixes_graph(void)
1.1 deraadt 606: {
1.70 espie 607: Suff *s, *s2;
608: GNode *gn;
609: unsigned int i;
610:
611: for (gn = ohash_first(&transforms, &i); gn != NULL;
612: gn = ohash_next(&transforms, &i)) {
613: if (Lst_IsEmpty(&gn->commands) && Lst_IsEmpty(&gn->children))
614: continue;
615: if ((gn->special & SPECIAL_MASK) == SPECIAL_PATH)
616: continue;
617: if (parse_transform(gn->name, &s, &s2)) {
618: SuffInsert(&s2->children, s);
619: SuffInsert(&s->parents, s2);
620: }
1.66 espie 621: }
1.1 deraadt 622: }
623:
624: /*-
625: *-----------------------------------------------------------------------
1.70 espie 626: * setup_paths
1.1 deraadt 627: * Extend the search paths for all suffixes to include the default
628: * search path.
629: *
630: * Side Effects:
631: * The searchPath field of all the suffixes is extended by the
1.64 espie 632: * directories in defaultPath. If paths were specified for the
1.1 deraadt 633: * ".h" suffix, the directories are stuffed into a global variable
1.54 jsg 634: * called ".INCLUDES" with each directory preceded by a -I. The same
1.1 deraadt 635: * is done for the ".a" suffix, except the variable is called
636: * ".LIBS" and the flag is -L.
637: *-----------------------------------------------------------------------
638: */
1.70 espie 639: static void
640: setup_paths(void)
1.1 deraadt 641: {
1.70 espie 642: unsigned int i;
643: Suff *s;
1.66 espie 644:
1.70 espie 645: for (s = ohash_first(&suffixes, &i); s != NULL;
646: s = ohash_next(&suffixes, &i)) {
647: if (!Lst_IsEmpty(&s->searchPath))
1.66 espie 648: Dir_Concat(&s->searchPath, defaultPath);
1.70 espie 649: else
1.66 espie 650: Lst_Clone(&s->searchPath, defaultPath, Dir_CopyDir);
651: }
1.1 deraadt 652: }
653:
654: void
1.70 espie 655: process_suffixes_after_makefile_is_read(void)
1.1 deraadt 656: {
1.70 espie 657: /* once the Makefile is finish reading, we can set up the default PATH
658: * stuff, and build the final suffixes graph
659: */
660: setup_paths();
661: /* and we link all transforms to active suffixes at this point. */
662: build_suffixes_graph();
1.1 deraadt 663: }
1.41 espie 664: /********** Implicit Source Search Functions *********/
1.1 deraadt 665:
666: /*-
667: *-----------------------------------------------------------------------
668: * SuffAddSrc --
669: * Add a suffix as a Src structure to the given list with its parent
670: * being the given Src structure. If the suffix is the null suffix,
671: * the prefix is used unaltered as the file name in the Src structure.
672: *
673: * Side Effects:
674: * A Src structure is created and tacked onto the end of the list
675: *-----------------------------------------------------------------------
676: */
1.27 espie 677: static void
1.51 espie 678: SuffAddSrc(
1.70 espie 679: void *sp, /* suffix for which to create a Src structure */
680: void *lsp) /* list and parent for the new Src */
1.1 deraadt 681: {
1.70 espie 682: Suff *s = (Suff *)sp;
683: LstSrc *ls = (LstSrc *)lsp;
684: Src *s2; /* new Src structure */
685: Src *targ; /* Target structure */
1.1 deraadt 686:
1.66 espie 687: targ = ls->s;
1.5 millert 688:
1.41 espie 689: s2 = emalloc(sizeof(Src));
1.70 espie 690: s2->file = Str_concat(targ->pref, s->name, 0);
691: s2->pref = targ->pref;
692: s2->parent = targ;
693: s2->node = NULL;
694: s2->suff = s;
695: s2->children = 0;
1.65 espie 696: targ->children++;
1.25 espie 697: Lst_AtEnd(ls->l, s2);
1.1 deraadt 698: #ifdef DEBUG_SRC
1.70 espie 699: Lst_Init(&s2->cp);
1.29 espie 700: Lst_AtEnd(&targ->cp, s2);
1.66 espie 701: printf("2 add %x %x to %x:", targ, s2, ls->l);
1.27 espie 702: Lst_Every(ls->l, PrintAddr);
1.1 deraadt 703: printf("\n");
704: #endif
1.41 espie 705:
1.1 deraadt 706: }
707:
708: /*-
709: *-----------------------------------------------------------------------
710: * SuffAddLevel --
711: * Add all the children of targ as Src structures to the given list
712: *
713: * Side Effects:
1.41 espie 714: * Lots of structures are created and added to the list
1.1 deraadt 715: *-----------------------------------------------------------------------
716: */
717: static void
1.51 espie 718: SuffAddLevel(
1.70 espie 719: Lst l, /* list to which to add the new level */
720: Src *targ) /* Src structure to use as the parent */
1.1 deraadt 721: {
1.66 espie 722: LstSrc ls;
1.1 deraadt 723:
1.66 espie 724: ls.s = targ;
725: ls.l = l;
1.1 deraadt 726:
1.66 espie 727: Lst_ForEach(&targ->suff->children, SuffAddSrc, &ls);
1.1 deraadt 728: }
729:
730: /*-
731: *----------------------------------------------------------------------
732: * SuffRemoveSrc --
733: * Free all src structures in list that don't have a reference count
734: *
735: * Results:
1.41 espie 736: * Ture if an src was removed
1.1 deraadt 737: *
738: * Side Effects:
739: * The memory is free'd.
740: *----------------------------------------------------------------------
741: */
742: static int
1.51 espie 743: SuffRemoveSrc(Lst l)
1.1 deraadt 744: {
1.66 espie 745: LstNode ln;
746: Src *s;
747: int t = 0;
1.1 deraadt 748:
749: #ifdef DEBUG_SRC
1.66 espie 750: printf("cleaning %lx: ", (unsigned long)l);
751: Lst_Every(l, PrintAddr);
752: printf("\n");
1.1 deraadt 753: #endif
754:
755:
1.66 espie 756: for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) {
757: s = (Src *)Lst_Datum(ln);
758: if (s->children == 0) {
759: free(s->file);
760: if (!s->parent)
761: free(s->pref);
762: else {
1.1 deraadt 763: #ifdef DEBUG_SRC
1.66 espie 764: LstNode ln2 = Lst_Member(&s->parent->cp, s);
765: if (ln2 != NULL)
766: Lst_Remove(&s->parent->cp, ln2);
1.1 deraadt 767: #endif
1.66 espie 768: --s->parent->children;
769: }
1.1 deraadt 770: #ifdef DEBUG_SRC
1.66 espie 771: printf("free: [l=%x] p=%x %d\n", l, s, s->children);
772: Lst_Destroy(&s->cp, NOFREE);
1.1 deraadt 773: #endif
1.66 espie 774: Lst_Remove(l, ln);
775: free(s);
776: t |= 1;
777: return true;
778: }
1.1 deraadt 779: #ifdef DEBUG_SRC
1.66 espie 780: else {
781: printf("keep: [l=%x] p=%x %d: ", l, s, s->children);
782: Lst_Every(&s->cp, PrintAddr);
783: printf("\n");
784: }
785: #endif
1.1 deraadt 786: }
787:
1.66 espie 788: return t;
1.1 deraadt 789: }
790:
791: /*-
792: *-----------------------------------------------------------------------
793: * SuffFindThem --
794: * Find the first existing file/target in the list srcs
795: *
796: * Results:
797: * The lowest structure in the chain of transformations
798: *-----------------------------------------------------------------------
799: */
800: static Src *
1.51 espie 801: SuffFindThem(
1.70 espie 802: Lst srcs, /* list of Src structures to search through */
803: Lst slst)
1.1 deraadt 804: {
1.70 espie 805: Src *s; /* current Src */
806: Src *rs; /* returned Src */
807: char *ptr;
1.66 espie 808:
809: rs = NULL;
810:
811: while ((s = (Src *)Lst_DeQueue(srcs)) != NULL) {
1.70 espie 812: if (DEBUG(SUFF))
1.66 espie 813: printf("\ttrying %s...", s->file);
1.1 deraadt 814:
1.66 espie 815: /*
816: * A file is considered to exist if either a node exists in the
817: * graph for it or the file actually exists.
818: */
819: if (Targ_FindNode(s->file, TARG_NOCREATE) != NULL) {
1.1 deraadt 820: #ifdef DEBUG_SRC
1.66 espie 821: printf("remove %x from %x\n", s, srcs);
1.1 deraadt 822: #endif
1.66 espie 823: rs = s;
824: break;
825: }
1.1 deraadt 826:
1.67 espie 827: if ((ptr = Dir_FindFile(s->file, &s->suff->searchPath))
1.66 espie 828: != NULL) {
829: rs = s;
1.1 deraadt 830: #ifdef DEBUG_SRC
1.66 espie 831: printf("remove %x from %x\n", s, srcs);
1.1 deraadt 832: #endif
1.66 espie 833: free(ptr);
834: break;
835: }
836:
1.70 espie 837: if (DEBUG(SUFF))
838: printf("not there\n");
1.66 espie 839:
840: SuffAddLevel(srcs, s);
841: Lst_AtEnd(slst, s);
1.1 deraadt 842: }
843:
1.70 espie 844: if (DEBUG(SUFF) && rs)
845: printf("got it\n");
1.66 espie 846: return rs;
1.1 deraadt 847: }
848:
849: /*-
850: *-----------------------------------------------------------------------
851: * SuffFindCmds --
852: * See if any of the children of the target in the Src structure is
853: * one from which the target can be transformed. If there is one,
854: * a Src structure is put together for it and returned.
855: *
856: * Results:
1.18 espie 857: * The Src structure of the "winning" child, or NULL if no such beast.
1.1 deraadt 858: *
859: * Side Effects:
860: * A Src structure may be allocated.
861: *-----------------------------------------------------------------------
862: */
863: static Src *
1.51 espie 864: SuffFindCmds(
865: Src *targ, /* Src structure to play with */
866: Lst slst)
1.41 espie 867: {
1.70 espie 868: LstNode ln; /* General-purpose list node */
869: GNode *t; /* Target GNode */
870: GNode *s; /* Source GNode */
871: int prefLen; /* The length of the defined prefix */
872: Suff *suff; /* Suffix on matching beastie */
873: Src *ret; /* Return value */
874: const char *cp;
1.66 espie 875:
876: t = targ->node;
877: prefLen = strlen(targ->pref);
878:
879: for (ln = Lst_First(&t->children); ln != NULL; ln = Lst_Adv(ln)) {
880: s = (GNode *)Lst_Datum(ln);
881:
882: cp = strrchr(s->name, '/');
883: if (cp == NULL) {
884: cp = s->name;
885: } else {
886: cp++;
887: }
888: if (strncmp(cp, targ->pref, prefLen) == 0) {
889: /* The node matches the prefix ok, see if it has a known
890: * suffix. */
1.70 espie 891: suff = find_suff(&cp[prefLen]);
892: if (suff != NULL) {
1.66 espie 893: /*
894: * It even has a known suffix, see if there's a
895: * transformation defined between the node's
896: * suffix and the target's suffix.
897: *
898: * XXX: Handle multi-stage transformations
899: * here, too.
900: */
1.67 espie 901: if (Lst_Member(&suff->parents, targ->suff)
1.66 espie 902: != NULL) {
903: /*
904: * Hot Damn! Create a new Src structure
905: * to describe this transformation
906: * (making sure to duplicate the source
907: * node's name so Suff_FindDeps can
908: * free it again (ick)), and return the
909: * new structure.
910: */
911: ret = emalloc(sizeof(Src));
912: ret->file = estrdup(s->name);
913: ret->pref = targ->pref;
914: ret->suff = suff;
915: ret->parent = targ;
916: ret->node = s;
917: ret->children = 0;
918: targ->children++;
1.1 deraadt 919: #ifdef DEBUG_SRC
1.66 espie 920: Lst_Init(&ret->cp);
921: printf("3 add %x %x\n", targ, ret);
922: Lst_AtEnd(&targ->cp, ret);
923: #endif
924: Lst_AtEnd(slst, ret);
1.70 espie 925: if (DEBUG(SUFF))
926: printf(
927: "\tusing existing source %s\n",
928: s->name);
1.66 espie 929: return ret;
1.70 espie 930: }
1.66 espie 931: }
1.1 deraadt 932: }
933: }
1.66 espie 934: return NULL;
1.41 espie 935: }
936:
937: static void
1.80 guenther 938: SuffLinkParent(GNode *cgn, GNode *pgn)
939: {
940: Lst_AtEnd(&cgn->parents, pgn);
941: if (!has_been_built(cgn))
942: pgn->unmade++;
943: else if ( ! (cgn->type & (OP_EXEC|OP_USE))) {
944: if (cgn->built_status == MADE)
945: pgn->childMade = true;
946: (void)Make_TimeStamp(pgn, cgn);
947: }
948: }
949:
950: static void
1.51 espie 951: SuffExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn)
1.41 espie 952: {
1.70 espie 953: GNode *gn; /* New source 8) */
954: char *cp; /* Expanded value */
955: LIST members;
1.66 espie 956:
1.41 espie 957:
1.66 espie 958: if (DEBUG(SUFF))
959: printf("Expanding \"%s\"...", cgn->name);
1.41 espie 960:
1.66 espie 961: cp = Var_Subst(cgn->name, &pgn->context, true);
962: if (cp == NULL) {
963: printf("Problem substituting in %s", cgn->name);
964: printf("\n");
965: return;
966: }
1.41 espie 967:
1.66 espie 968: Lst_Init(&members);
1.41 espie 969:
1.66 espie 970: if (cgn->type & OP_ARCHV) {
971: /*
972: * Node was an archive(member) target, so we want to call
973: * on the Arch module to find the nodes for us, expanding
974: * variables in the parent's context.
975: */
1.70 espie 976: const char *sacrifice = (const char *)cp;
1.41 espie 977:
1.66 espie 978: (void)Arch_ParseArchive(&sacrifice, &members, &pgn->context);
979: } else {
980: /* Break the result into a vector of strings whose nodes
981: * we can find, then add those nodes to the members list.
982: * Unfortunately, we can't use brk_string because it
983: * doesn't understand about variable specifications with
984: * spaces in them... */
1.70 espie 985: const char *start, *cp2;
1.66 espie 986:
987: for (start = cp; *start == ' ' || *start == '\t'; start++)
988: continue;
989: for (cp2 = start; *cp2 != '\0';) {
990: if (isspace(*cp2)) {
991: /* White-space -- terminate element, find the
992: * node, add it, skip any further spaces. */
993: gn = Targ_FindNodei(start, cp2, TARG_CREATE);
994: cp2++;
995: Lst_AtEnd(&members, gn);
996: while (isspace(*cp2))
997: cp2++;
998: /* Adjust cp2 for increment at start of loop,
999: * but set start to first non-space. */
1000: start = cp2;
1001: } else if (*cp2 == '$')
1002: /* Start of a variable spec -- contact variable
1003: * module to find the end so we can skip over
1004: * it. */
1005: Var_ParseSkip(&cp2, &pgn->context);
1006: else if (*cp2 == '\\' && cp2[1] != '\0')
1007: /* Escaped something -- skip over it. */
1008: cp2+=2;
1009: else
1010: cp2++;
1.70 espie 1011: }
1.41 espie 1012:
1.70 espie 1013: if (cp2 != start) {
1014: /* Stuff left over -- add it to the list too. */
1015: gn = Targ_FindNodei(start, cp2, TARG_CREATE);
1016: Lst_AtEnd(&members, gn);
1017: }
1.41 espie 1018: }
1.66 espie 1019: /* Add all elements of the members list to the parent node. */
1020: while ((gn = (GNode *)Lst_DeQueue(&members)) != NULL) {
1021: if (DEBUG(SUFF))
1022: printf("%s...", gn->name);
1023: if (Lst_Member(&pgn->children, gn) == NULL) {
1024: Lst_Append(&pgn->children, after, gn);
1025: after = Lst_Adv(after);
1.80 guenther 1026: SuffLinkParent(gn, pgn);
1.66 espie 1027: }
1028: }
1029: /* Free the result. */
1030: free(cp);
1.41 espie 1031: if (DEBUG(SUFF))
1.66 espie 1032: printf("\n");
1.41 espie 1033: }
1034:
1035: static void
1.51 espie 1036: SuffExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn)
1.41 espie 1037: {
1.70 espie 1038: Suff *s;
1039: char *cp; /* Expanded value */
1.41 espie 1040:
1.70 espie 1041: LIST exp; /* List of expansions */
1042: Lst path; /* Search path along which to expand */
1.41 espie 1043:
1.66 espie 1044: if (DEBUG(SUFF))
1045: printf("Wildcard expanding \"%s\"...", cgn->name);
1.41 espie 1046:
1.66 espie 1047: /* Find a path along which to expand the word.
1048: *
1049: * If the word has a known suffix, use that path.
1050: * If it has no known suffix and we're allowed to use the null
1051: * suffix, use its path.
1052: * Else use the default system search path. */
1.70 espie 1053: s = find_best_suffix(cgn->name, cgn->name + strlen(cgn->name));
1.41 espie 1054:
1.70 espie 1055: if (s != NULL) {
1.66 espie 1056: if (DEBUG(SUFF))
1057: printf("suffix is \"%s\"...", s->name);
1058: path = &s->searchPath;
1059: } else
1060: /* Use default search path. */
1061: path = defaultPath;
1.41 espie 1062:
1.66 espie 1063: /* Expand the word along the chosen path. */
1064: Lst_Init(&exp);
1065: Dir_Expand(cgn->name, path, &exp);
1066:
1067: /* Fetch next expansion off the list and find its GNode. */
1068: while ((cp = (char *)Lst_DeQueue(&exp)) != NULL) {
1.70 espie 1069: GNode *gn; /* New source 8) */
1.66 espie 1070: if (DEBUG(SUFF))
1071: printf("%s...", cp);
1072: gn = Targ_FindNode(cp, TARG_CREATE);
1073:
1074: /* If gn isn't already a child of the parent, make it so and
1075: * up the parent's count of unmade children. */
1076: if (Lst_Member(&pgn->children, gn) == NULL) {
1077: Lst_Append(&pgn->children, after, gn);
1078: after = Lst_Adv(after);
1.80 guenther 1079: SuffLinkParent(gn, pgn);
1.66 espie 1080: }
1.41 espie 1081: }
1082:
1.66 espie 1083: if (DEBUG(SUFF))
1084: printf("\n");
1.1 deraadt 1085: }
1086:
1087: /*-
1088: *-----------------------------------------------------------------------
1089: * SuffExpandChildren --
1090: * Expand the names of any children of a given node that contain
1091: * variable invocations or file wildcards into actual targets.
1092: *
1093: * Side Effects:
1094: * The expanded node is removed from the parent's list of children,
1095: * and the parent's unmade counter is decremented, but other nodes
1.41 espie 1096: * may be added.
1.1 deraadt 1097: *-----------------------------------------------------------------------
1098: */
1.27 espie 1099: static void
1.77 espie 1100: SuffExpandChildren(LstNode ln, /* LstNode of child, so we can replace it */
1101: GNode *pgn)
1102: {
1103: GNode *cgn = (GNode *)Lst_Datum(ln);
1.66 espie 1104:
1105: /* First do variable expansion -- this takes precedence over wildcard
1106: * expansion. If the result contains wildcards, they'll be gotten to
1107: * later since the resulting words are tacked on to the end of the
1108: * children list. */
1109: if (strchr(cgn->name, '$') != NULL)
1110: SuffExpandVarChildren(ln, cgn, pgn);
1111: else if (Dir_HasWildcards(cgn->name))
1112: SuffExpandWildChildren(ln, cgn, pgn);
1113: else
1.70 espie 1114: /* Third case: nothing to expand. */
1.66 espie 1115: return;
1116:
1117: /* Since the source was expanded, remove it from the list of children to
1118: * keep it from being processed. */
1119: pgn->unmade--;
1120: Lst_Remove(&pgn->children, ln);
1.1 deraadt 1121: }
1122:
1.77 espie 1123: void
1124: expand_children_from(GNode *parent, LstNode from)
1125: {
1126: LstNode np, ln;
1127:
1128: for (ln = from; ln != NULL; ln = np) {
1129: np = Lst_Adv(ln);
1130: SuffExpandChildren(ln, parent);
1131: }
1132: }
1133:
1.1 deraadt 1134: /*-
1135: *-----------------------------------------------------------------------
1136: * SuffApplyTransform --
1137: * Apply a transformation rule, given the source and target nodes
1138: * and suffixes.
1139: *
1140: * Results:
1.42 espie 1141: * true if successful, false if not.
1.1 deraadt 1142: *
1143: * Side Effects:
1144: * The source and target are linked and the commands from the
1145: * transformation are added to the target node's commands list.
1146: * All attributes but OP_DEPMASK and OP_TRANSFORM are applied
1147: * to the target. The target also inherits all the sources for
1148: * the transformation rule.
1149: *-----------------------------------------------------------------------
1150: */
1.42 espie 1151: static bool
1.51 espie 1152: SuffApplyTransform(
1153: GNode *tGn, /* Target node */
1154: GNode *sGn, /* Source node */
1155: Suff *t, /* Target suffix */
1156: Suff *s) /* Source suffix */
1.1 deraadt 1157: {
1.66 espie 1158: LstNode ln; /* General node */
1159: char *tname; /* Name of transformation rule */
1160: GNode *gn; /* Node for same */
1.1 deraadt 1161:
1.66 espie 1162: if (Lst_AddNew(&tGn->children, sGn)) {
1.41 espie 1163: /* Not already linked, so form the proper links between the
1164: * target and source. */
1.80 guenther 1165: SuffLinkParent(sGn, tGn);
1.1 deraadt 1166: }
1167:
1.66 espie 1168: if ((sGn->type & OP_OPMASK) == OP_DOUBLEDEP) {
1169: /* When a :: node is used as the implied source of a node, we
1.74 espie 1170: * have to link all its cohorts in as sources as well. There's
1.78 espie 1171: * only one implied src, as that will be sufficient to get
1.74 espie 1172: * the .IMPSRC variable set for tGn. */
1.66 espie 1173: for (ln=Lst_First(&sGn->cohorts); ln != NULL; ln=Lst_Adv(ln)) {
1174: gn = (GNode *)Lst_Datum(ln);
1175:
1176: if (Lst_AddNew(&tGn->children, gn)) {
1177: /* Not already linked, so form the proper links
1178: * between the target and source. */
1.80 guenther 1179: SuffLinkParent(gn, tGn);
1.66 espie 1180: }
1181: }
1182: }
1183: /* Locate the transformation rule itself. */
1184: tname = Str_concat(s->name, t->name, 0);
1.70 espie 1185: gn = find_transform(tname);
1.66 espie 1186: free(tname);
1187:
1.70 espie 1188: if (gn == NULL)
1.66 espie 1189: /*
1190: * Not really such a transformation rule (can happen when we're
1191: * called to link an OP_MEMBER and OP_ARCHV node), so return
1192: * false.
1193: */
1194: return false;
1.1 deraadt 1195:
1.66 espie 1196: if (DEBUG(SUFF))
1.67 espie 1197: printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name,
1.66 espie 1198: tGn->name);
1.1 deraadt 1199:
1.66 espie 1200: /* Record last child for expansion purposes. */
1201: ln = Lst_Last(&tGn->children);
1.5 millert 1202:
1.66 espie 1203: /* Pass the buck to Make_HandleUse to apply the rule. */
1204: Make_HandleUse(gn, tGn);
1.1 deraadt 1205:
1.66 espie 1206: /* Deal with wildcards and variables in any acquired sources. */
1.77 espie 1207: expand_children_from(tGn, Lst_Succ(ln));
1.1 deraadt 1208:
1.66 espie 1209: /* Keep track of another parent to which this beast is transformed so
1210: * the .IMPSRC variable can be set correctly for the parent. */
1.74 espie 1211: tGn->impliedsrc = sGn;
1.1 deraadt 1212:
1.66 espie 1213: return true;
1.1 deraadt 1214: }
1215:
1.70 espie 1216: static Suff *
1217: find_suffix_as_suffix(Lst l, const char *b, const char *e)
1218: {
1219: LstNode ln;
1220: Suff *s;
1221:
1222: for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) {
1223: s = (Suff *)Lst_Datum(ln);
1224: if (suffix_is_suffix(s, b, e))
1225: return s;
1226: }
1227: return NULL;
1228: }
1.1 deraadt 1229:
1230: /*-
1231: *-----------------------------------------------------------------------
1232: * SuffFindArchiveDeps --
1233: * Locate dependencies for an OP_ARCHV node.
1234: *
1235: * Side Effects:
1236: * Same as Suff_FindDeps
1237: *-----------------------------------------------------------------------
1238: */
1239: static void
1.51 espie 1240: SuffFindArchiveDeps(
1.70 espie 1241: GNode *gn, /* Node for which to locate dependencies */
1.51 espie 1242: Lst slst)
1.1 deraadt 1243: {
1.70 espie 1244: char *eoarch; /* End of archive portion */
1245: char *eoname; /* End of member portion */
1246: GNode *mem; /* Node for member */
1247: Suff *ms; /* Suffix descriptor for member */
1248: char *name; /* Start of member's name */
1.66 espie 1249:
1250: /* The node is an archive(member) pair. so we must find a suffix
1251: * for both of them. */
1252: eoarch = strchr(gn->name, '(');
1253: if (eoarch == NULL)
1254: return;
1255:
1256: name = eoarch + 1;
1257:
1258: eoname = strchr(name, ')');
1259: if (eoname == NULL)
1260: return;
1261:
1262: /* To simplify things, call Suff_FindDeps recursively on the member now,
1263: * so we can simply compare the member's .PREFIX and .TARGET variables
1264: * to locate its suffix. This allows us to figure out the suffix to
1265: * use for the archive without having to do a quadratic search over the
1266: * suffix list, backtracking for each one... */
1267: mem = Targ_FindNodei(name, eoname, TARG_CREATE);
1268: SuffFindDeps(mem, slst);
1269:
1270: /* Create the link between the two nodes right off. */
1.80 guenther 1271: if (Lst_AddNew(&gn->children, mem))
1272: SuffLinkParent(mem, gn);
1.66 espie 1273:
1274: /* Copy variables from member node to this one. */
1.76 espie 1275: Var(TARGET_INDEX, gn) = Var(TARGET_INDEX, mem);
1276: Var(PREFIX_INDEX, gn) = Var(PREFIX_INDEX, mem);
1.66 espie 1277:
1278: ms = mem->suffix;
1279: if (ms == NULL) {
1280: /* Didn't know what it was -- use .NULL suffix if not in make
1281: * mode. */
1282: if (DEBUG(SUFF))
1.81 espie 1283: printf("using empty suffix\n");
1284: ms = emptySuff;
1.66 espie 1285: }
1.5 millert 1286:
1.1 deraadt 1287:
1.66 espie 1288: /* Set the other two local variables required for this target. */
1.76 espie 1289: Var(MEMBER_INDEX, gn) = mem->name;
1290: Var(ARCHIVE_INDEX, gn) = gn->name;
1.1 deraadt 1291:
1.66 espie 1292: if (ms != NULL) {
1293: /*
1294: * Member has a known suffix, so look for a transformation rule
1295: * from it to a possible suffix of the archive. Rather than
1296: * searching through the entire list, we just look at suffixes
1297: * to which the member's suffix may be transformed...
1298: */
1.1 deraadt 1299:
1.70 espie 1300: Suff *suff;
1.1 deraadt 1301:
1.70 espie 1302: suff = find_suffix_as_suffix(&ms->parents, gn->name, eoarch);
1303:
1304: if (suff != NULL) {
1.66 espie 1305: /* Got one -- apply it. */
1.70 espie 1306: if (!SuffApplyTransform(gn, mem, suff, ms) &&
1307: DEBUG(SUFF))
1.66 espie 1308: printf("\tNo transformation from %s -> %s\n",
1.70 espie 1309: ms->name, suff->name);
1.66 espie 1310: }
1.1 deraadt 1311: }
1312:
1.66 espie 1313: /* Pretend gn appeared to the left of a dependency operator so
1314: * the user needn't provide a transformation from the member to the
1315: * archive. */
1316: if (OP_NOP(gn->type))
1317: gn->type |= OP_DEPENDS;
1318:
1319: /* Flag the member as such so we remember to look in the archive for
1320: * its modification time. */
1321: mem->type |= OP_MEMBER;
1.1 deraadt 1322: }
1323:
1.70 espie 1324: static void
1325: record_possible_suffix(Suff *s, GNode *gn, char *eoname, Lst srcs, Lst targs)
1326: {
1327: int prefLen;
1328: Src *targ;
1329: char *sopref = gn->name;
1330:
1331: targ = emalloc(sizeof(Src));
1332: targ->file = estrdup(gn->name);
1333: targ->suff = s;
1334: targ->node = gn;
1335: targ->parent = NULL;
1336: targ->children = 0;
1337: #ifdef DEBUG_SRC
1338: Lst_Init(&targ->cp);
1339: #endif
1340:
1341: /* Allocate room for the prefix, whose end is found by
1342: * subtracting the length of the suffix from the end of
1343: * the name. */
1344: prefLen = (eoname - targ->suff->nameLen) - sopref;
1345: targ->pref = emalloc(prefLen + 1);
1346: memcpy(targ->pref, sopref, prefLen);
1347: targ->pref[prefLen] = '\0';
1348:
1349: /* Add nodes from which the target can be made. */
1350: SuffAddLevel(srcs, targ);
1351:
1352: /* Record the target so we can nuke it. */
1353: Lst_AtEnd(targs, targ);
1354: }
1355:
1356: static void
1357: record_possible_suffixes(GNode *gn, Lst srcs, Lst targs)
1358: {
1359: char *s = gn->name;
1360: char *e = s + strlen(s);
1361: const char *p;
1362: uint32_t hv;
1363: unsigned int slot;
1364: Suff *suff;
1365:
1366: if (e == s)
1367: return;
1368:
1369: p = e;
1370: hv = *--p;
1371:
1372: while (p != s) {
1373: slot = ohash_lookup_interval(&suffixes, p, e, hv);
1374: suff = ohash_find(&suffixes, slot);
1.72 espie 1375: if (suff != NULL && (suff->flags & SUFF_ACTIVE))
1.70 espie 1376: record_possible_suffix(suff, gn, e, srcs, targs);
1377: if (e - p >= (ptrdiff_t)maxLen)
1378: break;
1379: reverse_hash_add_char(&hv, --p);
1380: }
1381: }
1382:
1.1 deraadt 1383: /*-
1384: *-----------------------------------------------------------------------
1385: * SuffFindNormalDeps --
1386: * Locate implicit dependencies for regular targets.
1387: *
1388: * Side Effects:
1389: * Same as Suff_FindDeps...
1390: *-----------------------------------------------------------------------
1391: */
1392: static void
1.51 espie 1393: SuffFindNormalDeps(
1394: GNode *gn, /* Node for which to find sources */
1395: Lst slst)
1.1 deraadt 1396: {
1.70 espie 1397: LIST srcs; /* List of sources at which to look */
1398: LIST targs; /* List of targets to which things can be
1399: * transformed. They all have the same file,
1400: * but different suff and pref fields */
1401: Src *bottom; /* Start of found transformation path */
1402: Src *src; /* General Src pointer */
1403: char *pref; /* Prefix to use */
1404: Src *targ; /* General Src target pointer */
1.66 espie 1405:
1406:
1407: Lst_Init(&srcs);
1408: Lst_Init(&targs);
1409:
1410: /* We're caught in a catch-22 here. On the one hand, we want to use any
1411: * transformation implied by the target's sources, but we can't examine
1412: * the sources until we've expanded any variables/wildcards they may
1413: * hold, and we can't do that until we've set up the target's local
1414: * variables and we can't do that until we know what the proper suffix
1415: * for the target is (in case there are two suffixes one of which is a
1416: * suffix of the other) and we can't know that until we've found its
1417: * implied source, which we may not want to use if there's an existing
1418: * source that implies a different transformation.
1419: *
1420: * In an attempt to get around this, which may not work all the time,
1421: * but should work most of the time, we look for implied sources first,
1422: * checking transformations to all possible suffixes of the target, use
1423: * what we find to set the target's local variables, expand the
1424: * children, then look for any overriding transformations they imply.
1425: * Should we find one, we discard the one we found before. */
1426:
1.1 deraadt 1427:
1.70 espie 1428: record_possible_suffixes(gn, &srcs, &targs);
1.66 espie 1429: /* Handle target of unknown suffix... */
1.75 espie 1430: if (Lst_IsEmpty(&srcs)) {
1.70 espie 1431: if (DEBUG(SUFF))
1.81 espie 1432: printf("\tNo known suffix on %s. Using empty suffix\n",
1.66 espie 1433: gn->name);
1.5 millert 1434:
1.66 espie 1435: targ = emalloc(sizeof(Src));
1436: targ->file = estrdup(gn->name);
1.81 espie 1437: targ->suff = emptySuff;
1.66 espie 1438: targ->node = gn;
1439: targ->parent = NULL;
1440: targ->children = 0;
1.70 espie 1441: targ->pref = estrdup(gn->name);
1.1 deraadt 1442: #ifdef DEBUG_SRC
1.66 espie 1443: Lst_Init(&targ->cp);
1.1 deraadt 1444: #endif
1445:
1.66 espie 1446: /* Only use the default suffix rules if we don't have commands
1447: * or dependencies defined for this gnode. */
1448: if (Lst_IsEmpty(&gn->commands) && Lst_IsEmpty(&gn->children))
1449: SuffAddLevel(&srcs, targ);
1450: else {
1451: if (DEBUG(SUFF))
1452: printf("not ");
1453: }
1.1 deraadt 1454:
1.66 espie 1455: if (DEBUG(SUFF))
1456: printf("adding suffix rules\n");
1.1 deraadt 1457:
1.66 espie 1458: Lst_AtEnd(&targs, targ);
1459: }
1.5 millert 1460:
1.66 espie 1461: /* Using the list of possible sources built up from the target
1462: * suffix(es), try and find an existing file/target that matches. */
1463: bottom = SuffFindThem(&srcs, slst);
1464:
1465: if (bottom == NULL) {
1466: /* No known transformations -- use the first suffix found for
1467: * setting the local variables. */
1468: if (!Lst_IsEmpty(&targs))
1469: targ = (Src *)Lst_Datum(Lst_First(&targs));
1470: else
1471: targ = NULL;
1472: } else {
1473: /* Work up the transformation path to find the suffix of the
1474: * target to which the transformation was made. */
1475: for (targ = bottom; targ->parent != NULL; targ = targ->parent)
1476: continue;
1477: }
1478:
1479: /* The .TARGET variable we always set to be the name at this point,
1480: * since it's only set to the path if the thing is only a source and
1481: * if it's only a source, it doesn't matter what we put here as far
1482: * as expanding sources is concerned, since it has none... */
1.76 espie 1483: Var(TARGET_INDEX, gn) = gn->name;
1.66 espie 1484:
1.76 espie 1485: pref = targ != NULL ? estrdup(targ->pref) : gn->name;
1486: Var(PREFIX_INDEX, gn) = pref;
1.66 espie 1487:
1488: /* Now we've got the important local variables set, expand any sources
1489: * that still contain variables or wildcards in their names. */
1.77 espie 1490: expand_all_children(gn);
1.66 espie 1491:
1492: if (targ == NULL) {
1493: if (DEBUG(SUFF))
1494: printf("\tNo valid suffix on %s\n", gn->name);
1.1 deraadt 1495:
1496: sfnd_abort:
1.70 espie 1497: /* Deal with finding the thing on the default search path if the
1498: * node is only a source (not on the lhs of a dependency operator
1499: * or [XXX] it has neither children or commands). */
1.66 espie 1500: if (OP_NOP(gn->type) ||
1.67 espie 1501: (Lst_IsEmpty(&gn->children) &&
1.66 espie 1502: Lst_IsEmpty(&gn->commands))) {
1503: gn->path = Dir_FindFile(gn->name,
1504: (targ == NULL ? defaultPath :
1505: &targ->suff->searchPath));
1506: if (gn->path != NULL) {
1507: char *ptr;
1.76 espie 1508: Var(TARGET_INDEX, gn) = estrdup(gn->path);
1.66 espie 1509:
1510: if (targ != NULL) {
1511: /* Suffix known for the thing -- trim
1512: * the suffix off the path to form the
1513: * proper .PREFIX variable. */
1.67 espie 1514: int savep = strlen(gn->path) -
1.66 espie 1515: targ->suff->nameLen;
1516: char savec;
1517:
1518: gn->suffix = targ->suff;
1519:
1520: savec = gn->path[savep];
1521: gn->path[savep] = '\0';
1522:
1.70 espie 1523: if ((ptr = strrchr(gn->path, '/')) !=
1524: NULL)
1.66 espie 1525: ptr++;
1526: else
1527: ptr = gn->path;
1528:
1.76 espie 1529: Var(PREFIX_INDEX, gn) = estrdup(ptr);
1.66 espie 1530:
1531: gn->path[savep] = savec;
1532: } else {
1.70 espie 1533: /* The .PREFIX gets the full path if the
1534: * target has no known suffix. */
1.66 espie 1535: gn->suffix = NULL;
1536:
1.70 espie 1537: if ((ptr = strrchr(gn->path, '/')) !=
1538: NULL)
1.66 espie 1539: ptr++;
1540: else
1541: ptr = gn->path;
1542:
1.76 espie 1543: Var(PREFIX_INDEX, gn) = estrdup(ptr);
1.66 espie 1544: }
1545: }
1546: } else {
1547: /* Not appropriate to search for the thing -- set the
1548: * path to be the name so Dir_MTime won't go grovelling
1549: * for it. */
1550: gn->suffix = targ == NULL ? NULL : targ->suff;
1551: efree(gn->path);
1552: gn->path = estrdup(gn->name);
1553: }
1.1 deraadt 1554:
1.66 espie 1555: goto sfnd_return;
1556: }
1.2 deraadt 1557:
1.66 espie 1558: /* Check for overriding transformation rule implied by sources. */
1559: if (!Lst_IsEmpty(&gn->children)) {
1560: src = SuffFindCmds(targ, slst);
1561:
1562: if (src != NULL) {
1563: /* Free up all the Src structures in the transformation
1564: * path up to, but not including, the parent node. */
1565: while (bottom && bottom->parent != NULL) {
1566: (void)Lst_AddNew(slst, bottom);
1567: bottom = bottom->parent;
1568: }
1569: bottom = src;
1.1 deraadt 1570: }
1571: }
1.5 millert 1572:
1.66 espie 1573: if (bottom == NULL) {
1574: /* No idea from where it can come -- return now. */
1575: goto sfnd_abort;
1576: }
1577:
1578: /* We now have a list of Src structures headed by 'bottom' and linked
1579: * via their 'parent' pointers. What we do next is create links between
1580: * source and target nodes (which may or may not have been created) and
1581: * set the necessary local variables in each target. The commands for
1582: * each target are set from the commands of the transformation rule
1583: * used to get from the src suffix to the targ suffix. Note that this
1584: * causes the commands list of the original node, gn, to be replaced by
1585: * the commands of the final transformation rule. Also, the unmade
1586: * field of gn is incremented. Etc. */
1587: if (bottom->node == NULL) {
1588: bottom->node = Targ_FindNode(bottom->file, TARG_CREATE);
1.1 deraadt 1589: }
1590:
1.66 espie 1591: for (src = bottom; src->parent != NULL; src = src->parent) {
1592: targ = src->parent;
1.1 deraadt 1593:
1.66 espie 1594: src->node->suffix = src->suff;
1.5 millert 1595:
1.66 espie 1596: if (targ->node == NULL) {
1597: targ->node = Targ_FindNode(targ->file, TARG_CREATE);
1598: }
1.1 deraadt 1599:
1.70 espie 1600: SuffApplyTransform(targ->node, src->node,
1601: targ->suff, src->suff);
1.1 deraadt 1602:
1.66 espie 1603: if (targ->node != gn) {
1604: /* Finish off the dependency-search process for any
1605: * nodes between bottom and gn (no point in questing
1606: * around the filesystem for their implicit source when
1607: * it's already known). Note that the node can't have
1608: * any sources that need expanding, since SuffFindThem
1609: * will stop on an existing node, so all we need to do
1610: * is set the standard and System V variables. */
1611: targ->node->type |= OP_DEPS_FOUND;
1.1 deraadt 1612:
1.76 espie 1613: Var(PREFIX_INDEX, targ->node) = estrdup(targ->pref);
1.1 deraadt 1614:
1.76 espie 1615: Var(TARGET_INDEX, targ->node) = targ->node->name;
1.66 espie 1616: }
1.1 deraadt 1617: }
1618:
1.66 espie 1619: gn->suffix = src->suff;
1.1 deraadt 1620:
1.66 espie 1621: /* So Dir_MTime doesn't go questing for it... */
1622: efree(gn->path);
1623: gn->path = estrdup(gn->name);
1.1 deraadt 1624:
1.66 espie 1625: /* Nuke the transformation path and the Src structures left over in the
1626: * two lists. */
1.1 deraadt 1627: sfnd_return:
1.66 espie 1628: if (bottom)
1629: (void)Lst_AddNew(slst, bottom);
1.1 deraadt 1630:
1.66 espie 1631: while (SuffRemoveSrc(&srcs) || SuffRemoveSrc(&targs))
1632: continue;
1.1 deraadt 1633:
1.66 espie 1634: Lst_ConcatDestroy(slst, &srcs);
1635: Lst_ConcatDestroy(slst, &targs);
1.1 deraadt 1636: }
1.5 millert 1637:
1638:
1.1 deraadt 1639: /*-
1640: *-----------------------------------------------------------------------
1641: * Suff_FindDeps --
1642: * Find implicit sources for the target described by the graph node
1643: * gn
1644: *
1645: * Side Effects:
1646: * Nodes are added to the graph below the passed-in node. The nodes
1647: * are marked to have their IMPSRC variable filled in. The
1648: * PREFIX variable is set for the given node and all its
1649: * implied children.
1650: *
1651: * Notes:
1652: * The path found by this target is the shortest path in the
1653: * transformation graph, which may pass through non-existent targets,
1654: * to an existing target. The search continues on all paths from the
1655: * root suffix until a file is found. I.e. if there's a path
1656: * .o -> .c -> .l -> .l,v from the root and the .l,v file exists but
1657: * the .c and .l files don't, the search will branch out in
1658: * all directions from .o and again from all the nodes on the
1659: * next level until the .l,v node is encountered.
1660: *-----------------------------------------------------------------------
1661: */
1662:
1663: void
1.51 espie 1664: Suff_FindDeps(GNode *gn)
1.1 deraadt 1665: {
1.5 millert 1666:
1.66 espie 1667: SuffFindDeps(gn, &srclist);
1668: while (SuffRemoveSrc(&srclist))
1669: continue;
1.1 deraadt 1670: }
1671:
1672:
1673: static void
1.51 espie 1674: SuffFindDeps(GNode *gn, Lst slst)
1.1 deraadt 1675: {
1.66 espie 1676: if (gn->type & OP_DEPS_FOUND) {
1677: /*
1678: * If dependencies already found, no need to do it again...
1679: */
1680: return;
1681: } else {
1682: gn->type |= OP_DEPS_FOUND;
1683: }
1.5 millert 1684:
1.70 espie 1685: if (DEBUG(SUFF))
1.66 espie 1686: printf("SuffFindDeps (%s)\n", gn->name);
1.5 millert 1687:
1.81 espie 1688: if (gn->type & OP_ARCHV)
1.66 espie 1689: SuffFindArchiveDeps(gn, slst);
1.81 espie 1690: else
1.66 espie 1691: SuffFindNormalDeps(gn, slst);
1.1 deraadt 1692: }
1693:
1694: /*-
1695: *-----------------------------------------------------------------------
1696: * Suff_Init --
1697: * Initialize suffixes module
1698: *
1699: * Side Effects:
1700: * Many
1701: *-----------------------------------------------------------------------
1702: */
1703: void
1.51 espie 1704: Suff_Init(void)
1.1 deraadt 1705: {
1.66 espie 1706: Static_Lst_Init(&srclist);
1.70 espie 1707: ohash_init(&transforms, 4, &gnode_info);
1.66 espie 1708:
1709: /*
1710: * Create null suffix for single-suffix rules (POSIX). The thing doesn't
1711: * actually go on the suffix list or everyone will think that's its
1712: * suffix.
1713: */
1.70 espie 1714: emptySuff = new_suffix("");
1715: make_suffix_known(emptySuff);
1716: Dir_Concat(&emptySuff->searchPath, defaultPath);
1717: ohash_init(&suffixes, 4, &suff_info);
1.72 espie 1718: order = 0;
1.70 espie 1719: clear_suffixes();
1720: special_path_hack();
1.1 deraadt 1721:
1722: }
1723:
1724:
1725: /********************* DEBUGGING FUNCTIONS **********************/
1726:
1.70 espie 1727: static void
1.81 espie 1728: SuffPrintName(void *p)
1.1 deraadt 1729: {
1.81 espie 1730: Suff *s = (Suff *)p;
1731: printf("%s ", s == emptySuff ? "<empty>" : s->name);
1.1 deraadt 1732: }
1733:
1.27 espie 1734: static void
1.51 espie 1735: SuffPrintSuff(void *sp)
1.1 deraadt 1736: {
1.66 espie 1737: Suff *s = (Suff *)sp;
1738:
1.81 espie 1739: printf("# %-5s ", s->name);
1.66 espie 1740:
1.81 espie 1741: if (!Lst_IsEmpty(&s->parents)) {
1742: printf(" ->");
1743: Lst_Every(&s->parents, SuffPrintName);
1744: }
1745: if (!Lst_IsEmpty(&s->children)) {
1746: printf(" <-");
1747: Lst_Every(&s->children, SuffPrintName);
1.1 deraadt 1748: }
1.66 espie 1749: fputc('\n', stdout);
1.1 deraadt 1750: }
1751:
1.27 espie 1752: static void
1.70 espie 1753: SuffPrintTrans(GNode *t)
1.1 deraadt 1754: {
1.66 espie 1755: printf("%-16s: ", t->name);
1756: Targ_PrintType(t->type);
1757: fputc('\n', stdout);
1758: Lst_Every(&t->commands, Targ_PrintCmd);
1759: fputc('\n', stdout);
1.1 deraadt 1760: }
1761:
1.81 espie 1762: static int
1763: compare_order(const void *a, const void *b)
1764: {
1765: const Suff **pa = (const Suff **)a;
1766: const Suff **pb = (const Suff **)b;
1767: return (*pb)->order - (*pa)->order;
1768: }
1769:
1770: static void
1771: print_path(Suff *s)
1772: {
1773: /* do we need to print it ? compare against defaultPath */
1774: LstNode ln1, ln2;
1775: bool first = true;
1776:
1777: for (ln1 = Lst_First(&s->searchPath), ln2 = Lst_First(defaultPath);
1778: ln1 != NULL && ln2 != NULL;
1779: ln1 = Lst_Adv(ln1)) {
1780: if (Lst_Datum(ln1) == Lst_Datum(ln2)) {
1781: ln2 = Lst_Adv(ln2);
1782: continue;
1783: }
1784: if (first) {
1785: printf(".PATH%s:", s->name);
1786: first = false;
1787: }
1788: printf(" %s", PathEntry_name(Lst_Datum(ln1)));
1789: }
1790: if (!first)
1791: printf("\n\n");
1792: }
1793:
1.1 deraadt 1794: void
1.51 espie 1795: Suff_PrintAll(void)
1.1 deraadt 1796: {
1.81 espie 1797: Suff **t;
1798: GNode **u;
1.70 espie 1799: unsigned int i;
1.81 espie 1800: bool reprint;
1.70 espie 1801:
1802:
1.81 espie 1803: printf("# Suffixes graph\n");
1804: t = sort_ohash_by_name(&suffixes);
1805: for (i = 0; t[i] != NULL; i++)
1806: if (!(t[i]->flags & SUFF_PATH))
1807: SuffPrintSuff(t[i]);
1808:
1809: printf("\n.PATH: ");
1810: Dir_PrintPath(defaultPath);
1811: printf("\n\n");
1812: for (i = 0; t[i] != NULL; i++)
1813: if (!(t[i]->flags & SUFF_PATH))
1814: print_path(t[i]);
1815: free(t);
1816:
1817: reprint = false;
1818: t = sort_ohash(&suffixes, compare_order);
1819: printf(".SUFFIXES:");
1820: for (i = 0; t[i] != NULL; i++) {
1821: if (t[i]->flags & SUFF_PATH)
1822: continue;
1823: printf(" %s", t[i]->name);
1824: if (!(t[i]->flags & SUFF_ACTIVE))
1825: reprint = true;
1826: }
1827: printf("\n\n");
1828: u = sort_ohash_by_name(&transforms);
1829: for (i = 0; u[i] != NULL; i++)
1830: SuffPrintTrans(u[i]);
1831: free(u);
1832:
1833: if (reprint) {
1834: printf(".SUFFIXES:");
1835: for (i = 0; t[i] != NULL; i++)
1836: if (t[i]->flags & SUFF_ACTIVE)
1837: printf(" %s", t[i]->name);
1838: printf("\n");
1839: }
1840: free(t);
1.1 deraadt 1841: }
1.42 espie 1842:
1843: #ifdef DEBUG_SRC
1844: static void
1.51 espie 1845: PrintAddr(void *a)
1.42 espie 1846: {
1.66 espie 1847: printf("%lx ", (unsigned long)a);
1.42 espie 1848: }
1849: #endif