/*
 *	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 "malloc.h"
#include "libz.h"

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

/* crc table and hash algorithm from pathalias */
/*
 * fold a string into a long int.  31 bit crc (from andrew appel).
 * the crc table is computed at run time by crcinit() -- we could
 * precompute, but it takes 1 clock tick on a 750.
 *
 * This fast table calculation works only if POLY is a prime polynomial
 * in the field of integers modulo 2.  Since the coefficients of a
 * 32-bit polynomail won't fit in a 32-bit word, the high-order bit is
 * implicit.  IT MUST ALSO BE THE CASE that the coefficients of orders
 * 31 down to 25 are zero.  Happily, we have candidates, from
 * E. J.  Watson, "Primitive Polynomials (Mod 2)", Math. Comp. 16 (1962):
 *      x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + x^0
 *      x^31 + x^3 + x^0
 *
 * We reverse the bits to get:
 *      111101010000000000000000000000001 but drop the last 1
 *         f   5   0   0   0   0   0   0
 *      010010000000000000000000000000001 ditto, for 31-bit crc
 *         4   8   0   0   0   0   0   0
 */

#define POLY32 0xf5000000       /* 32-bit polynomial */
#define POLY31 0x48000000       /* 31-bit polynomial */
#define POLY POLY31     /* use 31-bit to avoid sign problems */

static long CrcTable[128];

static void crcinit __((void));
static void
crcinit()
{       
	register int i,j;
	register long sum;

	for (i = 0; i < 128; i++) {
		sum = 0;
		for (j = 7-1; j >= 0; --j)
			if (i & (1 << j))
				sum ^= POLY >> j;
		CrcTable[i] = sum;
	}
}


struct syment {
	const char    *name;
	struct syment *next;
};

struct sptree *spt_symtab = NULL;

spkey_t
symbol(s)
	const void *s;
{
	register const char *ucp;
	register spkey_t key;
	register struct syment *se, *pe;
	char *newname;
	static const char *idname = "";
	static spkey_t id, idkey = 1;
	struct spblk *spl;

	if (s == NULL)
		return 0;
	if (spt_symtab == NULL) {
		spt_symtab = sp_init();
		crcinit();
	}

	key = 0;
	for (ucp = s; *ucp != '\0'; ++ucp)
		key = (key >> 7) ^ CrcTable[(key ^ *ucp) & 0x7f];

	if (key == idkey && strcmp(s, (const char *)idname) == 0)
		return id;
	idkey = key;
	pe = NULL;
	spl = sp_lookup(key, spt_symtab);
	if (spl != NULL) {
		se = (struct syment *)spl->data;
		do {
			if (strcmp(se->name, s) == 0) {
				idname = se->name;
				id = (spkey_t)se;
				return id;
			}
			pe = se;
			se = se->next;
		} while (se != NULL);
	}
	se = (struct syment *)emalloc(sizeof (struct syment));
	newname = (char *) emalloc((u_int)(strlen(s)+1));
	strcpy(newname, s);
	se->name = newname;
	idname = se->name;
	se->next = NULL;
	if (pe != NULL)
		pe->next = se;
	else
		(void) sp_install(key, (const void *)se, 0, spt_symtab);
	id = (spkey_t)se;
	return id;
}

/*
 * 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", (char *)se->name);
	putchar('\n');
	return 0;
}

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