static char sccsid[]="%Z% %M% %I% %E% %U%";
/************************************************/
/*												*/
/*	akxshash.c									*/
/*												*/
/*		  coded by A.Kobayashi 2010/5/20		*/
/*												*/
/************************************************/
#include "akxcommon.h"

#define MULTI	AKX_HASX_MULTIPLIER2
static int lMULTIPLIER =MULTI;
static int lMULTIPLIER2=MULTI*MULTI;
static int lMULTIPLIER3=MULTI*MULTI*MULTI;
static int lMULTIPLIER4=MULTI*MULTI*MULTI*MULTI;

static int _hashr();
static int _hashs();
static int _hashd();
static int _hashd2();
static int _hashi();
static int _hashk();
static int _hashp();
static int _hashu();
static int _hashf();
static int _hashfunc();

#define _SETUP(kpp,plalen) {	\
	i = hp->ha_hix;	\
	kp = hp->ha_key;	\
	if (!i && !kp) return -1024;	\
	rp = hp->ha_reg;	\
	np = hp->ha_next;	\
	klen = hp->ha_keylen;	\
	if (klen > 0) len1 = klen + 1;	\
	else {	\
		rpp  = (char **)rp;	\
		used = rp + (hp->ha_maxreg+1)*sizeof(char *);	\
	}	\
	if (kp) {	\
		lklen = _getkey(klen,kp,kpp,plalen);	\
		if (lklen < 0) return lklen;	\
		if (iCASE) kp = _dupcasekey(kp,lklen);	\
	}	\
	if (i > 0) {	\
		if (kp && i>hp->ha_prereg) return -1025;	\
	}	\
	else i=_hashf(kp,lklen,hp->ha_prereg);	\
}

int akxshasx(func,hp)
char func;
HASHB *hp;
{
	int i;
	int  ilen,opt,imaxlen,iCASE;
	uchar *hkey,*kp,cmd,c,cc;
	uint ulkey[2];

	if (!hp) return -1;

	cmd = akxcupper(func);
	if ((c=hp->ha_id[1])=='L' || c=='2') {
		if (cmd == 'I') {
			if (c == 'L') i = akxshasl(func,hp);
			else i = akxshasl2(func,hp);
		}
		else {
			if (cmd!='K' && cmd!='P') {
				if (c == 'L') imaxlen=sizeof(long);
				else imaxlen = sizeof(long)*2;
				hkey = (uchar *)ulkey;
				if (!(kp=(uchar *)hp->ha_key)) return -1024;
				ilen = hp->ha_keylen;
				if (ilen == imaxlen) memcpy(hkey,kp,imaxlen);
				else {
					ulkey[0] = ulkey[1] = 0;
					memcpy(hkey,kp,ilen);
				}
				hp->ha_key = (char *)hkey;
			}
			if (c == 'L') i = akxshasl(func,hp);
			else i = akxshasl2(func,hp);
			if (cmd!='K' && cmd!='P') {
				hp->ha_key = (char *)kp;
			}
		}
		return i;
	}

	cc = hp->ha_id[0];
	c = toupper(cc);
	if (c == AKX_HASX_ID_NO_USE_ALL) opt = AKX_HASX_OPT_NO_USE_ALL;
	else if (c == AKX_HASX_ID_NO_NEXT) opt = AKX_HASX_OPT_NO_NEXT;
	else opt = 0;
	if (c == cc) iCASE = 0;
	else iCASE = 1;

	switch (akxcupper(func)) {
		case 'I':
			i = _hashi(hp,opt);
			break;
		case 'S':
			i = _hashs(hp,opt,iCASE);
			break;
		case 'R':
			i = _hashr(hp,iCASE);
			break;
		case 'D':
			if (opt) i = _hashd2(hp,iCASE);
			else i = _hashd(hp,iCASE);
			break;
		case 'K':
			i = _hashk(hp);
			break;
		case 'P':
			i = _hashp(hp);
			break;
		case 'U':
			i = _hashu(hp);
			break;
		case 'F':
			i = _hashfunc(hp,iCASE);
			break;
		default:
			i = -2;
	}
	return i;
}

