/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:hash.c 12.0$ */
/* $ACIS:hash.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/lib/tools/RCS/hash.c,v $ */

#ifndef lint
static char *rcsid = "$Header:hash.c 12.0$";
#endif

#include <stdio.h>
#include <utils.h>
#include <hash.h>

/***=====================================================================***/

#define WHERE_AM_I   "hash.c"

#ifdef DEBUG_UTILS
int ht_debug;
#endif /* DEBUG_UTILS */
static hashtable *ht_free= NULL;
static hashelem  *he_free= NULL;

static hashtable *ht_glbl= NULL;
static hashelem  *he_glbl= NULL;


#define _ht_free(t) (t->ht_next=ht_free,ht_free=t)
#define _he_free(e) (e->he_next=he_free,he_free=e)

#ifdef USE_MACROS

#define _ht_new()  (ht_free?(ht_glbl=ht_free,ht_free=ht_free->ht_next,ht_glbl):((hashtable *)u_malloc(sizeof(hashtable))))
#define _he_new()  (he_free?(he_glbl=he_free,he_free=he_free->he_next,he_glbl):((hashelem *)u_malloc(sizeof(hashelem))))

#else

hashtable *
_ht_new()
{
   if (ht_free) {
      ht_glbl= ht_free;
      ht_free= ht_free->ht_next;
      return(ht_glbl);
   }
   else return((hashtable *)u_malloc(sizeof(hashtable)));
}


hashelem *
_he_new()
{
   if (he_free) {
      he_glbl= he_free;
      he_free= he_free->he_next;
      return(he_glbl);
   }
   else return((hashelem *)u_malloc(sizeof(hashelem)));
}

#endif /* ifdef USE_MACROS */

/***=====================================================================***/

#define Size(h)    (h->ht_size)
#define Elems(h)   (h->ht_elems)
#define Nth(h,n)   (h->ht_elems[n])

#define Info(h)    (h->he_elem)
#define Next(h)    (h->he_next)
#define Key(h)     (h->he_key)

/***=====================================================================***/

_hash(key,size)
register1 char *key;
register2 int  size;
{
   D_ENTRY2(ht_debug,"_hash(%s,%d)\n",key,size);
   RETURN((key[0]+key[1])%size);
}

/***=====================================================================***/

hashtable *
ht_new(size)
register3 int     size;
{
register1 int       knt;
register2 hashtable *ht;

   D_ENTRY1(ht_debug,"ht_new(%d)\n",size);
   if (size<1)
      RETURN(NULL);
   ht= _ht_new();
   Size(ht)=  size;
   Elems(ht)= (hashelem **)u_calloc(size,(unsigned)sizeof(hashelem *));
   for (knt=0;knt<size;knt++) {
       Nth(ht,knt)= (hashelem *)NULL;
   }
   ht->ht_next= NULL;
   RETURN(ht);
}

/***=====================================================================***/

hashtable *
ht_rehash(otable,size)
register6 hashtable *otable;
int        size;
{
register5 hashtable *ht;
register3 hashelem  *he,*he_tmp;
register1 int        knt,index;

   D_ENTRY2(ht_debug,"ht_rehash(0x%x,%d)\n",otable,size);
   if (size<0)
      RETURN(NULL);
   ht= ht_new(size);
   for (knt=0;knt<Size(otable);knt++) {
       he= Nth(otable,knt);
       while (he!=NULL) {
	  index= _hash(Key(he),size);
	  he_tmp= Next(he);
	  Next(he)= Nth(ht,index);
	  Nth(ht,index)= he;
	  he= he_tmp;
       }
   }
   u_free(Elems(otable));
   _ht_free(otable);
   RETURN(ht);
}

/***=====================================================================***/

