$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r77190 - trunk/tools/build/v2/engine
From: steven_at_[hidden]
Date: 2012-03-03 16:46:55
Author: steven_watanabe
Date: 2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
New Revision: 77190
URL: http://svn.boost.org/trac/boost/changeset/77190
Log:
Fix alias violations in hash.
Text files modified: 
   trunk/tools/build/v2/engine/builtins.c  |    30 ++----                                  
   trunk/tools/build/v2/engine/class.c     |     7                                         
   trunk/tools/build/v2/engine/compile.c   |     9 -                                       
   trunk/tools/build/v2/engine/debug.c     |    23 +++-                                    
   trunk/tools/build/v2/engine/filesys.c   |    17 +-                                      
   trunk/tools/build/v2/engine/hash.c      |   186 ++++++++++++++------------------------- 
   trunk/tools/build/v2/engine/hash.h      |    49 +++++++++-                              
   trunk/tools/build/v2/engine/hcache.c    |   162 +++++++++++++++++++---------------      
   trunk/tools/build/v2/engine/hdrmacro.c  |    15 +-                                      
   trunk/tools/build/v2/engine/modules.c   |    14 +-                                      
   trunk/tools/build/v2/engine/native.c    |    25 +++--                                   
   trunk/tools/build/v2/engine/pathunix.c  |    37 ++++---                                 
   trunk/tools/build/v2/engine/rules.c     |    32 ++----                                  
   trunk/tools/build/v2/engine/search.c    |    20 ++-                                     
   trunk/tools/build/v2/engine/subst.c     |     7                                         
   trunk/tools/build/v2/engine/timestamp.c |    59 +++++++-----                            
   trunk/tools/build/v2/engine/variable.c  |    20 +--                                     
   17 files changed, 365 insertions(+), 347 deletions(-)
Modified: trunk/tools/build/v2/engine/builtins.c
==============================================================================
--- trunk/tools/build/v2/engine/builtins.c	(original)
+++ trunk/tools/build/v2/engine/builtins.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -1102,14 +1102,12 @@
           source_name = list_next( source_name ),
           target_name = list_next( target_name ) )
     {
-        RULE   r_;
-        RULE * r = &r_;
+        RULE * r;
         RULE * imported;
-        r_.name = source_name->value;
 
         if ( !source_module->rules ||
-            !hashcheck( source_module->rules, (HASHDATA * *)&r ) )
-            unknown_rule( frame, "IMPORT", source_module, r_.name );
+            !(r = (RULE *)hash_find( source_module->rules, source_name->value ) ) )
+            unknown_rule( frame, "IMPORT", source_module, source_name->value );
 
         imported = import_rule( r, target_module, target_name->value );
         if ( localize )
@@ -1153,12 +1151,10 @@
 
     for ( ; rules; rules = list_next( rules ) )
     {
-        RULE   r_;
-        RULE * r = &r_;
-        r_.name = rules->value;
+        RULE * r;
 
-        if ( !m->rules || !hashcheck( m->rules, (HASHDATA * *)&r ) )
-            unknown_rule( frame, "EXPORT", m, r_.name );
+        if ( !m->rules || !(r = (RULE *)hash_find( m->rules, rules->value ) ) )
+            unknown_rule( frame, "EXPORT", m, rules->value );
 
         r->exported = 1;
     }
@@ -1583,10 +1579,8 @@
 
     module_t * module = bindmodule( module_name->value );
 
-    native_rule_t n;
-    native_rule_t * np = &n;
-    n.name = rule_name->value;
-    if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
+    native_rule_t * np;
+    if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, rule_name->value ) ) )
     {
         args_refer( np->arguments );
         new_rule_body( module, np->name, np->arguments, np->procedure, 1 );
@@ -1595,7 +1589,7 @@
     {
         backtrace_line( frame->prev );
         printf( "error: no native rule \"%s\" defined in module \"%s.\"\n",
-                object_str( n.name ), object_str( module->name ) );
+                object_str( rule_name->value ), object_str( module->name ) );
         backtrace( frame->prev );
         exit( 1 );
     }
@@ -1611,10 +1605,8 @@
 
     module_t * module = bindmodule( module_name->value );
 