static int _hashi(hp,opt)
HASHB *hp;
int   opt;
{
	int i=0,j,mx,m1,*np;
	int klen,len1;
	char *rp,**rpp;

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

	if (i >= 0) {
		klen = hp->ha_keylen;
		if (klen > 0) {
			len1 = klen + 1;
			for (j=0;j<mx;j++) {
				*rp = 0;
				rp += len1;
			}
		}
		else {
			memset(rp,0,(mx+1)*(sizeof(int)+1));
			rpp = (char **)rp;
			rpp[0] = (char *)akxm_cct_mem_new(mx*32);
		}
		if (np) memset(np,0,mx*sizeof(int));
		hp->ha_aux = m1;
	}

	return i;
}

static int _getkey(klen,p,kpp,plalen)
int klen,*plalen;
char *p,**kpp;
{
	int ret;

	ret = akxt_get_gep_data(klen,p,kpp,plalen);
	if (ret == -1) ret = -1031;
	else if (ret == -2) ret = -1026;

	return ret;
}

static int _cmpkey(klen,kp,lklen,p)
int klen,lklen;
char *kp,*p;
{
	int ret;

	if (!kp) return 0;
	ret = akxt_cmp_gep_data(klen,kp,lklen,p);
	if (ret == -256) ret = -1032;
	else if (ret == -257) ret = -1027;

	return ret;
}

static char *_dupcasekey(kp,lklen)
char *kp;
int lklen;
{
	static char *case_key=NULL;
	static int  case_key_len=0;

	if (case_key) {
		if (lklen > case_key_len) {
			case_key = Realloc(case_key,lklen+1);
			case_key_len = lklen;
		}
	}
	else {
		case_key = Malloc(lklen+1);
		case_key_len = lklen;
	}
	akxcuppern(case_key,kp,lklen);
	*(case_key+lklen) = '\0';
	return case_key;
}

static int _setkey(klen,kp,lklen,lalen,rp,used,i)
int klen,lklen,lalen,i;
char *kp,*rp,*used;
{
	char *p,**rpp;

	if (!kp) return i;
	if (klen > 0) p = rp + (i-1)*(klen+1);
	else p = used + i - 1;
	*p = 1;
	if (klen > 0) memcpy(p+1,kp,klen);
	else {
		rpp = (char **)rp;
#if 1
		p = akxm_cct_malloc(rpp[0],lalen);
		if (!p) return -1028;
		rpp[i] = p;
#else
		p = rpp[i-1];
		if (p) p = Realloc(p,lalen);
		else p = Malloc(lalen);
		if (!p) return -1028;
		rpp[i-1] = p;
#endif
		if (klen < 0) {
			memcpy(p,&lklen,sizeof(int));
			memcpy(p+sizeof(int),kp,lklen);
		}
		else memcpy(p,kp,lalen);
	}
	return i;
}

static int _hashs(hp,opt,iCASE)
HASHB *hp;
int   opt,iCASE;
{
	int i,*np,k,maxk,iax,i_start,count;
	char *p,*kp,*rp,**rpp,*used,f;
	int len1,klen;
	int ldlen,lklen,lalen;

	_SETUP(&kp,&lalen)
	maxk = hp->ha_maxreg;

	iax = hp->ha_aux;
	i_start = i;
	count = 0;

  L10:
	if (klen > 0) {
		p = rp + (i-1)*len1;
		f = *p++;
	}
	else {
		f = used[i-1];
	/*	p = rpp[i-1];	*/
		p = rpp[i];
	}
	if (!f) return _setkey(klen,kp,lklen,lalen,rp,used,i);
	else if (!_cmpkey(klen,kp,lklen,p)) return i;

	if (!np) return 0;
	if (np[i-1] > 0) {
		i = np[i-1];
		count++;
		if (i!=i_start && count<maxk) goto L10;
	}
	if (iax < 0) return 0;

	k = i;
	i = iax;
  L20:
	i++;
	if (i > maxk) {
		if (opt) {
			hp->ha_aux = -i;
			return 0;
		}
		else i = 1;
	}
	if (klen > 0) p = rp + (i-1)*len1;
	else p = used + i - 1;
	if (!*p && !np[i-1]) {
		if ((i=_setkey(klen,kp,lklen,lalen,rp,used,i))<=0) return i;
		np[k-1] = i;
		hp->ha_aux = i;
	}
	else if (!opt && i==iax) {
		hp->ha_aux = -i;
		i = 0;
	}
	else goto L20;
	return i;
}

