static    char    sccsid[]="%Z% %M% %I% %E% %U%";
/************************************************
 *	akxsQue.c
 *
 *		coded   by A.Kobayashi 96.2.8
 *		updated by A.Kobayashi 97.5.13
 *
 *
 ************************************************/
#include "akxcommon.h"

#define DEBUGP(x)

#ifdef QUE_TEST_MAIN
#ifdef Malloc
#undef Malloc
#endif
#ifdef Free
#undef Free
#endif
#define Malloc	malloc
#define Free	free
int main()
{
	tdtQueCtl *pQueCtl;
	char *cp;
	int rc,i;

	pQueCtl = akxs_que_init(0,0);
	printf("set 1:rc=%d\n",akxs_que_put(pQueCtl,QUE_PUT,1));
	printf("set 2:rc=%d\n",akxs_que_put(pQueCtl,QUE_PUT,2));
	printf("set 3:rc=%d\n",akxs_que_put(pQueCtl,QUE_PUT,3));
	printf("set 4:rc=%d\n",akxs_que_put(pQueCtl,QUE_PUT,4));

	rc=akxs_que_move(pQueCtl,QUE_TOP_PREV,NULL);
	printf("MOVE_TOPP:rc=%d\n",rc);
	for (i=1;;i++) {
		rc=akxs_que_peek(pQueCtl,QUE_NEXT,&cp);
		printf("PEEK_NEXT %d:rc=%d cp=%08x\n",i,rc,cp);
		if (rc<1) break;
	}

	rc=akxs_que_move(pQueCtl,QUE_BOT_NEXT,NULL);
	printf("MOVE_BOTN:rc=%d\n",rc);
	for (i=1;;i++) {
		rc=akxs_que_peek(pQueCtl,QUE_PREV,&cp);
		printf("PEEK_PREV %d:rc=%d cp=%08x\n",i,rc,cp);
		if (rc<1) break;
	}

	for (i=1;;i++) {
		rc=akxs_que_get(pQueCtl,QUE_GET,&cp);
		printf("get %d:rc=%d cp=%08x\n",i,rc,cp);
		if (rc<1) break;
	}

	rc=akxs_que_free(pQueCtl);
	printf("Free:rc=%d\n",rc);

	exit(0);
}
#endif /* QUE_TEST_MAIN */

#define AKX_CHAIN_END	((tdtQueChain *)-1)

static tdtQueChain *_get_free(pCt)
tdtQueCtl *pCt;
{
	tdtQueChain *pn;

	if (!pCt) return NULL;
	
	pn = pCt->qct_fre;
	if (pn) {
DEBUGP(printf("_get_free:not null pn = %08x\n",pn);)
		pCt->qct_fre = pn->qc_next;
	}
	else {
		pn = (tdtQueChain *)Malloc(sizeof(tdtQueChain));
DEBUGP(printf("_get_free:new pn = %08x\n",pn);)
	}
	return pn;
}

static int _put_free(pCt,pt)
tdtQueCtl *pCt;
tdtQueChain *pt;
{
	tdtQueChain *pn;

	if (!pCt) return -1;
DEBUGP(printf("_put_free:pt = %08x pQueFree = %08x\n",pt,pCt->qct_fre);)
	pt->qc_next = pCt->qct_fre;
	pCt->qct_fre = pt;
	return 0;
}

static int _que_del_cur(pCt)
tdtQueCtl *pCt;
{
	tdtQueChain *pCur;
	tdtQueChain *pN, *pP;

	if (!pCt) return -1;
	pCur = pCt->qct_cur;
	if (pCur==AKX_CHAIN_END || !pCur) return 0;
	pP = pCur->qc_prev;
	pN = pCur->qc_next;
DEBUGP(printf("QueDel:pCur=%08x  pP=%08x  pN=%08x\n",pCur,pP,pN);)
	if (pN && pN!=AKX_CHAIN_END) {
		pN->qc_prev = pP;
DEBUGP(printf("QueDel: Prev=%08x\n",pN->qc_prev);)
	}
	else {
		pCt->qct_bot = pP;
	}
	if (pP) {
		pP->qc_next = pN;
DEBUGP(printf("QueDel: Next=%08x\n",pP->qc_next);)
	}
	else {
		if (pN == AKX_CHAIN_END) pN = NULL;
		pCt->qct_top = pN;
	}
	pCt->qct_cur = pN;
DEBUGP(printf("QueDel: Top =%08x  Bot =%08x\n",pCt->qct_top,pCt->qct_bot);)
	_put_free(pCt,pCur);
	pCt->qct_used--;
	return 1;
}