-    native_rule_t n;
-    native_rule_t * np = &n;
-    n.name = rule_name->value;
-    if ( module->native_rules && hashcheck( module->native_rules, (HASHDATA * *)&np ) )
+    native_rule_t * np;
+    if ( module->native_rules && (np = (native_rule_t *)hash_find( module->native_rules, rule_name->value ) ) )
     {
         int expected_version = atoi( object_str( version->value ) );
         if ( np->version == expected_version )
Modified: trunk/tools/build/v2/engine/class.c
==============================================================================
--- trunk/tools/build/v2/engine/class.c	(original)
+++ trunk/tools/build/v2/engine/class.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -19,8 +19,7 @@
 {
     for ( ; class_names; class_names = class_names->next )
     {
-        OBJECT * * p = &class_names->value;
-        if ( !hashcheck( classes, (HASHDATA * *)&p ) )
+        if ( !hash_find( classes, class_names->value ) )
         {
             printf( "Class %s is not defined\n", object_str( class_names->value ) );
             abort();
@@ -118,11 +117,13 @@
     OBJECT   * * pp = &xname->value;
     module_t   * class_module = 0;
     module_t   * outer_module = frame->module;
+    int found;
 
     if ( !classes )
         classes = hashinit( sizeof( OBJECT * ), "classes" );
 
-    if ( hashenter( classes, (HASHDATA * *)&pp ) )
+    pp = (OBJECT * *)hash_insert( classes, xname->value, &found );
+    if ( !found )
     {
         *pp = object_copy( xname->value );
     }
Modified: trunk/tools/build/v2/engine/compile.c
==============================================================================
--- trunk/tools/build/v2/engine/compile.c	(original)
+++ trunk/tools/build/v2/engine/compile.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -203,13 +203,8 @@
     }
 
     /* If the checking rule can not be found, also bail. */
-    {
-        RULE checker_, *checker = &checker_;
-
-        checker->name = type_name;
-        if ( !typecheck->rules || !hashcheck( typecheck->rules, (HASHDATA * *)&checker ) )
-            return;
-    }
+    if ( !typecheck->rules || !hash_find( typecheck->rules, type_name ) )
+        return;
 
     while ( values != 0 )
     {
Modified: trunk/tools/build/v2/engine/debug.c
==============================================================================
--- trunk/tools/build/v2/engine/debug.c	(original)
+++ trunk/tools/build/v2/engine/debug.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -30,18 +30,25 @@
     if ( DEBUG_PROFILE )
     {
         clock_t start = clock();
-        profile_info info;
-        profile_info * p = &info;
-
-        if ( !rulename ) p = &profile_other;
+        profile_info * p;
 
         if ( !profile_hash && rulename )
             profile_hash = hashinit( sizeof( profile_info ), "profile" );
 
-        info.name = rulename;
-
-        if ( rulename && hashenter( profile_hash, (HASHDATA * *)&p ) )
-            p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+        if ( rulename )
+        {
+            int found;
+            p = (profile_info *)hash_insert( profile_hash, rulename, &found );
+            if ( !found )
+            {
+                p->name = rulename;
+                p->cumulative = p->net = p->num_entries = p->stack_count = p->memory = 0;
+            }
+        }
+        else
+        {
+             p = &profile_other;
+        }
 
         ++p->num_entries;
         ++p->stack_count;
Modified: trunk/tools/build/v2/engine/filesys.c
==============================================================================
--- trunk/tools/build/v2/engine/filesys.c	(original)
+++ trunk/tools/build/v2/engine/filesys.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -39,22 +39,23 @@
 file_info_t * file_info( OBJECT * filename )
 {
     file_info_t *finfo = &filecache_finfo;
+    int found;
 
     if ( !filecache_hash )
         filecache_hash = hashinit( sizeof( file_info_t ), "file_info" );
 
     filename = path_as_key( filename );
 
-    finfo->name = filename;
-    finfo->is_file = 0;
-    finfo->is_dir = 0;
-    finfo->size = 0;
-    finfo->time = 0;
-    finfo->files = 0;
-    if ( hashenter( filecache_hash, (HASHDATA**)&finfo ) )
+    finfo = (file_info_t *)hash_insert( filecache_hash, filename, &found );
+    if ( !found )
     {
         /* printf( "file_info: %s\n", filename ); */
-        finfo->name = object_copy( finfo->name );
+        finfo->name = object_copy( filename );
+        finfo->is_file = 0;
+        finfo->is_dir = 0;
+        finfo->size = 0;
+        finfo->time = 0;
+        finfo->files = 0;
     }
 
     object_free( filename );
Modified: trunk/tools/build/v2/engine/hash.c
==============================================================================
--- trunk/tools/build/v2/engine/hash.c	(original)
+++ trunk/tools/build/v2/engine/hash.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -37,20 +37,9 @@
     struct item  * next;
 };
 
-/* This structure overlays the one handed to hashenter(). Its actual size is
- * given to hashinit().
- */
-
-struct hashdata
-{
-    OBJECT * key;
-    /* rest of user data */
-};
-
 typedef struct item
 {
     struct hashhdr  hdr;
-    struct hashdata data;
 } ITEM ;
 
 # define MAX_LISTS 32
@@ -105,6 +94,10 @@
 
 #define hash_bucket(hp,keyval) ((hp)->tab.base + ( (keyval) % (hp)->tab.nel ))
 
+#define hash_data_key(data) (*(OBJECT * *)(data))
+#define hash_item_data(item) ((HASHDATA *)((char *)item + sizeof(struct hashhdr)))
+#define hash_item_key(item) (hash_data_key(hash_item_data(item)))
+
 /*  Find the hash item for the given data. Returns pointer to the
     item and if given a pointer to the item before the found item.
     If it's the first item in a bucket, there is no previous item,
@@ -121,7 +114,7 @@
 
     for ( ; i; i = i->hdr.next )
     {
-        if ( object_equal( i->data.key, keydata ) )
+        if ( object_equal( hash_item_key( i ), keydata ) )
         {
             if (previous)
             {
@@ -136,52 +129,13 @@
 }
 
 /*
- * hash_free() - remove the given item from the table if it's there.
- * Returns 1 if found, 0 otherwise.
- *
- * NOTE: 2nd argument is HASHDATA*, not HASHDATA** as elsewhere.
- */
-int
-hash_free(
-    register struct hash *hp,
-    HASHDATA *data)
-{
-    ITEM * i = 0;
-    ITEM * prev = 0;
-    unsigned int keyval = hash_keyval(data->key);
-
-    i = hash_search( hp, keyval, data->key, &prev );
-    if (i)
-    {
-        /* mark it free so we skip it during enumeration */
-        i->data.key = 0;
-        /* unlink the record from the hash chain */
-        if (prev) prev->hdr.next = i->hdr.next;
-        else *hash_bucket(hp,keyval) = i->hdr.next;
-        /* link it into the freelist */
-        i->hdr.next = hp->items.free;
-        hp->items.free = i;
-        /* we have another item */
-        hp->items.more++;
-
-        return 1;
-    }
-    return 0;
-}
-
-/*
- * hashitem() - find a record in the table, and optionally enter a new one
+ * hash_insert() - insert a record in the table or return the existing one
  */
 
-int
-hashitem(
-    register struct hash *hp,
-    HASHDATA **data,
-    int enter )
-{
-    register ITEM *i;
-    OBJECT *b = (*data)->key;
-    unsigned int keyval = hash_keyval(b);
+HASHDATA * hash_insert( struct hash * hp, OBJECT * key, int * found )
+{
+    ITEM * i;
+    unsigned int keyval = hash_keyval( key );
 
     #ifdef HASH_DEBUG_PROFILE
     profile_frame prof[1];
@@ -189,38 +143,24 @@
         profile_enter( 0, prof );
     #endif
 
-    if ( enter && !hp->items.more )
+    if ( !hp->items.more )
         hashrehash( hp );
 
-    if ( !enter && !hp->items.nel )
+    i = hash_search( hp, keyval, key, 0 );
+    if ( i )
     {
-        #ifdef HASH_DEBUG_PROFILE
-        if ( DEBUG_PROFILE )
-            profile_exit( prof );
-        #endif
-        return 0;
+        *found = 1;
     }
-
-    i = hash_search( hp, keyval, (*data)->key, 0 );
-    if (i)
-    {
-        *data = &i->data;
-        #ifdef HASH_DEBUG_PROFILE
-        if ( DEBUG_PROFILE ) profile_exit( prof );
-        #endif
-        return !0;
-    }
-
-    if ( enter )
+    else
     {
-        ITEM * * base = hash_bucket(hp,keyval);
+        ITEM * * base = hash_bucket( hp, keyval );
 
         /* try to grab one from the free list */
         if ( hp->items.free )
         {
             i = hp->items.free;
             hp->items.free = i->hdr.next;
-            assert( i->data.key == 0 );
+            assert( hash_item_key( i ) == 0 );
         }
         else
         {
@@ -228,23 +168,58 @@
             hp->items.next += hp->items.size;
         }
         hp->items.more--;
-        memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
         i->hdr.next = *base;
         *base = i;
-        *data = &i->data;
-        #ifdef OPT_BOEHM_GC
-        if (sizeof(HASHDATA) == hp->items.datalen)
-        {
-            GC_REGISTER_FINALIZER(i->data.key,&hash_mem_finalizer,hp,0,0);
-        }
+        *found = 0;
+    }
+
+    #ifdef HASH_DEBUG_PROFILE
+    if ( DEBUG_PROFILE )
+        profile_exit( prof );
+    #endif
+
+    return hash_item_data( i );
+}
+
+/*
+ * hash_find() - find a record in the table or NULL if none exists
+ */
+
+HASHDATA * hash_find( struct hash *hp, OBJECT *key )
+{
+    ITEM *i;
+    unsigned int keyval = hash_keyval(key);
+
+    #ifdef HASH_DEBUG_PROFILE
+    profile_frame prof[1];
+    if ( DEBUG_PROFILE )
+        profile_enter( 0, prof );
+    #endif
+
+    if ( !hp->items.nel )
+    {
+        #ifdef HASH_DEBUG_PROFILE
+        if ( DEBUG_PROFILE )
+            profile_exit( prof );
         #endif
+        return 0;
     }
 
+    i = hash_search( hp, keyval, key, 0 );
+
     #ifdef HASH_DEBUG_PROFILE
     if ( DEBUG_PROFILE )
         profile_exit( prof );
     #endif
-    return 0;
+
+    if (i)
+    {
+        return hash_item_data( i );
+    }
+    else
+    {
+        return 0;
+    }
 }
 
 /*
@@ -278,9 +253,9 @@
         for ( ; nel--; next += hp->items.size )
         {
             register ITEM *i = (ITEM *)next;
-            ITEM **ip = hp->tab.base + object_hash( i->data.key ) % hp->tab.nel;
+            ITEM **ip = hp->tab.base + object_hash( hash_item_key( i ) ) % hp->tab.nel;
             /* code currently assumes rehashing only when there are no free items */
-            assert( i->data.key != 0 );
+            assert( hash_item_key( i ) != 0 );
 
             i->hdr.next = *ip;
             *ip = i;
@@ -301,8 +276,8 @@
         for ( ; nel--; next += hp->items.size )
         {
             ITEM * i = (ITEM *)next;
-            if ( i->data.key != 0 )  /* DO not enumerate freed items. */
-                f( &i->data, data );
+            if ( hash_item_key( i ) != 0 )  /* DO not enumerate freed items. */
+                f( hash_item_data( i ), data );
         }
     }
 }
@@ -359,45 +334,16 @@
     hash_mem_free( hp->items.datalen, (char *)hp );
 }
 
-const char *
-hashname ( struct hash * hp )
-{
-    return hp->name;
-}
-
 static void * hash_mem_alloc(size_t datalen, size_t size)
 {
-    if (sizeof(HASHDATA) == datalen)
-    {
-        return BJAM_MALLOC_RAW(size);
-    }
-    else
-    {
-        return BJAM_MALLOC(size);
-    }
+    return BJAM_MALLOC(size);
 }
 
 static void hash_mem_free(size_t datalen, void * data)
 {
-    if (sizeof(HASHDATA) == datalen)
-    {
-        BJAM_FREE_RAW(data);
-    }
-    else
-    {
-        BJAM_FREE(data);
-    }
+    BJAM_FREE(data);
 }
 
-#ifdef OPT_BOEHM_GC
-static void hash_mem_finalizer(OBJECT * key, struct hash * hp)
-{
-    HASHDATA d;
-    d.key = key;
-    hash_free(hp,&d);
-}
-#endif
-
 
 /* ---- */
 
Modified: trunk/tools/build/v2/engine/hash.h
==============================================================================
--- trunk/tools/build/v2/engine/hash.h	(original)
+++ trunk/tools/build/v2/engine/hash.h	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -11,16 +11,55 @@
 #ifndef BOOST_JAM_HASH_H
 #define BOOST_JAM_HASH_H
 
+/*
+ * An opaque struct representing an item in the
+ * hash table.  The first element of every struct
+ * stored in the table must be an OBJECT * which
+ * is treated as the key.
+ */
 typedef struct hashdata HASHDATA;
 
+/*
+ * hashinit() - initialize a hash table, returning a handle.
+ * datalen is the size of the items.  name is used for debugging.
+ */
 struct hash * hashinit     ( int datalen, const char * name );
-int           hashitem     ( struct hash * hp, HASHDATA * * data, int enter );
+
+/*
+ * hashdone() - free a hash table, given its handle
+ */
 void          hashdone     ( struct hash * hp );
+
+/*
+ * hashenumerate() - call f(i, data) on each item, i in the hash
+ * table.  The order of the items is unspecified.
+ */
 void          hashenumerate( struct hash * hp, void (* f)( void *, void * ), void * data );
-int           hash_free    ( struct hash * hp, HASHDATA * data );
-const char *  hashname     ( struct hash * hp );
 
-#define hashenter( hp, data ) ( !hashitem( hp, data, !0 ) )
-#define hashcheck( hp, data ) hashitem( hp, data, 0 )
+/*
+ * hash_insert() - insert a new item in a hash table, or return an
+ * existing one.
+ *
+ * Preconditions:
+ *   - hp must be a hash table created by hashinit
+ *   - key must be an object created by object_new
+ *
+ * Postconditions:
+ *   - if the key does not already exist in the hash
+ *     table, *found == 0 and the result will be a
+ *     pointer to an uninitialized item.  The key
+ *     of the new item must be set to a value equal to
+ *     key before any further operations on the
+ *     hash table except hashdone.
+ *   - if the key is present then *found == 1 and
+ *     the result is a pointer to the existing
+ *     record.
+ */
+HASHDATA *    hash_insert  ( struct hash * hp, OBJECT * key, int * found );
+
+/*
+ * hash_find() - find a record in the table or NULL if none exists
+ */
+HASHDATA *    hash_find    ( struct hash * hp, OBJECT * key );
 
 #endif
Modified: trunk/tools/build/v2/engine/hcache.c
==============================================================================
--- trunk/tools/build/v2/engine/hcache.c	(original)
+++ trunk/tools/build/v2/engine/hcache.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -174,8 +174,6 @@
 
 void hcache_init()
 {
-    HCACHEDATA   cachedata;
-    HCACHEDATA * c;
     FILE       * f;
     OBJECT     * version;
     int          header_count = 0;
@@ -201,6 +199,8 @@
 
     while ( 1 )
     {
+        HCACHEDATA   cachedata;
+        HCACHEDATA * c;
         OBJECT * record_type;
         OBJECT * time_str;
         OBJECT * age_str;
@@ -209,6 +209,7 @@
         int      i;
         int      count;
         LIST   * l;
+        int      found;
 
         record_type = read_netstring( f );
         if ( !record_type )
@@ -225,21 +226,19 @@
             goto bail;
         }
 
-        c = &cachedata;
-
-        c->boundname       = read_netstring( f );
-        time_str           = read_netstring( f );
-        age_str            = read_netstring( f );
-        includes_count_str = read_netstring( f );
+        cachedata.boundname = read_netstring( f );
+        time_str            = read_netstring( f );
+        age_str             = read_netstring( f );
+        includes_count_str  = read_netstring( f );
 
-        if ( !c->boundname || !time_str || !age_str || !includes_count_str )
+        if ( !cachedata.boundname || !time_str || !age_str || !includes_count_str )
         {
             fprintf( stderr, "invalid %s\n", hcachename );
             goto bail;
         }
 
-        c->time = atoi( object_str( time_str ) );
-        c->age = atoi( object_str( age_str ) ) + 1;
+        cachedata.time = atoi( object_str( time_str ) );
+        cachedata.age = atoi( object_str( age_str ) ) + 1;
 
         count = atoi( object_str( includes_count_str ) );
         for ( l = 0, i = 0; i < count; ++i )
@@ -252,7 +251,7 @@
             }
             l = list_new( l, s );
         }
-        c->includes = l;
+        cachedata.includes = l;
 
         hdrscan_count_str = read_netstring( f );
         if ( !includes_count_str )
@@ -273,9 +272,18 @@
             }
             l = list_new( l, s );
         }