static int _hashr(hp,iCASE)
HASHB *hp;
int iCASE;
{
	int i,*np,maxk;
	char *p,*kp,*rp,**rpp,*used,f;
	int len1,klen;
	int ldlen,lklen;
	int count,i_start;

	_SETUP(&kp,NULL)
	maxk = hp->ha_maxreg;
	i_start = i;
	count = 0;
  L10:
	if (klen > 0) {
		p = rp + (i-1)*len1;
		f = *p++;
	}
	else {
		f = used[i-1];
	/*	p = rpp[i-1];	*/
		p = rpp[i];
	}
	if (f && !_cmpkey(klen,kp,lklen,p)) return i;

	if (np) {
		if ((i=np[i-1]) > 0) {
			count++;
			if (i!=i_start && count<maxk) goto L10;
		}
	}

	return 0;
}

static int _hashd(hp,iCASE)
HASHB *hp;
int iCASE;
{
	int i,*np,k;	
	char *p,*kp,*rp,**rpp,*used,f;
	int len1,klen;
	int ldlen,lklen,s;
	int nsp[10],isp;

	_SETUP(&kp,NULL)

	isp = k = 0;

  L10:
	if (klen > 0) {
		p = rp + (i-1)*len1;
		f = *p++;
	}
	else {
		f = used[i-1];
	/*	p = rpp[i-1];	*/
		p = rpp[i];
	}
	if (f) s = _cmpkey(klen,kp,lklen,p);
	else s = 1;
	if (s) {
		k = i;
		if (!f) {
			if (isp < 10) nsp[isp++] = i;
			else {
				memcpy(&nsp[0],&nsp[1],(isp-1)*sizeof(int));
				nsp[isp-1] = i;
			}
		}
		else {
			isp = 0;
			nsp[isp++] = i;
		}
		if ((i=np[i-1]) > 0) goto L10;
	}
	if (i > 0) {
		if (klen > 0) p = rp + (i-1)*len1;
		else p = used + i - 1;
		*p = 0;
		if (k > 0) {
			if (!np[i-1]) {
				while (isp > 0) {
					np[nsp[--isp]-1] = 0;
				}
			}
			else if (i > hp->ha_prereg) {
				np[k-1] = np[i-1];
				np[i-1] = 0;
			}
		}
		if (hp->ha_aux < 0) {
			hp->ha_aux = i - 1;
			/* A.Kobayashi 2010/5/20 
			   iaux == 0 だと_hashsで空きをサーチするときに、
			   一周したかの判定ができず無限ループになることがある */
			if (hp->ha_aux <= 0) hp->ha_aux = hp->ha_maxreg;
		}
	}
	return i;
}

static int _hashd2(hp,iCASE)
HASHB *hp;
int iCASE;
{
	char *p,*rp,*used;
	int i,klen;

	i = _hashr(hp,iCASE);
	if (i > 0) {
		rp = hp->ha_reg;
		if ((klen=hp->ha_keylen) > 0) p = rp + (i-1)*(klen+1);
		else p = rp + (hp->ha_maxreg+1)*sizeof(char *) + i - 1;
		*p = 0;
	}
	return i;
}

static int _hashp(hp)
HASHB *hp;
{
	int i;
	char *p,*pk,**rpp;
	int len1,klen;

	if ((i=hp->ha_hix)<=0 || i>hp->ha_maxreg) return -1029;
	if ((klen=hp->ha_keylen) > 0) {
		len1 = klen + 1;
		p = hp->ha_reg + (i-1)*len1;
		pk = p + 1;
	}
	else {
		rpp = (char **)hp->ha_reg;
	/*	pk = rpp[i-1];	*/
		pk = rpp[i];
		p = hp->ha_reg + (hp->ha_maxreg+1)*sizeof(char *) + i - 1;
	}
	if (*p == 1) {
		hp->ha_key = pk;
		return i;
	}
	return 0;
}

