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

#define DEBUGP(x)

#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 _hashi();
static int _hashk();
static int _hashp();
static int _hashu();
static int _hashc();
static int _hashf();
static int _hashfunc();
static int _set_en_col(/*ih,iUSHORT,en,col,usen,uscol*/);
static void _set_col_max(/*iUSHORT,col,uscol*/);
static int _free_reg(/*maxreg,datlen,reg,opt*/);

/* -1,-2 */
#define _SETUP(kpp,plalen,aux_klen) {	\
	ret = 0; \
	i = hp->ha_hix;	\
	kp = hp->ha_key;	\
	if (!i && !kp) ret = -1;	\
  else {	\
	rp = hp->ha_reg;	\
	iUSHORT = hp->ha_id[1] & AKX_HASX_OPT_USE_USHORT; \
	if (iUSHORT) { \
		usen = (ushort *)hp->ha_next;	\
		usnp = usen + hp->ha_maxreg;	\
		uscol = usnp + hp->ha_maxreg;	\
		usfn = uscol + 2;	\
	} else { \
		en = hp->ha_next;	\
		np = en + hp->ha_maxreg;	\
		col = np + hp->ha_maxreg;	\
		fn = col + 2;	\
	} \
	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,aux_klen);	\
		if (lklen < 0) return lklen;	\
		if (iCASE) kp = _dupcasekey(kp,lklen);	\
	}	\
	if (i > 0) {	\
		if (kp && i>hp->ha_prereg) ret = -2;	\
	}	\
	else i=_hashf(kp,lklen,hp->ha_prereg);	\
	hp->ha_aux = i;	\
  }	\
}

/* 01 -185140101 */
/********1*********2*********3*********4*********5*********7*/
/* 引数 : func : 'I','S','R','D','K','P','U','C','F'		*/
/*		  hp : HASHB *										*/
/*				ha_id[0] : 'X' : akxshasx					*/
/*						   'L' : akxshasl					*/
/*						   '2' : akxshasl2					*/
/*				ha_id[1] : オプション(opt)					*/
/*					0x01 : ignore case						*/
/*					0x02 : ignore 半角/倍角					*/
/*					0x04 : 衝突発生時にnextを使わない		*/
/*					0x08 : not delete						*/
/*					0x10 : キー値保存に、Malloc()を使う		*/
/*						   m_alloc<>NULL のときは、off扱い	*/
/*					0x20 : m_alloc,pConstCtを使う			*/
/*							(0x10より優先する)				*/
/*					0x40 : next等はushortを使う				*/
/*					0x80 : 予約								*/
/*				rpp[0] : NULL : keyはMalloc()する			*/
/*								opt=0x10(ON)and0x20(OFF)	*/
/*					   : opt=0x10(OFF)and 0x20(OFF):		*/
/*						 akxm_cct_mem_new()で設定されている	*/
/*								(Malloc()を使用)			*/
/*					   : opt=0x20(ON): pACになっている		*/
/*		  aux_klen : > 0 : 固定長キー						*/
/*					 = 0 : 可変長キー						*/
/*					 < 0 : len+キー形式						*/
/************************************************************/
int akxshasxn(func,hp,aux_klen)
char func;
HASHB *hp;
int aux_klen;
{
	int i,ilen,opt,imaxlen,iCASE;
	uchar *hkey,*kp,cmd,c,cc;
	ulong ulkey[2];
	char *argv[2];

	if (!hp) return -185140101;

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

			hp->ha_key = (char *)kp;
			if (cmd == 'K') {
				if (c == 'L') memcpy(kp,&argv[0],ilen);
				else memcpy(kp,hkey,ilen);
			}
			else if (cmd == 'P') hp->ha_key = argv[0];
		}
		return i;
	}
#if 1
	opt = hp->ha_id[1];
	iCASE = opt & AKX_HASX_OPT_CASE_KEY;
#else
	cc = hp->ha_id[0];
	c = toupper(cc);
	if (c == AKX_HASX_ID_NO_NEXT) opt = AKX_HASX_OPT_NO_NEXT;
	else opt = 0;
	if (c == cc) iCASE = 0;
	else iCASE = 1;
#endif
	switch (akxcupper(func)) {
		case 'R':
			i = _hashr(hp,aux_klen,iCASE);
			break;
		case 'S':
			i = _hashs(hp,aux_klen,opt,iCASE);
			break;
		case 'D':
#if 1
			if (opt & AKX_HASX_OPT_NOT_DELETE) {
/*
printf("akxshasxn: opt=%08x hp->ha_aux=%08x\n",opt,hp->ha_aux);
*/
				i = -185140104;
			}
#else
			if (hp->ha_aux & AKX_HASX_OPT_NOT_DELETE) i = -185140104;
#endif
			else i = _hashd(hp,aux_klen,iCASE);
			break;
		case 'I':
		/*	opt = hp->ha_aux;	*/
			i = _hashi(hp,opt);
			break;
		case 'K':
			i = _hashk(hp);
			break;
		case 'P':
			i = _hashp(hp);
			break;
		case 'U':
			i = _hashu(hp);
			break;
		case 'C':
			i = _hashc(hp);
			break;
		case 'F':
			i = _hashfunc(hp,aux_klen,iCASE);
			break;
		default:
			i = -185140103;
	}
	return i;
}

/************************************/
/*									*/
/************************************/
int akxshasx(func,hp)
char func;
HASHB *hp;
{
	akxshasxn(func,hp,0);
}