static int _que_add_cur(pCt)
tdtQueCtl *pCt;
{
	tdtQueChain *pCur;
	tdtQueChain *pn, *pN, *pP;

	if (!pCt) return -1;
	pCur = pCt->qct_cur;
	if (pCur == AKX_CHAIN_END) pCur = pCt->qct_bot;
	if (!(pn = _get_free(pCt))) return -2;
DEBUGP(printf("QueAdd: pCur = %08x pn = %08x\n",pCur,pn);)
	if (pCur) {
		pP = pCur->qc_prev;
		pN = pCur->qc_next;
DEBUGP(printf("QueAdd: pP=%08x  pN=%08x\n",pP,pN);)
		if (pN && pN!=AKX_CHAIN_END) {
			pN->qc_prev = pn;
		}
		else {
			pCt->qct_bot = pn;
		}
		pn->qc_prev = pCur;
		pn->qc_next = pN;
		pCur->qc_next = pn;
	}
	else {
		pn->qc_prev = NULL;
		pn->qc_next = pN = pCt->qct_top;
		if (pN) {
			pN->qc_prev = pn;
		}
#ifndef NO_STOP
		else {
			pn->qc_next = AKX_CHAIN_END;
		}
#endif
		pCt->qct_top = pn;
		if (!pCt->qct_bot) pCt->qct_bot = pn;
	}
	pCt->qct_cur = pn;
DEBUGP(printf("QueAdd: Top =%08x  Bot =%08x\n",pCt->qct_top,pCt->qct_bot);)
DEBUGP(printf("QueAdd: Prev=%08x  Next=%08x\n",pn->qc_prev,pn->qc_next);)
	pCt->qct_used++;
	return 0;
}

tdtQueCtl *akxs_que_new(lBS,lRM)
int lBS,lRM;
{
	tdtQueCtl *pCt;
	tdtQueChain *p1,*p2;

	if (pCt = (tdtQueCtl *)Malloc(sizeof(tdtQueCtl))) {
		pCt->qct_bfsz = lBS;
		pCt->qct_max = lRM;
		pCt->qct_num = 0;
		pCt->qct_used = 0;
		pCt->qct_top = NULL;
		pCt->qct_bot = NULL;
		pCt->qct_cur = NULL;
		pCt->qct_fre = NULL;
	}
	return pCt;
}

tdtQueCtl *akxs_que_init(lBS,lRM)
int lBS,lRM;
{
	return akxs_que_new(lBS,lRM);
}

/************************************
	rc > 0	キューあり
	rc = 0	キューなし
	rc < 0	Error
*************************************/
int akxs_que_ctl(pCt,iOpt,cppBuff)
tdtQueCtl *pCt;
int iOpt;
char **cppBuff;
{
	int iRc=0;
	char *cp;
	tdtQueChain *pt,*pb,*pn;

DEBUGP(printf("QueCtl: pCt=%08x iOpt=%d cppBuff=%08x\n",pCt,iOpt,cppBuff);)
	if (!pCt) return -1;
	if (iOpt==QUE_PUT_CUR) {
		if (cppBuff) {
			iRc = _que_add_cur(pCt);
			if (!iRc) {
				if (pt=pCt->qct_cur) {
					iRc = 1;
					pt->qc_buf = *cppBuff;
DEBUGP(printf("QueCtl:PUT: pt=%08x\n",pt);)
				}
			}
		}
		else iRc = -2;
	}
	else if (iOpt==QUE_GET_CUR || iOpt==QUE_PEEK_CUR) {
		pt=pCt->qct_cur;
DEBUGP(printf("QueCtl:GET/PEEK pt=%08x\n",pt);)
		if (pt && pt!=AKX_CHAIN_END) {
			iRc = 1;
			if (cppBuff) {
				*cppBuff = pt->qc_buf;
			}
			if (iOpt==QUE_GET_CUR) _que_del_cur(pCt);
		}
	}
	else {
		switch (iOpt) {
			case QUE_MOVE_TOP:
				pt=pCt->qct_top;
				break;
			case QUE_MOVE_BOT:
				pt=pCt->qct_bot;
				break;
#ifdef NO_STOP
			case QUE_MOVE_NEXT:
				if (pt=pCt->qct_cur) pt = pt->qc_next;
				else pt = pCt->qct_top;
				break;
			case QUE_MOVE_PREV:
				if (pt=pCt->qct_cur) pt = pt->qc_prev;
				else pt = pCt->qct_bot;
				break;
#else
			case QUE_MOVE_NEXT:
				pt = pCt->qct_cur;
				if (!pt) pt = pCt->qct_top;
				else if (pt != AKX_CHAIN_END) pt = pt->qc_next;
				break;
			case QUE_MOVE_PREV:
				pt = pCt->qct_cur;
				if (pt == AKX_CHAIN_END) pt = pCt->qct_bot;
				else if (pt) pt = pt->qc_prev;
				break;
#endif
			default:
				return -9;
		}
DEBUGP(printf("QueCtl:MOVE: pt=%08x\n",pt);)
		pCt->qct_cur = pt;
		if (pt && pt!=AKX_CHAIN_END) iRc = 1;
	}
	return iRc;
}

