#ifndef HASL2
static    char    sccsid[]="%Z% %M% %I% %E% %U%";
#endif
/*************************************************
 *
 *	akxshasl.c
 *
 *		  coded by A.Kobayashi 2003/06/13
 *
 *************************************************/
#ifndef HASL2
#include "akxcommon.h"
#endif

#define DEBUGP(x)
#define DEBUGPX(x)

static int  max_count=0;

static int _haslf();
int akxshaslr(/*hp,key*/);

int akxshasli(hp)
HASHB *hp;
{
	int i=0,mx,m1,*np,j;
	int  opt;
	char c;

	if (!hp) return -1;
	opt = 0;
	if ((mx=hp->ha_maxreg)<=0) i-=4;
	if ((m1=hp->ha_prereg)<=0) i-=8;
	if (m1>=mx) i-=16;
	if (!hp->ha_reg) i-=32;
	if (!(np=hp->ha_next)) i -=64;

	if (i>=0) {
		memset(hp->ha_reg,0,mx*sizeof(tdtHaslCell));
		hp->ha_aux=m1;
DEBUGP(printf("hasli: aux=%d\n",hp->ha_aux);)
		memset(np,0,mx*sizeof(int));
		np += mx;
		for (j=0;j<mx;j++) np[j]=j+1;
		np[mx] = 0;
	}

	return (i);
}

static int _haslf(hp,key)
HASHB *hp;
#ifdef HASL2
ulong key[];
#else
long key;
#endif
{
	int i;
	ulong hey[2];

	if (!hp) return -1;
#ifdef HASL2
	if (!key) return -1224;
	if (!(key[0] & 0xff000000)) hey[0] = X_HTONL(key[0]);
	else hey[0] = key[0];
	if (!(key[1] & 0xff000000)) hey[1] = X_HTONL(key[1]);
	else hey[1] = key[1];
	i=(hey[0]+hey[1])%hp->ha_prereg+1;
DEBUGP(printf("_haslf: hey=%08x %08x ih=%d\n",hey[0],hey[1],i);)
#else
	if (!(key & 0xff000000)) key = X_HTONL(key);
	i=(ulong)key%hp->ha_prereg+1;
DEBUGP(printf("_haslf: key=%08x ih=%d\n",key,i);)
#endif
	return i;
}

