version 1.69, 2007/09/17 11:43:12 |
version 1.70, 2007/09/17 12:42:09 |
|
|
* |
* |
* Suff_End Cleanup the module |
* Suff_End Cleanup the module |
* |
* |
* Suff_DoPaths This function is used to make life easier |
|
* when searching for a file according to its |
|
* suffix. It takes the global search path, |
|
* as defined using the .PATH: target, and appends |
|
* its directories to the path of each of the |
|
* defined suffixes, as specified using |
|
* .PATH<suffix>: targets. In addition, all |
|
* directories given for suffixes labeled as |
|
* include files or libraries, using the .INCLUDES |
|
* or .LIBS targets, are played with using |
|
* Dir_MakeFlags to create the .INCLUDES and |
|
* .LIBS global variables. |
|
* |
|
* Suff_ClearSuffixes Clear out all the suffixes and defined |
* Suff_ClearSuffixes Clear out all the suffixes and defined |
* transformations. |
* transformations. |
* |
* |
* Suff_IsTransform Return true if the passed string is the lhs |
|
* of a transformation rule. |
|
* |
|
* Suff_AddSuffix Add the passed string as another known suffix. |
* Suff_AddSuffix Add the passed string as another known suffix. |
* |
* |
* Suff_GetPath Return the search path for the given suffix. |
* Suff_GetPath Return the search path for the given suffix. |
|
|
* |
* |
* Suff_AddLib Mark the given suffix as denoting a library. |
* Suff_AddLib Mark the given suffix as denoting a library. |
* |
* |
* Suff_AddTransform Add another transformation to the suffix |
* Suff_ParseAsTransform Line might be a suffix line, check it. |
* graph. Returns GNode suitable for framing, I |
* If it's not, return NULL. Otherwise, add |
* mean, tacking commands, attributes, etc. on. |
* another transformation to the suffix graph. |
|
* Returns GNode suitable for framing, I mean, |
|
* tacking commands, attributes, etc. on. |
* |
* |
* Suff_SetNull Define the suffix to consider the suffix of |
* Suff_SetNull Define the suffix to consider the suffix of |
* any file that doesn't have a known one. |
* any file that doesn't have a known one. |
|
|
* if the target had no implicit sources. |
* if the target had no implicit sources. |
*/ |
*/ |
|
|
|
/* The suffix specifications are *really weird* |
|
* Here is how it works: |
|
* - each time you encounter a .SUFFIX: .s1 .s2 .s3 |
|
* you add the suffixes to the list of known suffixes, keeping it ordered. |
|
* - when you see a |
|
* .s1.s2: |
|
* line, you match it against the known suffixes at this point, and it |
|
* is tagged as a transform rule. |
|
* - when you encounter a .SUFFIX: |
|
* you reset the list of suffixes to empty, but you keep all the transforms |
|
* around. |
|
* - at the end of all Makefiles, you match recognized transforms against |
|
* suffixes existing at this point. |
|
* |
|
* The description of SusV3 is really sketchy, but this is how make works, |
|
* gmake works that way as well. |
|
* |
|
* The only difference is that gmake keeps its transform rules on the main |
|
* target list, so if you define two suffixes and a transform, then resets |
|
* the suffix and define a normal rule with the same name, you'll override |
|
* the transform. |
|
*/ |
#include <ctype.h> |
#include <ctype.h> |
#include <stdio.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <stdlib.h> |
|
#include <stdint.h> |
|
#include <stddef.h> |
#include <string.h> |
#include <string.h> |
|
#include <ohash.h> |
#include "config.h" |
#include "config.h" |
#include "defines.h" |
#include "defines.h" |
#include "dir.h" |
#include "dir.h" |
#include "direxpand.h" |
#include "direxpand.h" |
|
#include "engine.h" |
#include "arch.h" |
#include "arch.h" |
#include "suff.h" |
#include "suff.h" |
#include "var.h" |
#include "var.h" |
|
|
#include "lst.h" |
#include "lst.h" |
#include "memory.h" |
#include "memory.h" |
#include "gnode.h" |
#include "gnode.h" |
|
#include "make.h" |
#include "stats.h" |
#include "stats.h" |
#include "engine.h" |
|
|
|
static LIST sufflist; /* Lst of suffixes */ |
static struct ohash suffixes; /* hash of suffixes */ |
#ifdef CLEANUP |
size_t maxLen; /* optimization: remember longest suffix */ |
static LIST suffClean; /* Lst of suffixes to be cleaned */ |
|
#endif |
|
static LIST srclist; /* Lst of sources */ |
static LIST srclist; /* Lst of sources */ |
static LIST transforms; /* Lst of transformation rules */ |
static struct ohash transforms; |
|
|
static int sNum = 0; /* Counter for assigning suffix numbers */ |
static int sNum = 0; /* Counter for assigning suffix numbers */ |
|
|
|
|
* Structure describing an individual suffix. |
* Structure describing an individual suffix. |
*/ |
*/ |
typedef struct Suff_ { |
typedef struct Suff_ { |
char *name; /* The suffix itself */ |
size_t nameLen; /* Length of the suffix */ |
int nameLen; /* Length of the suffix */ |
short flags; /* Type of suffix */ |
short flags; /* Type of suffix */ |
#define SUFF_INCLUDE 0x01 /* One which is #include'd */ |
#define SUFF_INCLUDE 0x01 /* One which is #include'd */ |
#define SUFF_LIBRARY 0x02 /* One which contains a library */ |
#define SUFF_LIBRARY 0x02 /* One which contains a library */ |
#define SUFF_NULL 0x04 /* The empty suffix */ |
#define SUFF_NULL 0x04 /* The empty suffix */ |
#define SUFF_EXISTS 0x08 /* So that we don't have to destroy them */ |
LIST searchPath; /* The path along which files of this suffix |
#define SUFF_PATH 0x10 /* False suffix: actually, the path keyword */ |
* may be found */ |
LIST searchPath; /* The path along which files of this suffix |
int sNum; /* The suffix number */ |
* may be found */ |
LIST parents; /* Suffixes we have a transformation to */ |
int sNum; /* The suffix number */ |
LIST children; /* Suffixes we have a transformation from */ |
LIST parents; /* Suffixes we have a transformation to */ |
LIST ref; /* List of lists this suffix is referenced */ |
LIST children; /* Suffixes we have a transformation from */ |
|
char name[1]; /* The suffix itself */ |
} Suff; |
} Suff; |
|
|
|
static struct ohash_info suff_info = { |
|
offsetof(struct Suff_, name), NULL, hash_alloc, hash_free, element_alloc |
|
}; |
|
|
/* |
/* |
* Structure used in the search for implied sources. |
* Structure used in the search for implied sources. |
*/ |
*/ |
typedef struct Src_ { |
typedef struct Src_ { |
char *file; /* The file to look for */ |
char *file; /* The file to look for */ |
char *pref; /* Prefix from which file was formed */ |
char *pref; /* Prefix from which file was formed */ |
Suff *suff; /* The suffix on the file */ |
Suff *suff; /* The suffix on the file */ |
struct Src_ *parent; /* The Src for which this is a source */ |
struct Src_ *parent; /* The Src for which this is a source */ |
GNode *node; /* The node describing the file */ |
GNode *node; /* The node describing the file */ |
int children; /* Count of existing children (so we don't free |
int children; /* Count of existing children (so we don't free |
* this thing too early or never nuke it) */ |
* this thing too early or never nuke it) */ |
#ifdef DEBUG_SRC |
#ifdef DEBUG_SRC |
LIST cp; /* Debug; children list */ |
LIST cp; /* Debug; children list */ |
#endif |
#endif |
} Src; |
} Src; |
|
|
|
|
* function... |
* function... |
*/ |
*/ |
typedef struct { |
typedef struct { |
Lst l; |
Lst l; |
Src *s; |
Src *s; |
} LstSrc; |
} LstSrc; |
|
|
static Suff *suffNull; /* The NULL suffix for this run */ |
static Suff *suffNull; /* The NULL suffix for this run */ |
static Suff *emptySuff; /* The empty suffix required for POSIX |
static Suff *emptySuff; /* The empty suffix required for POSIX |
* single-suffix transformation rules */ |
* single-suffix transformation rules */ |
|
|
|
|
static char *SuffStrIsPrefix(const char *, const char *); |
static void build_path_variable(struct ohash *, int, const char *, const char *); |
static char *SuffSuffIsSuffix(Suff *, const char *); |
static void add_property(const char *, const char *, int); |
static int SuffSuffIsSuffixP(void *, const void *); |
#define parse_transform(s, p, q) parse_transformi(s, s + strlen(s), p, q) |
static int SuffSuffIsPrefix(void *, const void *); |
static bool parse_transformi(const char *, const char *, Suff **, Suff **); |
static int SuffHasNameP(void *, const void *); |
#define new_suffix(s) new_suffixi(s, NULL) |
static int GNodeHasNameP(void *, const void *); |
static Suff *new_suffixi(const char *, const char *); |
static void SuffUnRef(Lst, Suff *); |
static void reverse_hash_add_char(uint32_t *, const char *); |
|
static uint32_t reverse_hashi(const char *, const char **); |
|
static unsigned int reverse_slot(struct ohash *, const char *, const char **); |
|
static void clear_suffixes(void); |
|
static void record_possible_suffix(Suff *, GNode *, char *, Lst, Lst); |
|
static void record_possible_suffixes(GNode *, Lst, Lst); |
|
static Suff *find_suffix_as_suffix(Lst, const char *, const char *); |
|
static Suff *add_suffixi(const char *, const char *); |
|
|
#ifdef CLEANUP |
#ifdef CLEANUP |
static void SuffFree(void *); |
static void SuffFree(void *); |
#endif |
#endif |
static void SuffInsert(Lst, Suff *); |
static void SuffInsert(Lst, Suff *); |
static bool SuffParseTransform(const char *, Suff **, Suff **); |
|
static void SuffRebuildGraph(void *, void *); |
|
static void SuffAddSrc(void *, void *); |
static void SuffAddSrc(void *, void *); |
static int SuffRemoveSrc(Lst); |
static int SuffRemoveSrc(Lst); |
static void SuffAddLevel(Lst, Src *); |
static void SuffAddLevel(Lst, Src *); |
|
|
static void SuffFindNormalDeps(GNode *, Lst); |
static void SuffFindNormalDeps(GNode *, Lst); |
static void SuffPrintName(void *); |
static void SuffPrintName(void *); |
static void SuffPrintSuff(void *); |
static void SuffPrintSuff(void *); |
static void SuffPrintTrans(void *); |
static void SuffPrintTrans(GNode *); |
|
|
static LstNode suff_find_by_name(const char *); |
#define find_suff(name) find_suffi(name, NULL) |
static LstNode transform_find_by_name(const char *); |
static Suff *find_suffi(const char *, const char *); |
|
static Suff *find_best_suffix(const char *, const char *); |
|
static GNode *find_transform(const char *); |
|
static GNode *find_or_create_transformi(const char *, const char *); |
|
static void setup_paths(void); |
|
static void build_suffixes_graph(void); |
|
static void special_path_hack(void); |
|
|
#ifdef DEBUG_SRC |
#ifdef DEBUG_SRC |
static void PrintAddr(void *); |
static void PrintAddr(void *); |
#endif |
#endif |
/*************** Lst Predicates ****************/ |
|
/*- |
/* we usually look at suffixes `backwards', which makes it necessary for |
*----------------------------------------------------------------------- |
* us to have a specific hash function that proceeds backwards. |
* SuffStrIsPrefix -- |
|
* See if prefix is a prefix of str. |
|
* |
|
* Results: |
|
* NULL if it ain't, pointer to character in str after prefix if so |
|
*----------------------------------------------------------------------- |
|
*/ |
*/ |
static char * |
|
SuffStrIsPrefix(const char *prefix, const char *str) |
|
|
static void |
|
reverse_hash_add_char(uint32_t *pk, const char *s) |
{ |
{ |
while (*str && *prefix == *str) { |
*pk = ((*pk << 2) | (*pk >> 30)) ^ *s; |
prefix++; |
} |
str++; |
|
|
static uint32_t |
|
reverse_hashi(const char *s, const char **e) |
|
{ |
|
const char *p; |
|
uint32_t k; |
|
|
|
if (*e == NULL) |
|
*e = s + strlen(s); |
|
p = *e; |
|
if (p == s) |
|
k = 0; |
|
else |
|
k = *--p; |
|
while (p != s) { |
|
reverse_hash_add_char(&k, --p); |
} |
} |
|
return k; |
|
} |
|
|
return *prefix ? NULL : (char *)str; |
static unsigned int |
|
reverse_slot(struct ohash *h, const char *s, const char **e) |
|
{ |
|
uint32_t hv; |
|
|
|
hv = reverse_hashi(s, e); |
|
return ohash_lookup_interval(h, s, *e, hv); |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* SuffSuffIsSuffix -- |
|
* See if suff is a suffix of str. str should point to the end of the |
|
* string to check. |
|
* |
|
* Results: |
|
* NULL if it ain't, pointer to first character of suffix in str if |
|
* it is. |
|
*----------------------------------------------------------------------- |
|
*/ |
|
static char * |
static char * |
SuffSuffIsSuffix(Suff *s, const char *str) |
suffix_is_suffix(Suff *s, const char *str, const char *estr) |
{ |
{ |
const char *p1; /* Pointer into suffix name */ |
const char *p1; /* Pointer into suffix name */ |
const char *p2; /* Pointer into string being examined */ |
const char *p2; /* Pointer into string being examined */ |
|
|
|
if (estr - str < (ptrdiff_t) s->nameLen) |
|
return NULL; |
p1 = s->name + s->nameLen; |
p1 = s->name + s->nameLen; |
p2 = str; |
p2 = estr; |
|
|
while (p1 != s->name) { |
while (p1 != s->name) { |
p1--; |
p1--; |
|
|
return (char *)p2; |
return (char *)p2; |
} |
} |
|
|
/*- |
static Suff * |
*----------------------------------------------------------------------- |
find_suffi(const char *name, const char *ename) |
* SuffSuffIsSuffixP -- |
|
* Predicate form of SuffSuffIsSuffix. Passed as the callback function |
|
* to Lst_Find. |
|
* |
|
* Results: |
|
* 0 if the suffix is the one desired, non-zero if not. |
|
*----------------------------------------------------------------------- |
|
*/ |
|
static int |
|
SuffSuffIsSuffixP(void *s, const void *str) |
|
{ |
{ |
return !SuffSuffIsSuffix((Suff *)s, (const char *)str); |
unsigned int slot; |
|
#ifdef STATS_SUFF |
|
STAT_SUFF_LOOKUP_NAME++; |
|
#endif |
|
slot = reverse_slot(&suffixes, name, &ename); |
|
return ohash_find(&suffixes, slot); |
} |
} |
|
|
static int |
static GNode * |
SuffHasNameP(void *s, const void *sname) |
find_transform(const char *name) |
{ |
{ |
return strcmp((const char *)sname, ((Suff *)s)->name); |
unsigned int slot; |
} |
|
|
|
static LstNode |
|
suff_find_by_name(const char *name) |
|
{ |
|
#ifdef STATS_SUFF |
#ifdef STATS_SUFF |
STAT_SUFF_LOOKUP_NAME++; |
STAT_TRANSFORM_LOOKUP_NAME++; |
#endif |
#endif |
return Lst_FindConst(&sufflist, SuffHasNameP, name); |
slot = ohash_qlookup(&transforms, name); |
} |
|
|
|
static int |
return ohash_find(&transforms, slot); |
GNodeHasNameP(void *gn, const void *name) |
|
{ |
|
return strcmp((const char *)name, ((GNode *)gn)->name); |
|
} |
} |
|
|
static LstNode |
static GNode * |
transform_find_by_name(const char *name) |
find_or_create_transformi(const char *name, const char *end) |
{ |
{ |
|
GNode *r; |
|
unsigned int slot; |
|
|
#ifdef STATS_SUFF |
#ifdef STATS_SUFF |
STAT_TRANSFORM_LOOKUP_NAME++; |
STAT_TRANSFORM_LOOKUP_NAME++; |
#endif |
#endif |
return Lst_FindConst(&transforms, GNodeHasNameP, name); |
slot = ohash_qlookupi(&transforms, name, &end); |
} |
|
/*- |
|
*----------------------------------------------------------------------- |
|
* SuffSuffIsPrefix -- |
|
* See if the suffix described by s is a prefix of the string. Care |
|
* must be taken when using this to search for transformations and |
|
* what-not, since there could well be two suffixes, one of which |
|
* is a prefix of the other... |
|
* |
|
* Results: |
|
* 0 if s is a prefix of str. non-zero otherwise |
|
*----------------------------------------------------------------------- |
|
*/ |
|
static int |
|
SuffSuffIsPrefix(void *s, const void *str) |
|
{ |
|
return SuffStrIsPrefix(((Suff *)s)->name, |
|
(const char *)str) == NULL ? 1 : 0; |
|
} |
|
|
|
/*********** Maintenance Functions ************/ |
r = ohash_find(&transforms, slot); |
|
|
static void |
if (r == NULL) { |
SuffUnRef(Lst l, Suff *sp) |
r = Targ_NewGNi(name, end); |
{ |
ohash_insert(&transforms, slot, r); |
LstNode ln = Lst_Member(l, sp); |
} |
if (ln != NULL) |
return r; |
Lst_Remove(l, ln); |
} |
} |
|
|
|
#ifdef CLEANUP |
#ifdef CLEANUP |
/*- |
/*- |
|
|
static void |
static void |
SuffFree(void *sp) |
SuffFree(void *sp) |
{ |
{ |
Suff *s = (Suff *)sp; |
Suff *s = (Suff *)sp; |
|
|
if (s == suffNull) |
|
suffNull = NULL; |
|
|
|
if (s == emptySuff) |
if (s == emptySuff) |
emptySuff = NULL; |
emptySuff = NULL; |
|
|
Lst_Destroy(&s->ref, NOFREE); |
|
Lst_Destroy(&s->children, NOFREE); |
Lst_Destroy(&s->children, NOFREE); |
Lst_Destroy(&s->parents, NOFREE); |
Lst_Destroy(&s->parents, NOFREE); |
Lst_Destroy(&s->searchPath, Dir_Destroy); |
Lst_Destroy(&s->searchPath, Dir_Destroy); |
|
|
static void |
static void |
SuffInsert(Lst l, Suff *s) |
SuffInsert(Lst l, Suff *s) |
{ |
{ |
LstNode ln; /* current element in l we're examining */ |
LstNode ln; /* current element in l we're examining */ |
Suff *s2 = NULL; /* the suffix descriptor in this element */ |
Suff *s2 = NULL; /* the suffix descriptor in this element */ |
|
|
for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) { |
for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) { |
s2 = (Suff *)Lst_Datum(ln); |
s2 = (Suff *)Lst_Datum(ln); |
|
|
break; |
break; |
} |
} |
|
|
if (DEBUG(SUFF)) { |
if (DEBUG(SUFF)) |
printf("inserting %s(%d)...", s->name, s->sNum); |
printf("inserting %s(%d)...", s->name, s->sNum); |
} |
|
if (ln == NULL) { |
if (ln == NULL) { |
if (DEBUG(SUFF)) { |
if (DEBUG(SUFF)) |
printf("at end of list\n"); |
printf("at end of list\n"); |
} |
|
Lst_AtEnd(l, s); |
Lst_AtEnd(l, s); |
Lst_AtEnd(&s->ref, l); |
|
} else if (s2->sNum != s->sNum) { |
} else if (s2->sNum != s->sNum) { |
if (DEBUG(SUFF)) { |
if (DEBUG(SUFF)) |
printf("before %s(%d)\n", s2->name, s2->sNum); |
printf("before %s(%d)\n", s2->name, s2->sNum); |
} |
|
Lst_Insert(l, ln, s); |
Lst_Insert(l, ln, s); |
Lst_AtEnd(&s->ref, l); |
|
} else if (DEBUG(SUFF)) { |
} else if (DEBUG(SUFF)) { |
printf("already there\n"); |
printf("already there\n"); |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Suff_ClearSuffixes -- |
* Suff_ClearSuffixes -- |
* This is gross. Nuke the list of suffixes but keep all transformation |
* Nuke the list of suffixes but keep all transformation |
* rules around. The transformation graph is destroyed in this process, |
* rules around. |
* but we leave the list of rules so when a new graph is formed the rules |
|
* will remain. |
|
* This function is called from the parse module when a |
|
* .SUFFIXES:\n line is encountered. |
|
* |
* |
* Side Effects: |
* Side Effects: |
* the sufflist and its graph nodes are destroyed |
* Current suffixes are reset |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
static void |
Suff_ClearSuffixes(void) |
clear_suffixes(void) |
{ |
{ |
#ifdef CLEANUP |
unsigned int i; |
Lst_ConcatDestroy(&suffClean, &sufflist); |
Suff *s; |
#endif |
|
Lst_Init(&sufflist); |
for (s = ohash_first(&suffixes, &i); s != NULL; |
|
s = ohash_next(&suffixes, &i)) |
|
s->flags &= ~SUFF_EXISTS; |
|
|
sNum = 0; |
sNum = 0; |
|
maxLen = 0; |
suffNull = emptySuff; |
suffNull = emptySuff; |
} |
} |
|
|
/*- |
void |
*----------------------------------------------------------------------- |
Suff_ClearSuffixes(void) |
* SuffParseTransform -- |
{ |
* Parse a transformation string to find its two component suffixes. |
clear_suffixes(); |
* |
} |
* Results: |
|
* true if the string is a valid transformation and false otherwise. |
|
* |
/* okay = parse_transform(str, &src, &targ); |
* Side Effects: |
* try parsing a string as a transformation rule, returns true if |
* The passed pointers are overwritten. |
* successful. Fills &src, &targ with the constituent suffixes. |
*----------------------------------------------------------------------- |
* Special hack: source suffixes must exist OR be the special SUFF_PATH |
|
* pseudo suffix (.PATH) |
*/ |
*/ |
static bool |
static bool |
SuffParseTransform( |
parse_transformi(const char *str, const char *e, Suff **srcPtr, Suff **targPtr) |
const char *str, /* String being parsed */ |
|
Suff **srcPtr, /* Place to store source of trans. */ |
|
Suff **targPtr) /* Place to store target of trans. */ |
|
{ |
{ |
LstNode srcLn; /* element in suffix list of trans source*/ |
Suff *src, *target, *best_src, *best_target; |
Suff *src; /* Source of transformation */ |
const char *p; |
LstNode targLn; /* element in suffix list of trans target*/ |
|
const char *str2; /* Extra pointer (maybe target suffix) */ |
|
LstNode singleLn; /* element in suffix list of any suffix |
|
* that exactly matches str */ |
|
Suff *single = NULL;/* Source of possible transformation to |
|
* null suffix */ |
|
|
|
srcLn = NULL; |
size_t len; |
singleLn = NULL; |
uint32_t hv; |
|
unsigned int slot; |
|
|
/* |
/* empty string -> no suffix */ |
* Loop looking first for a suffix that matches the start of the |
if (e == str) |
* string and then for one that exactly matches the rest of it. If |
return false; |
* we can find two that meet these criteria, we've successfully |
|
* parsed the string. |
len = e - str; |
*/ |
|
for (;;) { |
if (len > 2 * maxLen) |
if (srcLn == NULL) |
return false; |
srcLn = Lst_FindConst(&sufflist, SuffSuffIsPrefix, str); |
|
else |
p = e; |
srcLn = Lst_FindFromConst(Lst_Succ(srcLn), |
best_src = best_target = NULL; |
SuffSuffIsPrefix, str); |
|
if (srcLn == NULL) { |
hv = *--p; |
/* |
while (p != str) { |
* Ran out of source suffixes -- no such rule |
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
*/ |
/* no double suffix in there */ |
if (singleLn != NULL) { |
if (p - str <= (ptrdiff_t)maxLen) { |
/* |
target = ohash_find(&suffixes, slot); |
* Not so fast Mr. Smith! There was a suffix |
if (target != NULL && (target->flags & SUFF_EXISTS)) { |
* that encompassed the entire string, so we |
src = find_suffi(str, p); |
* assume it was a transformation to the null |
if (src != NULL && |
* suffix (thank you POSIX). We still prefer to |
(src->flags & (SUFF_EXISTS | SUFF_PATH))) { |
* find a double rule over a singleton, hence |
/* XXX even if we find a set of suffixes, we |
* we leave this check until the end. |
* have to keep going to find the best one, |
* |
* namely, the one whose src appears first in |
* XXX: Use emptySuff over suffNull? |
* .SUFFIXES |
*/ |
*/ |
*srcPtr = single; |
if (best_src == NULL || |
*targPtr = suffNull; |
src->sNum < best_src->sNum) { |
return true; |
best_src = src; |
|
best_target = target; |
|
} |
|
} |
} |
} |
return false; |
|
} |
} |
src = (Suff *)Lst_Datum(srcLn); |
/* can't be a suffix anyways */ |
str2 = str + src->nameLen; |
if (e - p >= (ptrdiff_t)maxLen) |
if (*str2 == '\0') { |
break; |
single = src; |
reverse_hash_add_char(&hv, --p); |
singleLn = srcLn; |
} |
} else { |
|
targLn = suff_find_by_name(str2); |
if (p == str && best_src == NULL) { |
if (targLn != NULL) { |
/* no double suffix transformation, resort to single suffix if |
*srcPtr = src; |
* we find one. */ |
*targPtr = (Suff *)Lst_Datum(targLn); |
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
return true; |
src = ohash_find(&suffixes, slot); |
} |
if (src != NULL && (src->flags & (SUFF_EXISTS | SUFF_PATH))) { |
|
best_src = src; |
|
best_target = suffNull; |
} |
} |
} |
} |
|
if (best_src != NULL) { |
|
*srcPtr = best_src; |
|
*targPtr = best_target; |
|
return true; |
|
} else { |
|
return false; |
|
} |
} |
} |
|
|
/*- |
static void |
*----------------------------------------------------------------------- |
special_path_hack(void) |
* Suff_IsTransform -- |
|
* Return true if the given string is a transformation rule |
|
* |
|
* Results: |
|
* true if the string is a concatenation of two known suffixes. |
|
* false otherwise |
|
*----------------------------------------------------------------------- |
|
*/ |
|
bool |
|
Suff_IsTransform(const char *str) |
|
{ |
{ |
Suff *src, *targ; |
Suff *path = add_suffixi(".PATH", NULL); |
|
path->flags |= SUFF_PATH; |
|
} |
|
|
return SuffParseTransform(str, &src, &targ); |
static Suff * |
|
find_best_suffix(const char *s, const char *e) |
|
{ |
|
const char *p; |
|
uint32_t hv; |
|
unsigned int slot; |
|
Suff *best = NULL; |
|
Suff *suff; |
|
|
|
if (e == s) |
|
return NULL; |
|
p = e; |
|
hv = *--p; |
|
while (p != s) { |
|
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
|
suff = ohash_find(&suffixes, slot); |
|
if (suff != NULL) |
|
if (best == NULL || suff->sNum < best->sNum) |
|
best = suff; |
|
if (e - p >= (ptrdiff_t)maxLen) |
|
break; |
|
reverse_hash_add_char(&hv, --p); |
|
} |
|
return best; |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Suff_AddTransform -- |
* Suff_ParseAsTransform -- |
* Add the transformation rule described by the line to the |
* Try parsing a target line as a transformation rule, depending on |
* list of rules and place the transformation itself in the graph |
* existing suffixes. |
* |
* |
* Results: |
* Possibly create anew transform, or reset an existing one. |
* The node created for the transformation in the transforms list |
|
* |
|
* Side Effects: |
|
* The node is placed on the end of the transforms Lst and links are |
|
* made between the two suffixes mentioned in the target name |
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
GNode * |
GNode * |
Suff_AddTransform(const char *line) |
Suff_ParseAsTransform(const char *line, const char *end) |
{ |
{ |
GNode *gn; /* GNode of transformation rule */ |
GNode *gn; /* GNode of transformation rule */ |
Suff *s, /* source suffix */ |
Suff *s; /* source suffix */ |
*t; /* target suffix */ |
Suff *t; /* target suffix */ |
LstNode ln; /* Node for existing transformation */ |
|
|
|
ln = transform_find_by_name(line); |
if (!parse_transformi(line, end, &s, &t)) |
if (ln == NULL) { |
return NULL; |
/* |
|
* Make a new graph node for the transformation. It will be |
gn = find_or_create_transformi(line, end); |
* filled in by the Parse module. |
/* In case the transform already exists, nuke old commands and children. |
*/ |
* Note we can't free them, since there might be stuff that references |
gn = Targ_NewGN(line); |
* them elsewhere |
Lst_AtEnd(&transforms, gn); |
*/ |
} else { |
if (!Lst_IsEmpty(&gn->commands)) { |
/* |
|
* New specification for transformation rule. Just nuke the old |
|
* list of commands so they can be filled in again... We don't |
|
* actually free the commands themselves, because a given |
|
* command can be attached to several different |
|
* transformations. |
|
*/ |
|
gn = (GNode *)Lst_Datum(ln); |
|
Lst_Destroy(&gn->commands, NOFREE); |
Lst_Destroy(&gn->commands, NOFREE); |
Lst_Init(&gn->commands); |
Lst_Init(&gn->commands); |
|
} |
|
if (!Lst_IsEmpty(&gn->children)) { |
Lst_Destroy(&gn->children, NOFREE); |
Lst_Destroy(&gn->children, NOFREE); |
Lst_Init(&gn->children); |
Lst_Init(&gn->children); |
} |
} |
|
|
gn->type = OP_TRANSFORM; |
gn->type = OP_TRANSFORM; |
|
if (s->flags & SUFF_PATH) { |
|
gn->special = SPECIAL_PATH | SPECIAL_TARGET; |
|
gn->suffix = t; |
|
} |
|
|
(void)SuffParseTransform(line, &s, &t); |
if (DEBUG(SUFF)) |
|
|
/* |
|
* link the two together in the proper relationship and order |
|
*/ |
|
if (DEBUG(SUFF)) { |
|
printf("defining transformation from `%s' to `%s'\n", |
printf("defining transformation from `%s' to `%s'\n", |
s->name, t->name); |
s->name, t->name); |
|
return gn; |
|
} |
|
|
|
static void |
|
make_suffix_known(Suff *s) |
|
{ |
|
if ((s->flags & SUFF_EXISTS) == 0) { |
|
s->sNum = sNum++; |
|
s->flags |= SUFF_EXISTS; |
|
if (s->nameLen > maxLen) |
|
maxLen = s->nameLen; |
} |
} |
SuffInsert(&t->children, s); |
} |
SuffInsert(&s->parents, t); |
|
|
|
return gn; |
static Suff * |
|
new_suffixi(const char *str, const char *eptr) |
|
{ |
|
Suff *s; |
|
|
|
s = ohash_create_entry(&suff_info, str, &eptr); |
|
s->nameLen = eptr - str; |
|
Lst_Init(&s->searchPath); |
|
Lst_Init(&s->children); |
|
Lst_Init(&s->parents); |
|
s->flags = 0; |
|
return s; |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Suff_EndTransform -- |
* Suff_AddSuffix -- |
* Handle the finish of a transformation definition, removing the |
* Add the suffix in string to the end of the list of known suffixes. |
* transformation from the graph if it has neither commands nor |
* Should we restructure the suffix graph? Make doesn't... |
* sources. This is a callback procedure for the Parse module via |
|
* Lst_ForEach |
|
* |
* |
* Side Effects: |
* Side Effects: |
* If the node has no commands or children, the children and parents |
* A GNode is created for the suffix and a Suff structure is created and |
* lists of the affected suffices are altered. |
* added to the known suffixes, unless it was already known. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Suff_EndTransform(void *gnp) |
Suff_AddSuffixi(const char *str, const char *end) |
{ |
{ |
GNode *gn = (GNode *)gnp; |
(void)add_suffixi(str, end); |
|
} |
|
|
if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(&gn->commands) && |
static Suff * |
Lst_IsEmpty(&gn->children)) { |
add_suffixi(const char *str, const char *end) |
Suff *s, *t; |
{ |
|
Suff *s; /* new suffix descriptor */ |
|
|
if (!SuffParseTransform(gn->name, &s, &t)) |
unsigned int slot; |
return; |
|
|
|
if (DEBUG(SUFF)) { |
slot = reverse_slot(&suffixes, str, &end); |
printf("deleting transformation from `%s' to `%s'\n", |
s = ohash_find(&suffixes, slot); |
s->name, t->name); |
if (s == NULL) { |
} |
s = new_suffixi(str, end); |
|
ohash_insert(&suffixes, slot, s); |
/* |
|
* Remove the source from the target's children list. |
|
* |
|
* We'll be called twice when the next target is seen, but .c |
|
* and .o are only linked once... |
|
*/ |
|
SuffUnRef(&t->children, s); |
|
|
|
/* |
|
* Remove the target from the source's parents list |
|
*/ |
|
if (s != NULL) |
|
SuffUnRef(&s->parents, t); |
|
} else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) { |
|
printf("transformation %s complete\n", gn->name); |
|
} |
} |
|
make_suffix_known(s); |
|
return s; |
} |
} |
|
|
/*- |
Lst |
*----------------------------------------------------------------------- |
find_suffix_path(GNode *gn) |
* SuffRebuildGraph -- |
{ |
* Called from Suff_AddSuffix via Lst_ForEach to search through the |
if (gn->suffix != NULL && gn->suffix != emptySuff) |
* list of existing transformation rules and rebuild the transformation |
return &(gn->suffix->searchPath); |
* graph when it has been destroyed by Suff_ClearSuffixes. If the |
else |
* given rule is a transformation involving this suffix and another, |
return defaultPath; |
* existing suffix, the proper relationship is established between |
} |
* the two. |
|
* |
/* find out the tagged suffixes, build a temporary path, and construct |
* Side Effects: |
* a variable based on that. |
* The appropriate links will be made between this suffix and |
|
* others if transformation rules exist for it. |
|
*----------------------------------------------------------------------- |
|
*/ |
*/ |
static void |
static void |
SuffRebuildGraph( |
build_path_variable(struct ohash *h, int opt, const char *name, |
void *transformp, /* Transformation to test */ |
const char *flag) |
void *sp) /* Suffix to rebuild */ |
|
{ |
{ |
GNode *transform = (GNode *)transformp; |
char *value; |
Suff *s = (Suff *)sp; |
LIST path; |
char *cp; |
Suff *s; |
LstNode ln; |
unsigned int i; |
Suff *s2; |
|
|
|
/* First see if it is a transformation from this suffix. */ |
Lst_Init(&path); |
cp = SuffStrIsPrefix(s->name, transform->name); |
for (s = ohash_first(h, &i); s != NULL; s = ohash_next(h, &i)) { |
if (cp != NULL) { |
if (Lst_IsEmpty(&s->searchPath)) |
ln = suff_find_by_name(cp); |
continue; |
if (ln != NULL) { |
if (s->flags & opt) |
/* Found target. Link in and return, since it can't be |
Dir_Concat(&path, &s->searchPath); |
* anything else. */ |
|
s2 = (Suff *)Lst_Datum(ln); |
|
SuffInsert(&s2->children, s); |
|
SuffInsert(&s->parents, s2); |
|
return; |
|
} |
|
} |
} |
|
|
/* Not from, maybe to? */ |
value = Dir_MakeFlags(flag, &path); |
cp = SuffSuffIsSuffix(s, transform->name + strlen(transform->name)); |
Var_Set(name, value); |
if (cp != NULL) { |
free(value); |
/* Null-terminate the source suffix in order to find it. */ |
Lst_Destroy(&path, Dir_Destroy); |
*cp = '\0'; |
} |
ln = suff_find_by_name(transform->name); |
|
/* Replace the start of the target suffix. */ |
static void |
*cp = s->name[0]; |
add_property(const char *sname, const char *end, int opt) |
if (ln != NULL) { |
{ |
/* Found it -- establish the proper relationship. */ |
Suff *s; |
s2 = (Suff *)Lst_Datum(ln); |
|
SuffInsert(&s->children, s2); |
s = find_suffi(sname, end); |
SuffInsert(&s2->parents, s); |
if (s != NULL) { |
} |
s->flags |= opt; |
} |
} |
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Suff_AddSuffix -- |
|
* Add the suffix in string to the end of the list of known suffixes. |
|
* Should we restructure the suffix graph? Make doesn't... |
|
* |
|
* Side Effects: |
|
* A GNode is created for the suffix and a Suff structure is created and |
|
* added to the suffixes list unless the suffix was already known. |
|
*----------------------------------------------------------------------- |
|
*/ |
|
void |
void |
Suff_AddSuffix(const char *str) |
Suff_AddIncludei(const char *sname, const char *end) |
{ |
{ |
Suff *s; /* new suffix descriptor */ |
add_property(sname, end, SUFF_INCLUDE); |
LstNode ln; |
} |
|
|
ln = suff_find_by_name(str); |
void |
if (ln == NULL) { |
Suff_AddLibi(const char *sname, const char *end) |
s = emalloc(sizeof(Suff)); |
{ |
|
add_property(sname, end, SUFF_LIBRARY); |
s->name = estrdup(str); |
|
s->nameLen = strlen(s->name); |
|
Lst_Init(&s->searchPath); |
|
Lst_Init(&s->children); |
|
Lst_Init(&s->parents); |
|
Lst_Init(&s->ref); |
|
s->sNum = sNum++; |
|
s->flags = 0; |
|
|
|
Lst_AtEnd(&sufflist, s); |
|
/* |
|
* Look for any existing transformations from or to this suffix. |
|
* XXX: Only do this after a Suff_ClearSuffixes? |
|
*/ |
|
Lst_ForEach(&transforms, SuffRebuildGraph, s); |
|
} |
|
} |
} |
|
|
/*- |
static void |
*----------------------------------------------------------------------- |
build_suffixes_graph(void) |
* Suff_GetPath -- |
|
* Return the search path for the given suffix, if it's defined. |
|
* |
|
* Results: |
|
* The searchPath for the desired suffix or NULL if the suffix isn't |
|
* defined. |
|
*----------------------------------------------------------------------- |
|
*/ |
|
Lst |
|
Suff_GetPath(const char *sname) |
|
{ |
{ |
LstNode ln; |
Suff *s, *s2; |
Suff *s; |
GNode *gn; |
|
unsigned int i; |
|
|
ln = suff_find_by_name(sname); |
for (gn = ohash_first(&transforms, &i); gn != NULL; |
if (ln == NULL) { |
gn = ohash_next(&transforms, &i)) { |
return NULL; |
if (Lst_IsEmpty(&gn->commands) && Lst_IsEmpty(&gn->children)) |
} else { |
continue; |
s = (Suff *)Lst_Datum(ln); |
if ((gn->special & SPECIAL_MASK) == SPECIAL_PATH) |
return &s->searchPath; |
continue; |
|
if (parse_transform(gn->name, &s, &s2)) { |
|
SuffInsert(&s2->children, s); |
|
SuffInsert(&s->parents, s2); |
|
} |
} |
} |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Suff_DoPaths -- |
* setup_paths |
* Extend the search paths for all suffixes to include the default |
* Extend the search paths for all suffixes to include the default |
* search path. |
* search path. |
* |
* |
|
|
* ".LIBS" and the flag is -L. |
* ".LIBS" and the flag is -L. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
static void |
Suff_DoPaths(void) |
setup_paths(void) |
{ |
{ |
Suff *s; |
unsigned int i; |
LstNode ln; |
Suff *s; |
char *ptr; |
|
LIST inIncludes; /* Cumulative .INCLUDES path */ |
|
LIST inLibs; /* Cumulative .LIBS path */ |
|
|
|
Lst_Init(&inIncludes); |
for (s = ohash_first(&suffixes, &i); s != NULL; |
Lst_Init(&inLibs); |
s = ohash_next(&suffixes, &i)) { |
|
if (!Lst_IsEmpty(&s->searchPath)) |
for (ln = Lst_First(&sufflist); ln != NULL; ln = Lst_Adv(ln)) { |
|
s = (Suff *)Lst_Datum(ln); |
|
if (!Lst_IsEmpty(&s->searchPath)) { |
|
if (s->flags & SUFF_INCLUDE) { |
|
Dir_Concat(&inIncludes, &s->searchPath); |
|
} |
|
if (s->flags & SUFF_LIBRARY) { |
|
Dir_Concat(&inLibs, &s->searchPath); |
|
} |
|
Dir_Concat(&s->searchPath, defaultPath); |
Dir_Concat(&s->searchPath, defaultPath); |
} else |
else |
Lst_Clone(&s->searchPath, defaultPath, Dir_CopyDir); |
Lst_Clone(&s->searchPath, defaultPath, Dir_CopyDir); |
} |
} |
|
|
Var_Set(".INCLUDES", ptr = Dir_MakeFlags("-I", &inIncludes)); |
build_path_variable(&suffixes, SUFF_INCLUDE, ".INCLUDES", "-I"); |
free(ptr); |
build_path_variable(&suffixes, SUFF_LIBRARY, ".LIBS", "-L"); |
Var_Set(".LIBS", ptr = Dir_MakeFlags("-L", &inLibs)); |
|
free(ptr); |
|
|
|
Lst_Destroy(&inIncludes, Dir_Destroy); |
|
Lst_Destroy(&inLibs, Dir_Destroy); |
|
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Suff_AddInclude -- |
|
* Add the given suffix as a type of file which gets included. |
|
* Called from the parse module when a .INCLUDES line is parsed. |
|
* The suffix must have already been defined. |
|
* |
|
* Side Effects: |
|
* The SUFF_INCLUDE bit is set in the suffix's flags field |
|
*----------------------------------------------------------------------- |
|
*/ |
|
void |
void |
Suff_AddInclude(const char *sname) /* Name of suffix to mark */ |
process_suffixes_after_makefile_is_read(void) |
{ |
{ |
LstNode ln; |
/* once the Makefile is finish reading, we can set up the default PATH |
Suff *s; |
* stuff, and build the final suffixes graph |
|
*/ |
ln = suff_find_by_name(sname); |
setup_paths(); |
if (ln != NULL) { |
/* and we link all transforms to active suffixes at this point. */ |
s = (Suff *)Lst_Datum(ln); |
build_suffixes_graph(); |
s->flags |= SUFF_INCLUDE; |
|
} |
|
} |
} |
|
|
/*- |
|
*----------------------------------------------------------------------- |
|
* Suff_AddLib -- |
|
* Add the given suffix as a type of file which is a library. |
|
* Called from the parse module when parsing a .LIBS line. The |
|
* suffix must have been defined via .SUFFIXES before this is |
|
* called. |
|
* |
|
* Side Effects: |
|
* The SUFF_LIBRARY bit is set in the suffix's flags field |
|
*----------------------------------------------------------------------- |
|
*/ |
|
void |
|
Suff_AddLib(const char *sname) /* Name of suffix to mark */ |
|
{ |
|
LstNode ln; |
|
Suff *s; |
|
|
|
ln = suff_find_by_name(sname); |
|
if (ln != NULL) { |
|
s = (Suff *)Lst_Datum(ln); |
|
s->flags |= SUFF_LIBRARY; |
|
} |
|
} |
|
|
|
/********** Implicit Source Search Functions *********/ |
/********** Implicit Source Search Functions *********/ |
|
|
/*- |
/*- |
|
|
*/ |
*/ |
static void |
static void |
SuffAddSrc( |
SuffAddSrc( |
void *sp, /* suffix for which to create a Src structure */ |
void *sp, /* suffix for which to create a Src structure */ |
void *lsp) /* list and parent for the new Src */ |
void *lsp) /* list and parent for the new Src */ |
{ |
{ |
Suff *s = (Suff *)sp; |
Suff *s = (Suff *)sp; |
LstSrc *ls = (LstSrc *)lsp; |
LstSrc *ls = (LstSrc *)lsp; |
Src *s2; /* new Src structure */ |
Src *s2; /* new Src structure */ |
Src *targ; /* Target structure */ |
Src *targ; /* Target structure */ |
|
|
targ = ls->s; |
targ = ls->s; |
|
|
|
|
* Two birds, and all that... |
* Two birds, and all that... |
*/ |
*/ |
s2 = emalloc(sizeof(Src)); |
s2 = emalloc(sizeof(Src)); |
s2->file = estrdup(targ->pref); |
s2->file = estrdup(targ->pref); |
s2->pref = targ->pref; |
s2->pref = targ->pref; |
s2->parent = targ; |
s2->parent = targ; |
s2->node = NULL; |
s2->node = NULL; |
s2->suff = s; |
s2->suff = s; |
s2->children = 0; |
s2->children = 0; |
targ->children++; |
targ->children++; |
Lst_AtEnd(ls->l, s2); |
Lst_AtEnd(ls->l, s2); |
#ifdef DEBUG_SRC |
#ifdef DEBUG_SRC |
|
|
#endif |
#endif |
} |
} |
s2 = emalloc(sizeof(Src)); |
s2 = emalloc(sizeof(Src)); |
s2->file = Str_concat(targ->pref, s->name, 0); |
s2->file = Str_concat(targ->pref, s->name, 0); |
s2->pref = targ->pref; |
s2->pref = targ->pref; |
s2->parent = targ; |
s2->parent = targ; |
s2->node = NULL; |
s2->node = NULL; |
s2->suff = s; |
s2->suff = s; |
s2->children = 0; |
s2->children = 0; |
targ->children++; |
targ->children++; |
Lst_AtEnd(ls->l, s2); |
Lst_AtEnd(ls->l, s2); |
#ifdef DEBUG_SRC |
#ifdef DEBUG_SRC |
Lst_Init(&s2->cp); |
Lst_Init(&s2->cp); |
Lst_AtEnd(&targ->cp, s2); |
Lst_AtEnd(&targ->cp, s2); |
printf("2 add %x %x to %x:", targ, s2, ls->l); |
printf("2 add %x %x to %x:", targ, s2, ls->l); |
Lst_Every(ls->l, PrintAddr); |
Lst_Every(ls->l, PrintAddr); |
|
|
*/ |
*/ |
static void |
static void |
SuffAddLevel( |
SuffAddLevel( |
Lst l, /* list to which to add the new level */ |
Lst l, /* list to which to add the new level */ |
Src *targ) /* Src structure to use as the parent */ |
Src *targ) /* Src structure to use as the parent */ |
{ |
{ |
LstSrc ls; |
LstSrc ls; |
|
|
|
|
*/ |
*/ |
static Src * |
static Src * |
SuffFindThem( |
SuffFindThem( |
Lst srcs, /* list of Src structures to search through */ |
Lst srcs, /* list of Src structures to search through */ |
Lst slst) |
Lst slst) |
{ |
{ |
Src *s; /* current Src */ |
Src *s; /* current Src */ |
Src *rs; /* returned Src */ |
Src *rs; /* returned Src */ |
char *ptr; |
char *ptr; |
|
|
rs = NULL; |
rs = NULL; |
|
|
while ((s = (Src *)Lst_DeQueue(srcs)) != NULL) { |
while ((s = (Src *)Lst_DeQueue(srcs)) != NULL) { |
if (DEBUG(SUFF)) { |
if (DEBUG(SUFF)) |
printf("\ttrying %s...", s->file); |
printf("\ttrying %s...", s->file); |
} |
|
|
|
/* |
/* |
* A file is considered to exist if either a node exists in the |
* A file is considered to exist if either a node exists in the |
|
|
break; |
break; |
} |
} |
|
|
if (DEBUG(SUFF)) { |
if (DEBUG(SUFF)) |
printf("not there\n"); |
printf("not there\n"); |
} |
|
|
|
SuffAddLevel(srcs, s); |
SuffAddLevel(srcs, s); |
Lst_AtEnd(slst, s); |
Lst_AtEnd(slst, s); |
} |
} |
|
|
if (DEBUG(SUFF) && rs) { |
if (DEBUG(SUFF) && rs) |
printf("got it\n"); |
printf("got it\n"); |
} |
|
return rs; |
return rs; |
} |
} |
|
|
|
|
Src *targ, /* Src structure to play with */ |
Src *targ, /* Src structure to play with */ |
Lst slst) |
Lst slst) |
{ |
{ |
LstNode ln; /* General-purpose list node */ |
LstNode ln; /* General-purpose list node */ |
GNode *t, /* Target GNode */ |
GNode *t; /* Target GNode */ |
*s; /* Source GNode */ |
GNode *s; /* Source GNode */ |
int prefLen;/* The length of the defined prefix */ |
int prefLen; /* The length of the defined prefix */ |
Suff *suff; /* Suffix on matching beastie */ |
Suff *suff; /* Suffix on matching beastie */ |
Src *ret; /* Return value */ |
Src *ret; /* Return value */ |
const char *cp; |
const char *cp; |
|
|
t = targ->node; |
t = targ->node; |
prefLen = strlen(targ->pref); |
prefLen = strlen(targ->pref); |
|
|
if (strncmp(cp, targ->pref, prefLen) == 0) { |
if (strncmp(cp, targ->pref, prefLen) == 0) { |
/* The node matches the prefix ok, see if it has a known |
/* The node matches the prefix ok, see if it has a known |
* suffix. */ |
* suffix. */ |
LstNode ln2; |
suff = find_suff(&cp[prefLen]); |
ln2 = suff_find_by_name(&cp[prefLen]); |
if (suff != NULL) { |
if (ln2 != NULL) { |
|
/* |
/* |
* It even has a known suffix, see if there's a |
* It even has a known suffix, see if there's a |
* transformation defined between the node's |
* transformation defined between the node's |
|
|
* XXX: Handle multi-stage transformations |
* XXX: Handle multi-stage transformations |
* here, too. |
* here, too. |
*/ |
*/ |
suff = (Suff *)Lst_Datum(ln2); |
|
|
|
if (Lst_Member(&suff->parents, targ->suff) |
if (Lst_Member(&suff->parents, targ->suff) |
!= NULL) { |
!= NULL) { |
/* |
/* |
|
|
Lst_AtEnd(&targ->cp, ret); |
Lst_AtEnd(&targ->cp, ret); |
#endif |
#endif |
Lst_AtEnd(slst, ret); |
Lst_AtEnd(slst, ret); |
if (DEBUG(SUFF)) { |
if (DEBUG(SUFF)) |
printf ("\tusing existing source %s\n", s->name); |
printf( |
} |
"\tusing existing source %s\n", |
|
s->name); |
return ret; |
return ret; |
} |
} |
} |
} |
} |
} |
} |
} |
|
|
static void |
static void |
SuffExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn) |
SuffExpandVarChildren(LstNode after, GNode *cgn, GNode *pgn) |
{ |
{ |
GNode *gn; /* New source 8) */ |
GNode *gn; /* New source 8) */ |
char *cp; /* Expanded value */ |
char *cp; /* Expanded value */ |
LIST members; |
LIST members; |
|
|
|
|
if (DEBUG(SUFF)) |
if (DEBUG(SUFF)) |
|
|
* on the Arch module to find the nodes for us, expanding |
* on the Arch module to find the nodes for us, expanding |
* variables in the parent's context. |
* variables in the parent's context. |
*/ |
*/ |
const char *sacrifice = cp; |
const char *sacrifice = (const char *)cp; |
|
|
(void)Arch_ParseArchive(&sacrifice, &members, &pgn->context); |
(void)Arch_ParseArchive(&sacrifice, &members, &pgn->context); |
} else { |
} else { |
|
|
* Unfortunately, we can't use brk_string because it |
* Unfortunately, we can't use brk_string because it |
* doesn't understand about variable specifications with |
* doesn't understand about variable specifications with |
* spaces in them... */ |
* spaces in them... */ |
char *start, *cp2; |
const char *start, *cp2; |
|
|
for (start = cp; *start == ' ' || *start == '\t'; start++) |
for (start = cp; *start == ' ' || *start == '\t'; start++) |
continue; |
continue; |
|
|
cp2+=2; |
cp2+=2; |
else |
else |
cp2++; |
cp2++; |
} |
} |
|
|
if (cp2 != start) { |
if (cp2 != start) { |
/* Stuff left over -- add it to the list too. */ |
/* Stuff left over -- add it to the list too. */ |
gn = Targ_FindNodei(start, cp2, TARG_CREATE); |
gn = Targ_FindNodei(start, cp2, TARG_CREATE); |
Lst_AtEnd(&members, gn); |
Lst_AtEnd(&members, gn); |
} |
} |
} |
} |
/* Add all elements of the members list to the parent node. */ |
/* Add all elements of the members list to the parent node. */ |
while ((gn = (GNode *)Lst_DeQueue(&members)) != NULL) { |
while ((gn = (GNode *)Lst_DeQueue(&members)) != NULL) { |
|
|
static void |
static void |
SuffExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn) |
SuffExpandWildChildren(LstNode after, GNode *cgn, GNode *pgn) |
{ |
{ |
LstNode ln; /* List element for old source */ |
Suff *s; |
char *cp; /* Expanded value */ |
char *cp; /* Expanded value */ |
|
|
LIST exp; /* List of expansions */ |
LIST exp; /* List of expansions */ |
Lst path; /* Search path along which to expand */ |
Lst path; /* Search path along which to expand */ |
|
|
if (DEBUG(SUFF)) |
if (DEBUG(SUFF)) |
printf("Wildcard expanding \"%s\"...", cgn->name); |
printf("Wildcard expanding \"%s\"...", cgn->name); |
|
|
* If it has no known suffix and we're allowed to use the null |
* If it has no known suffix and we're allowed to use the null |
* suffix, use its path. |
* suffix, use its path. |
* Else use the default system search path. */ |
* Else use the default system search path. */ |
cp = cgn->name + strlen(cgn->name); |
s = find_best_suffix(cgn->name, cgn->name + strlen(cgn->name)); |
ln = Lst_FindConst(&sufflist, SuffSuffIsSuffixP, cp); |
|
|
|
if (ln != NULL) { |
if (s != NULL) { |
Suff *s = (Suff *)Lst_Datum(ln); |
|
|
|
if (DEBUG(SUFF)) |
if (DEBUG(SUFF)) |
printf("suffix is \"%s\"...", s->name); |
printf("suffix is \"%s\"...", s->name); |
path = &s->searchPath; |
path = &s->searchPath; |
|
|
|
|
/* Fetch next expansion off the list and find its GNode. */ |
/* Fetch next expansion off the list and find its GNode. */ |
while ((cp = (char *)Lst_DeQueue(&exp)) != NULL) { |
while ((cp = (char *)Lst_DeQueue(&exp)) != NULL) { |
GNode *gn; /* New source 8) */ |
GNode *gn; /* New source 8) */ |
if (DEBUG(SUFF)) |
if (DEBUG(SUFF)) |
printf("%s...", cp); |
printf("%s...", cp); |
gn = Targ_FindNode(cp, TARG_CREATE); |
gn = Targ_FindNode(cp, TARG_CREATE); |
|
|
else if (Dir_HasWildcards(cgn->name)) |
else if (Dir_HasWildcards(cgn->name)) |
SuffExpandWildChildren(ln, cgn, pgn); |
SuffExpandWildChildren(ln, cgn, pgn); |
else |
else |
/* Third case: nothing to expand. */ |
/* Third case: nothing to expand. */ |
return; |
return; |
|
|
/* Since the source was expanded, remove it from the list of children to |
/* Since the source was expanded, remove it from the list of children to |
|
|
} |
} |
/* Locate the transformation rule itself. */ |
/* Locate the transformation rule itself. */ |
tname = Str_concat(s->name, t->name, 0); |
tname = Str_concat(s->name, t->name, 0); |
ln = transform_find_by_name(tname); |
gn = find_transform(tname); |
free(tname); |
free(tname); |
|
|
if (ln == NULL) |
if (gn == NULL) |
/* |
/* |
* Not really such a transformation rule (can happen when we're |
* Not really such a transformation rule (can happen when we're |
* called to link an OP_MEMBER and OP_ARCHV node), so return |
* called to link an OP_MEMBER and OP_ARCHV node), so return |
|
|
*/ |
*/ |
return false; |
return false; |
|
|
gn = (GNode *)Lst_Datum(ln); |
|
|
|
if (DEBUG(SUFF)) |
if (DEBUG(SUFF)) |
printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name, |
printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name, |
tGn->name); |
tGn->name); |
|
|
return true; |
return true; |
} |
} |
|
|
|
static Suff * |
|
find_suffix_as_suffix(Lst l, const char *b, const char *e) |
|
{ |
|
LstNode ln; |
|
Suff *s; |
|
|
|
for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln)) { |
|
s = (Suff *)Lst_Datum(ln); |
|
if (suffix_is_suffix(s, b, e)) |
|
return s; |
|
} |
|
return NULL; |
|
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* SuffFindArchiveDeps -- |
* SuffFindArchiveDeps -- |
|
|
*/ |
*/ |
static void |
static void |
SuffFindArchiveDeps( |
SuffFindArchiveDeps( |
GNode *gn, /* Node for which to locate dependencies */ |
GNode *gn, /* Node for which to locate dependencies */ |
Lst slst) |
Lst slst) |
{ |
{ |
char *eoarch; /* End of archive portion */ |
char *eoarch; /* End of archive portion */ |
char *eoname; /* End of member portion */ |
char *eoname; /* End of member portion */ |
GNode *mem; /* Node for member */ |
GNode *mem; /* Node for member */ |
Suff *ms; /* Suffix descriptor for member */ |
Suff *ms; /* Suffix descriptor for member */ |
char *name; /* Start of member's name */ |
char *name; /* Start of member's name */ |
|
|
/* The node is an archive(member) pair. so we must find a suffix |
/* The node is an archive(member) pair. so we must find a suffix |
* for both of them. */ |
* for both of them. */ |
|
|
* searching through the entire list, we just look at suffixes |
* searching through the entire list, we just look at suffixes |
* to which the member's suffix may be transformed... |
* to which the member's suffix may be transformed... |
*/ |
*/ |
LstNode ln; |
|
|
|
/* Use first matching suffix... */ |
Suff *suff; |
ln = Lst_FindConst(&ms->parents, SuffSuffIsSuffixP, eoarch); |
|
|
|
if (ln != NULL) { |
suff = find_suffix_as_suffix(&ms->parents, gn->name, eoarch); |
|
|
|
if (suff != NULL) { |
/* Got one -- apply it. */ |
/* Got one -- apply it. */ |
if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), |
if (!SuffApplyTransform(gn, mem, suff, ms) && |
ms) && DEBUG(SUFF)) |
DEBUG(SUFF)) |
printf("\tNo transformation from %s -> %s\n", |
printf("\tNo transformation from %s -> %s\n", |
ms->name, ((Suff *)Lst_Datum(ln))->name); |
ms->name, suff->name); |
} |
} |
} |
} |
|
|
|
|
mem->type |= OP_MEMBER; |
mem->type |= OP_MEMBER; |
} |
} |
|
|
|
static void |
|
record_possible_suffix(Suff *s, GNode *gn, char *eoname, Lst srcs, Lst targs) |
|
{ |
|
int prefLen; |
|
Src *targ; |
|
char *sopref = gn->name; |
|
|
|
targ = emalloc(sizeof(Src)); |
|
targ->file = estrdup(gn->name); |
|
targ->suff = s; |
|
targ->node = gn; |
|
targ->parent = NULL; |
|
targ->children = 0; |
|
#ifdef DEBUG_SRC |
|
Lst_Init(&targ->cp); |
|
#endif |
|
|
|
/* Allocate room for the prefix, whose end is found by |
|
* subtracting the length of the suffix from the end of |
|
* the name. */ |
|
prefLen = (eoname - targ->suff->nameLen) - sopref; |
|
targ->pref = emalloc(prefLen + 1); |
|
memcpy(targ->pref, sopref, prefLen); |
|
targ->pref[prefLen] = '\0'; |
|
|
|
/* Add nodes from which the target can be made. */ |
|
SuffAddLevel(srcs, targ); |
|
|
|
/* Record the target so we can nuke it. */ |
|
Lst_AtEnd(targs, targ); |
|
} |
|
|
|
static void |
|
record_possible_suffixes(GNode *gn, Lst srcs, Lst targs) |
|
{ |
|
char *s = gn->name; |
|
char *e = s + strlen(s); |
|
const char *p; |
|
uint32_t hv; |
|
unsigned int slot; |
|
Suff *suff; |
|
|
|
if (e == s) |
|
return; |
|
|
|
p = e; |
|
hv = *--p; |
|
|
|
while (p != s) { |
|
slot = ohash_lookup_interval(&suffixes, p, e, hv); |
|
suff = ohash_find(&suffixes, slot); |
|
if (suff != NULL && (suff->flags & SUFF_EXISTS)) |
|
record_possible_suffix(suff, gn, e, srcs, targs); |
|
if (e - p >= (ptrdiff_t)maxLen) |
|
break; |
|
reverse_hash_add_char(&hv, --p); |
|
} |
|
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* SuffFindNormalDeps -- |
* SuffFindNormalDeps -- |
|
|
GNode *gn, /* Node for which to find sources */ |
GNode *gn, /* Node for which to find sources */ |
Lst slst) |
Lst slst) |
{ |
{ |
char *eoname; /* End of name */ |
|
char *sopref; /* Start of prefix */ |
|
LstNode ln; /* Next suffix node to check */ |
|
LstNode np; |
LstNode np; |
LIST srcs; /* List of sources at which to look */ |
LstNode ln; |
LIST targs; /* List of targets to which things can be |
LIST srcs; /* List of sources at which to look */ |
* transformed. They all have the same file, |
LIST targs; /* List of targets to which things can be |
* but different suff and pref fields */ |
* transformed. They all have the same file, |
Src *bottom; /* Start of found transformation path */ |
* but different suff and pref fields */ |
Src *src; /* General Src pointer */ |
Src *bottom; /* Start of found transformation path */ |
char *pref; /* Prefix to use */ |
Src *src; /* General Src pointer */ |
Src *targ; /* General Src target pointer */ |
char *pref; /* Prefix to use */ |
|
Src *targ; /* General Src target pointer */ |
|
|
|
|
eoname = gn->name + strlen(gn->name); |
|
|
|
sopref = gn->name; |
|
|
|
/* Begin at the beginning... */ |
|
ln = Lst_First(&sufflist); |
|
Lst_Init(&srcs); |
Lst_Init(&srcs); |
Lst_Init(&targs); |
Lst_Init(&targs); |
|
|
|
|
* children, then look for any overriding transformations they imply. |
* children, then look for any overriding transformations they imply. |
* Should we find one, we discard the one we found before. */ |
* Should we find one, we discard the one we found before. */ |
|
|
while (ln != NULL) { |
|
/* Look for next possible suffix... */ |
|
ln = Lst_FindFromConst(ln, SuffSuffIsSuffixP, eoname); |
|
|
|
if (ln != NULL) { |
record_possible_suffixes(gn, &srcs, &targs); |
int prefLen; /* Length of the prefix */ |
|
Src *targ; |
|
|
|
/* Allocate a Src structure to which things can be |
|
* transformed. */ |
|
targ = emalloc(sizeof(Src)); |
|
targ->file = estrdup(gn->name); |
|
targ->suff = (Suff *)Lst_Datum(ln); |
|
targ->node = gn; |
|
targ->parent = NULL; |
|
targ->children = 0; |
|
#ifdef DEBUG_SRC |
|
Lst_Init(&targ->cp); |
|
#endif |
|
|
|
/* Allocate room for the prefix, whose end is found by |
|
* subtracting the length of the suffix from the end of |
|
* the name. */ |
|
prefLen = (eoname - targ->suff->nameLen) - sopref; |
|
targ->pref = emalloc(prefLen + 1); |
|
memcpy(targ->pref, sopref, prefLen); |
|
targ->pref[prefLen] = '\0'; |
|
|
|
/* Add nodes from which the target can be made. */ |
|
SuffAddLevel(&srcs, targ); |
|
|
|
/* Record the target so we can nuke it. */ |
|
Lst_AtEnd(&targs, targ); |
|
|
|
/* Search from this suffix's successor... */ |
|
ln = Lst_Succ(ln); |
|
} |
|
} |
|
|
|
/* Handle target of unknown suffix... */ |
/* Handle target of unknown suffix... */ |
if (Lst_IsEmpty(&targs) && suffNull != NULL) { |
if (Lst_IsEmpty(&targs)) { |
if (DEBUG(SUFF)) { |
if (DEBUG(SUFF)) |
printf("\tNo known suffix on %s. Using .NULL suffix\n", |
printf("\tNo known suffix on %s. Using .NULL suffix\n", |
gn->name); |
gn->name); |
} |
|
|
|
targ = emalloc(sizeof(Src)); |
targ = emalloc(sizeof(Src)); |
targ->file = estrdup(gn->name); |
targ->file = estrdup(gn->name); |
|
|
targ->node = gn; |
targ->node = gn; |
targ->parent = NULL; |
targ->parent = NULL; |
targ->children = 0; |
targ->children = 0; |
targ->pref = estrdup(sopref); |
targ->pref = estrdup(gn->name); |
#ifdef DEBUG_SRC |
#ifdef DEBUG_SRC |
Lst_Init(&targ->cp); |
Lst_Init(&targ->cp); |
#endif |
#endif |
|
|
printf("\tNo valid suffix on %s\n", gn->name); |
printf("\tNo valid suffix on %s\n", gn->name); |
|
|
sfnd_abort: |
sfnd_abort: |
/* Deal with finding the thing on the default search path if |
/* Deal with finding the thing on the default search path if the |
* the node is only a source (not on the lhs of a dependency |
* node is only a source (not on the lhs of a dependency operator |
* operator or [XXX] it has neither children or commands). */ |
* or [XXX] it has neither children or commands). */ |
if (OP_NOP(gn->type) || |
if (OP_NOP(gn->type) || |
(Lst_IsEmpty(&gn->children) && |
(Lst_IsEmpty(&gn->children) && |
Lst_IsEmpty(&gn->commands))) { |
Lst_IsEmpty(&gn->commands))) { |
|
|
savec = gn->path[savep]; |
savec = gn->path[savep]; |
gn->path[savep] = '\0'; |
gn->path[savep] = '\0'; |
|
|
if ((ptr = strrchr(gn->path, '/')) |
if ((ptr = strrchr(gn->path, '/')) != |
!= NULL) |
NULL) |
ptr++; |
ptr++; |
else |
else |
ptr = gn->path; |
ptr = gn->path; |
|
|
|
|
gn->path[savep] = savec; |
gn->path[savep] = savec; |
} else { |
} else { |
/* The .PREFIX gets the full path if |
/* The .PREFIX gets the full path if the |
* the target has no known suffix. */ |
* target has no known suffix. */ |
gn->suffix = NULL; |
gn->suffix = NULL; |
|
|
if ((ptr = strrchr(gn->path, '/')) |
if ((ptr = strrchr(gn->path, '/')) != |
!= NULL) |
NULL) |
ptr++; |
ptr++; |
else |
else |
ptr = gn->path; |
ptr = gn->path; |
|
|
targ->node = Targ_FindNode(targ->file, TARG_CREATE); |
targ->node = Targ_FindNode(targ->file, TARG_CREATE); |
} |
} |
|
|
SuffApplyTransform(targ->node, src->node, targ->suff, |
SuffApplyTransform(targ->node, src->node, |
src->suff); |
targ->suff, src->suff); |
|
|
if (targ->node != gn) { |
if (targ->node != gn) { |
/* Finish off the dependency-search process for any |
/* Finish off the dependency-search process for any |
|
|
gn->type |= OP_DEPS_FOUND; |
gn->type |= OP_DEPS_FOUND; |
} |
} |
|
|
if (DEBUG(SUFF)) { |
if (DEBUG(SUFF)) |
printf("SuffFindDeps (%s)\n", gn->name); |
printf("SuffFindDeps (%s)\n", gn->name); |
} |
|
|
|
if (gn->type & OP_ARCHV) { |
if (gn->type & OP_ARCHV) { |
SuffFindArchiveDeps(gn, slst); |
SuffFindArchiveDeps(gn, slst); |
|
|
* do for it, so we just set the TARGET variable to the node's |
* do for it, so we just set the TARGET variable to the node's |
* name in order to give it a value). |
* name in order to give it a value). |
*/ |
*/ |
LstNode ln; |
|
Suff *s; |
Suff *s; |
|
|
ln = suff_find_by_name(LIBSUFF); |
s = find_suff(LIBSUFF); |
if (ln != NULL) { |
if (s != NULL) { |
gn->suffix = s = (Suff *)Lst_Datum(ln); |
gn->suffix = s; |
Arch_FindLib(gn, &s->searchPath); |
Arch_FindLib(gn, &s->searchPath); |
} else { |
} else { |
gn->suffix = NULL; |
gn->suffix = NULL; |
|
|
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
|
* Suff_SetNull -- |
|
* Define which suffix is the null suffix. |
|
* |
|
* Side Effects: |
|
* 'suffNull' is altered. |
|
* |
|
* Notes: |
* Notes: |
* Need to handle the changing of the null suffix gracefully so the |
|
* old transformation rules don't just go away. |
|
*----------------------------------------------------------------------- |
|
*/ |
*/ |
void |
void |
Suff_SetNull(const char *name) |
Suff_SetNulli(const char *name, const char *end) |
{ |
{ |
Suff *s; |
Suff *s; |
LstNode ln; |
|
|
|
ln = suff_find_by_name(name); |
s= find_suffi(name, end); |
if (ln != NULL) { |
if (s != NULL) { |
s = (Suff *)Lst_Datum(ln); |
/* pass the pumpkin */ |
if (suffNull != NULL) { |
suffNull->flags &= ~SUFF_NULL; |
suffNull->flags &= ~SUFF_NULL; |
|
} |
|
s->flags |= SUFF_NULL; |
s->flags |= SUFF_NULL; |
/* |
/* |
* XXX: Here's where the transformation mangling would take |
* XXX: Here's where the transformation mangling would take |
* place |
* place |
|
* we would need to handle the changing of the null suffix |
|
* gracefully so the old transformation rules don't just go |
|
* away. |
*/ |
*/ |
suffNull = s; |
suffNull = s; |
} else { |
} else { |
|
|
void |
void |
Suff_Init(void) |
Suff_Init(void) |
{ |
{ |
Static_Lst_Init(&sufflist); |
|
#ifdef CLEANUP |
|
Static_Lst_Init(&suffClean); |
|
#endif |
|
Static_Lst_Init(&srclist); |
Static_Lst_Init(&srclist); |
Static_Lst_Init(&transforms); |
ohash_init(&transforms, 4, &gnode_info); |
|
|
sNum = 0; |
|
/* |
/* |
* Create null suffix for single-suffix rules (POSIX). The thing doesn't |
* Create null suffix for single-suffix rules (POSIX). The thing doesn't |
* actually go on the suffix list or everyone will think that's its |
* actually go on the suffix list or everyone will think that's its |
* suffix. |
* suffix. |
*/ |
*/ |
emptySuff = suffNull = emalloc(sizeof(Suff)); |
emptySuff = new_suffix(""); |
|
emptySuff->flags |= SUFF_NULL; |
|
make_suffix_known(emptySuff); |
|
Dir_Concat(&emptySuff->searchPath, defaultPath); |
|
ohash_init(&suffixes, 4, &suff_info); |
|
sNum = 0; |
|
clear_suffixes(); |
|
special_path_hack(); |
|
|
suffNull->name = estrdup(""); |
|
suffNull->nameLen = 0; |
|
Lst_Init(&suffNull->searchPath); |
|
Dir_Concat(&suffNull->searchPath, defaultPath); |
|
Lst_Init(&suffNull->children); |
|
Lst_Init(&suffNull->parents); |
|
Lst_Init(&suffNull->ref); |
|
suffNull->sNum = sNum++; |
|
suffNull->flags = SUFF_NULL; |
|
|
|
} |
} |
|
|
|
|
|
|
void |
void |
Suff_End(void) |
Suff_End(void) |
{ |
{ |
Lst_Destroy(&sufflist, SuffFree); |
free_hash(&suffixes); |
Lst_Destroy(&suffClean, SuffFree); |
if (emptySuff) |
if (suffNull) |
SuffFree(emptySuff); |
SuffFree(suffNull); |
|
Lst_Destroy(&srclist, NOFREE); |
Lst_Destroy(&srclist, NOFREE); |
Lst_Destroy(&transforms, NOFREE); |
ohash_delete(&transforms): |
} |
} |
#endif |
#endif |
|
|
|
|
/********************* DEBUGGING FUNCTIONS **********************/ |
/********************* DEBUGGING FUNCTIONS **********************/ |
|
|
static void SuffPrintName(void *s) |
static void |
|
SuffPrintName(void *s) |
{ |
{ |
printf("%s ", ((Suff *)s)->name); |
printf("%s ", ((Suff *)s)->name); |
} |
} |
|
|
} |
} |
|
|
static void |
static void |
SuffPrintTrans(void *tp) |
SuffPrintTrans(GNode *t) |
{ |
{ |
GNode *t = (GNode *)tp; |
|
|
|
printf("%-16s: ", t->name); |
printf("%-16s: ", t->name); |
Targ_PrintType(t->type); |
Targ_PrintType(t->type); |
fputc('\n', stdout); |
fputc('\n', stdout); |
|
|
void |
void |
Suff_PrintAll(void) |
Suff_PrintAll(void) |
{ |
{ |
|
Suff *s; |
|
GNode *gn; |
|
unsigned int i; |
|
|
printf("#*** Suffixes:\n"); |
printf("#*** Suffixes:\n"); |
Lst_Every(&sufflist, SuffPrintSuff); |
|
|
|
|
for (s = ohash_first(&suffixes, &i); s != NULL; |
|
s = ohash_next(&suffixes, &i)) |
|
SuffPrintSuff(s); |
|
|
printf("#*** Transformations:\n"); |
printf("#*** Transformations:\n"); |
Lst_Every(&transforms, SuffPrintTrans); |
for (gn = ohash_first(&transforms, &i); gn != NULL; |
|
gn = ohash_next(&transforms, &i)) |
|
SuffPrintTrans(gn); |
} |
} |
|
|
#ifdef DEBUG_SRC |
#ifdef DEBUG_SRC |