/************************************

	rc = 0	Ok
	rc < 0	Error
*************************************/
int akxs_que_put(pCt,iOpt,cpBuff)
tdtQueCtl *pCt;
int iOpt;
char *cpBuff;
{
	if (!pCt) return -1;
	switch (iOpt) {
		case QUE_PUT_BOT:
		case QUE_BOT:
		case QUE_DFLT:
			akxs_que_ctl(pCt,QUE_MOVE_BOT,NULL);
DEBUGP(printf("QuePut:Bot\n");)
			break;
		case QUE_PUT_TOP:
		case QUE_TOP:
			if (akxs_que_ctl(pCt,QUE_MOVE_TOP,NULL))
				akxs_que_ctl(pCt,QUE_MOVE_PREV,NULL);
DEBUGP(printf("QuePut:Top\n");)
			break;
		case QUE_PUT_CUR:
		case QUE_CUR:
DEBUGP(printf("QuePut:Cur\n");)
			break;
		default:
			return -9;
	}
	return akxs_que_ctl(pCt,QUE_PUT_CUR,&cpBuff);
}

/************************************

	rc > 0	キューあり
	rc = 0	キューなし
	rc < 0	Error
*************************************/
int akxs_que_get(pCt,iOpt,cppBuff)
tdtQueCtl *pCt;
int iOpt;
char **cppBuff;
{
	if (cppBuff) *cppBuff = NULL;
	if (!pCt) return -1;
	switch (iOpt) {
		case QUE_GET_TOP:
		case QUE_TOP:
		case QUE_DFLT:
			akxs_que_ctl(pCt,QUE_MOVE_TOP,NULL);
DEBUGP(printf("QueGet:Top\n");)
			break;
		case QUE_GET_BOT:
		case QUE_BOT:
			akxs_que_ctl(pCt,QUE_MOVE_BOT,NULL);
DEBUGP(printf("QueGet:Bot\n");)
			break;
		case QUE_GET_CUR:
		case QUE_CUR:
DEBUGP(printf("QueGet:Cur\n");)
			break;
		default:
			return -9;
	}

	return akxs_que_ctl(pCt,QUE_GET_CUR,cppBuff);
}

/************************************

	rc > 0	キューあり
	rc = 0	キューなし
	rc < 0	Error
*************************************/
int akxs_que_peek(pCt,iOpt,cppBuff)
tdtQueCtl *pCt;
int iOpt;
char **cppBuff;
{
	int iRc;

	if (cppBuff) *cppBuff = NULL;
	if (!pCt) return -1;
	switch (iOpt) {
		case QUE_PEEK_TOP:
		case QUE_TOP:
		case QUE_DFLT:
DEBUGP(printf("QuePeek:Top\n");)
			akxs_que_ctl(pCt,QUE_MOVE_TOP,NULL);
			break;
		case QUE_PEEK_BOT:
		case QUE_BOT:
DEBUGP(printf("QuePeek:Bot\n");)
			akxs_que_ctl(pCt,QUE_MOVE_BOT,NULL);
			break;
		case QUE_PEEK_CUR:
		case QUE_CUR:
DEBUGP(printf("QuePeek:Cur\n");)
			break;
		case QUE_AFT_NEXT:
			iOpt = QUE_PEEK_NEXT;
		case QUE_PEEK_NEXT:
DEBUGP(printf("QuePeek:Next\n");)
			break;
		case QUE_AFT_PREV:
			iOpt = QUE_PEEK_PREV;
		case QUE_PEEK_PREV:
DEBUGP(printf("QuePeek:Prev\n");)
			break;
		case QUE_MOVE_PEEK_NEXT:
		case QUE_NEXT:
DEBUGP(printf("QuePeek:Move_Next\n");)
			akxs_que_ctl(pCt,QUE_MOVE_NEXT,NULL);
			break;
		case QUE_MOVE_PEEK_PREV:
		case QUE_PREV:
DEBUGP(printf("QuePeek:Move_Prev\n");)
			akxs_que_ctl(pCt,QUE_MOVE_PREV,NULL);
			break;
		default:
			return -9;
	}

	iRc =  akxs_que_ctl(pCt,QUE_PEEK_CUR,cppBuff);
	if (iRc>0) {
		switch (iOpt) {
			case QUE_PEEK_NEXT:
				akxs_que_ctl(pCt,QUE_MOVE_NEXT,NULL);
				break;
			case QUE_PEEK_PREV:
				akxs_que_ctl(pCt,QUE_MOVE_PREV,NULL);
		}
	}
	return iRc;
}