static int _haslf_ih(hp,key)
HASHB *hp;
#ifdef HASL2
ulong key[];
#else
long key;
#endif
{
	int ih;

	if (!hp) return -1;
#ifdef HASL2
	if (!key) return -1224;
	if ((ih=hp->ha_hix)<=0) {
		ih=_haslf(hp,key);
#else
	if ((ih=hp->ha_hix)<=0) {
		ih=_haslf(hp,key);
#endif
	}
	else if (ih > hp->ha_prereg) return -1225;
	return ih;
}

static int _cmpkey(ce,key)
tdtHaslCell *ce;
#ifdef HASL2
ulong key[];
#else
long key;
#endif
{
#ifdef HASL2
	if ((ce->hc_akey[0]==key[0]) && (ce->hc_akey[1]==key[1]))
#else
	if (ce->hc_hkey==key)
#endif
		return 0;
	else
		return 1;
}

int akxshasls(hp,key)
HASHB *hp;
#ifdef HASL2
ulong key[];
#else
long key;
#endif
{
	int ih,*en,*fn;
	int i,k,i_start,*data;
	tdtHaslCell *cell,*ce;
	char c,**argv;

	if ((ih=_haslf_ih(hp,key)) <= 0) return ih;

	cell=(tdtHaslCell *)hp->ha_reg-1;
	if (argv=(char **)hp->ha_key) data=(int *)argv[1];
	else data=NULL;
	en = hp->ha_next;
	fn = en + hp->ha_maxreg;
	i=i_start=en[ih-1];
	if (i) {
  L10:
		ce=&cell[i];
		if (!_cmpkey(ce,key)) {
			ce->hc_datp=data;
			return i;
		}
DEBUGP(printf("hasls: next[%d]=%d\n",i,ce->hc_next);)
		if ((k=ce->hc_next) > 0) {
			i = k;
			goto L10;
		}
	}
	else i = ih;

	if (!(k = fn[0])) return 0;
DEBUGP(printf("hasls: k=%d\n",k);)
	fn[0] = fn[k];
	if (i_start) {
		ce=&cell[i];
		ce->hc_next = k;
	}
	else en[i-1] = k;
	ce=&cell[k];
	ce->hc_next = 0;
	ce->hc_flag = 1;
#ifdef HASL2
	ce->hc_akey[0]=key[0];
	ce->hc_akey[1]=key[1];
#else
	ce->hc_hkey=key;
#endif
	ce->hc_datp=data;
	return k;
}

int akxshaslr(hp,key)
HASHB *hp;
#ifdef HASL2
ulong key[];
#else
long key;
#endif
{
	int i,ih,*en,*fn;
	tdtHaslCell *cell,*ce;
	char **argv;

	if ((ih=_haslf_ih(hp,key)) <= 0) return ih;

	cell=(tdtHaslCell *)hp->ha_reg-1;
	en = hp->ha_next;
	if (i=en[ih-1]) {
  L10:
		ce=&cell[i];
		if (!_cmpkey(ce,key)) {
			if (argv=(char **)hp->ha_key) {
				argv[1]=(char *)ce->hc_datp;
/*
printf("akxshaslr: argv=%08x argv[1]=%08x\n",argv,argv[1]);
*/
			}
			return i;
		}
		else if ((i=ce->hc_next)>0) goto L10;
	}
	return 0;
}

int akxshasld(hp,key)
HASHB *hp;
#ifdef HASL2
ulong key[];
#else
long key;
#endif
{
	int i,ih,*en,*fn,isp;
	tdtHaslCell *cell,*ce,*cek;
	char c,**argv;

	if ((ih=_haslf_ih(hp,key)) <= 0) return ih;

	cell=(tdtHaslCell *)hp->ha_reg-1;
	en = hp->ha_next;
	fn = en + hp->ha_maxreg;
	cek = NULL;

	if (!(i=en[ih-1])) return 0;
  L10:
	ce = &cell[i];
	if (_cmpkey(ce,key)) {
		cek = ce;
		if ((i=ce->hc_next)>0) goto L10;
		return 0;
	}
	if (cek) cek->hc_next = ce->hc_next;
	else  en[ih-1] = ce->hc_next;
	isp = fn[0];
	fn[i] = isp;
	fn[0] = i;
	ce->hc_next = 0;
	ce->hc_flag = 0;
	if (argv=(char **)hp->ha_key) argv[1]=(char *)ce->hc_datp;
	return i;
}

#ifdef HASL2
int akxshasl2k(hp,key)
HASHB *hp;
ulong key[];
#else
int akxshaslk(hp,keyp)
HASHB *hp;
long *keyp;
#endif
{
	int i;
	tdtHaslCell *ce;
	char **argv;

	if (!hp) return -1;
	i=hp->ha_hix;
	if (i<=0 || i>hp->ha_maxreg) return -1225;
	ce=&((tdtHaslCell *)hp->ha_reg)[i]-1;
	if (ce->hc_flag) {
#ifdef HASL2
		if (key) {
			key[0]=ce->hc_akey[0];
			key[1]=ce->hc_akey[1];
		}
#else
		if (keyp) *keyp=ce->hc_hkey;
#endif
		if (argv=(char **)hp->ha_key) argv[1]=(char *)ce->hc_datp;
		return i;
	}
	return 0;
}

int akxshaslp(hp)
HASHB *hp;
{
	int i;
	tdtHaslCell *ce;
	char **argv;

	if (!hp) return -1;
	i=hp->ha_hix;
	if (i<=0 || i>hp->ha_maxreg) return -1225;
	ce=&((tdtHaslCell *)hp->ha_reg)[i]-1;
	if (ce->hc_flag) {
		if (argv=(char **)hp->ha_key) {
#ifdef HASL2
			argv[0]=(char *)ce->hc_akey;
#else
			argv[0]=(char *)&ce->hc_hkey;
#endif
			argv[1]=(char *)ce->hc_datp;
		}
		return i;
	}
	return 0;
}

int akxshaslu(hp)
HASHB *hp;
{
	int x,i,max,n;
	char *key;

	if (!hp) return -1;
	key = hp->ha_key;
	hp->ha_key = NULL;
	x = hp->ha_hix;
	max = hp->ha_maxreg;
	n = 0;
	for (i=1;i<=max;i++) {
		hp->ha_hix = i;
#ifdef HASL2
		if (akxshasl2k(hp,NULL) > 0) n++;
#else
		if (akxshaslk(hp,NULL) > 0) n++;
#endif
	}
	hp->ha_hix = x;
	hp->ha_key = key;
	return n;
}

HASHB *akxs_hasl_new2(sKeyLen,lMaxReg,lPreReg,iOpt)
short sKeyLen;
int  lMaxReg,lPreReg;
int   iOpt;
{
	HASHB *tph;
	int l,pre;
	int  opt;
	char c;
#if 0
	if (/*sKeyLen<=0 || */lMaxReg<2 || lPreReg<0 ||
	    (lPreReg>0 && lMaxReg<=lPreReg))  {
#else
	if (lMaxReg<2 || lPreReg<0) {
#endif
		errno = -1201;
		return NULL;
	}
	if (lPreReg > 0) {
		if (lMaxReg<=lPreReg) {
			errno = -1202;
			return NULL;
		}
	}
	if (!(l=lPreReg)) {
		pre = 0;
		if ((l=akxs_hasx_pre_reg(lMaxReg,pre)) < 1) {
			errno = -1203;
			return NULL;
		}
DEBUGP(printf("HaslNew mso=%d\n",l);)
	}
	if (!(tph=(HASHB *)Malloc(sizeof(HASHB)))) {
		errno = -1204;
		return NULL;
	}
	memset(tph,0,sizeof(HASHB));
	tph->ha_id[0] = 'H';
#ifdef HASL2
	tph->ha_id[1] = '2';
#else
	tph->ha_id[1] = 'L';
#endif
	tph->ha_keylen = sKeyLen;
	tph->ha_maxreg = lMaxReg;
	tph->ha_prereg = l;
	tph->ha_hix    = 0;
	if (!(tph->ha_reg=Malloc(lMaxReg*sizeof(tdtHaslCell)))) {
		akxs_hasl_free(tph);
		errno = -1205;
		return NULL;
	}
	if (!(tph->ha_next=(int *)Malloc((lMaxReg*2+1)*sizeof(int)))) {
		akxs_hasl_free(tph);
		errno = -1206;
		return NULL;
	}
	if (errno=akxshasli(tph)) {
		akxs_hasl_free(tph);
		return NULL;
	}
	return tph;
}

int akxs_hasl_free(tph)
HASHB *tph;
{
	if (tph) {
		if (tph->ha_reg) Free(tph->ha_reg);
		Free(tph);
	}
	return 0;
}

int akxshasl(func,hp)
char func;
HASHB *hp;
{
	char cmd,**argv;
	int i;
#ifdef HASL2
	ulong key[2];
#else
	long key;
#endif

	if (!hp) return -1;
	if (!(argv=(char **)hp->ha_key))  return -1224;

	switch (cmd=akxcupper(func)) {
	  case 'R':
	  case 'S':
	  case 'D':
	  case 'F':
#ifdef HASL2
			key[0]=((long *)argv[0])[0];
			key[1]=((long *)argv[0])[1];
#else
			memcpy(&key,&argv[0],sizeof(long));
#endif
			break;
	  default:
#ifdef HASL2
			key[0] = -1;
			key[1] = -1;
#else
	  		key = -1;
#endif
	}
	switch (cmd) {
	  case 'R':
			i=akxshaslr(hp,key);
			break;
	  case 'S':
			i=akxshasls(hp,key);
			break;
	  case 'D':
			i=akxshasld(hp,key);
			break;
	  case 'I':
			i=akxshasli(hp);
			break;
	  case 'K':
#ifdef HASL2
			i=akxshasl2k(hp,key);
			((long *)argv[0])[0]=key[0];
			((long *)argv[0])[1]=key[1];
#else
			i=akxshaslk(hp,&key);
			argv[0]=(char *)key;
#endif
			break;
	  case 'P':
			i=akxshaslp(hp);
			break;
	  case 'U':
			i=akxshaslu(hp);
			break;
	  case 'F':
			i=_haslf(hp,key);
			break;
	  default:
			i=-2;
	}
	return i;
}

HASHB *akxs_hasl_new(sKeyLen,lMaxReg,lPreReg)
short sKeyLen;
int  lMaxReg,lPreReg;
{
	return akxs_hasl_new2(sKeyLen,lMaxReg,lPreReg,0);
}

static int _xhasl_chk(tpxhashb,cCmd,lH,ippDat)
tdtRbChain *tpxhashb;
char cCmd;
long lH;
int **ippDat;
{
	int ret;
	tdtRbChain *tpcurr;
	int i,offset,next,ix,max,*argv[2];
	HASHB *tph;

	ret = 0;
	i = lH;
	offset = 0;
	tpcurr = tpxhashb;
	tph = (HASHB *)tpcurr->rbc_buf;
	max = tph->ha_maxreg;
	while (tpcurr) {
		next = offset + max;
		if (next >= i) {
			if (tph=(HASHB *)tpcurr->rbc_buf) {
				tph->ha_hix = ix = i - offset;
				tph->ha_key = (char *)argv;
				ret = akxshaslp(tph);
/*
printf("_xhasl_chk: i=%d ix=%d ret=%d\n",i,ix,ret);
*/
				if (ret > 0) {
					*ippDat = argv[1];
					return i;
				}
			}
			break;
		}
		tpcurr = tpcurr->rbc_next;
		offset = next;
	}
	return ret;
}

static int _xhasl_max(tpxhashb)
tdtRbChain *tpxhashb;
{
	tdtRbChain *tpcurr;
	int max,count;
	HASHB *tph;

	count = 0;
	tpcurr = tpxhashb;
	tph = (HASHB *)tpcurr->rbc_buf;
	max = tph->ha_maxreg;
	while (tpcurr) {
		count += max;
		tpcurr = tpcurr->rbc_next;
	}
/*
printf("_xhasl_max: count=%d\n",count);
*/
	return count;
}

int akxs_xhasl(tpxhashb,cCmnd,key,ippDat)
tdtRbChain *tpxhashb;
char cCmnd;
#ifdef HASL2
ulong key[];
#else
long key;
#endif
int **ippDat;
{
	tdtRbChain *tpcurr,*tpnext;
	int l,i,offset,*dummy;
	HASHB *tph;
	char cCmd,c,*argv[2];
/*
printf("akxs_xhasl: tpxhashb=%08x cCmnd=%c key=%d ippDat=%08x\n",
tpxhashb,cCmnd,key,ippDat);
*/
	if (!tpxhashb) return -1;
	if (!ippDat) ippDat = &dummy;
	cCmd = akxcupper(cCmnd);
	if (cCmd=='P' || cCmd=='K')
#ifdef HASL2
		return _xhasl_chk(tpxhashb,cCmd,key[0],ippDat);
#else
		return _xhasl_chk(tpxhashb,cCmd,key,ippDat);
#endif
	else if (cCmd=='M') return _xhasl_max(tpxhashb);
	l = 0;
	offset = 0;
	tpnext = tpxhashb;
	while (tpnext) {
		tpcurr = tpnext;
		tph = (HASHB *)tpcurr->rbc_buf;
		tph->ha_hix = 0;
		tph->ha_key = (char *)argv;
		if (cCmd == 'R') {
			i = akxshaslr(tph,key);
			if (i > 0) *ippDat = (int *)argv[1];
		}
		else if (cCmd == 'S') {
			argv[1] = (char *)*ippDat;
			i = akxshasls(tph,key);
		}
		else if (cCmd == 'D') i = akxshasld(tph,key);
		if (i) {
			if (i>0) i += offset;
			return i;
		}
		tpnext = tpcurr->rbc_next;
		offset += tph->ha_maxreg;
	}
/*
printf("akxs_xhasl:(%08x)->xha_xhnext=NULL\n",tpcurr);
*/
	if (cCmd=='R' || cCmd=='D') return i;
	c = tph->ha_id[0];
	if (!(tpnext=akxs_xhasl_new(tph->ha_keylen,tph->ha_maxreg,tph->ha_prereg,0))) return -76;
	tph = (HASHB *)tpnext->rbc_buf;
	tph->ha_id[0] = c;
	tpcurr->rbc_next = tpnext;
	if ((i=akxs_xhasl(tpnext,cCmd,key,ippDat)) > 0) i += offset;
	return i;
}

tdtRbChain *akxs_xhasl_new(sKeyLen,lMaxReg,lPreReg,iOpt)
short sKeyLen;
int  lMaxReg,lPreReg,iOpt;
{
	tdtRbChain *p;

	if (!(p=(tdtRbChain *)Malloc(sizeof(tdtRbChain)))) {
		errno = -1303;
		return NULL;
	}
	p->rbc_buf = (char *)akxs_hasl_new2(sKeyLen,lMaxReg,lPreReg,iOpt);
	p->rbc_next = NULL;
	return p;
}

int akxs_xhasl_free(tpxhashb)
tdtRbChain *tpxhashb;
{
	tdtRbChain *p;
	HASHB *tph;

	if (p=tpxhashb) {
		if (tph=(HASHB *)p->rbc_buf) akxs_hasl_free(tph);
		akxs_xhasl_free(p->rbc_next);
		Free(p);
	}
	return 0;
}