/* 02 -185140201 */
/************************************/
/*									*/
/************************************/
static int _hashi(hp,opt)
HASHB *hp;
int   opt;
{
	int i,j,mx,m1,*np;
	ushort *usnp;
	int klen,len1,aux;
	char *rp,**rpp;

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

	if (i >= 0) {
		klen = hp->ha_keylen;
		aux = hp->ha_aux;
		aux |= opt;
/*
printf("_hashi: klen=%d aux=%08x\n",klen,aux);
*/
		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));
			if (!(aux & (AKX_HASX_OPT_USE_MALLOC | AKX_HASX_OPT_TMP_MALLOC))) {
				rpp = (char **)rp;
				if (aux & AKX_HASX_OPT_RESET_MEM) akxm_cct_reset((tdtCONSTCT *)rpp[0]);
				else rpp[0] = (char *)akxm_cct_mem_new(mx*32);
/*
printf("_hashi: rpp[0]=%08x\n",rpp[0]);
*/
			}
		}
		if (hp->ha_id[1] & AKX_HASX_OPT_USE_USHORT) {
			usnp = (ushort *)np;
			memset(usnp,0,mx*sizeof(short)*2+2);
			usnp += mx*2 + 2;		/* fpの前に2つ衝突回数用を確保 */
			if (aux & AKX_HASX_OPT_NOT_DELETE) *usnp = 1;
			else {
				for (j=0;j<mx;j++) usnp[j] = j + 1;
				usnp[mx] = 0;
			}
		}
		else {
			memset(np,0,mx*sizeof(int)*2+2);
			np += mx*2 + 2;		/* fpの前に2つ衝突回数用を確保 */
			if (aux & AKX_HASX_OPT_NOT_DELETE) *np = 1;
			else {
				for (j=0;j<mx;j++) np[j] = j + 1;
				np[mx] = 0;
			}
		}
	}
	return i;
}

/* 03 -185140301 */
/************************************/
/*									*/
/************************************/
static int _getkey(klen,p,kpp,plalen,aux_klen)
int klen,*plalen,aux_klen;
char *p,**kpp;
{
	int ret,lalen;

	if (!klen && aux_klen>0) {
		if (kpp) *kpp = p;
		if (plalen) *plalen = aux_klen + 1;
		ret = aux_klen;
	}
	else {
		ret = akxt_get_gep_data(klen,p,kpp,plalen);
		if (ret == -1) ret = -1031;
		else if (ret == -2) ret = -1026;
	}
	return ret;
}

/* 04 -185140401 */
/************************************/
/*									*/
/************************************/
static int _cmpkey(klen,kp,lklen,p,aux_klen)
int klen,lklen,aux_klen;
char *kp,*p;
{
	int ret;
	if (!kp) return 0;
	if (!klen && aux_klen>0) {
		ret = strncmp(kp,p,aux_klen);
/*
printf("_cmpkey: ret=%d klen=%d kp=[%s] lklen=%d p=[%s] aux_klen=%d\n",
ret,klen,strmem(kp,aux_klen),lklen,p,aux_klen);
*/
	}
	else {
		ret = akxt_cmp_gep_data(klen,kp,lklen,p);
		if (ret == -256) ret = -1032;
		else if (ret == -257) ret = -1027;
	}
	return ret;
}

/* 05 -185140501 */
/************************************/
/*									*/
/************************************/
static int _setkey(klen,kp,lklen,lalen,rp,used,i,m_alloc,pConstCt)
int klen,lklen,lalen,i;
char *kp,*rp,*used;
char *(*m_alloc)();
tdtCONSTCT *pConstCt;
{
	char *p,**rpp;

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

/* 06 -185140601 */
/************************************/
/*									*/
/************************************/
static char *_dupcasekey(kp,lklen)
char *kp;
int lklen;
{
#if 1	/* 2022.6.4 */
	static char wrk[256],*p0=NULL;
	char *case_key;
	int wrk_len;

	wrk_len = sizeof(wrk);
	if ((lklen=akxmemwork(lklen,&case_key,&p0,wrk,wrk_len)) < 0) {
		case_key = wrk;
		wrk_len--;
		lklen = X_MIN(lklen,wrk_len);
	}
#else
	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;
	}
#endif
	akxcuppern(case_key,kp,lklen);
	*(case_key+lklen) = '\0';
	return case_key;
}

/* 07 -185140701 */
/************************************/
/*									*/
/************************************/
static int _hashs(hp,aux_klen,opt,iCASE)
HASHB *hp;
int   aux_klen,opt,iCASE;
{
	int i,*np,k,ih,*en,*fn,ret,*col;
	ushort *usnp,*usen,*usfn,*uscol;
	char *p,*kp,*rp,**rpp,*used,f;
	int len1,klen,iUSHORT,iNDEL;
	int ldlen,lklen,lalen;
	tdtAllocCtl *pAC;
	char *(*m_alloc)();
	tdtCONSTCT *pConstCt;

	_SETUP(&kp,&lalen,aux_klen)
	if (ret < 0) return -185140750+ret;

	ih = i;
	i = _set_en_col(ih,iUSHORT,en,col,usen,uscol);
DEBUGP(printf("hashs: ih=%d key=[%s]\n",ih,hp->ha_key);)

	if (i) {
  L10:
DEBUGP(printf("hashs: i=%d\n",i);)
		if (klen>0) p = rp + (i-1)*len1 + 1;
		else p = rpp[i];
		if (!_cmpkey(klen,kp,lklen,p,aux_klen)) return i;
		if (opt & AKX_HASX_OPT_NO_NEXT) return 0;
		if (iUSHORT) {
			if ((k=usnp[i-1]) > 0) {
				i = k;
				(*uscol)++;
				goto L10;
			}
			usen = usnp;
		}
		else {
			if ((k=np[i-1]) > 0) {
				i = k;
				(*col)++;
				goto L10;
			}
			en = np;
		}
	}
	else i = ih;

	iNDEL = opt & AKX_HASX_OPT_NOT_DELETE;
	if (iUSHORT) {
		if (!(k = usfn[0])) return 0;
		if (iNDEL) usfn[0] = k + 1;
		else usfn[0] = usfn[k];
		usen[i-1] = k;
		usnp[k-1] = 0;
	}
	else {
		if (!(k = fn[0])) return 0;
		if (iNDEL) fn[0] = k + 1;
		else fn[0] = fn[k];
		en[i-1] = k;
		np[k-1] = 0;
	}
	_set_col_max(iUSHORT,col,uscol);
/*	if (hp->ha_id[1] == 'M') {	*/
/*	if (opt & (AKX_HASX_OPT_USE_MALLOC | AKX_HASX_OPT_TMP_MALLOC)) {	*/
	if (opt & AKX_HASX_OPT_TMP_MALLOC) {
		pAC = (tdtAllocCtl *)rpp[0];
		m_alloc  = pAC->ac_malloc;
		pConstCt = pAC->ac_constct;
	}
	else {
		m_alloc  = NULL;
		pConstCt = NULL;
	}
	_setkey(klen,kp,lklen,lalen,rp,used,k,m_alloc,pConstCt);
	return k;
}