-        c->hdrscan = l;
+        cachedata.hdrscan = l;
 
-        if ( !hashenter( hcachehash, (HASHDATA * *)&c ) )
+        c = (HCACHEDATA *)hash_insert( hcachehash, cachedata.boundname, &found );
+        if ( !found )
+        {
+            c->boundname = cachedata.boundname;
+            c->time      = cachedata.time;
+            c->includes  = cachedata.includes;
+            c->hdrscan   = cachedata.hdrscan;
+            c->age       = cachedata.age;
+        }
+        else
         {
             fprintf( stderr, "can't insert header cache item, bailing on %s\n",
                 hcachename );
@@ -375,76 +383,90 @@
 
 LIST * hcache( TARGET * t, int rec, regexp * re[], LIST * hdrscan )
 {
-    HCACHEDATA cachedata;
-    HCACHEDATA * c = &cachedata;
+    HCACHEDATA * c;
 
     LIST * l = 0;
 
     ++queries;
 
-    c->boundname = t->boundname;
-
-    if (hashcheck (hcachehash, (HASHDATA **) &c))
+    if ( ( c = (HCACHEDATA *)hash_find( hcachehash, t->boundname ) ) )
     {
-    if (c->time == t->time)
-    {
-        LIST *l1 = hdrscan, *l2 = c->hdrscan;
-        while (l1 && l2) {
-        if (l1->value != l2->value) {
-            l1 = NULL;
-        } else {
-            l1 = list_next(l1);
-            l2 = list_next(l2);
-        }
-        }
-        if (l1 || l2) {
-        if (DEBUG_HEADER)
-            printf("HDRSCAN out of date in cache for %s\n",
-               object_str( t->boundname ));
-
-        printf("HDRSCAN out of date for %s\n", object_str( t->boundname ) );
-        printf(" real  : ");
-        list_print(hdrscan);
-        printf("\n cached: ");
-        list_print(c->hdrscan);
-        printf("\n");
-
-        list_free(c->includes);
-        list_free(c->hdrscan);
-        c->includes = 0;
-        c->hdrscan = 0;
-        } else {
-        if (DEBUG_HEADER)
-            printf ("using header cache for %s\n", object_str( t->boundname ) );
-        c->age = 0;
-        ++hits;
-        l = list_copy (0, c->includes);
-        return l;
-        }
-    } else {
-        if (DEBUG_HEADER)
-            printf ("header cache out of date for %s\n", object_str( t->boundname ) );
-        list_free (c->includes);
-        list_free(c->hdrscan);
-        c->includes = 0;
-        c->hdrscan = 0;
-    }
-    } else {
-    if (hashenter (hcachehash, (HASHDATA **)&c)) {
-        c->boundname = object_copy( c->boundname );
-        c->next = hcachelist;
-        hcachelist = c;
+        if ( c->time == t->time )
+        {
+            LIST *l1 = hdrscan, *l2 = c->hdrscan;
+            while ( l1 && l2 )
+            {
+                if (l1->value != l2->value)
+                {
+                    l1 = NULL;
+                }
+                else
+                {
+                    l1 = list_next( l1 );
+                    l2 = list_next( l2 );
+                }
+            }
+            if ( l1 || l2 )
+            {
+                if (DEBUG_HEADER)
+                    printf( "HDRSCAN out of date in cache for %s\n",
+                        object_str( t->boundname ) );
+
+                printf( "HDRSCAN out of date for %s\n",
+                    object_str( t->boundname ) );
+                printf(" real  : ");
+                list_print( hdrscan );
+                printf( "\n cached: " );
+                list_print( c->hdrscan );
+                printf( "\n" );
+
+                list_free( c->includes );
+                list_free( c->hdrscan );
+                c->includes = 0;
+                c->hdrscan = 0;
+            }
+            else
+            {
+                if (DEBUG_HEADER)
+                    printf( "using header cache for %s\n",
+                        object_str( t->boundname ) );
+                c->age = 0;
+                ++hits;
+                l = list_copy( 0, c->includes );
+                return l;
+            }
+        }
+        else
+        {
+            if (DEBUG_HEADER)
+                printf ("header cache out of date for %s\n",
+                    object_str( t->boundname ) );
+            list_free( c->includes );
+            list_free( c->hdrscan );
+            c->includes = 0;
+            c->hdrscan = 0;
+        }
     }
+    else
+    {
+        int found;
+        c = (HCACHEDATA *)hash_insert( hcachehash, t->boundname, &found );
+        if ( !found )
+        {
+            c->boundname = object_copy( t->boundname );
+            c->next = hcachelist;
+            hcachelist = c;
+        }
     }
 
     /* 'c' points at the cache entry. Its out of date. */
 
-    l = headers1 (0, t->boundname, rec, re);
+    l = headers1( 0, t->boundname, rec, re );
 
     c->time = t->time;
     c->age = 0;
-    c->includes = list_copy (0, l);
-    c->hdrscan = list_copy(0, hdrscan);
+    c->includes = list_copy( 0, l );
+    c->hdrscan = list_copy( 0, hdrscan );
 
     return l;
 }
Modified: trunk/tools/build/v2/engine/hdrmacro.c
==============================================================================
--- trunk/tools/build/v2/engine/hdrmacro.c	(original)
+++ trunk/tools/build/v2/engine/hdrmacro.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -95,6 +95,7 @@
         if ( regexec( re, buf ) && re->startp[1] )
         {
             OBJECT * symbol;
+            int found;
             /* we detected a line that looks like "#define  MACRO  filename */
             ((char *)re->endp[1])[0] = '\0';
             ((char *)re->endp[2])[0] = '\0';
@@ -107,10 +108,11 @@
             if ( !header_macros_hash )
                 header_macros_hash = hashinit( sizeof( HEADER_MACRO ), "hdrmacros" );
 
-            v->symbol   = symbol = object_new( re->startp[1] );
-            v->filename = 0;
-            if ( hashenter( header_macros_hash, (HASHDATA **)&v ) )
+            symbol = object_new( re->startp[1] );
+            v = (HEADER_MACRO *)hash_insert( header_macros_hash, symbol, &found );
+            if ( !found )
             {
+                v->symbol = symbol;
                 v->filename = object_new( re->startp[2] );  /* never freed */
             }
             else
@@ -128,12 +130,9 @@
 
 OBJECT * macro_header_get( OBJECT * macro_name )
 {
-    HEADER_MACRO var;
-    HEADER_MACRO * v = &var;
+    HEADER_MACRO * v;
 
-    v->symbol = macro_name;
-
-    if ( header_macros_hash && hashcheck( header_macros_hash, (HASHDATA **)&v ) )
+    if ( header_macros_hash && ( v = (HEADER_MACRO *)hash_find( header_macros_hash, macro_name ) ) )
     {
         if ( DEBUG_HEADER )
             printf( "### macro '%s' evaluated to '%s'\n", object_str( macro_name ), object_str( v->filename ) );
Modified: trunk/tools/build/v2/engine/modules.c
==============================================================================
--- trunk/tools/build/v2/engine/modules.c	(original)
+++ trunk/tools/build/v2/engine/modules.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -31,15 +31,14 @@
     {
         PROFILE_ENTER( BINDMODULE );
 
-        module_t m_;
-        module_t * m = &m_;
+        module_t * m;
+        int found;
 
         if ( !module_hash )
             module_hash = hashinit( sizeof( module_t ), "modules" );
 
-        m->name = name;
-
-        if ( hashenter( module_hash, (HASHDATA * *)&m ) )
+        m = (module_t *)hash_insert( module_hash, name, &found );
+        if ( !found )
         {
             m->name = object_copy( name );
             m->variables = 0;
@@ -160,9 +159,10 @@
 
     for ( ; module_names; module_names = module_names->next )
     {
+        int found;
         OBJECT * s = module_names->value;
-        OBJECT * * ss = &s;
-        if( hashenter( h, (HASHDATA * *)&ss ) )
+        OBJECT * * ss = (OBJECT * *)hash_insert( h, s, &found );
+        if( !found )
         {
             *ss = object_copy( s );
         }
Modified: trunk/tools/build/v2/engine/native.c
==============================================================================
--- trunk/tools/build/v2/engine/native.c	(original)
+++ trunk/tools/build/v2/engine/native.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -5,6 +5,7 @@
 #include "native.h"
 #include "hash.h"
 #include "object.h"
+#include "assert.h"
 
 void declare_native_rule( const char * module, const char * rule, const char * * args,
                           LIST * (*f)( FRAME *, int ), int version )
@@ -20,24 +21,28 @@
     {
         object_free( module_obj );
     }
-    if (m->native_rules == 0) {
+    if (m->native_rules == 0)
+    {
         m->native_rules = hashinit( sizeof( native_rule_t ), "native rules");
     }
 
     {
-        native_rule_t n, *np = &n;
-        n.name = object_new( rule );
-        if (args)
+        native_rule_t *np;
+        OBJECT * name = object_new( rule );
+        int found;
+        np = (native_rule_t *)hash_insert( m->native_rules, name, &found );
+        np->name = name;
+        assert( !found );
+        if ( args )
         {
-            n.arguments = args_new();
-            lol_build( n.arguments->data, args );
+            np->arguments = args_new();
+            lol_build( np->arguments->data, args );
         }
         else
         {
-            n.arguments = 0;
+            np->arguments = 0;
         }
-        n.procedure = function_builtin( f, 0 );
-        n.version = version;
-        hashenter(m->native_rules, (HASHDATA**)&np);
+        np->procedure = function_builtin( f, 0 );
+        np->version = version;
     }
 }
Modified: trunk/tools/build/v2/engine/pathunix.c
==============================================================================
--- trunk/tools/build/v2/engine/pathunix.c	(original)
+++ trunk/tools/build/v2/engine/pathunix.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -374,16 +374,18 @@
 
 static void path_write_key( char * path_, string * out )
 {
-    struct path_key_entry e, *result = &e;
+    struct path_key_entry * result;
     OBJECT * path = object_new( path_ );
+    int found;
 
     /* This is only called by path_as_key, which initializes the cache. */
     assert( path_key_cache );
 
-    result->path = path;
-    if ( hashenter( path_key_cache, (HASHDATA * *)&result ) )
+    result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+    if ( !found )
     {
         /* path_ is already normalized. */
+        result->path = path;
         ShortPathToLongPath( path_, out );
         result->key = object_new( out->value );
     }
@@ -414,23 +416,25 @@
 
 void path_add_key( OBJECT * path )
 {
-    struct path_key_entry e, *result = &e;
+    struct path_key_entry * result;
+    int found;
 
     if ( ! path_key_cache )
         path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
 
-    result->path = path;
-    if ( hashenter( path_key_cache, (HASHDATA * *)&result ) )
+    result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+    if ( !found )
     {
         string buf[1];
         OBJECT * normalized;
-        struct path_key_entry ne, *nresult = ≠
+        struct path_key_entry * nresult;
+        result->path = path;
         string_copy( buf, object_str( path ) );
         normalize_path( buf );
         normalized = object_new( buf->value );
         string_free( buf );
-        nresult->path = normalized;
-        if ( hashenter( path_key_cache, (HASHDATA * *)&nresult ) || nresult == result )
+        nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
+        if ( !found || nresult == result )
         {
             nresult->path = object_copy( normalized );
             nresult->key = object_copy( path );
@@ -446,24 +450,27 @@
 
 OBJECT * path_as_key( OBJECT * path )
 {
-    struct path_key_entry e, *result = &e;
+    struct path_key_entry * result;
+    int found;
 
     if ( ! path_key_cache )
         path_key_cache = hashinit( sizeof( struct path_key_entry ), "path to key" );
 
-    result->path = path;
-    if ( hashenter( path_key_cache, (HASHDATA * *)&result ) )
+    result = (struct path_key_entry *)hash_insert( path_key_cache, path, &found );
+    if ( !found )
     {
         string buf[1];
         OBJECT * normalized;
-        struct path_key_entry ne, *nresult = ≠
+        struct path_key_entry * nresult;
+        result->path = path;
         string_copy( buf, object_str( path ) );
         normalize_path( buf );
         normalized = object_new( buf->value );
-        nresult->path = normalized;
-        if ( hashenter( path_key_cache, (HASHDATA * *)&nresult ) || nresult == result )
+        nresult = (struct path_key_entry *)hash_insert( path_key_cache, normalized, &found );
+        if ( !found || nresult == result )
         {
             string long_path[1];
+            nresult->path = normalized;
             string_new( long_path );
             ShortPathToLongPath( buf->value, long_path );
             nresult->path = object_copy( normalized );
Modified: trunk/tools/build/v2/engine/rules.c
==============================================================================
--- trunk/tools/build/v2/engine/rules.c	(original)
+++ trunk/tools/build/v2/engine/rules.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -76,12 +76,11 @@
 
 static RULE * enter_rule( OBJECT * rulename, module_t * target_module )
 {
-    RULE rule;
-    RULE * r = &rule;
+    int found;
+    RULE * r;
 
-    r->name = rulename;
-
-    if ( hashenter( demand_rules( target_module ), (HASHDATA * *)&r ) )
+    r = (RULE *)hash_insert( demand_rules(target_module), rulename, &found );
+    if ( !found )
     {
         r->name = object_copy( rulename );
         r->procedure = 0;
@@ -149,15 +148,14 @@
 
 TARGET * bindtarget( OBJECT * target_name )
 {
-    TARGET target;
-    TARGET * t = ⌖
+    int found;
+    TARGET * t;
 
     if ( !targethash )
         targethash = hashinit( sizeof( TARGET ), "targets" );
 
-    t->name = target_name;
-
-    if ( hashenter( targethash, (HASHDATA * *)&t ) )
+    t = (TARGET *)hash_insert( targethash, target_name, &found );
+    if ( !found )
     {
         memset( (char *)t, '\0', sizeof( *t ) );
         t->name = object_copy( target_name );
@@ -685,35 +683,31 @@
 
 RULE * lookup_rule( OBJECT * rulename, module_t * m, int local_only )
 {
-    RULE       rule;
-    RULE     * r = &rule;
+    RULE     * r;
     RULE     * result = 0;
     module_t * original_module = m;
 
-    r->name = rulename;
-
     if ( m->class_module )
         m = m->class_module;
 
-    if ( m->rules && hashcheck( m->rules, (HASHDATA * *)&r ) )
+    if ( m->rules && ( r = (RULE *)hash_find( m->rules, rulename ) ) )
         result = r;
     else if ( !local_only && m->imported_modules )
     {
         /* Try splitting the name into module and rule. */
-        char *p = strchr( object_str( r->name ), '.' ) ;
+        char *p = strchr( object_str( rulename ), '.' ) ;
         if ( p )
         {
             string buf[1];
             OBJECT * module_part;
             OBJECT * rule_part;
             string_new( buf );
-            string_append_range( buf, object_str( r->name ), p );
+            string_append_range( buf, object_str( rulename ), p );
             module_part = object_new( buf->value );
             rule_part = object_new( p + 1 );
-            r->name = module_part;
             /* Now, r->name keeps the module name, and p+1 keeps the rule name.
              */
-            if ( hashcheck( m->imported_modules, (HASHDATA * *)&r ) )
+            if ( hash_find( m->imported_modules, module_part ) )
                 result = lookup_rule( rule_part, bindmodule( module_part ), 1 );
             object_free( rule_part );
             object_free( module_part );
Modified: trunk/tools/build/v2/engine/search.c
==============================================================================
--- trunk/tools/build/v2/engine/search.c	(original)
+++ trunk/tools/build/v2/engine/search.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -139,7 +139,7 @@
     {
         while ( varlist )
         {
-            BINDING b, *ba = &b;
+            BINDING * ba;
             file_info_t *ff;
             OBJECT * key;
             OBJECT * test_path;
@@ -159,9 +159,7 @@
             ff = file_query( key );
             timestamp( key, time );
 
-            b.binding = key;
-
-            if ( hashcheck( explicit_bindings, (HASHDATA**)&ba ) )
+            if ( ( ba = (BINDING *)hash_find( explicit_bindings, key ) ) )
             {
                 if ( DEBUG_SEARCH )
                     printf(" search %s: found explicitly located target %s\n",
@@ -213,15 +211,19 @@
 
     if ( explicitly_located )
     {
-        BINDING b;
-        BINDING * ba = &b;
+        int found;
+        BINDING * ba;
         OBJECT * key = path_as_key( boundname );
-        b.binding = key;
-        b.target = target;
         /* CONSIDER: we probably should issue a warning is another file
            is explicitly bound to the same location. This might break
            compatibility, though. */
-        if ( !hashenter( explicit_bindings, (HASHDATA * *)&ba ) )
+        ba = (BINDING *)hash_insert( explicit_bindings, key, &found );
+        if ( !found )
+        {
+            ba->binding = key;
+            ba->target = target;
+        }
+        else
         {
             object_free( key );
         }
Modified: trunk/tools/build/v2/engine/subst.c
==============================================================================
--- trunk/tools/build/v2/engine/subst.c	(original)
+++ trunk/tools/build/v2/engine/subst.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -20,13 +20,14 @@
 
 regexp* regex_compile( OBJECT* pattern )
 {
-    regex_entry entry, *e = &entry;
-    entry.pattern = pattern;
+    int found;
+    regex_entry * e ;
 
     if ( !regex_hash )
         regex_hash = hashinit(sizeof(regex_entry), "regex");
 
-    if ( hashenter( regex_hash, (HASHDATA **)&e ) )
+    e = (regex_entry *)hash_insert( regex_hash, pattern, &found );
+    if ( !found )
     {
         e->pattern = object_copy( pattern );
         e->regex = regcomp( (char*)pattern );
Modified: trunk/tools/build/v2/engine/timestamp.c
==============================================================================
--- trunk/tools/build/v2/engine/timestamp.c	(original)
+++ trunk/tools/build/v2/engine/timestamp.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -71,8 +71,8 @@
 
     PATHNAME   f1;
     PATHNAME   f2;
-    BINDING    binding;
-    BINDING  * b = &binding;
+    int        found;
+    BINDING  * b;
     string     buf[ 1 ];
 
     target = path_as_key( target );
@@ -83,12 +83,14 @@
         bindhash = hashinit( sizeof( BINDING ), "bindings" );
 
     /* Quick path - is it there? */
-    b->name = target;
-    b->time = b->flags = 0;
-    b->progress = BIND_INIT;
 
-    if ( hashenter( bindhash, (HASHDATA * *)&b ) )
+    b = (BINDING *)hash_insert( bindhash, target, &found );
+    if ( !found )
+    {
         b->name = object_copy( target );  /* never freed */
+        b->time = b->flags = 0;
+        b->progress = BIND_INIT;
+    }
 
     if ( b->progress != BIND_INIT )
         goto afterscanning;
@@ -100,8 +102,8 @@
 
     /* Scan directory if not already done so. */
     {
-        BINDING binding;
-        BINDING * b = &binding;
+        int found;
+        BINDING * b;
         OBJECT * name;
 
         f2 = f1;
@@ -109,12 +111,15 @@
         path_parent( &f2 );
         path_build( &f2, buf, 0 );
 
-        b->name = name = object_new( buf->value );
-        b->time = b->flags = 0;
-        b->progress = BIND_INIT;
+        name = object_new( buf->value );
 
-        if ( hashenter( bindhash, (HASHDATA * *)&b ) )
+        b = (BINDING *)hash_insert( bindhash, name, &found );
+        if ( !found )
+        {
             b->name = object_copy( name );
+            b->time = b->flags = 0;
+            b->progress = BIND_INIT;
+        }
 
         if ( !( b->flags & BIND_SCANNED ) )
         {
@@ -128,8 +133,8 @@
     /* Scan archive if not already done so. */
     if ( f1.f_member.len )
     {
-        BINDING binding;
-        BINDING * b = &binding;
+        int found;
+        BINDING * b;
         OBJECT * name;
 
         f2 = f1;
@@ -138,12 +143,15 @@
         string_truncate( buf, 0 );
         path_build( &f2, buf, 0 );
 
-        b->name = name = object_new( buf->value );
-        b->time = b->flags = 0;
-        b->progress = BIND_INIT;
+        name = object_new( buf->value );
 
-        if ( hashenter( bindhash, (HASHDATA * *)&b ) )
+        b = (BINDING *)hash_insert( bindhash, name, &found );
+        if ( !found )
+        {
             b->name = object_copy( name );
+            b->time = b->flags = 0;
+            b->progress = BIND_INIT;
+        }
 
         if ( !( b->flags & BIND_SCANNED ) )
         {
@@ -174,17 +182,18 @@
 
 static void time_enter( void * closure, OBJECT * target, int found, time_t time )
 {
-    BINDING binding;
-    BINDING * b = &binding;
+    int item_found;
+    BINDING * b;
     struct hash * bindhash = (struct hash *)closure;
 
     target = path_as_key( target );
 
-    b->name = target;
-    b->flags = 0;
-
-    if ( hashenter( bindhash, (HASHDATA * *)&b ) )
-        b->name = object_copy( target );  /* never freed */
+    b = (BINDING *)hash_insert( bindhash, target, &item_found );
+    if ( !item_found )
+    {
+        b->name = object_copy( target );
+        b->flags = 0;
+    }
 
     b->time = time;
     b->progress = found ? BIND_FOUND : BIND_SPOTTED;
Modified: trunk/tools/build/v2/engine/variable.c
==============================================================================
--- trunk/tools/build/v2/engine/variable.c	(original)
+++ trunk/tools/build/v2/engine/variable.c	2012-03-03 16:46:53 EST (Sat, 03 Mar 2012)
@@ -201,12 +201,9 @@
     else
 #endif
     {
-        VARIABLE var;
-        VARIABLE * v = &var;
+        VARIABLE * v;
 
-        v->symbol = symbol;
-
-        if ( module->variables && hashcheck( module->variables, (HASHDATA * *)&v ) )
+        if ( module->variables && ( v = (VARIABLE *)hash_find( module->variables, symbol ) ) )
         {
             if ( DEBUG_VARGET )
                 var_dump( v->symbol, v->value, "get" );
@@ -279,17 +276,18 @@
 
 static VARIABLE * var_enter( struct module_t * module, OBJECT * symbol )
 {
-    VARIABLE var;
-    VARIABLE * v = &var;
+    int found;
+    VARIABLE * v;
 
     if ( !module->variables )
         module->variables = hashinit( sizeof( VARIABLE ), "variables" );
 
-    v->symbol = symbol;
-    v->value = 0;
-
-    if ( hashenter( module->variables, (HASHDATA * *)&v ) )
+    v = (VARIABLE *)hash_insert( module->variables, symbol, &found );
+    if ( !found )
+    {
         v->symbol = object_copy( symbol );
+        v->value = 0;
+    }
 
     return v;
 }