static int _hashk(hp)
HASHB *hp;
{
	int i,klen;
	char *p,*pk;

	p = hp->ha_key;
	if ((i=_hashp(hp)) > 0) {
		pk = hp->ha_key;
		if (hp->ha_key = p) {
			klen = hp->ha_keylen;
			if (!klen) {
				strcpy(p,pk);
			}
			else {
				if (klen < 0) {
					memcpy(&klen,pk,sizeof(int));
					if (klen < 0) return -1030;
					klen += sizeof(int);
				}
				memcpy(p,pk,klen);
			}
		}
	}
	return i;
}

static int _hashu(hp)
HASHB *hp;
{
	int x,i,max,n;
	char *p;

	p = hp->ha_key;
	x = hp->ha_hix;
	max = hp->ha_maxreg;
	n = 0;
	for (i=1;i<=max;i++) {
		hp->ha_hix = i;
		if (_hashp(hp) > 0) n++;
	}
	hp->ha_key = p;
	hp->ha_hix = x;
	return n;
}

static int _hashf(kp,lklen,mso,iCASE)
uchar *kp;
int lklen,mso,iCASE;
{
	int i,k,klen,len,mult=lMULTIPLIER;
	uchar  uc,*p;
	uint  uk;

	klen = lklen;
	p = kp;
	if (klen >= 4) {
		k = *p++;
		for (i=1;i<klen;i++) {
			k = k*mult + *p++;
		}
	}
	else {
		if (klen == 1)
			k = *p;
		else if (klen == 2) {
			k = *p++;
			k = k*mult + *p;
		}
		else if (klen == 3) {
			k = *p++;
			k = k*mult + *p++;
			k = k*mult + *p;
		}
		else return 1;
	}
	uk = k;
	return uk%mso + 1;
}

static int _hashfunc(hp,iCASE)
HASHB *hp;
int iCASE;
{
	char *kp,*kkp;
	int lklen;

	if (!(kp = hp->ha_key)) return -1024;
	lklen = _getkey(hp->ha_keylen,kp,&kkp,NULL);
	if (lklen < 0) return lklen;
	if (iCASE) kkp = _dupcasekey(kkp,lklen);
	return _hashf(kkp,lklen,hp->ha_prereg);
}

int akxs_hasx_pre_reg(lMaxReg,pre)
int lMaxReg,pre;
{
	int i,iMAX_SOSU,*sosu;
	int max,l,mso,m,ll,m1;

	max = lMaxReg;
	if ((mso=pre) >= 0) {
		if (mso<=0 || mso>1000) mso = 731;
		if (mso==1000) l = max;
		else l = (max * mso)/1000;
	}
	else {
		if ((l = -pre) > max) l = max;
	}
	if (l > 3) {
		if (!(l & 0x01)) {
			if (l+1 < max) l++;
			else if (l > 1) l--;
		}
		iMAX_SOSU = akxg_sosu_tbl(&sosu);
		if (l > sosu[iMAX_SOSU-1]) {
			for (ll=l;ll<max;ll+=2) {
				if (akxg_sosu_chk(ll)) return ll;
			}
			for (ll=l-2;ll>7;ll-=2) {
				if (akxg_sosu_chk(ll)) return ll;
			}
		}
		else if (l > 7) {
			m1 = sosu[iMAX_SOSU-1];
			for (i=iMAX_SOSU-1;i>=0;i--) {
				if ((m=sosu[i])<=max && m<=l) {
					if (m1 > max) m1 = m;
					return m1;
				}
				m1 = m;
			}
		}
	}
	return l;
}

