static char sccsid[]="%Z% %M% %I% %E% %U%";
#include "akxcommon.h"

#define MAXLINE	128
#define KEYLEN	(sizeof(char *))
#define SIZELEN	(sizeof(long))

static int Memafout = 0;
static int Memnfout = 0;
static int Memcontl = 0;
static int Memafhas = 0;
static int Hashinit = 0;
static HASHB hm;
static char Hmkey[KEYLEN];
static char Memafname[MAXLINE]={'\0'};
static char Memnfname[MAXLINE]={'\0'};
static char Memctname[MAXLINE]={'\0'};
static tdtRbChain tRbChain,*tpRbChainTop;
static int giUseMemory = 0;
static int giCountAlloc = 0;
static int giCountFree = 0;
static int giCountRealloc = 0;
static int maxreg = 0;
static char *ghkey[2];
static int giAFDUMP = 0;
static int giNFDUMP = 0;
static int giAFHASH = 0;

/********************************************/
/*                                          */
/********************************************/
static void _sdump(pi,n,buf)
char *pi;
int  n;
char *buf;
{
	char *pp,*p;
	int  i;

	p = pi;
	pp = buf;
	sprintf(pp,"%08x ",p);
	if (p) {
		pp += strlen(pp);
		for (i=0;i<n;i++,p++) {
			sprintf(pp,"%02x ",(int)*p & 0xff);
			pp += 3;
		}
		*pp++ = '[';
		p = pi;
		for (i=0;i<n;i++) {
			*pp++ = akxctoank(*p++);
		}
		strcpy(pp,"]");
	}
}

