/*=-=-=-=-=-=-=-=-=-=-  RCCL/RCI Notice of Copyright  -=-=-=-=-=-=-=-=-=-=-=*
 *									    *
 *	Copyright (C) 1987 by Mike Parker. Permission to use, distribute    *
 *	and copy is granted for non-commercial and research purposes only,  *
 *	providing the authors are acknowledged and this copyright notice is *
 *	displayed. The authors provide this software in hope that it will   *
 *	useful, but do not assume responsibility for its use.		    *
 *									    *
 *	This software was developed using the facilities of the McGill 	    *
 *	University Research Center for Intelligent Machines, Montreal,	    *
 *	Canada, for a project undertaken and supported by the RCA Advanced  *
 *	Technology Laboratories, Moorestown, New Jersey.		    *
 *									    *
 *=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/

#include "../h/malloc.h"

#define NULL 0

typedef struct _entry {
	  struct _entry *link;
	  char *name;
	  char *obj; } ENTRY;

static ENTRY **table = 0;
static int entries = 0;
static int table_size = 0;

static int get_index = 0;
static ENTRY *last = NULL;

static startoff();
static ENTRY **find();
static grow();
static int hash();

static int initDone = 0;
#define INIT_CHECK()	if (!initDone) doInit();
static doInit()
{
	if (table)
	 { OLD(table);
	   table = 0;
	 }
	entries = 0;
	table_size = 0;
	get_index = 0;
	last = NULL;
	initDone = 1;
	requestFlagInit(&initDone);
}

static startoff()
{
 register int i;

 table_size = 15;
 table = (ENTRY **) malloc(table_size*sizeof(ENTRY *));
 if (table == NULL)
  { return (-1);
  }
 for (i=0;i<table_size;i++)
  { table[i] = 0;
  }
 entries = 0;
 return (0);
}

static ENTRY **find(name)
char *name;
{
 register ENTRY **e;

 for (e= &table[hash(name)];*e;e= &(*e)->link)
  { if (strcmp((*e)->name,name) == 0)
     { break;
     }
  }
 return(e);
}

static grow()
{
 ENTRY **oldt;
 int oldsize;
 int i;
 ENTRY *e;
 ENTRY *f;
 int h;

 oldt = table;
 oldsize = table_size;
 table_size = (oldsize * 2) + 1;
 table = (ENTRY **) malloc(table_size*sizeof(ENTRY *));
 if (table == NULL)
  { return (-1);
  }
 bzero(table,table_size*sizeof(ENTRY *));
 for (i=0;i<oldsize;i++)
  { for (e=oldt[i];e;e=f)
     { f = e->link;
       h = hash(e->name);
       e->link = table[h];
       table[h] = e;
     }
  }
 OLD(oldt);
 return (0);
}

char *hash_insert(name,object,clobber,oldo)
char *name, *object;
int clobber;
char **oldo;
{
 ENTRY **e;

 INIT_CHECK();

 if (table_size == 0)
  { if(startoff())
     { return (NULL);
     }
  }
 if (entries >= table_size)
  { if (grow())
     { return (NULL);
     }
  }
 e = find(name);
 if (!*e)
  { if ((*e = NEW(ENTRY)) == NULL)
     { return (NULL);
     }
    (*e)->link = 0;
    if (((*e)->name = copyofstr(name)) == NULL)
     { return (NULL);
     }
    entries ++;
    if (oldo)
     { oldo = NULL;
     }
    return ((*e)->obj = object);
  }
 else if (clobber)
  { if (oldo)
     { *oldo = (*e)->obj;
     }
    return ((*e)->obj = object);
  }
 else
  { if (oldo)
     { *oldo = NULL;
     }
    return (NULL);
  }
}

char *hash_delete(name)
char *name;
{
 ENTRY **e;
 char *o;

 INIT_CHECK();

 if (table_size == 0)
  { return(0);
  }
 e = find(name);
 if (*e)
  { ENTRY *f;
    f = (*e)->link;
    o = (*e)->obj;
    OLD(*e);
    *e = f;
    entries --;
  }
 else
  { o = 0;
  }
 return(o);
}

char *hash_find(name)
char *name;
{
 ENTRY **e;

 INIT_CHECK();

 if (table_size == 0)
  { return(0);
  }
 e = find(name);
 if (*e)
  { return((*e)->obj);
  }
 else
  { return(0);
  }
}

char *hash_get (string, init)
char **string;
int init;
{
 ENTRY *e;

 INIT_CHECK();

 if (init)
  { get_index = 0;
    last = NULL;
    return(0);
  }
 e = NULL;
 if (last)
  { e = last->link;
  }
 while (!e && (get_index < table_size))
  { e = table[get_index++];
  }
 last = e;
 if (string)
  { *string = ((e) ? e->name : NULL);
  }
 return ((e) ? e->obj : NULL);
}

static int hash(name)
register char *name;
{
 register unsigned long int code;

 code = 0;
 while (*name)
  { code += *name ++;
    code <<= 2;
    code += (code >> 24) & 0xff;
  }
 return(code%table_size);
}