HASHB *akxs_hasx_new2(sKeyLen,lMaxReg,lPreReg,iOpt)
short sKeyLen;
int  lMaxReg,lPreReg;
int   iOpt;
{
	HASHB *tph;
	int l,pre;
	int  opt,iCASE;
	char c,*p;

	if (!(iCASE = iOpt & AKX_HASX_OPT_CASE_KEY)) {
		if (sKeyLen>0 && sKeyLen<=sizeof(long))
			return akxs_hasl_new2(sKeyLen,lMaxReg,lPreReg,iOpt);
		/*	return akxs_hasl_new2(sizeof(long),lMaxReg,lPreReg,iOpt);	*/
		else if (sKeyLen>sizeof(long) && sKeyLen<=sizeof(long)*2)
			return akxs_hasl2_new2(sKeyLen,lMaxReg,lPreReg,iOpt);
		/*	return akxs_hasl2_new2(sizeof(long)*2,lMaxReg,lPreReg,iOpt);	*/
	}
	if (lMaxReg<2 || lPreReg<0) {
		errno = -1101;
		return NULL;
	}
	opt = iOpt & 0x03;
	if (lPreReg > 0) {
		if ((opt==AKX_HASX_OPT_NO_NEXT && lMaxReg<lPreReg) ||
		    (opt!=AKX_HASX_OPT_NO_NEXT && lMaxReg<=lPreReg)) {
			errno = -1102;
			return NULL;
		}
	}
	if (!(l=lPreReg)) {
		if (opt < AKX_HASX_OPT_NO_NEXT) pre = 0;
		else pre = 1000;
		if ((l=akxs_hasx_pre_reg(lMaxReg,pre)) < 1) {
			errno = -1103;
			return NULL;
		}
	}

	if (!(tph=(HASHB *)Malloc(sizeof(HASHB)))) {
		errno = -1104;
		return NULL;
	}
	memset(tph,0,sizeof(HASHB));
	c = 'H';
	tph->ha_id[1] = 'X';
	tph->ha_keylen = sKeyLen;
	tph->ha_maxreg = lMaxReg;
	tph->ha_prereg = l;
	tph->ha_hix    = 0;

	if (sKeyLen > 0) l = lMaxReg*(sKeyLen+1);
	else l = (lMaxReg+1)*(sizeof(char *)+1);
	if (!(tph->ha_reg=Malloc(l))) {
		akxs_hasx_free(tph);
		errno = -1105;
		return NULL;
	}
	memset(tph->ha_reg,0,l);

	if (opt < AKX_HASX_OPT_NO_NEXT) {
		l = lMaxReg*sizeof(int);
		if (!(tph->ha_next=(int *)Malloc(l))) {
			akxs_hasx_free(tph);
			errno = -1106;
			return NULL;
		}
		if (opt == AKX_HASX_OPT_NO_USE_ALL) c = AKX_HASX_ID_NO_USE_ALL;
	}
	else {
		c = AKX_HASX_ID_NO_NEXT;
	}
	if (iCASE) c = tolower(c);
	tph->ha_id[0] = c;

	if (errno=akxshasx('i',tph)) {
		akxs_hasx_free(tph);
		return NULL;
	}
	return tph;
}

int akxs_hasx_free(tph)
HASHB *tph;
{
	int i;
	char **rpp,*p;

	if (tph) {
		if (tph->ha_id[1]=='L') return (int)akxs_hasl_free(tph);
		if (tph->ha_reg) {
			if (tph->ha_keylen <= 0) {
				rpp=(char **)tph->ha_reg;
#if 1
				akxm_cct_mem_free(rpp[0]);
#else
				for (i=0;i<tph->ha_maxreg;i++) {
					if (p=*rpp++) Free(p);
				}
#endif
			}
			Free(tph->ha_reg);
		}
		if (tph->ha_next) Free(tph->ha_next);
		Free(tph);
	}
	return 0;
}

int akxs_hasx_func(kp,lklen,mso,iCASE)
uchar *kp;
int lklen;
int mso,iCASE;
{
	if (!kp || !mso) return -1111;
	if (iCASE) kp = _dupcasekey(kp,lklen);
	return _hashf(kp,lklen,mso);
}

static int _xhashf();
static int _xhash_chk();
static int _xhash_used();
static int _xhash_max();

