home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.2 (Developer) / NS_dev_3.2.iso / NextDeveloper / Source / GNU / cctools / as / hash.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-07  |  29.7 KB  |  990 lines

  1. /* hash.c - hash table lookup strings -
  2.    Copyright (C) 1987 Free Software Foundation, Inc.
  3.  
  4. This file is part of GAS, the GNU Assembler.
  5.  
  6. GAS is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GAS is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GAS; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /*
  21.  * BUGS, GRIPES, APOLOGIA etc.
  22.  *
  23.  * A typical user doesn't need ALL this: I intend to make a library out
  24.  * of it one day - Dean Elsner.
  25.  * Also, I want to change the definition of a symbol to (address,length)
  26.  * so I can put arbitrary binary in the names stored. [see hsh.c for that]
  27.  *
  28.  * This slime is common coupled inside the module. Com-coupling (and other
  29.  * vandalism) was done to speed running time. The interfaces at the
  30.  * module's edges are adequately clean.
  31.  *
  32.  * There is no way to (a) run a test script through this heap and (b)
  33.  * compare results with previous scripts, to see if we have broken any
  34.  * code. Use GNU (f)utilities to do this. A few commands assist test.
  35.  * The testing is awkward: it tries to be both batch & interactive.
  36.  * For now, interactive rules!
  37.  */
  38.  
  39. /*
  40.  *  The idea is to implement a symbol table. A test jig is here.
  41.  *  Symbols are arbitrary strings; they can't contain '\0'.
  42.  *    [See hsh.c for a more general symbol flavour.]
  43.  *  Each symbol is associated with a char*, which can point to anything
  44.  *  you want, allowing an arbitrary property list for each symbol.
  45.  *
  46.  *  The basic operations are:
  47.  *
  48.  *    new                     creates symbol table, returns handle
  49.  *    find (symbol)           returns char*
  50.  *    insert (symbol,char*)   error if symbol already in table
  51.  *    delete (symbol)         returns char* if symbol was in table
  52.  *    apply                   so you can delete all symbols before die()
  53.  *    die                     destroy symbol table (free up memory)
  54.  *
  55.  *  Supplementary functions include:
  56.  *
  57.  *    say                     how big? what % full?
  58.  *    replace (symbol,newval) report previous value
  59.  *    jam (symbol,value)      assert symbol:=value
  60.  *
  61.  *  You, the caller, have control over errors: this just reports them.
  62.  *
  63.  *  This package requires malloc(), free().
  64.  *  Malloc(size) returns NULL or address of char[size].
  65.  *  Free(address) frees same.
  66.  */
  67.  
  68. /*
  69.  *  The code and its structures are re-enterent.
  70.  *  Before you do anything else, you must call hash_new() which will
  71.  *  return the address of a hash-table-control-block (or NULL if there
  72.  *  is not enough memory). You then use this address as a handle of the
  73.  *  symbol table by passing it to all the other hash_...() functions.
  74.  *  The only approved way to recover the memory used by the symbol table
  75.  *  is to call hash_die() with the handle of the symbol table.
  76.  *
  77.  *  Before you call hash_die() you normally delete anything pointed to
  78.  *  by individual symbols. After hash_die() you can't use that symbol
  79.  *  table again.
  80.  *
  81.  *  The char* you associate with a symbol may not be NULL (0) because
  82.  *  NULL is returned whenever a symbol is not in the table. Any other
  83.  *  value is OK, except DELETED, #defined below.
  84.  *
  85.  *  When you supply a symbol string for insertion, YOU MUST PRESERVE THE
  86.  *  STRING until that symbol is deleted from the table. The reason is that
  87.  *  only the address you supply, NOT the symbol string itself, is stored
  88.  *  in the symbol table.
  89.  *
  90.  *  You may delete and add symbols arbitrarily.
  91.  *  Any or all symbols may have the same 'value' (char *). In fact, these
  92.  *  routines don't do anything with your symbol values.
  93.  *
  94.  *  You have no right to know where the symbol:char* mapping is stored,
  95.  *  because it moves around in memory; also because we may change how it
  96.  *  works and we don't want to break your code do we? However the handle
  97.  *  (address of struct hash_control) is never changed in
  98.  *  the life of the symbol table.
  99.  *
  100.  *  What you CAN find out about a symbol table is:
  101.  *    how many slots are in the hash table?
  102.  *    how many slots are filled with symbols?
  103.  *    (total hashes,collisions) for (reads,writes) (*)
  104.  *  All of the above values vary in time.
  105.  *  (*) some of these numbers will not be meaningful if we change the
  106.  *  internals.
  107.  */
  108.  
  109. /*
  110.  *  I N T E R N A L
  111.  *
  112.  *  Hash table is an array of hash_entries; each entry is a pointer to a
  113.  *  a string and a user-supplied value 1 char* wide.
  114.  *
  115.  *  The array always has 2 ** n elements, n>0, n integer.
  116.  *  There is also a 'wall' entry after the array, which is always empty
  117.  *  and acts as a sentinel to stop running off the end of the array.
  118.  *  When the array gets too full, we create a new array twice as large
  119.  *  and re-hash the symbols into the new array, then forget the old array.
  120.  *  (Of course, we copy the values into the new array before we junk the
  121.  *  old array!)
  122.  *
  123.  */
  124.  
  125. #include <stdio.h>
  126. #define TRUE           (1)
  127. #define FALSE          (0)
  128. #include <ctype.h>
  129. #define min(a, b)    ((a) < (b) ? (a) : (b))
  130.  
  131. #include "hash.h"
  132. char *xmalloc();
  133.  
  134. #define DELETED     ((char *)1)    /* guarenteed invalid address */
  135. #define START_POWER    (11)    /* power of two: size of new hash table *//* JF was 6 */
  136. /* JF These next two aren't used any more. */
  137. /* #define START_SIZE    (64)    / * 2 ** START_POWER */
  138. /* #define START_FULL    (32)      / * number of entries before table expands */
  139. #define islive(ptr) (ptr->hash_string && ptr->hash_string!=DELETED)
  140.                 /* above TRUE if a symbol is in entry @ ptr */
  141.  
  142. #define STAT_SIZE      (0)      /* number of slots in hash table */
  143.                 /* the wall does not count here */
  144.                 /* we expect this is always a power of 2 */
  145. #define STAT_ACCESS    (1)    /* number of hash_ask()s */
  146. #define STAT__READ     (0)      /* reading */
  147. #define STAT__WRITE    (1)      /* writing */
  148. #define STAT_COLLIDE   (3)    /* number of collisions (total) */
  149.                 /* this may exceed STAT_ACCESS if we have */
  150.                 /* lots of collisions/access */
  151. #define STAT_USED      (5)    /* slots used right now */
  152. #define STATLENGTH     (6)    /* size of statistics block */
  153. #if STATLENGTH != HASH_STATLENGTH
  154. Panic! Please make #include "stat.h" agree with previous definitions!
  155. #endif
  156.  
  157. /* #define SUSPECT to do runtime checks */
  158. /* #define TEST to be a test jig for hash...() */
  159.  
  160. #ifdef TEST            /* TEST: use smaller hash table */
  161. #undef  START_POWER
  162. #define START_POWER (3)
  163. #undef  START_SIZE
  164. #define START_SIZE  (8)
  165. #undef  START_FULL
  166. #define START_FULL  (4)
  167. #endif
  168.  
  169. /*------------------ plan ---------------------------------- i = internal
  170.  
  171. struct hash_control * c;
  172. struct hash_entry   * e;                                                    i
  173. int                   b[z];     buffer for statistics
  174.                       z         size of b
  175. char                * s;        symbol string (address) [ key ]
  176. char                * v;        value string (address)  [datum]
  177. boolean               f;        TRUE if we found s in hash table            i
  178. char                * t;        error string; "" means OK
  179. int                   a;        access type [0...n)                         i
  180.  
  181. c=hash_new       ()             create new hash_control
  182.  
  183. hash_die         (c)            destroy hash_control (and hash table)
  184.                                 table should be empty.
  185.                                 doesn't check if table is empty.
  186.                                 c has no meaning after this.
  187.  
  188. hash_say         (c,b,z)        report statistics of hash_control.
  189.                                 also report number of available statistics.
  190.  
  191. v=hash_delete    (c,s)          delete symbol, return old value if any.
  192.     ask()                       NULL means no old value.
  193.     f
  194.  
  195. v=hash_replace   (c,s,v)        replace old value of s with v.
  196.     ask()                       NULL means no old value: no table change.
  197.     f
  198.  
  199. t=hash_insert    (c,s,v)        insert (s,v) in c.
  200.     ask()                       return error string.
  201.     f                           it is an error to insert if s is already
  202.                                 in table.
  203.                                 if any error, c is unchanged.
  204.  
  205. t=hash_jam       (c,s,v)        assert that new value of s will be v.       i
  206.     ask()                       it may decide to GROW the table.            i
  207.     f                                                                       i
  208.     grow()                                                                  i
  209. t=hash_grow      (c)            grow the hash table.                        i
  210.     jam()                       will invoke JAM.                            i
  211.  
  212. ?=hash_apply     (c,y)          apply y() to every symbol in c.
  213.     y                           evtries visited in 'unspecified' order.
  214.  
  215. v=hash_find      (c,s)          return value of s, or NULL if s not in c.
  216.     ask()
  217.     f
  218.  
  219. f,e=hash_ask()   (c,s,a)        return slot where s SHOULD live.            i
  220.     code()                      maintain collision stats in c.              i
  221.  
  222. .=hash_code      (c,s)          compute hash-code for s,                    i
  223.                                 from parameters of c.                       i
  224.  
  225. */
  226.  
  227. static char hash_found;        /* returned by hash_ask() to stop extra */
  228.                 /* testing. hash_ask() wants to return both */
  229.                 /* a slot and a status. This is the status. */
  230.                 /* TRUE: found symbol */
  231.                 /* FALSE: absent: empty or deleted slot */
  232.                 /* Also returned by hash_jam(). */
  233.                 /* TRUE: we replaced a value */
  234.                 /* FALSE: we inserted a value */
  235.  
  236. static struct hash_entry * hash_ask();
  237. static int hash_code ();
  238. static char * hash_grow();
  239.  
  240. /*
  241.  *             h a s h _ n e w ( )
  242.  *
  243.  */
  244. struct hash_control *
  245. hash_new()            /* create a new hash table */
  246.                 /* return NULL if failed */
  247.                 /* return handle (address of struct hash) */
  248. {
  249.   register struct hash_control * retval;
  250.   register struct hash_entry *   room;    /* points to hash table */
  251.   register struct hash_entry *   wall;
  252.   register struct hash_entry *   entry;
  253.   char *                malloc();
  254.   register int *                 ip;    /* scan stats block of struct hash_control */
  255.   register int *                 nd;    /* limit of stats block */
  256.  
  257.   if ( room = (struct hash_entry *) malloc( sizeof(struct hash_entry)*((1<<START_POWER) + 1) ) )
  258.                 /* +1 for the wall entry */
  259.     {
  260.       if ( retval = (struct hash_control *) malloc(sizeof(struct hash_control)) )
  261.     {
  262.       nd = retval->hash_stat + STATLENGTH;
  263.       for (ip=retval->hash_stat; ip<nd; ip++)
  264.         {
  265.           *ip = 0;
  266.         }
  267.  
  268.       retval -> hash_stat[STAT_SIZE]  = 1<<START_POWER;
  269.       retval -> hash_mask             = (1<<START_POWER) - 1;
  270.       retval -> hash_sizelog      = START_POWER;
  271.                 /* works for 1's compl ok */
  272.       retval -> hash_where            = room;
  273.       retval -> hash_wall             =
  274.         wall                          = room + (1<<START_POWER);
  275.       retval -> hash_full             = (1<<START_POWER)/2;
  276.       for (entry=room; entry<=wall; entry++)
  277.         {
  278.           entry->hash_string = NULL;
  279.         }
  280.     }
  281.     }
  282.   else
  283.     {
  284.       retval = NULL;        /* no room for table: fake a failure */
  285.     }
  286.   return(retval);        /* return NULL or set-up structs */
  287. }
  288.  
  289. /*
  290.  *           h a s h _ d i e ( )
  291.  *
  292.  * Table should be empty, but this is not checked.
  293.  * To empty the table, try hash_apply()ing a symbol deleter.
  294.  * Return to free memory both the hash table and it's control
  295.  * block.
  296.  * 'handle' has no meaning after this function.
  297.  * No errors are recoverable.
  298.  */
  299. void
  300. hash_die(handle)
  301.      struct hash_control * handle;
  302. {
  303.   free((char *)handle->hash_where);
  304.   free((char *)handle);
  305. }
  306.  
  307. /*
  308.  *           h a s h _ s a y ( )
  309.  *
  310.  * Return the size of the statistics table, and as many statistics as
  311.  * we can until either (a) we have run out of statistics or (b) caller
  312.  * has run out of buffer.
  313.  * NOTE: hash_say treats all statistics alike.
  314.  * These numbers may change with time, due to insertions, deletions
  315.  * and expansions of the table.
  316.  * The first "statistic" returned is the length of hash_stat[].
  317.  * Then contents of hash_stat[] are read out (in ascending order)
  318.  * until your buffer or hash_stat[] is exausted.
  319.  */
  320. void
  321. hash_say(handle,buffer,bufsiz)
  322.      register struct hash_control * handle;
  323.      register int                   buffer[/*bufsiz*/];
  324.      register int                   bufsiz;
  325. {
  326.   register int * nd;            /* limit of statistics block */
  327.   register int * ip;            /* scan statistics */
  328.  
  329.   ip = handle -> hash_stat;
  330.   nd = ip + min(bufsiz-1,STATLENGTH);
  331.   if (bufsiz>0)            /* trust nothing! bufsiz<=0 is dangerous */
  332.     {
  333.       *buffer++ = STATLENGTH;
  334.       for (; ip<nd; ip++,buffer++)
  335.     {
  336.       *buffer = *ip;
  337.     }
  338.     }
  339. }
  340.  
  341. /*
  342.  *           h a s h _ d e l e t e ( )
  343.  *
  344.  * Try to delete a symbol from the table.
  345.  * If it was there, return its value (and adjust STAT_USED).
  346.  * Otherwise, return NULL.
  347.  * Anyway, the symbol is not present after this function.
  348.  *
  349.  */
  350. char *                /* NULL if string not in table, else */
  351.                 /* returns value of deleted symbol */
  352. hash_delete(handle,string)
  353.      register struct hash_control * handle;
  354.      register char *                string;
  355. {
  356.   register char *                   retval; /* NULL if string not in table */
  357.   register struct hash_entry *      entry; /* NULL or entry of this symbol */
  358.  
  359.   entry = hash_ask(handle,string,STAT__WRITE);
  360.   if (hash_found)
  361.     {
  362.       retval = entry -> hash_value;
  363.       entry -> hash_string = DELETED; /* mark as deleted */
  364.       handle -> hash_stat[STAT_USED] -= 1; /* slots-in-use count */
  365. #ifdef SUSPECT
  366.       if (handle->hash_stat[STAT_USED]<0)
  367.         {
  368. #ifdef NeXT
  369.           as_fatal("hash_delete");
  370. #else !defined(NeXT)
  371.           error("hash_delete");
  372. #endif NeXT
  373.         }
  374. #endif /* def SUSPECT */
  375.     }
  376.   else
  377.     {
  378.       retval = NULL;
  379.     }
  380.   return(retval);
  381. }
  382.  
  383. /*
  384.  *                   h a s h _ r e p l a c e ( )
  385.  *
  386.  * Try to replace the old value of a symbol with a new value.
  387.  * Normally return the old value.
  388.  * Return NULL and don't change the table if the symbol is not already
  389.  * in the table.
  390.  */
  391. char *
  392. hash_replace(handle,string,value)
  393.      register struct hash_control * handle;
  394.      register char *                string;
  395.      register char *                value;
  396. {
  397.   register struct hash_entry *      entry;
  398.   register char *                   retval;
  399.  
  400.   entry = hash_ask(handle,string,STAT__WRITE);
  401.   if (hash_found)
  402.     {
  403.       retval = entry -> hash_value;
  404.       entry -> hash_value = value;
  405.     }
  406.   else
  407.     {
  408.       retval = NULL;
  409.     }
  410.   ;
  411.   return (retval);
  412. }
  413.  
  414. /*
  415.  *                   h a s h _ i n s e r t ( )
  416.  *
  417.  * Insert a (symbol-string, value) into the hash table.
  418.  * Return an error string, "" means OK.
  419.  * It is an 'error' to insert an existing symbol.
  420.  */
  421.  
  422. char *                /* return error string */
  423. hash_insert(handle,string,value)
  424.      register struct hash_control * handle;
  425.      register char *                string;
  426.      register char *                value;
  427. {
  428.   register struct hash_entry * entry;
  429.   register char *              retval;
  430.  
  431.   retval = "";
  432.   if (handle->hash_stat[STAT_USED] > handle->hash_full)
  433.     {
  434.       retval = hash_grow(handle);
  435.     }
  436.   if ( ! * retval)
  437.     {
  438.       entry = hash_ask(handle,string,STAT__WRITE);
  439.       if (hash_found)
  440.     {
  441.       retval = "exists";
  442.     }
  443.       else
  444.     {
  445.       entry -> hash_value  = value;
  446.       entry -> hash_string = string;
  447.       handle-> hash_stat[STAT_USED]  += 1;
  448.     }
  449.     }
  450.   return(retval);
  451. }
  452.  
  453. /*
  454.  *               h a s h _ j a m ( )
  455.  *
  456.  * Regardless of what was in the symbol table before, after hash_jam()
  457.  * the named symbol has the given value. The symbol is either inserted or
  458.  * (its value is) relpaced.
  459.  * An error message string is returned, "" means OK.
  460.  *
  461.  * WARNING: this may decide to grow the hashed symbol table.
  462.  * To do this, we call hash_grow(), WHICH WILL recursively CALL US.
  463.  *
  464.  * We report status internally: hash_found is TRUE if we replaced, but
  465.  * false if we inserted.
  466.  */
  467. char *
  468. hash_jam(handle,string,value)
  469.      register struct hash_control * handle;
  470.      register char *                string;
  471.      register char *                value;
  472. {
  473.   register char *                   retval;
  474.   register struct hash_entry *      entry;
  475.  
  476.   retval = "";
  477.   if (handle->hash_stat[STAT_USED] > handle->hash_full)
  478.     {
  479.       retval = hash_grow(handle);
  480.     }
  481.   if (! * retval)
  482.     {
  483.       entry = hash_ask(handle,string,STAT__WRITE);
  484.       if ( ! hash_found)
  485.     {
  486.       entry -> hash_string = string;
  487.       handle->hash_stat[STAT_USED] += 1;
  488.     }
  489.       entry -> hash_value = value;
  490.     }
  491.   return(retval);
  492. }
  493.  
  494. /*
  495.  *               h a s h _ g r o w ( )
  496.  *
  497.  * Grow a new (bigger) hash table from the old one.
  498.  * We choose to double the hash table's size.
  499.  * Return a human-scrutible error string: "" if OK.
  500.  * Warning! This uses hash_jam(), which had better not recurse
  501.  * back here! Hash_jam() conditionally calls us, but we ALWAYS
  502.  * call hash_jam()!
  503.  * Internal.
  504.  */
  505. static char *
  506. hash_grow(handle)            /* make a hash table grow */
  507.      struct hash_control * handle;
  508. {
  509.   register struct hash_entry *      newwall;
  510.   register struct hash_entry *      newwhere;
  511.   struct hash_entry *      newtrack;
  512.   register struct hash_entry *      oldtrack;
  513.   register struct hash_entry *      oldwhere;
  514.   register struct hash_entry *      oldwall;
  515.   register int                      temp;
  516.   int                      newsize;
  517.   char *                   string;
  518.   char *                   retval;
  519. #ifdef SUSPECT
  520.   int                      oldused;
  521. #endif
  522.  
  523.   /*
  524.    * capture info about old hash table
  525.    */
  526.   oldwhere = handle -> hash_where;
  527.   oldwall  = handle -> hash_wall;
  528. #ifdef SUSPECT
  529.   oldused  = handle -> hash_stat[STAT_USED];
  530. #endif
  531.   /*
  532.    * attempt to get enough room for a hash table twice as big
  533.    */
  534.   temp = handle->hash_stat[STAT_SIZE];
  535.   if ( newwhere = (struct hash_entry *) xmalloc((long)((temp+temp+1)*sizeof(struct hash_entry))))
  536.                 /* +1 for wall slot */
  537.     {
  538.       retval = "";        /* assume success until proven otherwise */
  539.       /*
  540.        * have enough room: now we do all the work.
  541.        * double the size of everything in handle,
  542.        * note: hash_mask frob works for 1's & for 2's complement machines
  543.        */
  544.       handle->hash_mask              = handle->hash_mask + handle->hash_mask + 1;
  545.       handle->hash_stat[STAT_SIZE] <<= 1;
  546.       newsize                        = handle->hash_stat[STAT_SIZE];
  547.       handle->hash_where             = newwhere;
  548.       handle->hash_full            <<= 1;
  549.       handle->hash_sizelog        += 1;
  550.       handle->hash_stat[STAT_USED]   = 0;
  551.       handle->hash_wall              =
  552.       newwall                        = newwhere + newsize;
  553.       /*
  554.        * set all those pesky new slots to vacant.
  555.        */
  556.       for (newtrack=newwhere; newtrack < newwall; newtrack++)
  557.     {
  558.       newtrack -> hash_string = NULL;
  559.     }
  560.       /*
  561.        * we will do a scan of the old table, the hard way, using the
  562.        * new control block to re-insert the data into new hash table.
  563.        */
  564.       handle -> hash_stat[STAT_USED] = 0;    /* inserts will bump it up to correct */
  565.       for (oldtrack=oldwhere; oldtrack < oldwall; oldtrack++)
  566.     {
  567.       if ( (string=oldtrack->hash_string) && string!=DELETED )
  568.         {
  569.           if ( * (retval = hash_jam(handle,string,oldtrack->hash_value) ) )
  570.         {
  571.           break;
  572.         }
  573.         }
  574.     }
  575. #ifdef SUSPECT
  576.       if ( !*retval && handle->hash_stat[STAT_USED] != oldused)
  577.     {
  578.       retval = "hash_used";
  579.     }
  580. #endif
  581.       if (!*retval)
  582.     {
  583.       /*
  584.        * we have a completely faked up control block.
  585.        * return the old hash table.
  586.        */
  587.       free((char *)oldwhere);
  588.       /*
  589.        * Here with success. retval is already "".
  590.        */
  591.     }
  592.     }
  593.   else
  594.     {
  595.       retval = "no room";
  596.     }
  597.   return(retval);
  598. }
  599.  
  600. /*
  601.  *          h a s h _ a p p l y ( )
  602.  *
  603.  * Use this to scan each entry in symbol table.
  604.  * For each symbol, this calls (applys) a nominated function supplying the
  605.  * symbol's value (and the symbol's name).
  606.  * The idea is you use this to destroy whatever is associted with
  607.  * any values in the table BEFORE you destroy the table with hash_die.
  608.  * Of course, you can use it for other jobs; whenever you need to
  609.  * visit all extant symbols in the table.
  610.  *
  611.  * We choose to have a call-you-back idea for two reasons:
  612.  *  asthetic: it is a neater idea to use apply than an explicit loop
  613.  *  sensible: if we ever had to grow the symbol table (due to insertions)
  614.  *            then we would lose our place in the table when we re-hashed
  615.  *            symbols into the new table in a different order.
  616.  *
  617.  * The order symbols are visited depends entirely on the hashing function.
  618.  * Whenever you insert a (symbol, value) you risk expanding the table. If
  619.  * you do expand the table, then the hashing function WILL change, so you
  620.  * MIGHT get a different order of symbols visited. In other words, if you
  621.  * want the same order of visiting symbols as the last time you used
  622.  * hash_apply() then you better not have done any hash_insert()s or
  623.  * hash_jam()s since the last time you used hash_apply().
  624.  *
  625.  * In future we may use the value returned by your nominated function.
  626.  * One idea is to abort the scan if, after applying the function to a
  627.  * certain node, the function returns a certain code.
  628.  * To be safe, please make your functions of type char *. If you always
  629.  * return NULL, then the scan will complete, visiting every symbol in
  630.  * the table exactly once. ALL OTHER RETURNED VALUES have no meaning yet!
  631.  * Caveat Actor!
  632.  *
  633.  * The function you supply should be of the form:
  634.  *      char * myfunct(string,value)
  635.  *              char * string;        |* the symbol's name *|
  636.  *              char * value;         |* the symbol's value *|
  637.  *      {
  638.  *        |* ... *|
  639.  *        return(NULL);
  640.  *      }
  641.  *
  642.  * The returned value of hash_apply() is (char*)NULL. In future it may return
  643.  * other values. NULL means "completed scan OK". Other values have no meaning
  644.  * yet. (The function has no graceful failures.)
  645.  */
  646. char *
  647. hash_apply(handle,function)
  648.      struct hash_control * handle;
  649.      char*                 (*function)();
  650. {
  651.   register struct hash_entry *      entry;
  652.   register struct hash_entry *      wall;
  653.  
  654.   wall = handle->hash_wall;
  655.   for (entry = handle->hash_where; entry < wall; entry++)
  656.     {
  657.       if (islive(entry))    /* silly code: tests entry->string twice! */
  658.     {
  659.       (*function)(entry->hash_string,entry->hash_value);
  660.     }
  661.     }
  662.   return (NULL);
  663. }
  664.  
  665. /*
  666.  *          h a s h _ f i n d ( )
  667.  *
  668.  * Given symbol string, find value (if any).
  669.  * Return found value or NULL.
  670.  */
  671. char *
  672. hash_find(handle,string)    /* return char* or NULL */
  673.      struct hash_control * handle;
  674.      char *                string;
  675. {
  676.   register struct hash_entry *      entry;
  677.   register char *                   retval;
  678.  
  679.   entry = hash_ask(handle,string,STAT__READ);
  680.   if (hash_found)
  681.     {
  682.       retval = entry->hash_value;
  683.     }
  684.   else
  685.     {
  686.       retval = NULL;
  687.     }
  688.   return(retval);
  689. }
  690.  
  691. /*
  692.  *          h a s h _ a s k ( )
  693.  *
  694.  * Searches for given symbol string.
  695.  * Return the slot where it OUGHT to live. It may be there.
  696.  * Return hash_found: TRUE only if symbol is in that slot.
  697.  * Access argument is to help keep statistics in control block.
  698.  * Internal.
  699.  */
  700. static struct hash_entry *    /* string slot, may be empty or deleted */
  701. hash_ask(handle,string,access)
  702.      struct hash_control * handle;
  703.      char *                string;
  704.      int                   access; /* access type */
  705. {
  706.   register char    *string1;    /* JF avoid strcmp calls */
  707.   register char *                   s;
  708.   register int                      c;
  709.   register struct hash_entry *      slot;
  710.   register int                      collision; /* count collisions */
  711.  
  712.   slot = handle->hash_where + hash_code(handle,string); /* start looking here */
  713.   handle->hash_stat[STAT_ACCESS+access] += 1;
  714.   collision = 0;
  715.   hash_found = FALSE;
  716.   while ( (s = slot->hash_string) && s!=DELETED )
  717.     {
  718.         for(string1=string;;) {
  719.         if(!(c= *s++)) {
  720.             if(!*string1)
  721.                 hash_found = TRUE;
  722.             break;
  723.         }
  724.         if(*string1++!=c)
  725.             break;
  726.     }
  727.     if(hash_found)
  728.         break;
  729.       collision++;
  730.       slot++;
  731.     }
  732.   /*
  733.    * slot:                                                      return:
  734.    *       in use:     we found string                           slot
  735.    *       at empty:
  736.    *                   at wall:        we fell off: wrap round   ????
  737.    *                   in table:       dig here                  slot
  738.    *       at DELETED: dig here                                  slot
  739.    */
  740.   if (slot==handle->hash_wall)
  741.     {
  742.       slot = handle->hash_where; /* now look again */
  743.       while( (s = slot->hash_string) && s!=DELETED )
  744.     {
  745.       for(string1=string;*s;string1++,s++) {
  746.         if(*string1!=*s)
  747.         break;
  748.       }
  749.       if(*s==*string1) {
  750.           hash_found = TRUE;
  751.           break;
  752.         }
  753.       collision++;
  754.       slot++;
  755.     }
  756.       /*
  757.        * slot:                                                   return:
  758.        *       in use: we found it                                slot
  759.        *       empty:  wall:         ERROR IMPOSSIBLE             !!!!
  760.        *               in table:     dig here                     slot
  761.        *       DELETED:dig here                                   slot
  762.        */
  763.     }
  764. /*   fprintf(stderr,"hash_ask(%s)->%d(%d)\n",string,hash_code(handle,string),collision); */
  765.   handle -> hash_stat[STAT_COLLIDE+access] += collision;
  766.   return(slot);            /* also return hash_found */
  767. }
  768.  
  769. /*
  770.  *           h a s h _ c o d e
  771.  *
  772.  * Does hashing of symbol string to hash number.
  773.  * Internal.
  774.  */
  775. static int
  776. hash_code(handle,string)
  777.      struct hash_control * handle;
  778.      register char *                string;
  779. {
  780.   register long int                 h;      /* hash code built here */
  781.   register long int                 c;      /* each character lands here */
  782.   register int               n;      /* Amount to shift h by */
  783.  
  784.   n = (handle->hash_sizelog - 3);
  785.   h = 0;
  786.   while (c = *string++)
  787.     {
  788.       h += c;
  789.       h = (h<<3) + (h>>n) + c;
  790.     }
  791.   return (h & handle->hash_mask);
  792. }
  793.  
  794. /*
  795.  * Here is a test program to exercise above.
  796.  */
  797. #ifdef TEST
  798.  
  799. #define TABLES (6)        /* number of hash tables to maintain */
  800.                 /* (at once) in any testing */
  801. #define STATBUFSIZE (12)    /* we can have 12 statistics */
  802.  
  803. int statbuf[STATBUFSIZE];    /* display statistics here */
  804. char answer[100];        /* human farts here */
  805. char * hashtable[TABLES];    /* we test many hash tables at once */
  806. char * h;            /* points to curent hash_control */
  807. char ** pp;
  808. char *  p;
  809. char *  name;
  810. char *  value;
  811. int     size;
  812. int     used;
  813. char    command;
  814. int     number;            /* number 0:TABLES-1 of current hashed */
  815.                 /* symbol table */
  816.  
  817. main()
  818. {
  819.   char (*applicatee());
  820.   char * hash_find();
  821.   char * destroy();
  822.   char * what();
  823.   struct hash_control * hash_new();
  824.   char * hash_replace();
  825.   int *  ip;
  826.  
  827.   number = 0;
  828.   h = 0;
  829.   printf("type h <RETURN> for help\n");
  830.   for(;;)
  831.     {
  832.       printf("hash_test command: ");
  833.       gets(answer);
  834.       command = answer[0];
  835.       if (isupper(command)) command = tolower(command);    /* ecch! */
  836.       switch (command)
  837.     {
  838.     case '#':
  839.       printf("old hash table #=%d.\n",number);
  840.       whattable();
  841.       break;
  842.     case '?':
  843.       for (pp=hashtable; pp<hashtable+TABLES; pp++)
  844.         {
  845.           printf("address of hash table #%d control block is %xx\n"
  846.              ,pp-hashtable,*pp);
  847.         }
  848.       break;
  849.     case 'a':
  850.       hash_apply(h,applicatee);
  851.       break;
  852.     case 'd':
  853.       hash_apply(h,destroy);
  854.       hash_die(h);
  855.       break;
  856.     case 'f':
  857.       p = hash_find(h,name=what("symbol"));
  858.       printf("value of \"%s\" is \"%s\"\n",name,p?p:"NOT-PRESENT");
  859.       break;
  860.     case 'h':
  861.       printf("# show old, select new default hash table number\n");
  862.       printf("? display all hashtable control block addresses\n");
  863.       printf("a apply a simple display-er to each symbol in table\n");
  864.       printf("d die: destroy hashtable\n");
  865.       printf("f find value of nominated symbol\n");
  866.       printf("h this help\n");
  867.       printf("i insert value into symbol\n");
  868.       printf("j jam value into symbol\n");
  869.       printf("n new hashtable\n");
  870.       printf("r replace a value with another\n");
  871.       printf("s say what %% of table is used\n");
  872.       printf("q exit this program\n");
  873.       printf("x delete a symbol from table, report its value\n");
  874.       break;
  875.     case 'i':
  876.       p = hash_insert(h,name=what("symbol"),value=what("value"));
  877.       if (*p)
  878.         {
  879.           printf("symbol=\"%s\"  value=\"%s\"  error=%s\n",name,value,p);
  880.         }
  881.       break;
  882.     case 'j':
  883.       p = hash_jam(h,name=what("symbol"),value=what("value"));
  884.       if (*p)
  885.         {
  886.           printf("symbol=\"%s\"  value=\"%s\"  error=%s\n",name,value,p);
  887.         }
  888.       break;
  889.     case 'n':
  890.       h = hashtable[number] = (char *) hash_new();
  891.       break;
  892.     case 'q':
  893.       exit();
  894.     case 'r':
  895.       p = hash_replace(h,name=what("symbol"),value=what("value"));
  896.       printf("old value was \"%s\"\n",p?p:"{}");
  897.       break;
  898.     case 's':
  899.       hash_say(h,statbuf,STATBUFSIZE);
  900.       for (ip=statbuf; ip<statbuf+STATBUFSIZE; ip++)
  901.         {
  902.           printf("%d ",*ip);
  903.         }
  904.       printf("\n");
  905.       break;
  906.     case 'x':
  907.       p = hash_delete(h,name=what("symbol"));
  908.       printf("old value was \"%s\"\n",p?p:"{}");
  909.       break;
  910.     default:
  911.       printf("I can't understand command \"%c\"\n",command);
  912.       break;
  913.     }
  914.     }
  915. }
  916.  
  917. char *
  918. what(description)
  919.      char * description;
  920. {
  921.   char * retval;
  922.   char * malloc();
  923.  
  924.   printf("   %s : ",description);
  925.   gets(answer);
  926.   /* will one day clean up answer here */
  927.   retval = malloc(strlen(answer)+1);
  928.   if (!retval)
  929.     {
  930. #ifdef NeXT
  931.       as_fatal("room");
  932. #else !defined(NeXT)
  933.       error("room");
  934. #endif NeXT
  935.     }
  936.   (void)strcpy(retval,answer);
  937.   return(retval);
  938. }
  939.  
  940. char *
  941. destroy(string,value)
  942.      char * string;
  943.      char * value;
  944. {
  945.   free(string);
  946.   free(value);
  947.   return(NULL);
  948. }
  949.  
  950.  
  951. char *
  952. applicatee(string,value)
  953.      char * string;
  954.      char * value;
  955. {
  956.   printf("%.20s-%.20s\n",string,value);
  957.   return(NULL);
  958. }
  959.  
  960. whattable()            /* determine number: what hash table to use */
  961.                 /* also determine h: points to hash_control */
  962. {
  963.  
  964.   for (;;)
  965.     {
  966.       printf("   what hash table (%d:%d) ?  ",0,TABLES-1);
  967.       gets(answer);
  968.       sscanf(answer,"%d",&number);
  969.       if (number>=0 && number<TABLES)
  970.     {
  971.       h = hashtable[number];
  972.       if (!h)
  973.         {
  974.           printf("warning: current hash-table-#%d. has no hash-control\n",number);
  975.         }
  976.       return;
  977.     }
  978.       else
  979.     {
  980.       printf("invalid hash table number: %d\n",number);
  981.     }
  982.     }
  983. }
  984.  
  985.  
  986.  
  987. #endif /* #ifdef TEST */
  988.  
  989. /* end: hash.c */
  990.