/* 08 */
/************************************/
/*									*/
/************************************/
static int _hashr(hp,aux_klen,iCASE)
HASHB *hp;
int aux_klen,iCASE;
{
	int i,*np,k,ih,*en,*fn,ret,*col;
	ushort *usnp,*usen,*usfn,*uscol;
	char *p,*kp,*rp,**rpp,*used,f;
	int len1,klen,iUSHORT;
	int ldlen,lklen;
	int count,i_start;

	_SETUP(&kp,NULL,aux_klen)
	if (ret < 0) return -185140850+ret;

	ih = i;
	i = _set_en_col(ih,iUSHORT,en,col,usen,uscol);
	if (i) {
  L10:
		if (klen > 0) p = rp + (i-1)*len1 + 1;
		else p = rpp[i];
		if (!_cmpkey(klen,kp,lklen,p,aux_klen)) goto LEND;
		if (iUSHORT) {
			if ((i=usnp[i-1]) > 0) {
				(*uscol)++;
				goto L10;
			}
		}
		else {
			if ((i=np[i-1]) > 0) {
				(*col)++;
				goto L10;
			}
		}
	}
	i = 0;
 LEND:
	_set_col_max(iUSHORT,col,uscol);
	return i;
}

/* 09 */
/************************************/
/*									*/
/************************************/
static int _hashd(hp,aux_klen,iCASE)
HASHB *hp;
int aux_klen,iCASE;
{
	int i,*np,k,ih,*en,*fn,ret,*col;
	ushort *usnp,*usen,*usfn,*uscol;
	char *p,*kp,*rp,**rpp,*used,f;
	int len1,klen,iUSHORT;
	int ldlen,lklen,s;
	int nsp[10],isp;

	_SETUP(&kp,NULL,aux_klen)
	if (ret < 0) return -185140950+ret;

	ih = i;
	i = _set_en_col(ih,iUSHORT,en,col,usen,uscol);
	k = 0;
	if (!i) return 0;
  L10:
	if (klen>0) p = rp + (i-1)*len1 + 1;
	else p = rpp[i];
	if (_cmpkey(klen,kp,lklen,p,aux_klen)) {
		k = i;
		if (iUSHORT) {
			if ((i=usnp[i-1])>0) {
				(*uscol)++;
				goto L10;
			}
		}
		else {
			if ((i=np[i-1])>0) {
				(*col)++;
				goto L10;
			}
		}
		return 0;
	}
	if (iUSHORT) {
		if (k) usnp[k-1] = usnp[i-1];
		else  usen[ih-1] = usnp[i-1];
		isp = usfn[0];
		usfn[i] = isp;
		usfn[0] = i;
		usnp[i-1] = 0;
	}
	else {
		if (k) np[k-1] = np[i-1];
		else  en[ih-1] = np[i-1];
		isp = fn[0];
		fn[i] = isp;
		fn[0] = i;
		np[i-1] = 0;
	}
	_set_col_max(iUSHORT,col,uscol);
	if (klen > 0) p = rp + (i-1)*len1;
	else {
		p = used + i - 1;
		rpp[i] = NULL;
	}
	*p = 0;
	return i;
}

/* 10 -185141001 */
/************************************/
/*									*/
/************************************/
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 -185141001;
	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;
	else i = 0;
	hp->ha_hix = 0;
	return i;
}

/* 11 -185141101 */
/************************************/
/*									*/
/************************************/
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 -185141101;
					klen += sizeof(int);
				}
				memcpy(p,pk,klen);
			}
		}
	}
	return i;
}

/* 12 */
/************************************/
/*									*/
/************************************/
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;
}

/* 13 */
/************************************/
/*									*/
/************************************/
static int _hashf(kp,lklen,mso)
uchar *kp;
int lklen,mso;
{
	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;
}