XHASHB *akxs_xhash_new2(sKeyLen,lMaxReg,lPreReg,lDatLen)
short sKeyLen;
int  lMaxReg,lPreReg,lDatLen;
{
	XHASHB *p;
	int l;
	char c;

	if (lMaxReg<2 || lPreReg<0 ||
	    (lPreReg>0 && lMaxReg<=lPreReg)) {
		errno = -1301;
		return NULL;
	}
	if (!(l=lPreReg)) {
		if ((l = akxs_hasx_pre_reg(lMaxReg,0)) < 1) {
			errno = -1302;
			return NULL;
		}
	}
	if (!(p=(XHASHB *)Malloc(sizeof(XHASHB)))) {
		errno = -1303;
		return NULL;
	}

	if (sKeyLen>0 && sKeyLen<=sizeof(long)) c = 'L';
	else if (sKeyLen>sizeof(long) && sKeyLen<=sizeof(long)*2) c = '2';
	else c = 'X';

	p->xha_id[0] = AKX_HASX_ID_NO_USE_ALL;
	p->xha_id[1] = c;
	p->xha_keylen = sKeyLen;
	p->xha_maxreg = lMaxReg;
	p->xha_prereg = l;
	p->xha_datlen = lDatLen;
	p->xha_xhix   = 0;
	p->xha_hashb  = NULL;
	p->xha_xhnext = NULL;
	p->xha_datreg = NULL;
	return p;
}

int akxs_xhash2(tp_xhashb,cCmnd,cpKey,cppDat)
XHASHB *tp_xhashb;
char cCmnd, *cpKey;
char **cppDat;		/* cCmnd='S'or's'のときは、(char *)と読み替える */
{
	XHASHB *tpcur,*tpnext;
	int l,i,offset,len;
	HASHB *tph,ha;
	int ret,opt;
	char cCmd,c,cc;

	if (!tp_xhashb) return -1;
	cCmd = akxcupper(cCmnd);
	if ((cCmd=='R'||cCmd=='P'||cCmd=='K') && cppDat) *cppDat = NULL;
	switch (cCmd) {
		case 'R':
		case 'S':
		case 'D':
			if (tp_xhashb->xha_xhix) return _xhash_chk(tp_xhashb,cCmd,cpKey,cppDat);
			break;
		case 'K':
		case 'P':
			return _xhash_chk(tp_xhashb,cCmd,cpKey,cppDat);
		case 'U':
			return _xhash_used(tp_xhashb);
		case 'M':
			return _xhash_max(tp_xhashb);
		case 'F':
			if (!(tph=tp_xhashb->xha_hashb)) {
				len = tp_xhashb->xha_keylen;
#if 1
				tph = &ha;
				tph->ha_id[0] = tp_xhashb->xha_id[0];
				tph->ha_id[1] = tp_xhashb->xha_id[1];
#else
				if (len>0 && len<=sizeof(long)) c = 'L';
				else if (len>sizeof(long) && len<=sizeof(long)*2) c = '2';
				else c = 'X';
				tph = &ha;
				tph->ha_id[0]  = 'H';
				tph->ha_id[1]  = c;
#endif
				tph->ha_keylen = len;
				tph->ha_maxreg = tp_xhashb->xha_maxreg;
				tph->ha_prereg = tp_xhashb->xha_prereg;
			}
			tph->ha_key = cpKey;
			tph->ha_hix = 0;
			return akxshasx(cCmd,tph);
		default:
			return -72;
	}
	if (!cpKey) return -1;
	l = 0;
	offset = 0;
	tpnext = tp_xhashb;
	while (tpnext) {
		tpcur = tpnext;
		if (!(tph=tpcur->xha_hashb)) {
			if (cCmd == 'R' || cCmd == 'D') return 0;
			cc = tpcur->xha_id[0];
			c = toupper(cc);
			if (c == AKX_HASX_ID_NO_USE_ALL)
				opt = AKX_HASX_OPT_NO_USE_ALL;
			else if (c == AKX_HASX_ID_NO_NEXT)
				opt = AKX_HASX_OPT_NO_NEXT;
			else opt = 0;
			if (c != cc) opt |= AKX_HASX_OPT_CASE_KEY;
			if (tph=akxs_hasx_new2(tpcur->xha_keylen,tpcur->xha_maxreg,
			                     tpcur->xha_prereg,opt))
				tpcur->xha_hashb = tph;
			else return errno;
		}
		tph->ha_key = cpKey;
#if 0
		if (!l) {
			if (!(l=tpcur->xha_xhix))
				l = akxshasx('f',tph);
		}
		tph->ha_hix = l;
#else
		tph->ha_hix = 0;
#endif
		if (cCmd=='S' && cppDat && tpcur->xha_datlen == -2 && tph->ha_id[1]=='L')
			tph->ha_next = (int *)cppDat;
		if (i=akxshasx(cCmd,tph)) {
			if (i>0) {
				if ((ret=akxs_dreg_proc(tpcur,cCmd,i,cppDat))<0) return ret;
				i += offset;
			}
			return i;
		}
		tpnext = tpcur->xha_xhnext;
		offset += tpcur->xha_maxreg;
	}
	if (cCmd == 'R' || cCmd == 'D') return i;
	if (!(tpnext=(XHASHB *)Malloc(sizeof(XHASHB)))) return -76;
	tpcur->xha_xhnext = tpnext;
	memcpy(tpnext,tpcur,sizeof(XHASHB));
	tpnext->xha_xhix = l;
	tpnext->xha_hashb = NULL;
	tpnext->xha_xhnext = NULL;
	tpnext->xha_datreg = NULL;
	if ((i = akxs_xhash2(tpnext,cCmd,cpKey,cppDat))>0) i += offset;
	tpnext->xha_xhix = 0;
	return i;
}