#if 1	/* 2020.12.5 */
/********************************************/
/*                                          */
/********************************************/
static int _addrchk(p)
char *p;
{
	if (!p) return 0;
#if defined(AIX) || defined(HPUX)
	if ((long)p & 0x0f000000) {
#else
	if ((long)p & 0x20000000) ;
	else if ((long)p & 0xf0000000 || !((int)p & 0x0ff00000)) {
#endif
		return 0;
	}
	return 1;
}

/********************************************/
/*                                          */
/********************************************/
int akxm_addrchk(p)
char *p;
{
	return _addrchk(p);
}
#else
/********************************************/
/*                                          */
/********************************************/
static int _addrchk(p)
char *p;
{
	if (!p ||
#if defined(AIX) || defined(HPUX)
	    ((int)p & 0x0f000000)
#else
	    ((int)p & 0xf0000000)
#endif
	   ) return 0;
	else return 1;
}
#endif

/********************************************/
/*                                          */
/********************************************/
static void _malloc_log(size,p,line,file)
int size,line;
char *p,*file;
{
	FILE *fd;

	if (Memafout && giAFDUMP) {
		if (fd = fopen(Memafname, "a" )) {
			fprintf(fd,"alloc   size=%10d addr=%08x [%5d](%s)\n",
			        size,p,line,file);
			fclose(fd);
		}
	}
}

/********************************************/
/*                                          */
/********************************************/
static int _new_hm(tpRbChain, maxreg)
tdtRbChain *tpRbChain;
int maxreg;
{
	int len, i, *pD;
	char *p;
	HASHB *pH;
	tdtRbChain *pC;

	if (maxreg < 3) return -1;
	len = sizeof(tdtRbChain)+sizeof(HASHB)+sizeof(char *)+
	      maxreg*sizeof(tdtHaslCell)+(maxreg*2+1)*sizeof(int);
	giCountAlloc++;
	giUseMemory += len;
	if (!(p = malloc(len))) return -1;
	_malloc_log(len,p,__LINE__,__FILE__);

	pC = (tdtRbChain *)p;
	p += sizeof(tdtRbChain);
	pH = (HASHB *)p;
	p += sizeof(HASHB);
	p += sizeof(char *);
	pH->ha_next = (int *)p;
	p += (maxreg*2+1)*sizeof(int);

	pC->rbc_buf  = (char *)pH;
	pC->rbc_next = NULL;

	pH->ha_id[0] = AKX_HASX_ID_NO_USE_ALL;
	pH->ha_id[1] = 'L';
	pH->ha_keylen = KEYLEN;
	pH->ha_maxreg = maxreg;
	pH->ha_prereg = (maxreg*997)/1000;
	if (!(pH->ha_prereg & 0x1)) pH->ha_prereg++;
	pH->ha_reg = p;
	pH->ha_key = (char *)ghkey;
	pH->ha_aux = 0;
	pH->ha_hix = 0;
	if ((i = akxshasl('I',pH)) < 0) return i;
	tpRbChain->rbc_next = pC;
	memset(p,0,maxreg*SIZELEN);
	return 0;
}

/********************************************/
/*                                          */
/********************************************/
static int _xhash(pProc,cCmd,pKey,len,psize)
char *pProc;
char  cCmd;
char **pKey;
int   len,*psize;
{
	HASHB *pH;
	tdtRbChain *pC,*pN;
	int i=-1,k;
	char **pD,*p;

	cCmd = akxcupper(cCmd);
	ghkey[0] = *pKey;
	pC = tpRbChainTop;
	while (pC) {
/*
printf("_xhash: pC=%08x rbc_buf=%08x rbc_next=%08x\n",pC,pC->rbc_buf,pC->rbc_next);
*/
		pH = (HASHB *)pC->rbc_buf;
		pH->ha_hix = 0;
		if (cCmd == 'S') ghkey[1] = (char *)*psize;
		i = akxshasl(cCmd,pH);
		if (i) break;
		pN = pC->rbc_next;
		if (!pN) {
			if (cCmd == 'S') {
				i = _new_hm(pC,pH->ha_maxreg);
#ifdef NOTICE_MEMCTL
				printf("%s: _new_hm rc = %d\n",pProc,i);
#endif
				if (i >= 0) pN = pC->rbc_next;
#ifdef NOTICE
				else printf("###### %s:no entry ret=%d ######\n",pProc,i);
#endif
			}
		}
		pC = pN;
	}
	if (i>0 && cCmd != 'S') *psize = (int)ghkey[1];
	return i;
}

/********************************************/
/*                                          */
/********************************************/
static int set_parm(buf,len)
char *buf;
int  len;
{
	char *argv[3],parm[128];
	int  n;

	if (!buf) return -1;
/*
printf("set_parm: buf=[%s] len=%d\n",buf,len);
*/
	n = akxtgetargvn2(buf,len,argv,3,parm,sizeof(parm),0x17);
	if (n >= 2) {
		if (!stricmp(argv[0],"afhash")) {	/* afhash:maxreg */
			if (Hashinit > 0) return 1;
			maxreg = atoi(argv[1]);
			Memafhas = 1;
		}
		else if (!stricmp(argv[0],"afdump")) {	/* afdump:Memafname */
			strnzcpy(Memafname,argv[1],sizeof(Memafname)-1);
			Memafout = 1;
			if (n>=3 && !stricmp(argv[2],"off")) Memafout = 3;
		}
		else if (!stricmp(argv[0],"nfdump")) {	/* nfdump:Memnfname */
			strnzcpy(Memnfname,argv[1],sizeof(Memnfname)-1);
			Memnfout = 1;
			if (n>=3 && !stricmp(argv[2],"off")) Memnfout = 3;
		}
	}

	return 0;
}

/********************************************/
/*                                          */
/********************************************/
static int setup(opt)
int opt;
{
	int ret=0;
	FILE *fd;
	char buf[60];

	giAFDUMP = giNFDUMP = giAFHASH = 0;
	sprintf(buf,"***** Start Time (%s) *****\n",akx_log_time());
	if (Memafout>0) {
		if (fd = fopen( Memafname, "w" )) {
			fprintf(fd,"%s",buf);
			fclose(fd);
			if (!(Memafout & 0x02)) giAFDUMP = 1;
			Memafout = 1;
		}
		else Memafout = 0;
	}
	if (Memnfout>0) {
		if (fd = fopen(Memnfname, "w" )) {
			fprintf(fd,"%s",buf);
			fclose(fd);
			if (!(Memnfout & 0x02)) giNFDUMP = 1;
			Memnfout = 1;
		}
		else Memnfout = 0;
	}
	if (Memafhas==1) {
		Memafhas = 0;
		if (Hashinit > 0) ret = 11;
		else if (!(opt & 0x01) &&
		         (giCountAlloc || giCountFree || giCountRealloc)) ret = 12;
		else {
			ret = _new_hm(&tRbChain, maxreg);
#ifdef NOTICE_MEMCTL
			printf("akxm_mem_init: _new_hm rc = %d\n",ret);
#endif
			if (ret >= 0) {
				tpRbChainTop = tRbChain.rbc_next;
				Hashinit = 1;
				giAFHASH = 1;
				ret = 0;
			}
		}
	}
	if (giAFDUMP + giNFDUMP + giAFHASH) Memcontl = 1;
	else if (!ret) ret = 10;
	return ret;
}

/********************************************/
/*                                          */
/********************************************/
int akxm_mem_init(memtlname)
char *memtlname;
{
	int  len,ret;
	FILE *fd;
	char *p,buf[MAXLINE];

	if (!memtlname) return -1;
	strnzcpy(Memctname,memtlname,sizeof(Memctname)-1);
	if (fd = fopen( memtlname, "r" )) {
		while ((len=akxa_get_line(buf,MAXLINE,fd,0x03)) >= 0) {
			if (len>8 && *buf!='#') {
				if ((ret=set_parm(buf,len)) < 0) return ret;
			}
		}
		fclose(fd);
	}
	ret = setup(0x01);
	return ret;
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_malloc(size,file,line)
int  size;
char *file;
int  line;
{
	int i;
	char  *p;

	giCountAlloc++;
	p = (char *)malloc( size );
	if (Memcontl<1) return p;

	_malloc_log(size,p,line,file);

	if (p) {
		if (Hashinit == 1 && giAFHASH) {
			i = _xhash("akxm_malloc",'S',(char *)&p,KEYLEN,&size);
#ifdef NOTICE
			if (i <= 0) printf("###### (%s)[%d] akxm_malloc: malloc i=%d ######\n",file,line,i);
#endif
			giUseMemory += size;
		}
	}
	return p;
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_realloc(p,size,file,line)
char *p;
int  size;
char *file;
int  line;
{
	FILE *fd;
	char *np;
	int i,old_size;

	giCountRealloc++;
	if (Memcontl<1) {
		if (!p) {
#ifdef NOTICE_NULL_POINTER
			printf("###### akxm_realloc:NULL pointer (%s)[%d], realloc addr=%08x\n",
			       file,line,p);
#endif
			np = NULL;
		}
		else np = (char *)realloc(p,size);
		return np;
	}

	if (Hashinit == 1 && giAFHASH) {
		i = _xhash("akxm_realloc",'D',(char *)&p,KEYLEN,&old_size);
		if (i <= 0) {
#ifdef NOTICE
			printf("###### (%s)[%d] akxm_realloc:no malloc i=%d ######\n",file,line,i);
#endif
			if (Memafout && giAFDUMP) {
				if (fd = fopen( Memafname, "a" )) {
					fprintf(fd,"realloc size=%10d addr=%08x [%5d](%s) old addr=%08x\n",
					size,0,line,file,p);
					fprintf(fd,"##### no malloc addr=%08x #####\n",p);
					fclose(fd);
				}
			}
			return NULL;
		}
	}

	if (!p) {
#ifdef NOTICE_NULL_POINTER
	printf("###### akxm_realloc:NULL pointer (%s)[%d], realloc addr=%08x\n",
	       file,line,p);
#endif
		np = NULL;
	}
	else np = (char *)realloc(p,size);

	if (Memafout && giAFDUMP) {
		if (fd = fopen( Memafname, "a" )) {
			fprintf(fd,"realloc size=%10d addr=%08x [%5d](%s) old addr=%08x\n",
			        size,np,line,file,p);
			fclose(fd);
		}
	}
	if (Hashinit == 1 && np && giAFHASH) {
		if (size > old_size) {
			giUseMemory += size-old_size;
			old_size = size;
		}
		i = _xhash("akxm_realloc",'S',(char *)&np,4,&old_size);
#ifdef NOTICE
		if (i <= 0) printf("###### akxm_realloc:(%s)[%d] realloc i=%d ######\n",i);
#endif
	}
	return np;
}

/********************************************/
/*                                          */
/********************************************/
void akxm_free(p,file,line)
char *p;
char *file;
int  line;
{
	FILE *fd;
	int i,size;
	char buf[128];

	giCountFree++;
	if (Memcontl<1) {
		if (p) free( p );
#ifdef NOTICE_NULL_POINTER
		else printf("###### akxm_free:NULL pointer (%s)[%d], free addr=%08x\n",
		            file,line,p);
#endif
		return;
	}

	if (Memafout && giAFDUMP) {
		if (fd = fopen( Memafname, "a" )) {
			fprintf(fd,"free                    addr=%08x [%5d](%s)\n",
			        p,line,file);
			fclose(fd);
		}
	}
	if (Hashinit == 1 && giAFHASH) {
		i = _xhash("akxm_free",'D',(char *)&p,KEYLEN,&size);
		if (i) {
			free( p );
			giUseMemory -= size;
		}
		else {
			_sdump(p,16,buf);
#ifdef NOTICE
			printf("###### akxm_free:no malloc (%s)[%d], free addr=%08x\n%s\n",
			       file,line,p,buf);
#endif
			if (Memafout && giAFDUMP) {
				if (fd = fopen( Memafname, "a" )) {
					fprintf(fd,"##### no malloc addr=%08x #####\n%s\n",p,buf);
					fclose(fd);
				}
			}
		}
	}
	else {
		if (_addrchk(p)) free( p );
		else if (p) {
#ifdef NOTICE
			printf("###### akxm_free: (%s)[%d],invalid free addr: %x\n",
			       file,line,p);
#endif
			if (Memafout && giAFDUMP) {
				if (fd = fopen( Memafname, "a" )) {
					fprintf(fd,"##### invalid free addr=%08x #####\n",p);
					fclose(fd);
				}
			}
		}
#ifdef NOTICE_NULL_POINTER
		else printf("###### akxm_free:NULL pointer (%s)[%d], free addr=%08x\n",
			        file,line,p);
#endif
	}
}

/********************************************/
/*                                          */
/********************************************/
int akxm_no_free(f)
int f;
{
	static int nkai=0;
	int i,j=0;
	char *p,buf[70];
	FILE *fd;
	HASHB *pH;
	tdtRbChain *pC;

	if (Memcontl<1 || Hashinit == 0/* || !giNFDUMP*/) return (-1);

	sprintf(buf,"***** Nofree(%3d)(%s) *****\n",++nkai,akx_log_time());
	if (Memafout>0) {
		if (fd = fopen( Memafname, "a" )) {
			fprintf(fd,"%s",buf);
			fclose(fd);
		}
	}
	fd = NULL;
	if (giNFDUMP && Memnfout) fd = fopen( Memnfname, "a" );
	if (fd) fprintf(fd,"%s",buf);
	pC = tpRbChainTop;
	while (pC) {
		pH = (HASHB *)pC->rbc_buf;
		for (i=1;i<=pH->ha_maxreg;i++) {
			pH->ha_hix = i;
			if (akxshasl('K',pH)) {
				j++;
				if (fd) {
					fprintf(fd,"akxm_no_free: j=%d addr=%08x size=%d\n",
					        j,ghkey[0],ghkey[1]);
				}
			}
		}
		pC = pC->rbc_next;
	}
	if (fd)	fclose(fd);

	return (j);
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_strndup(s,n,file,line)
char *s;
char *file;
int	  line,n;
{
	char *np;

	if (!s) {
#ifdef NOTICE_NULL_POINTER
		printf("###### akxm_strndup:NULL pointer (%s)[%d], strdup addr=%08x\n",
			       file,line,s);
#endif
		np = NULL;
	}
	else np = akxm_memndup(s,strlen(s),n,file,line);
	return np;
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_strdup(s,file,line)
char *s;
char *file;
int	  line;
{
	char *np;

	if (!s) {
#ifdef NOTICE_NULL_POINTER
		printf("###### akxm_strndup:NULL pointer (%s)[%d], strdup addr=%08x\n",
			       file,line,s);
#endif
		np = NULL;
	}
	else np = akxm_memndup(s,strlen(s),0,file,line);
	return np;
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_memndup(s,len,n,file,line)
char *s;
char *file;
int	  len,line,n;
{
	char *p=NULL;

	if (s && len>=0) {
		if (n <= 0) n = len - n;
		p = akxm_malloc(n+1,file,line);
		if (p) {
			memnzcpy(p,s,len,n);
		}
	}
	else if (!s) {
#ifdef NOTICE_NULL_POINTER
		printf("###### akxm_memndup:NULL pointer (%s)[%d], memndup addr=%08x n=%d\n",
			       file,line,s,n);
#endif
	}
	return p;
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_memdup(s,len,file,line)
char *s;
char *file;
int	  len,line;
{
	return akxm_memndup(s,len,0,file,line);
}

/****************************************/
/*										*/
/****************************************/
char *akxm_mrealloc(p0,len,file,line)
char *p0;
int  len;
char *file;
int	 line;
{
	char *p;
/*
printf("akxm_mrealloc: p0=%08x [%5d](%s)\n",p0,line,file);
*/
	if (len > 0) {
		if (p0) p = akxm_realloc(p0,len,file,line);
		else p = akxm_malloc(len,file,line);
	}
	else p = NULL;
	return p;
}

/********************************************/
/*                                          */
/********************************************/
int akxm_stat_memory(m,parm)
int  m;
long parm[];
{
	if (parm) {
		if (m > 0) parm[0] = giCountAlloc;
		if (m > 1) parm[1] = giCountFree;
		if (m > 2) parm[2] = giCountRealloc;
		if (m > 3) parm[3] = giUseMemory;
		if (m > 4) parm[4] = (long)Memctname;
		if (m > 5) parm[5] = (long)maxreg;
		if (m > 6) parm[6] = (long)Memafname;
		if (m > 7) parm[7] = (long)Memnfname;
		if (m > 8) parm[ 8] = Memcontl;
		if (m > 9) parm[ 9] = giAFDUMP;
		if (m >10) parm[10] = giNFDUMP;
		if (m >11) parm[11] = giAFHASH;
	}
	return giUseMemory;
}

/********************************************/
/*                                          */
/********************************************/
int akxm_mem_init_msg(msg,msglen)
char *msg;
int  msglen;
{
	int  len,ret,opt=0;
	SSP_S ssp;

	if (!msg) return -1;
	ssp.sp = 0;
	while ((len=akxtmgetline(msg,msglen,&ssp)) >= 0) {
		if (len>8 && *msg!='#') {
			if ((ret=set_parm(ssp.wd,len)) < 0) return ret;
		}
		else if (len>=3 && !memcmp(msg,"#!f",3)) opt |= 0x01;
	}
	ret = setup(opt);
	return ret;
}

/********************************************/
/*                                          */
/********************************************/
int akxm_mem_cntl(m,parm)
int  m;
long parm[];
{
	int ret=0,cntl,option=0,i;

	if (!parm || m<=0) return -1;
	
	cntl = parm[0];	/* 1:start 2:stop */
	if (m > 1) option = parm[1];	/* 0:no parm, 1:flag, 2:, 3: */
/*
printf("akxm_mem_cntl: m=%d cntl=%d option=%d\n",m,cntl,option);
*/
	switch (cntl) {
	case 2:	/* stop */
		if (option) {
			if (m>2 && parm[2]) giAFDUMP = !parm[2];
			if (m>3 && parm[3]) giNFDUMP = !parm[3];
			if (m>4 && parm[4]) giAFHASH = !parm[4];
		}
		else {
			if (Memcontl) {
				giAFHASH = Memcontl = 0;
			}
			else ret = 2;	/* already stopped */
		}
		break;
	case 1:
		if (!option) {				/* no param */
			if (Memcontl) ret = 1;	/* already started */
			else Memcontl = 1;
		}
		else if (option == 1) {		/* flags */
			if (m>2 && parm[2]) giAFDUMP = parm[2];
			if (m>3 && parm[3]) giNFDUMP = parm[3];
			if (m>4 && parm[4]) {
				if (Hashinit > 0) {
					if (giAFHASH) ret = 1;
					else ret = 11;
				}
				else ret = 12;
			}
			Memcontl = 1;
		}
		else if (option == 2) {		/* control data */
			if (m>2 && parm[2]) {
				strnzcpy(Memafname,(char *)parm[2],sizeof(Memafname)-1);
				Memafout = 1;
			}
			if (m>3 && parm[3]) {
				strnzcpy(Memnfname,(char *)parm[3],sizeof(Memnfname)-1);
				Memnfout = 1;
			}
			if (m>4 && parm[4]) {
				if (Hashinit > 0) ret = 11;
				else {
					maxreg = parm[4];
					Memafhas = 1;
				}
			}
			ret = setup(0);
		}
		break;
	}
	return ret;
}

/********************************************/
/*                                          */
/********************************************/
int akxm_mem_init_opt(opt,proc,maxreg)
int opt;	/* =0: ctl file name, =1: proc name, =2: proc number */
char *proc;
int maxreg;	/* <=0: set 500 */
{
	char buf[33],mem_name[41],nof_name[41];
	int  ret;
	long parm[5];

	if (!opt) ret = akxm_mem_init(proc);
	else {
		if (proc) {
			if (opt == 1) strnzcpy(buf,proc,sizeof(buf)-1);
			else sprintf(buf,"%d",(int)proc);
			sprintf(mem_name,"mem_%s.log",buf);
			sprintf(nof_name,"nof_%s.log",buf);
			if (maxreg <= 0) maxreg = 500;
			parm[0] = 1;	/* start */
			parm[1] = 2;	/* ctl data */
			parm[2] = (long)mem_name;
			parm[3] = (long)nof_name;
			parm[4] = maxreg;
			ret = akxm_mem_cntl(5,parm);
		}
		else ret = -1;
	}
	return ret;
}

/********************************************/
/*                                          */
/********************************************/
int akxm_mem_check(p,len,opt)
char *p;
int  len;
int  opt;
{
	int size,i,rc;
	HASHB *pH;
	tdtRbChain *pC;
	ulong addr,hkey;

	if (!_addrchk(p)) size = -4601;
	else if (Hashinit == 1 && giAFHASH) {
		i = _xhash("akxm_mem_check",'R',(char *)&p,4,&size);
		if (i < 0) size = i;
		else if (i) return X_MIN(len,size);
		else {
			addr = (ulong)p;
			pC = tpRbChainTop;
			while (pC) {
				pH = (HASHB *)pC->rbc_buf;
				for (i=1;i<=pH->ha_maxreg;i++) {
					pH->ha_hix = i;
					if ((rc=akxshaslk(pH,&hkey)) < 0) return rc;
					else if (rc) {
						size = (int)ghkey[1];
						if (addr>=hkey && addr<=hkey+size) {
/*
printf("akxm_mem_check: size=%d hkey=%d addr=%d\n",size,hkey,addr);
*/
							size -= (addr-hkey);
							return X_MIN(len,size);
						}
					}
				}
				pC = pC->rbc_next;
			}
			size = -4602;
		}
	}
	else if (opt & 0x01) size = len;
	else size = -4603;
	return size;
}

/********************************************/
/*                                          */
/********************************************/
void akxm_mem_sdump(pi,n,buf)
char *pi;
int  n;
char *buf;
{
	_sdump(pi,n,buf);
}

/********************************************************/
/*	akxm_cct_new										*/
/********************************************************/
tdtCONSTCT *akxm_cct_new(size_t size, int extent)
{
	tdtCONSTCT *p;
/*
printf("akxm_cct_new: size=%d extent=%d\n",size,extent);
*/
	if (size   <= 0) size   = D_CMB_SIZE;
	if (extent <= 0) extent = D_CCT_EXTENT;

	if (p = (tdtCONSTCT *)Malloc(sizeof(tdtCONSTCT))) {
		p->cct_top  = NULL;
		p->cct_cur  = NULL;
		p->cct_size = size;
		p->cct_ext  = extent;
	}
/*
printf("akxm_cct_new: size=%ld extent=%d p=%08x\n",size,extent,p);
*/
	return p;
}

/********************************************/
/*                                          */
/********************************************/
void akxm_cct_free(tdtCONSTCT *conct)
{
	tdtCMBCTL *cmb,*cmb1;

	if (_addrchk(conct)) {
		cmb = conct->cct_top;
		while(_addrchk(cmb)) {
			cmb1 = cmb->cbc_next;
			Free(cmb);
			cmb = cmb1;
		}
		Free(conct);
	}
	return;
}

/********************************************/
/*                                          */
/********************************************/
static int _get_new_cmb(tdtCONSTCT *conct, size_t len)
{
	tdtCMBCTL *cmb;
	size_t mlen;
	char *p;
/*
printf("_get_new_cmb: len=%d\n",len);
*/
	if (!conct) return -1;

	mlen = len>conct->cct_size ? len : conct->cct_size;
	if (!(p=Malloc(sizeof(tdtCMBCTL)+mlen))) return -2;
	memset(p,0,sizeof(tdtCMBCTL)+mlen);
	cmb = (tdtCMBCTL *)p;
	cmb->cbc_buf = p + sizeof(tdtCMBCTL);
	cmb->cbc_msize = mlen;
	cmb->cbc_rem = mlen;
/*
printf("_get_new_cmb: rem=%d\n",mlen);
*/
	if (conct->cct_top) {
		cmb = conct->cct_cur;
		cmb->cbc_next = (tdtCMBCTL *)p;
/*
printf("_get_new_cmb: next=%08x\n",p);
*/
	}
	else {
		conct->cct_top = (tdtCMBCTL *)p;
/*
printf("_get_new_cmb: top=%08x\n",p);
*/
	}
	cmb = (tdtCMBCTL *)p;
	conct->cct_cur = cmb;

	return 0;
}

/********************************************/
/*                                          */
/********************************************/
int akxm_cct_mem_get(tdtCONSTCT *conct, size_t len, char **pmem)
{
	tdtCMBCTL *cmb;
	size_t mlen,mrem;
	char *p;
	int i,ret,extent;

	if (!pmem) return -1;
	*pmem = NULL;
	if (!conct) return -1;
	if (len <= 0) return len;

	cmb = conct->cct_top;
	if ((extent=conct->cct_ext) <= 0) extent = D_CCT_EXTENT;
	for (i=0;i<extent;i++) {
		if (!cmb) {
			if (ret = _get_new_cmb(conct, len)) return ret;
			cmb = conct->cct_cur;
		}
		mrem = cmb->cbc_rem;
/*
printf("akxm_cct_mem_get: len=%d mrem=%d\n",len,mrem);
*/
		if (len & 0x01) ;
		else if (len & 0x02) mrem = (mrem>>1)<<1;
		else if (len & 0x04) mrem = (mrem>>2)<<2;
		else if (len & 0x08) mrem = (mrem>>3)<<3;
		else if (len & 0x10) mrem = (mrem>>4)<<4;
/*
printf("akxm_cct_mem_get: mrem=%d\n",mrem);
*/
		if (mrem >= len) {
			*pmem = cmb->cbc_buf + cmb->cbc_msize - mrem;
			cmb->cbc_rem = mrem - len;
/*
printf("akxm_cct_mem_get: pmem=%08x rem=%d\n",*pmem,cmb->cbc_rem);
*/
			break;
		}
		cmb = cmb->cbc_next;
/*
printf("akxm_cct_mem_get: next cmb=%08x\n",cmb);
*/
	}
	return 0;
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_cct_mem_alloc(tdtCONSTCT *conct, size_t len)
{
	char *pmem = NULL;

	akxm_cct_mem_get(conct, len, &pmem);
	return pmem;
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_cct_mem_alloc_m(tdtCONSTCT *conct, size_t len, char *file, int line)
{
	char *p;
	FILE *fd;

	p = akxm_cct_mem_alloc(conct, len);
	if (Memafout && giAFDUMP) {
		if (fd = fopen( Memafname, "a" )) {
			fprintf(fd,"ct_alloc size=%10d addr=%08x [%5d](%s)\n",
			        (int)len,p,line,file);
			fclose(fd);
		}
	}
	return p;
}

/********************************************/
/*                                          */
/********************************************/
static int _cct_used(tdtCONSTCT *conct, int reset)
{
	tdtCMBCTL *cmb;
	long n,len;
	FILE *fd;

	n = 0;
	if (_addrchk(conct)) {
		cmb = conct->cct_top;
		while (_addrchk(cmb)) {
			len = cmb->cbc_msize - cmb->cbc_rem;
			n += len;
			if (Memafout && giAFDUMP) {
				if (fd = fopen( Memafname, "a" )) {
					fprintf(fd,"ct_used size=%10d addr=%08x msize=%d\n",
					        len,cmb,cmb->cbc_msize);
					fclose(fd);
				}
			}
			if (reset) cmb->cbc_rem = cmb->cbc_msize;
			cmb = cmb->cbc_next;
		}
/*
printf("_cct_mem_used: mem=%d\n",n);
*/
	}
	else n = -1;
	return n;
}

/********************************************/
/*                                          */
/********************************************/
tdtCONSTCT *akxm_cct_mem_new(size)
int size;
{
	return akxm_cct_new((size_t)size,0);
}

/********************************************/
/*                                          */
/********************************************/
void akxm_cct_mem_free(tdtCONSTCT *conct)
{
	return akxm_cct_free(conct);
}

/********************************************/
/*                                          */
/********************************************/
char *akxm_cct_malloc(conct,len)
tdtCONSTCT *conct;
int len;
{
	return akxm_cct_mem_alloc(conct,(size_t)len);
}

/********************************************/
/*                                          */
/********************************************/
int akxm_cct_mem_used(tdtCONSTCT *conct)
{
	return _cct_used(conct,0);
}

/********************************************/
/*                                          */
/********************************************/
int akxm_cct_reset(tdtCONSTCT *conct)
{
	return _cct_used(conct,1);
}

/****************************************/
/*										*/
/****************************************/
int akxm_alloc_ctl_is(pAC)
tdtAllocCtl *pAC;
{
	int ret;

	ret = 0;
	if (pAC) {
		if (pAC->ac_malloc) {
			ret = 1;
			if (pAC->ac_constct) ret++;
		}
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int akxm_alloc_ctl_pp(pAC,alen,pp)
tdtAllocCtl *pAC;
int alen;
char **pp;
{
	char *(*m_alloc)();
	tdtCONSTCT *pConstCt;
	char *p;
	int ret;

	ret = akxm_alloc_ctl_is(pAC);
	p = NULL;
	if (ret) {
		m_alloc = pAC->ac_malloc;
		if (ret == 2) p = m_alloc(pAC->ac_constct,alen);
		else p = m_alloc(alen);
	}
	if (pp) *pp = p;
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int akxm_malloc_ctl_pp(pAC,alen,pp)
tdtAllocCtl *pAC;
int alen;
char **pp;
{
	int ret;
	char *p;

	if (!(ret=akxm_alloc_ctl_pp(pAC,alen,pp))) {
		if (pp) *pp = Malloc(alen);
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
char *akxm_malloc_ctl(pAC,alen)
tdtAllocCtl *pAC;
int alen;
{
	char *p;

	akxm_malloc_ctl_pp(pAC,alen,&p);
	return p;
}

/****************************************/
/*										*/
/****************************************/
int akxm_malloc_constct_pp(m_alloc,pConstCt,alen,pp)
char *(*m_alloc)();
tdtCONSTCT *pConstCt;
int alen;
char **pp;
{
	int ret;
	char *p;

	ret = 0;
	if (m_alloc) {
		ret = 1;
		if (pConstCt) {
			p = m_alloc(pConstCt,alen);
			ret++;
		}
		else p = m_alloc(alen);
	}
	else p = Malloc(alen);
	if (pp) *pp = p;
	return ret;
}

/****************************************/
/*										*/
/****************************************/
char *akxm_malloc_constct(m_alloc,pConstCt,alen)
char *(*m_alloc)();
tdtCONSTCT *pConstCt;
int alen;
{
	char *p;

	akxm_malloc_constct_pp(m_alloc,pConstCt,alen,&p);
	return p;
}