/* 14 -185141401 */
/************************************/
/*									*/
/************************************/
static int _hashfunc(hp,aux_klen,iCASE)
HASHB *hp;
int aux_klen,iCASE;
{
	int i;
	char *kp,*kkp;
	int klen,lklen;

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

/* 15 */
/************************************/
/*									*/
/************************************/
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 = 997;	/*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--;
		}
DEBUGP(printf("akxs_hasx_pre_reg: max=%d pre=%d\n",max,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;
}

/* 16 -185141601 */
/********1*********2*********3*********4*********5*********7*/
/* 引数 : iOpt    : オプション								*/
/*					0x01 : ignore case						*/
/*					0x02 : ignore 半角/倍角					*/
/*					0x04 : 衝突発生時にnextを使わない		*/
/*					0x08 : not delete						*/
/*					0x10 : not use akxm_cct_malloc()		*/
/*						   m_alloc<>NULL のときは、off扱い	*/
/* 返却 : ハッシュ構造体									*/
/*	//	  ha_id[0] = 'H' ignore case  のときは、'h'			*/
/*	//	  ha_id[1] = 'X' m_alloc<>NULLのときは、'M'			*/
/*		  ha_id[0] = 'X'									*/
/*		  ha_id[1] = iOpt & 0x1f							*/
/*					 0x20 : m_alloc,pConstCtを使う			*/
/*					 0x40 : next等はushortを使う			*/
/*					 0x80 : 予約							*/
/************************************************************/
HASHB *akxs_hasxm_new2(sKeyLen,lMaxReg,lPreReg,iOpt,m_alloc,pConstCt)
short sKeyLen;
int   lMaxReg,lPreReg,iOpt;
char    *(*m_alloc)();
tdtCONSTCT *pConstCt;
{
	HASHB *tph;
	int l,pre,len,size;
	int  iCASE;
	char c,**rpp;
	tdtAllocCtl *pAC;
/*
printf("akxs_hasx_new2: sKeyLen=%d lMaxReg=%d lPreReg=%d iOpt=%08x\n  m_alloc=%08x pConstCt=%08x\n",
sKeyLen,lMaxReg,lPreReg,iOpt,m_alloc,pConstCt);
*/
/*	if (!(iCASE = iOpt & AKX_HASX_OPT_CASE_KEY)) {	*/
	if (!(iOpt & (AKX_HASX_OPT_CASE_KEY | AKX_HASX_OPT_IGN_KANJ))) {
		/* longまたはlong*2未満のキー長のときは、不足分をクリアする必要がある。
		   そこで、キー長をハッシュ構造体に保存しておき、akxshasx()からakxshasl()
		   またはakxshasl2()を呼ぶ前に不足分をクリアする時に利用する。*/
		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 || (lPreReg>0 && lMaxReg<=lPreReg)) {	*/
	if (lMaxReg<2 || lPreReg<0) {
		errno = -185141601;
		return NULL;
	}
	if (lPreReg > 0) {
		if (lMaxReg <= lPreReg) {
			errno = -185141602;
			return NULL;
		}
	}
	if (!(l=lPreReg)) {
		pre = 0;
		if ((l=akxs_hasx_pre_reg(lMaxReg,pre)) < 1) {
			errno = -185141603;
			return NULL;
		}
DEBUGP(printf("akxs_hasx_new2: l=%d\n",l);)
	}

	if (!(tph=(HASHB *)akxm_malloc_constct(m_alloc,pConstCt,sizeof(HASHB)))) {
		errno = -185141604;
		return NULL;
	}
	memset(tph,0,sizeof(HASHB));
#if 1
	tph->ha_id[0] = 'X';
#else
	c = 'H';
	if (iOpt & AKX_HASX_OPT_NO_NEXT) c = AKX_HASX_ID_NO_NEXT;
	if (iCASE) c = tolower(c);
	tph->ha_id[0] = c;
/*
printf("akxs_hasx_new: id=%c\n",c);
*/
	c = 'X';
#endif
	if (m_alloc) {
	/*	c = 'M';	*/
		iOpt &= ~AKX_HASX_OPT_USE_MALLOC;
		iOpt |= AKX_HASX_OPT_TMP_MALLOC;
	}
	tph->ha_id[1] = iOpt & ~AKX_HASX_OPT_USE_USHORT;
/*	tph->ha_id[1] = c;	*/
	if (lMaxReg <= USHRT_MAX) tph->ha_id[1] |= AKX_HASX_OPT_USE_USHORT;
	tph->ha_keylen = sKeyLen;
	tph->ha_maxreg = lMaxReg;
	tph->ha_prereg = l;
	tph->ha_aux    = iOpt | tph->ha_id[1];
	tph->ha_hix    = 0;

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

	if (iOpt & AKX_HASX_OPT_NOT_DELETE) l = lMaxReg*2 + 3;
	else  l = lMaxReg*3 + 3;
	if (tph->ha_id[1] & AKX_HASX_OPT_USE_USHORT) size = sizeof(short);
	else size = sizeof(int);
	if (!(tph->ha_next=(int *)akxm_malloc_constct(m_alloc,pConstCt,l*size))) {
		akxs_hasx_free(tph);
		errno = -185141606;
		return NULL;
	}
	if (errno=akxshasx('i',tph)) {
		akxs_hasx_free(tph);
		return NULL;
	}
	/* (iOpt & AKX_HASX_OPT_USE_MALLOC)==0 && (iOpt & AKX_HASX_OPT_TMP_MALLOC)==0 のときは、
	    上記で、rpp[0]は、akxm_cct_mem_new()で、設定されている */
	if (m_alloc) {
		if (!(pAC = (tdtAllocCtl *)akxm_malloc_constct(m_alloc,pConstCt,sizeof(tdtAllocCtl)))) {
			errno = -185141607;
			akxs_hasx_free(tph);
			return NULL;
		}
		pAC->ac_malloc = m_alloc;
		pAC->ac_constct = pConstCt;
		rpp = (char **)tph->ha_reg;
		rpp[0] = (char *)pAC;
	}
	/* rpp[0] ==NULL : keyはMalloc()する。klenでkeyの保存形式が変わる。
	   m_alloc==NULL : rpp[0] : akxm_cct_mem_new()で、設定されている。
	   m_alloc<>NULL : rpp[0] : pACになっている。 */
	return tph;
}

/* 17 */
/************************************/
/*									*/
/************************************/
HASHB *akxs_hasx_new2(sKeyLen,lMaxReg,lPreReg,iOpt)
short sKeyLen;
int   lMaxReg,lPreReg,iOpt;
{
	return akxs_hasxm_new2(sKeyLen,lMaxReg,lPreReg,iOpt,NULL,NULL);
}

/* 18 */
/************************************/
/*									*/
/************************************/
HASHB *akxs_hasx_new(sKeyLen,lMaxReg,lPreReg)
short sKeyLen;
int  lMaxReg,lPreReg;
{
	return akxs_hasx_new2(sKeyLen,lMaxReg,lPreReg,0);
}

/* 19 */
/*************************************/
/* m_alloc==NULLのときのみ、実行する */
/*************************************/
static int _free_reg(maxreg,datlen,reg,opt)
int maxreg,datlen,opt;
char *reg;
{
	int i;
	char **rpp,*p,**rpp0;

	if (reg) {
		if (datlen <= 0) {
			rpp = (char **)reg;
/*
printf("_free_reg: rpp[0]=%08x\n",rpp[0]);
*/
			if (rpp[0]) {
				if (opt & 0x04) akxm_cct_clear((tdtCONSTCT *)rpp[0]);
				akxm_cct_mem_free((tdtCONSTCT *)rpp[0]);
			}
			else {
				rpp++;
				rpp0 = rpp;
				for (i=0;i<maxreg;i++) {
					if (p=*rpp++) Free(p);
				}
				if (opt & 0x02) memset(rpp0,0,maxreg*sizeof(char *));
			}
		}
		else if (opt & 0x01) {
			memset(reg,0,maxreg*datlen);
		}
/*
printf("_free_reg: reg=%08x\n",reg);
*/
		Free(reg);
	}
	return 0;
}

/*************************************/
/* m_alloc==NULLのときのみ、実行する */
/*************************************/
int akxs_free_reg_opt(maxreg,datlen,reg,opt)
int maxreg,datlen,opt;
char *reg;
{
	return _free_reg(maxreg,datlen,reg,opt);
}

/*************************************/
/* m_alloc==NULLのときのみ、実行する */
/*************************************/
int akxs_free_reg(maxreg,datlen,reg)
int maxreg,datlen;
char *reg;
{
	return _free_reg(maxreg,datlen,reg,0);
}

/* 20 */
/************************************/
/*									*/
/************************************/
int akxs_hasx_free_opt(tph,opt)
HASHB *tph;
int opt;
{
	int i;
	char **rpp,*p;

	if (tph) {
		if (tph->ha_id[0] == 'L') akxs_hasl_free(tph);
	/*	else if (tph->ha_id[1] != 'M') {	*/
	/*	else if (!(tph->ha_id[1] & (AKX_HASX_OPT_USE_MALLOC | AKX_HASX_OPT_TMP_MALLOC))) {	*/
		else if (!(tph->ha_id[1] & AKX_HASX_OPT_TMP_MALLOC)) {
			if (tph->ha_reg) {
				_free_reg(tph->ha_maxreg,tph->ha_keylen,tph->ha_reg,opt);
			}
			if (tph->ha_next) Free(tph->ha_next);
			Free(tph);
		}
	}
	return 0;
}

/************************************/
/*									*/
/************************************/
int akxs_hasx_free(tph)
HASHB *tph;
{
	return akxs_hasx_free_opt(tph,0);
}

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

/* 22 */
int akxs_hasx_set_mult(mult)
int mult;
{
	int l=lMULTIPLIER;

	if (mult>0) lMULTIPLIER = mult;
	else if (mult<0) lMULTIPLIER=AKX_HASX_MULTIPLIER2;
	lMULTIPLIER2 = mult * mult;
	lMULTIPLIER3 = lMULTIPLIER2 * mult;
	lMULTIPLIER4 = lMULTIPLIER3 * mult;
	return l;
}

/* 23 */
/************************************/
/*									*/
/************************************/
int akxs_hasx_get_key(p,klen,kpp,plalen)
char *p,**kpp;
int  klen,*plalen;
{
	return _getkey(klen,p,kpp,plalen,0);
}

/* 24 */
/********1*********2*********3*********4*********5*******/
/* 引数 : hp	: HASHB									*/
/*				  hp->ha_hix= 0: 直前の'S','R','D'		*/
/*								 実行時の衝突数			*/
/*				  hp->ha_hix<>0: 前回実行時からの最大	*/
/*								 衝突数。復帰前に最大を	*/
/*								 0にする				*/
/* 返却 : >=0 :衝突数									*/
/*		   <0 :エラー									*/
/********************************************************/
static int _hashc(hp)
HASHB *hp;
{
	int max,n,x,*col,*ne;
	ushort *usne,*uscol;

	x = hp->ha_hix;
/*
printf("_hashc: x=%d\n",x);
*/
	max = hp->ha_maxreg;
	ne = hp->ha_next;
	usne = (ushort *)ne;
	if (hp->ha_id[1] & AKX_HASX_OPT_USE_USHORT) {
		uscol = usne + max*2;
		if (x) {
			uscol++;
			n = *uscol;
			*uscol = 0;
		}
		else n = *uscol;
	}
	else {
		col = ne + max*2;
		if (x) {
			col++;
			n = *col;
			*col = 0;
		}
		else n = *col;
	}
	return n;
}

/* 25 */
/************************************/
/*									*/
/************************************/
static int _set_en_col(ih,iUSHORT,en,col,usen,uscol)
int ih,iUSHORT,*en,*col;
ushort *usen,*uscol;
{
	int i;

	if (iUSHORT) {
		*uscol = 0;
		i = usen[ih-1];
	}
	else {
		*col = 0;
		i = en[ih-1];
	}
	return i;
}

/* 26 */
/************************************/
/*									*/
/************************************/
static void _set_col_max(iUSHORT,col,uscol)
int iUSHORT,*col;
ushort *uscol;
{
	int n,m;

	if (iUSHORT) {
		n = *uscol++;
		m = *uscol;
		if (n > m) *uscol = n;
	}
	else {
		n = *col++;
		m = *col;
		if (n > m) *col = n;
	}
}

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

/* 41 */
/********1*********2*********3*********4*********5*********7*/
/* 引数 : sKeyLen :											*/
/*		  iDatLen : 保存するデータの長さ					*/
/*					> 0 : 固定長							*/
/*					= 0 : string							*/
/*					=-1 : 先頭にデータ長がある				*/
/*					=-2 : データを保存しない				*/
/*		  iOpt    : オプション								*/
/*					0x01 : ignore case						*/
/*					0x02 : ignore 半角/倍角					*/
/*					0x04 : 衝突発生時にnextを使わない		*/
/*					0x08 : not delete						*/
/*					0x10 : not use akxm_cct_malloc()		*/
/*						   m_alloc<>NULL のときは、off扱い	*/
/* 返却 : xha :	XHASHB *									*/
/*		  xha_id[0]  : 'H' 固定								*/
/*		  xha_id[1]  : 'X'									*/
/*					   'L' sKeyLen>0 &&						*/
/*								sKeyLen<=sizeof(long))		*/
/*					   '2' sKeyLen>sizeof(long) &&			*/
/*								sKeyLen<=sizeof(long)*2		*/
/*		  xha_option : iOpt & 0x1f							*/
/*						0x20 : m_alloc,pConstCtを使う		*/
/*						0x40 : next等はushortを使う			*/
/*						0x80 : 予約							*/
/************************************************************/
XHASHB *akxs_xhashm_new2(sKeyLen,lMaxReg,lPreReg,lDatLen,iOpt,m_alloc,pConstCt)
short sKeyLen;
int  lMaxReg,lPreReg,lDatLen,iOpt;
char    *(*m_alloc)();
tdtCONSTCT *pConstCt;
{
	XHASHB *p;
	int l;
	char c;
/*
printf("akxs_xhashm_new2: sKeyLen=%d lMaxReg=%d lPreReg=%d lDatLen=%d iOpt=%08x\n",
sKeyLen,lMaxReg,lPreReg,lDatLen,iOpt);
*/
	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;
		}
	}
	p = (XHASHB *)akxm_malloc_constct(m_alloc,pConstCt,sizeof(XHASHB));
	if (!p) {
		errno = -1303;
		return NULL;
	}

	iOpt &= 0x1f;
	if (m_alloc) {
		iOpt &= ~AKX_HASX_OPT_USE_MALLOC;
		iOpt |= AKX_HASX_OPT_TMP_MALLOC;
	}
/*
	c = 'H';
	if (iOpt & AKX_HASX_OPT_CASE_KEY) c = toupper(c);
	p->xha_id[0] = c;
*/
	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] = 'H';
	p->xha_id[1] = c;
	p->xha_keylen = sKeyLen;
	p->xha_maxreg = lMaxReg;
	p->xha_prereg = l;
	p->xha_datlen = lDatLen;
	p->xha_option = iOpt;
	p->xha_xhix   = 0;
	p->xha_hashb  = NULL;
	p->xha_xhnext = NULL;
	p->xha_datreg = NULL;
	p->xha_malloc = m_alloc;
	p->xha_constct= pConstCt;
	return p;
}