static int _xhashf(kp,len,mso,iCASE)
uchar *kp;
short len;
int mso,iCASE;
{
	uchar uc,*p=kp;
	int lklen;

	if (!kp) return -35;
	if (len > 0) lklen = len;
	else if (len < 0) {
		memcpy(&lklen,p,sizeof(int));
		if (lklen < 0) return -32;
		p += sizeof(int);
	}
	else lklen = strlen((char *)p);
	return akxs_hasx_func(p,lklen,mso,iCASE);
}

int akxs_xhash_free(tp_xhashb)
XHASHB *tp_xhashb;
{
	HASHB *tph;
	int i;
	char **rpp,*p;

	if (tp_xhashb) {
		if (tph=tp_xhashb->xha_hashb) {
			akxs_hasx_free(tph);
		}
		if (p=tp_xhashb->xha_datreg) {
			if (tp_xhashb->xha_datlen <= 0) {
				rpp=(char **)p;
#if 1
				akxm_cct_mem_free(rpp[0]);
#else
				for (i=0;i<tp_xhashb->xha_maxreg;i++) {
					if (p=*rpp++) Free(p);
				}
#endif
			}
			Free(tp_xhashb->xha_datreg);
		}
		akxs_xhash_free(tp_xhashb->xha_xhnext);
		Free(tp_xhashb);
	}
	return 0;
}

XHASHB *akxs_xhash_new(sKeyLen,lMaxReg,lPreReg)
short sKeyLen;
int  lMaxReg,lPreReg;
{
	return akxs_xhash_new2(sKeyLen,lMaxReg,lPreReg,-2);
}

int akxs_xhash(tp_xhashb,cCmd,cpKey)
XHASHB *tp_xhashb;
char cCmd, *cpKey;
{
	return akxs_xhash2(tp_xhashb,cCmd,cpKey,NULL);
}

