/*
 *	Copyright 1988 by Rayan S. Zachariassen, all rights reserved.
 *	This will be free software, but only when it is finished.
 */

/*
 * Symbol routine: it maps an arbitrary string into a unique key
 * that can be used as an index into various tables.
 */

#include "hostenv.h"

#include <stdio.h>
#include <sys/types.h>

#include "splay.h"
#include "zmalloc.h"

#ifdef	symbol
#undef	symbol
#endif	/* symbol */

extern long pjwhash32n __((const void *, int));
extern long crc32n     __((const void *, int));


#define CRCorNOT 1 /* 0: pjwhash32n(), !0: crc32n() */

struct syment {
	struct syment *next;
	int        namelen;
	const char name[1];
};

struct sptree *spt_symtab = NULL;

spkey_t
symbol(s)
	const void *s;
{
	if (spt_symtab == NULL)
		spt_symtab = sp_init();
	return symbol_db(s, spt_symtab);
}

spkey_t
symbol_lookup(s)
	const void *s;
{
	if (spt_symtab == NULL)
		spt_symtab = sp_init();
	return symbol_lookup_db(s, spt_symtab);
}

spkey_t
symbol_lookup_db_mem_(s, slen, spt, usecrc)
	const void *s;
	const int slen;
	struct sptree *spt;
	const int usecrc;
{
	register spkey_t key;
	register struct syment *se, *pe;
	struct spblk *spl;

	if (s == NULL)
		return 0;

	if (usecrc)
	  key = crc32n(s, slen);
	else
	  key = pjwhash32n(s, slen);

	/* Ok, time for the hard work.  Lets see if we have this key
	   in the symtab splay tree */

	pe = NULL;
	spl = sp_lookup(key, spt);
	if (spl != NULL) {
		/* Got it !  Now see that we really have it, and
		   not only have a hash collision */

		se = (struct syment *)spl->data;
		do {
			if (se->namelen == slen &&
			    memcmp(se->name, s, slen) == 0) {
				/* Really found it! */
				return (spkey_t)se;
			}
			pe = se;
			se = se->next;
		} while (se != NULL);
	}
	return 0;
}

spkey_t
symbol_lookup_db_mem(s, slen, spt)
	const void *s;
	const int slen;
	struct sptree *spt;
{
  return symbol_lookup_db_mem_(s, slen, spt, CRCorNOT);
}



spkey_t
symbol_db_mem_(s, slen, spt, usecrc)
	const void *s;
	int slen, usecrc;
	struct sptree *spt;
{
	register spkey_t key;
	register struct syment *se, *pe;
	struct spblk *spl;

	if (s == NULL)
		return 0;

	if (usecrc)
	  key = crc32n(s,slen);
	else
	  key = pjwhash32n(s,slen);

	/* Ok, time for the hard work.  Lets see if we have this key
	   in the symtab splay tree */

	pe = NULL;
	spl = sp_lookup(key, spt);
	if (spl != NULL) {
		/* Got it !  Now see that we really have it, and
		   not only have a hash collision */

		se = (struct syment *)spl->data;
		do {
			if (se->namelen == slen &&
			    memcmp(se->name, s, slen) == 0) {
				/* Really found it! */
				return (spkey_t)se;
			}
			pe = se;
			se = se->next;
		} while (se != NULL);
	}
	se = (struct syment *)emalloc(sizeof (struct syment) + slen);
	memcpy((void*)se->name, s, slen);
	((char*)se->name)[slen] = 0;
	se->namelen = slen;
	se->next    = NULL;
	if (pe != NULL)
		pe->next = se;
	else {
		(void) sp_install(key, (const void *)se, 0, spt);
	}
	return (spkey_t)se;
}

spkey_t
symbol_db_mem(s, slen, spt)
	const void *s;
	int slen;
	struct sptree *spt;
{
  return symbol_db_mem_(s, slen, spt, CRCorNOT);
}

/*
 * Empty the entire symbol splay tree
 */
static int
symbol_null(spl)
	struct spblk *spl;
{
	struct syment *se, *sn;
	se = (struct syment *)spl->data;
	for (sn = se ? se->next : NULL; se != NULL; se = sn) {
	  sn = se->next;
	  free(se);
	}
	return 0;
}

void
symbol_null_db(spt)
	struct sptree *spt;
{
#if 0
	idname = "";
	idkey  = 0;
#endif
	sp_scan(symbol_null, (struct spblk *)NULL, spt);
	sp_null(spt);
}


/*
 * Remove named symbol from the splay tree
 */

void
symbol_free_db_mem_(s, slen, spt, usecrc)
	const void *s;
	int slen, usecrc;
	struct sptree *spt;
{
	register spkey_t key;
	register struct syment *se, *pe;
	struct spblk *spl;

	if (s == NULL || spt == NULL)
		return;

	if (usecrc)
	  key = crc32n(s, slen);
	else
	  key = pjwhash32n(s, slen);


	/* Ok, time for the hard work.  Lets see if we have this key
	   in the symtab splay tree (we can't use cache here!) */

	pe = NULL;
	spl = sp_lookup(key, spt);
	if (spl != NULL) {
		/* Got it !  Now see that we really have it, and
		   not only have a hash collision */

		se = (struct syment *)spl->data;
		do {
		  if (se->namelen == slen &&
		      memcmp(se->name, s, slen) == 0) {
		    /* Really found it! */
		    if (pe != NULL)
		      pe->next = se->next;
		    else
		      spl->data = (void*) se->next;
		    free(se);
		    break;
		  }
		  pe = se;
		  se = se->next;
		} while (se != NULL);
	}

	if (spl != NULL && spl->data == NULL)
		sp_delete(spl, spt);
}

void symbol_free_db_mem(s, slen, spt)
	const void *s;
	int slen;
	struct sptree *spt;
{
	symbol_free_db_mem_(s, slen, spt, CRCorNOT);
}

void
symbol_free_db(s, spt)
	const void *s;
	struct sptree *spt;
{
	if (s == NULL || spt == NULL)
		return;
	symbol_free_db_mem(s, strlen(s), spt);
}


/*
 * Return a printable string representation of the symbol whose key is passed.
 */

const char *
pname(id)
	spkey_t id;
{
	return (const char *)((struct syment *)id)->name;
}

#ifdef	MALLOC_TRACE
int
icpname(spl)
	struct spblk *spl;
{
	register struct syment *se;

	for (se = (struct syment *)spl->data; se != NULL ; se = se->next)
		printf(">%s", se->name);
	putchar('\n');
	return 0;
}

prsymtable()
{
	sp_scan(icpname, (struct spblk *)NULL, spt_symtab);
}
#endif	/* MALLOC_TRACE */


spkey_t
symbol_lookup_db(s, spt)
	const void *s;
	struct sptree *spt;
{
	if (s == NULL)
		return 0;

	return symbol_lookup_db_mem(s, strlen(s), spt);
}


spkey_t
symbol_db(s, spt)
	const void *s;
	struct sptree *spt;
{
	if (s == NULL)
		return 0;
	return symbol_db_mem(s, strlen(s), spt);
}


syntax highlighted by Code2HTML, v. 0.9.1