/************************************/
/*									*/
/************************************/
XHASHB *akxs_xhash_new2(sKeyLen,lMaxReg,lPreReg,lDatLen)
short sKeyLen;
int  lMaxReg,lPreReg,lDatLen;
{
	return akxs_xhashm_new2(sKeyLen,lMaxReg,lPreReg,lDatLen,0,NULL,NULL);
}

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

/************************************/
/*									*/
/************************************/
XHASHB *akxs_xhash_init(sKeyLen,lMaxReg,lPreReg)
short sKeyLen;
int  lMaxReg,lPreReg;
{
	return akxs_xhash_new(sKeyLen,lMaxReg,lPreReg);
}

/************************************/
/*									*/
/************************************/
int akxs_xhash_free_opt(tpxhashb,opt)
XHASHB *tpxhashb;
int opt;
{
	HASHB *tph;
	char *p;

/*
printf("akxs_xhash_free:tpxhashb=%08x\n",tpxhashb);
*/
	if (tpxhashb) {
		if (tph=tpxhashb->xha_hashb) {
			akxs_hasx_free(tph);
		}
		if (!tpxhashb->xha_malloc && (p=tpxhashb->xha_datreg)) {
			_free_reg(tpxhashb->xha_maxreg,tpxhashb->xha_datlen,p,opt);
		}
		akxs_xhash_free(tpxhashb->xha_xhnext);
		Free(tpxhashb);
	}
	return 0;
}