int akxs_dreg_proc(tpX,cCmd,i,cppDat)
XHASHB *tpX;
int i;
char cCmd,**cppDat;
{
	HASHB *tph;
	char *cpDat,**drg,*p,*dp;
	int  dlen,len,alen,mx;

	if (!cppDat) return 0;
	if ((dlen=tpX->xha_datlen) < -2) return 0;
	else if (dlen == -2) {
		tph = tpX->xha_hashb;
		if (tph->ha_id[1]=='L' && (cCmd=='R' || cCmd=='D'))
			*cppDat = (char *)tph->ha_next;
		return 0;
	}
	p = tpX->xha_datreg;
	if (dlen > 0) alen = ((dlen+sizeof(int))/sizeof(int))*sizeof(int);
	if (cCmd == 'R' || cCmd == 'D') {
		if (p) {
			if (dlen > 0) cpDat = p + alen*(i-1);
			else {
				drg = (char **)p;
				cpDat = drg[i];
			}
		}
		else cpDat = NULL;
		*cppDat = cpDat;
	}
	else if (cCmd == 'S') {
		cpDat = (char *)cppDat;
		if (!p) {
			mx = tpX->xha_maxreg;
			if (dlen > 0) len = alen*mx;
			else len = sizeof(char **)*(mx+1);
			if (!(p=Malloc(len))) return -77;
			tpX->xha_datreg = p;
			if (dlen <= 0) {
				memset(p,0,(mx+1)*sizeof(char **));
				drg = (char **)p;
				drg[0] = (char *)akxm_cct_mem_new(mx*32);
			}
		}
		if (dlen > 0) {
			dp = p + alen*(i-1);
			memcpy(dp,cpDat,dlen);
			*(dp+dlen) = '\0';
		}
		else {
			drg = (char **)p;
		/*	if (dp=drg[i]) Free(dp);	*/
			if (dlen < 0) {
				memcpy(&len,cpDat,sizeof(int));
				len += sizeof(int);
			}
			else len = strlen(cpDat);
			alen = len + 1;
		/*	if (!(dp=Malloc(alen))) return -78;	*/
			if (!(dp=akxm_cct_malloc(drg[0],alen))) return -78;
			memcpy(dp,cpDat,len);
			*(dp+len) = '\0';
			drg[i] = dp;
		}
	}
	return 0;
}

static int _xhash_chk(tp_xhashb,cCmd,cpKey,cppDat)
XHASHB *tp_xhashb;
char cCmd, *cpKey,**cppDat;
{
	XHASHB *tpcur;
	int i,offset,max,next,ix;
	HASHB *tph;
	int ret;
	char cCmdw;

	ret = -1029;
	i = tp_xhashb->xha_xhix;
	tp_xhashb->xha_xhix = 0;
	offset = 0;
	tpcur = tp_xhashb;
	max = tpcur->xha_maxreg;
	while (tpcur) {
		next = offset + max;
		if (next >= i) {
			ret = 0;
			if (tph=tpcur->xha_hashb) {
				tph->ha_hix = ix = i - offset;
				if (cCmd != 'P') tph->ha_key = cpKey;
				else if (cCmd=='S' && cppDat && tpcur->xha_datlen == -2 && tph->ha_id[1]=='L')
					tph->ha_next = (int *)cppDat;
				ret = akxshasx(cCmd,tph);
				if (ret > 0) {
					if ((cCmdw=cCmd)=='P' || cCmdw=='K') cCmdw = 'R';
					if ((ret=akxs_dreg_proc(tpcur,cCmdw,ix,cppDat))<0) return ret;
					if ((cCmd == 'P') && cpKey) *(char **)cpKey = tph->ha_key;
					return i;
				}
			}
			break;
		}
		tpcur = tpcur->xha_xhnext;
		offset = next;
	}
	return ret;
}

static int _xhash_used(tp_xhashb)
XHASHB *tp_xhashb;
{
	XHASHB *tpcur;
	int ret,count;
	HASHB *tph;

	count = 0;
	tpcur = tp_xhashb;
	while (tpcur) {
		tpcur->xha_xhix = 0;
		if (tph=tpcur->xha_hashb) {
			ret = akxshasx('U',tph);
			tpcur->xha_xhix = ret;
			if (ret > 0) count += ret;
		}
		tpcur = tpcur->xha_xhnext;
	}
	return count;
}

static int _xhash_max(tp_xhashb)
XHASHB *tp_xhashb;
{
	XHASHB *tpcur;
	int ret,m;
	HASHB *tph;

	m = 0;
	tpcur = tp_xhashb;
	while (tpcur) {
		m += tpcur->xha_maxreg;
		tpcur = tpcur->xha_xhnext;
	}
	return m;
}
