[BACK]Return to suff.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / make

Diff for /src/usr.bin/make/suff.c between version 1.69 and 1.70

version 1.69, 2007/09/17 11:43:12 version 1.70, 2007/09/17 12:42:09
Line 46 
Line 46 
  *   *
  *      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.
Line 74 
Line 58 
  *   *
  *      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.
Line 87 
Line 73 
  *                              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"
Line 104 
Line 116 
 #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 */
   
Line 120 
Line 130 
  * 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;
   
Line 155 
Line 170 
  * 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 *);
Line 191 
Line 212 
 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--;
Line 250 
Line 288 
         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
 /*-  /*-
Line 337 
Line 345 
 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);
Line 369 
Line 373 
 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);
Line 378 
Line 382 
                         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");
         }          }
Line 401 
Line 400 
 /*-  /*-
  *-----------------------------------------------------------------------   *-----------------------------------------------------------------------
  * 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.
  *   *
Line 766 
Line 735 
  *      ".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 *********/
   
 /*-  /*-
Line 865 
Line 778 
  */   */
 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;
   
Line 882 
Line 795 
                  * 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
Line 899 
Line 812 
 #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);
Line 928 
Line 841 
  */   */
 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;
   
Line 1011 
Line 924 
  */   */
 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
Line 1047 
Line 959 
                         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;
 }  }
   
Line 1080 
Line 990 
     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);
Line 1103 
Line 1013 
                 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
Line 1114 
Line 1023 
                                  * 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) {
                                         /*                                          /*
Line 1140 
Line 1047 
                                         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;
                             }                                  }
                         }                          }
                 }                  }
         }          }
Line 1154 
Line 1062 
 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))
Line 1177 
Line 1085 
                  * 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 {
Line 1186 
Line 1094 
                  * 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;
Line 1212 
Line 1120 
                                 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) {
Line 1240 
Line 1148 
 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);
Line 1255 
Line 1163 
          * 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;
Line 1274 
Line 1179 
   
         /* 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);
Line 1326 
Line 1231 
         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
Line 1390 
Line 1295 
         }          }
         /* 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
Line 1401 
Line 1306 
                  */                   */
                 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);
Line 1426 
Line 1329 
         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 --
Line 1438 
Line 1354 
  */   */
 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.  */
Line 1498 
Line 1414 
                  * 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);
                 }                  }
         }          }
   
Line 1523 
Line 1439 
         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 --
Line 1537 
Line 1512 
     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);
   
Line 1577 
Line 1544 
          * 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);
Line 1629 
Line 1558 
                 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
Line 1688 
Line 1617 
                         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))) {
Line 1714 
Line 1643 
                                         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;
Line 1724 
Line 1653 
   
                                         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;
Line 1797 
Line 1726 
                         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
Line 1882 
Line 1811 
                 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);
Line 1897 
Line 1825 
                  * 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;
Line 1919 
Line 1846 
 }  }
   
 /*-  /*-
  *-----------------------------------------------------------------------  
  * 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 {
Line 1967 
Line 1884 
 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;  
   
 }  }
   
   
Line 2009 
Line 1918 
 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);
 }  }
Line 2068 
Line 1977 
 }  }
   
 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);
Line 2082 
Line 1989 
 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

Legend:
Removed from v.1.69  
changed lines
  Added in v.1.70