/************************************/
/*									*/
/************************************/
int akxs_xhash_free(tpxhashb)
XHASHB *tpxhashb;
{
	return akxs_xhash_free_opt(tpxhashb,0);
}

/************************************/
/*									*/
/************************************/
int akxs_xhashn2(tpxhashb,cCmnd,cpKey,aux_klen,cppDat)
XHASHB *tpxhashb;
char cCmnd, *cpKey;	/* 'P' or 'p' のときは、				*/
					/* ハッシュ内部のキー域の先頭アドレスを	*/
					/* 受取るポインタのアドレスを設定する	*/
int  aux_klen;
char **cppDat;		/* cCmnd='S'or's'のときは、(char *)と読み替える */
					/* このときは、保存するデータ域の先頭アドレスを設定する	*/
					/* cCmnd='R'or'r' or 'D' or 'd' or、		*/
					/* 'P' or 'p' or 'K' or 'k' のときは		*/
					/* ハッシュ内部のデータ域の先頭アドレスを	*/
					/* 受取るポインタのアドレスを設定する		*/
{
	XHASHB *tpcur,*tpnext;
	int l,i,offset,len;
	HASHB *tph,ha;
	int ret,opt;
	char cCmd,c,cc;
/*
printf("akxs_xhashn2: tpxhashb=%08x cCmnd=%c cpKey=%08x cppDat=%08x\n",
tpxhashb,cCmnd,cpKey,cppDat);
*/
	if (!tpxhashb) return -1;
	cCmd = akxcupper(cCmnd);
	switch (cCmd) {
		case 'R':
		case 'D':
/*
printf("akxs_xhashn2: xha_xhix=%d cpKey=[%s]\n",tpxhashb->xha_xhix,cpKey);
*/
			if (cppDat) *cppDat = NULL;	/* add 2023.1.6 */
		case 'S':
			if (tpxhashb->xha_xhix) return _xhash_chk(tpxhashb,cCmd,cpKey,aux_klen,cppDat);
			break;
		case 'K':
		case 'P':
			return _xhash_chk(tpxhashb,cCmd,cpKey,aux_klen,cppDat);
		case 'U':
			return _xhash_used(tpxhashb);
		case 'M':
			return _xhash_max(tpxhashb);
		case 'C':
			return _xhash_coll(tpxhashb,cpKey);
		case 'F':
			if (!(tph=tpxhashb->xha_hashb)) {
				len = tpxhashb->xha_keylen;
				tph = &ha;
#if 1
				tph->ha_id[0] = tpxhashb->xha_id[0];
				tph->ha_id[1] = tpxhashb->xha_id[1];
#else
				tph->ha_id[0] = tpxhashb->xha_id[1];
				tph->ha_id[1] = tpxhashb->xha_option;
#endif
				tph->ha_keylen = len;
				tph->ha_maxreg = tpxhashb->xha_maxreg;
				tph->ha_prereg = tpxhashb->xha_prereg;
			}
			tph->ha_key = cpKey;
			tph->ha_hix = 0;
			return akxshasxn(cCmd,tph,aux_klen);
		default:
			return -72;
	}
	if (!cpKey) return -73;
	l = 0;
	offset = 0;
	tpnext = tpxhashb;
	while (tpnext) {
		tpcur = tpnext;
		if (!(tph=tpcur->xha_hashb)) {
/*
printf("akxs_xhashn2:(%08x)->xha_hashb=NULL\n",tpcur);
*/
			if (cCmd == 'R' || cCmd == 'D') return 0;
#if 1	/* 2021.9.16 */
		/*	if (!(tpcur->xha_option & AKX_HASX_OPT_CASE_KEY)) {
				cc = tpcur->xha_id[0];
				c = toupper(cc);
				if (c != cc) tpcur->xha_option |= AKX_HASX_OPT_CASE_KEY;
			}	*/
			if (tph=akxs_hasxm_new2(tpcur->xha_keylen,tpcur->xha_maxreg,tpcur->xha_prereg,
			                        tpcur->xha_option,tpcur->xha_malloc,tpcur->xha_constct))
#else
			cc = tpcur->xha_id[0];
			c = toupper(cc);
			opt = tpcur->xha_option;
			if (c != cc) opt |= AKX_HASX_OPT_CASE_KEY;
			if (tph=akxs_hasxm_new2(tpcur->xha_keylen,tpcur->xha_maxreg,
			                     tpcur->xha_prereg,opt,tpcur->xha_malloc,tpcur->xha_constct))
#endif
				tpcur->xha_hashb = tph;
			else return errno;
/*
printf("akxs_xhashn2:len=%d maxreg=%d mso=%d\n",tph->ha_keylen,tph->ha_maxreg,tph->ha_prereg);
*/
		}
		tph->ha_key = cpKey;
#if 0
		if (!l) {
			if (!(l=tpcur->xha_xhix))
				l = akxshasx('f',tph);
/*
printf("akxs_xhashn2:l=%d\n",l);
*/
		}
		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 = (char *)cppDat;
	*********/
		if (i=akxshasxn(cCmd,tph,aux_klen)) {
			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;
	}
/*
printf("akxs_xhashn2:(%08x)->xha_xhnext=NULL\n",tpcur);
*/
	if (cCmd == 'R' || cCmd == 'D') return i;
	if (!(tpnext=(XHASHB *)akxm_malloc_constct(tpcur->xha_malloc,tpcur->xha_constct,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_xhashn2(tpnext,cCmd,cpKey,aux_klen,cppDat))>0) i += offset;
	tpnext->xha_xhix = 0;
	return i;
}

/************************************/
/*									*/
/************************************/
int akxs_xhash2(tpxhashb,cCmnd,cpKey,cppDat)
XHASHB *tpxhashb;
char cCmnd, *cpKey;
char **cppDat;
{
	return akxs_xhashn2(tpxhashb,cCmnd,cpKey,0,cppDat);
}

/************************************/
/*									*/
/************************************/
int akxs_xhashn(tpxhashb,cCmd,cpKey,aux_len)
XHASHB *tpxhashb;
char cCmd, *cpKey;
int  aux_len;
{
	return akxs_xhashn2(tpxhashb,cCmd,cpKey,aux_len,NULL);
}

/************************************/
/*									*/
/************************************/
int akxs_xhash(tpxhashb,cCmd,cpKey)
XHASHB *tpxhashb;
char cCmd, *cpKey;
{
	return akxs_xhashn2(tpxhashb,cCmd,cpKey,0,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;
	char *(*m_alloc)();
	tdtCONSTCT *pConstCt;
/*
printf("akxs_dreg_proc: tpX=0x%08x,cCmd=[%c],i=%d,cppDat=0x%08x\n",tpX,cCmd,i,cppDat);
*/
	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;
/*
printf("akxs_dreg_proc: dlen=%d,p=0x%08x\n",dlen,p);
*/
	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;
/*
printf("akxs_dreg_proc:RD cpDat=[%s]\n",cpDat);
*/
	}
	else if (cCmd == 'S') {
		m_alloc  = tpX->xha_malloc;
		pConstCt = tpX->xha_constct;
		cpDat = (char *)cppDat;
		if (!p) {
			mx = tpX->xha_maxreg;
			if (dlen > 0) len = alen*mx;
			else len = sizeof(char **)*(mx+1);
			if (!(p=akxm_malloc_constct(m_alloc,pConstCt,len))) return -77;
			tpX->xha_datreg = p;
/*
printf("akxs_dreg_proc: dlen=%d,p=0x%08x\n",dlen,p);
*/
			if (dlen <= 0) {
				memset(p,0,sizeof(char **)*(mx+1));
				if (!(tpX->xha_option & (AKX_HASX_OPT_USE_MALLOC | AKX_HASX_OPT_TMP_MALLOC))) {
					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-1]) Free(dp);	*/
			if (dlen < 0) {
				memcpy(&len,cpDat,sizeof(int));
				len += sizeof(int);
			}
			else len = strlen(cpDat);
			alen = len + 1;
			if (tpX->xha_option & AKX_HASX_OPT_TMP_MALLOC)
				dp = akxm_malloc_constct(m_alloc,pConstCt,alen);
			else if (drg[0])
				dp = akxm_cct_malloc(drg[0],alen);
			else
				dp = Malloc(alen);
			if (!dp) return -78;
			memcpy(dp,cpDat,len);
			*(dp+len) = '\0';
			drg[i] = dp;
/*
printf("akxs_dreg_proc:S dp=[%s]\n",dp);
*/
		}
	}
	return 0;
}

/************************************/
/*									*/
/************************************/
static int _xhashf(kp,len,mso,aux_klen,iCASE)
uchar *kp;
short len;
int mso,aux_klen,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 if (aux_klen > 0) lklen = aux_klen;
	else
		lklen = strlen((char *)p);
	return akxs_hasx_func(p,lklen,mso,iCASE);
}

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

	ret = -1029;
	i = tpxhashb->xha_xhix;
	tpxhashb->xha_xhix = 0;
	offset = 0;
	tpcur = tpxhashb;
	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[0]=='L')
					tph->ha_next = (int *)cppDat;
				ret = akxshasxn(cCmd,tph,aux_klen);
				tph->ha_hix = 0;