hashtable *
ht_copy(otable,size)
register3 hashtable *otable;
register5 int        size;
{
register4 hashtable *ht;
register1 hashelem  *he;
register2 int        knt;

   D_ENTRY2(ht_debug,"ht_copy(0x%x,%d)\n",otable,size);
   if (size<1)
      RETURN(NULL);
   ht= ht_new(size);
   for (knt=0;knt<Size(otable);knt++) {
       he= Nth(otable,knt);
       while (he!=NULL) {
	  ht_put(ht,Key(he),Info(he));
	  he= Next(he);
       }
   }
   RETURN(ht);
}

/***=====================================================================***/

hetype *
ht_put(ht,key,info)
register3 hashtable *ht;
register1 char      *key;
register4 hetype    *info;
{
register6 int       index;
register5 hetype    *hi= NULL;
register2 hashelem  *he;

    D_ENTRY3(ht_debug,"ht_put(0x%x,%s,0x%x)\n",ht,key,info);
    if (ht==NULL)
       RETURN(NULL);
    index= _hash(key,Size(ht));
    he= Nth(ht,index);
    while (he!=NULL) {
       if (StrMatch(key,Key(he))) {
	  hi= Info(he);
	  Info(he)= info;
	  RETURN(hi);
       }
       else he= Next(he);
    }
    he= _he_new();
    Key(he)= (char *)u_malloc(strlen(key)+1);
    strcpy(Key(he),key);
    Info(he)= info;
    Next(he)= Nth(ht,index);
    Nth(ht,index)= he;
    RETURN(NULL);
}

/***=====================================================================***/

hetype *
ht_get(ht,key)
register3 hashtable *ht;
register2 char      *key;
{
register4 int        index;
register1 hashelem   *he;

    D_ENTRY2(ht_debug,"ht_get(0x%x,%s)\n",ht,key);
    if (ht==NULL)
       RETURN(NULL);
    index= _hash(key,Size(ht));
    he= Nth(ht,index);
    while (he!=NULL) {
       if (StrMatch(key,Key(he)))
          RETURN(Info(he));
       else
          he= Next(he);
    }
    RETURN(NULL);
}

/***=====================================================================***/

hetype    *
ht_remove(ht,key)
register4 hashtable *ht;
register3 char      *key;
{
register5 int        index;
register6 hetype     *hi;
register1 hashelem   *he,*htmp=NULL;

    D_ENTRY2(ht_debug,"ht_remove(0x%x,%s)\n",ht,key);
    if (ht==NULL)
       RETURN(NULL);
    index= _hash(key,Size(ht));
    he= Nth(ht,index);
    while (he!=NULL) {
       if (StrMatch(key,Key(he)))
          break;
       else {
	  htmp= he;
	  he= Next(he);
       }
    }
    if (he==NULL)   RETURN(NULL);
    if (htmp==NULL) Nth(ht,index)= Next(he);
    else            Next(htmp)= Next(he);
    hi= Info(he);
    _he_free(he);
    RETURN(hi);
}

/***=====================================================================***/

_ht_print(fil,ht,func)
register2 FILE *fil;
register1 hashtable *ht;
register5 int	(*func)();
{
register3 hashelem *he;
register4 int knt;

   for (knt=0;knt<Size(ht);knt++) {
       fprintf(fil,"%-2d) ");
       if (Nth(ht,knt)==NULL) {
	  fprintf(fil,"<nothing>\n");
	  continue;
       }
       else {
	  he= Nth(ht,knt);
	  while (he) {
	     (*func)(fil,Info(he));
	     he= Next(he);
	  }
       }
   }
}

/***=====================================================================***/

ht_iterate(ht,fun)
register2 hashtable   *ht;
register3 int   (*fun)();
{
register1 hashelem *he;
register4 int knt;

   D_ENTRY2(ht_debug,"ht_iterate(0x%x,0x%x)\n",ht,fun);
   for (knt=0;knt<Size(ht);knt++) {
       if ((he= Nth(ht,knt))!=NULL) {
	  while (he) {
	     (*fun)(Info(he));
	     he= Next(he);
	  }
       }
   }
   RETURN(TRUE);
}