/************************************

	rc > 0	キューあり
	rc = 0	キューなし
	rc < 0	Error
*************************************/
int akxs_que_move(pCt,iOpt)
tdtQueCtl *pCt;
int iOpt;
{
	int iRc, iOptw;

	if (!pCt) return -1;
	iOptw = iOpt;
	switch (iOpt) {
		case QUE_TOP:
			iOptw = QUE_MOVE_TOP;
		case QUE_MOVE_TOP:
DEBUGP(printf("QueMove:Top\n");)
			break;
		case QUE_BOT:
			iOptw = QUE_MOVE_BOT;
		case QUE_MOVE_BOT:
DEBUGP(printf("QueMove:Bot\n");)
			break;
		case QUE_NEXT:
		case QUE_DFLT:
			iOptw = QUE_MOVE_NEXT;
		case QUE_MOVE_NEXT:
DEBUGP(printf("QueMove:Next\n");)
			break;
		case QUE_PREV:
			iOptw = QUE_MOVE_PREV;
		case QUE_MOVE_PREV:
DEBUGP(printf("QueMove:Prev\n");)
			break;
		case QUE_TOP_PREV:
			iOpt = QUE_MOVE_TOPP;
		case QUE_MOVE_TOPP:
DEBUGP(printf("QueMove:Topp\n");)
			iOptw = QUE_MOVE_TOP;
			break;
		case QUE_BOT_NEXT:
			iOpt = QUE_MOVE_BOTN;
		case QUE_MOVE_BOTN:
DEBUGP(printf("QueMove:Botn\n");)
			iOptw = QUE_MOVE_BOT;
			break;
		default:
			return -9;
	}
	iRc =  akxs_que_ctl(pCt,iOptw,NULL);
	if (iRc>0) {
		switch (iOpt) {
			case QUE_MOVE_TOPP:
				iRc = akxs_que_ctl(pCt,QUE_MOVE_PREV,NULL);
				break;
			case QUE_MOVE_BOTN:
				iRc = akxs_que_ctl(pCt,QUE_MOVE_NEXT,NULL);
		}
	}
	return iRc;
}

int akxs_que_free(pCt)
tdtQueCtl *pCt;
{
	tdtQueChain *pw, *pn, *pp;

	if (!pCt) return -1;
	pw = pCt->qct_top;
	while (pw && pw!=AKX_CHAIN_END) {
		pn = pw->qc_next;
		Free(pw);
DEBUGP(printf("QueFree:Top p=%08x\n",pw);)
		pw = pn;
	}
	pCt->qct_top = NULL;
	pw = pCt->qct_fre;
	while (pw) {
		pn = pw->qc_next;
		Free(pw);
DEBUGP(printf("QueFree:Fre p=%08x\n",pw);)
		pw = pn;
	}
	pCt->qct_fre= NULL;
	Free(pCt);
	return 0;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxs_que_buf_free(pCt)
tdtQueCtl *pCt;
{
	char *addr;
	int  iRc;

	if (!pCt) return -1;

	while ((iRc=akxs_que_get(pCt,QUE_DFLT,&addr))>0) {
		if (addr) Free(addr);
	}
	if (iRc > 0) iRc = 0;
	return iRc;
}

/********************************************************/
/*                                                      */
/********************************************************/
int akxs_que_all_free(pCt)
tdtQueCtl *pCt;
{
	int iRc;

	if (!(iRc = akxs_que_buf_free(pCt))) iRc = akxs_que_free(pCt);

	return iRc;
}