/*
printf("_xhash_chk: cmd=%c i=%d ix=%d ret=%d\n",cCmd,i,ix,ret);
*/
				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(tpxhashb)
XHASHB *tpxhashb;
{
	XHASHB *tpcur;
	int ret,count;
	HASHB *tph;

	count = 0;
	tpcur = tpxhashb;
	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(tpxhashb)
XHASHB *tpxhashb;
{
	XHASHB *tpcur;
	int ret,m;
	HASHB *tph;

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

/********1*********2*********3*********4*********5*******/
/* 引数 : tpxhashb: XHASHB								*/
/*				  cpKey= NULL: 直前の'S','R','D'実行時の*/
/*							   衝突数					*/
/*				  cpKey<>NULL: 前回実行時からの最大		*/
/*							   衝突数。復帰前に最大を	*/
/*							   0にする					*/
/* 返却 : >=0 :衝突数									*/
/*		   <0 :エラー									*/
/********************************************************/
static int _xhash_coll(tpxhashb,cpKey)
XHASHB *tpxhashb;
char *cpKey;
{
	XHASHB *tpcur;
	int ret,count,x;
	HASHB *tph;

	x = count = 0;
	tpcur = tpxhashb;
	if (cpKey) x = 1;
	while (tpcur) {
		if (tph=tpcur->xha_hashb) {
			tph->ha_hix = x;
			ret = akxshasx('C',tph);
			if (ret > 0) {
				if (x) {
					if (ret > count) count = ret;
				}
				else count += ret;
			}
		}
		tpcur = tpcur->xha_xhnext;
	}
	return count;
}

/************************************/
/*									*/
/************************************/
int akxs_xhash_reset(tpxhashb)
XHASHB *tpxhashb;
{
	HASHB *tph;
	int i;
	char **rpp,*p;

/*
printf("akxs_xhash_reset:tpxhashb=%08x\n",tpxhashb);
*/
	if (tpxhashb) {
		if (tph=tpxhashb->xha_hashb) {
			tph->ha_aux = AKX_HASX_OPT_RESET_MEM;
			akxshasx('I',tph);
		}
		if (p=tpxhashb->xha_datreg) {
			if (tpxhashb->xha_datlen <= 0) {
				rpp = (char **)p;
				if (rpp[0]) akxm_cct_reset((tdtCONSTCT *)rpp[0]);
			}
		}
		akxs_xhash_reset(tpxhashb->xha_xhnext);
	}
	return 0;
}

/************************************/
/*									*/
/************************************/
static int _srami(hp)
HASHB *hp;
{
	int i=0;

	if (hp->ha_maxreg <= 0) i-=4;
	if (!hp->ha_reg) i -= 8;

	if (i >= 0) {
		memset(hp->ha_reg,0,hp->ha_maxreg);
	}

	return i;
}

/************************************/
/*									*/
/************************************/
static int _sramf_sub(c,opt)
char c;
int opt;
{
	int i;
/*
printf("_sramf_sub:Enter: c=[%c] opt=%d\n",c,opt);
*/
	i = 0;
	if (!c) i = 0;
	else if (c == '_') i = 1;
	else if (c>='A' && c<='Z') i = c - 'A' + 2;
	else if (opt >= 1) {
		if (c>='a' && c<='z') i = c - 'a' + 27 + 1;
		else if (opt >= 2) {
			if (c>='0' && c<='9') i = c - '0' + 27 + 26 + 1;
		}
	}
/*
printf("_sramf_sub:Exit: i=%d\n",i);
*/
	return i;
}

/************************************/
/*									*/
/************************************/
static int _sramf(hp)
HASHB *hp;
{
	int i,j,klen,opt,opt1;
	char *kp;

	if ((i=hp->ha_hix) > 0) {
		if (i > hp->ha_maxreg) i = -1;
/*
printf("_sramf:Exit: i=%d\n",i);
*/
	}
	else {
		opt1 = opt = hp->ha_aux;
		if (opt1 == 2) opt1 = 1;
		kp = hp->ha_key;
		if ((klen=hp->ha_keylen) > 2) klen = 2;
		i = _sramf_sub(*kp,opt1);
		if (i>0 && klen==2) {
			j = _sramf_sub(*(kp+1),opt);
			if (j > 0) i = i*hp->ha_prereg + j;
		}
/*
printf("_sramf:Exit: i=%d key=[%s]\n",i,kp);
*/
	}
	return i;
}

/************************************/
/*									*/
/************************************/
int akxs_sram(func,hp)
char func;
HASHB *hp;
{
	int i;
	char c,*p;
/*
printf("akxs_sram:Enter: func=[%c]\n",func);
*/
	if (!hp) i = -1;
	else if (func=='i' || func=='I') i = _srami(hp);
	else if ((i=_sramf(hp)) > 0) {
		p = hp->ha_reg + (i-1);
		if (func=='r' || func=='R') {
			if (!*p) i = 0;
		}
		else if (func=='s' || func=='S') *p = '1';
		else if (func=='d' || func=='D') *p = '\0';
		else i = -2;
	}
/*
printf("akxs_sram:Exit: i=%d\n",i);
*/
	return i;
}

/************************************/
/*									*/
/************************************/
HASHB *akxs_sram_new(sKeyLen,opt)
short sKeyLen;
int opt;
{
	HASHB *tph;
	int lMaxReg,pre;
	char c1,c2,key[3];
/*
printf("akxs_sram_new:Enter: sKeyLen=%d opt=%d\n",sKeyLen,opt);
*/
	if (sKeyLen <= 0) return NULL;
	else if (sKeyLen > 2) sKeyLen = 2;
	if (!(tph=(HASHB *)Malloc(sizeof(HASHB)))) return NULL;
	memset(tph,0,sizeof(HASHB));
	tph->ha_id[0] = 'R';
	tph->ha_id[1] = 'A';
	if (opt <= 0) {
		opt = 0;
		c1 = c2 = 'Z';
		pre = 27;
	}
	else if (opt == 1) {
		c1 = c2 = 'z';
		pre = 27 + 26;
	}
	else {
		opt = 2;
		c1 = 'z';
		c2 = '9';
		pre = 27 + 26 + 10;
	}
	key[0] = c1;
	key[1] = c2;
	key[2] = '\0';
	tph->ha_keylen = sKeyLen;
	tph->ha_key = key;
	tph->ha_aux = opt;
	tph->ha_prereg = pre;
	tph->ha_maxreg = lMaxReg = _sramf(tph);
/*
printf("akxs_sram_new: key=[%s] lMaxReg=%d\n",key,lMaxReg);
*/
	if (!(tph->ha_reg=Malloc(lMaxReg))) {
		Free(tph);
		return NULL;
	}
	if (akxs_sram('i',tph)) {
		akxs_sram_free(tph);
		return NULL;
	}
	return tph;
}

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