static    char    sccsid[]="%Z% %M% %I% %E% %U%";
/************************************************/
/*												*/
/*	akxafile.c									*/
/*												*/
/*		coded by A.Kobayashi 2023/01/05			*/
/*												*/
/************************************************/
#include "akxcommon.h"

static tdtM_FILE *m_file=NULL;
static tdtM_FILE _m_file[AKX_MFILE_FIXED_MAX_NO+1]=
{{'M','F',0,NULL,"stdin",NULL,0},{'M','F',1,NULL,"stdout",NULL,1}
,{'M','F',2,NULL,"stderr",NULL,1},{'M','F',3,NULL,"heredoc",NULL,0}};
static int gNextM_FILE=0;
static XHASHB *xha;
static MCAT mcat;

static int _m_file_set_mfp(M_FILE *rmfp,FILE *fp,char *name,char *mode);

M_FILE *m_stdin,*m_stdout,*m_stderr,*m_heredoc;

/****************************************/
/*										*/
/****************************************/
static int _akxa_file_new()
{
	long ih;

/*	memset(&_m_file[3],0,sizeof(_m_file)-sizeof(tdtM_FILE)*3);	*/
	m_file = _m_file;
	m_file[0].m_fp = stdin;
	m_file[1].m_fp = stdout;
	m_file[2].m_fp = stderr;
	m_file[3].m_fp = stdin;
	m_stdin  = m_file;
	m_stdout = m_file + 1;
	m_stderr = m_file + 2;
	m_heredoc = m_file + 3;
	m_heredoc->m_mcat = &mcat;
	memset(&mcat,0,sizeof(MCAT));
/*	gNextM_FILE = 3;	*/
/*	xha = akxs_xhash_new2(sizeof(FILE *),AKX_MFP_SETSIZE,0,sizeof(M_FILE));	*/
	xha = akxs_xhash_new2(0,AKX_MFP_SETSIZE,0,sizeof(M_FILE));
#if 0
/*	xha->xha_xhix = 1;	*/
	ih = akxs_xhash2(xha,'S',&stdin,m_file);
	ih = akxs_xhash2(xha,'R',&stdin,&m_stdin);
/*	xha->xha_xhix = 2;	*/
	ih = akxs_xhash2(xha,'S',&stdout,m_file+1);
	ih = akxs_xhash2(xha,'R',&stdout,&m_stdout);
/*	xha->xha_xhix = 3;	*/
	ih = akxs_xhash2(xha,'S',&stderr,m_file+2);
	ih = akxs_xhash2(xha,'R',&stderr,&m_stderr);
#endif
/*
printf("_akxa_file_new: fd=%d m_stdin =%08x\n",m_stdin->m_fd,m_stdin);
printf("_akxa_file_new: fd=%d m_stdout=%08x\n",m_stdout->m_fd,m_stdout);
printf("_akxa_file_new: fd=%d m_stderr=%08x\n",m_stderr->m_fd,m_stderr);
*/
	return 0;
}

/****************************************/
/*										*/
/****************************************/
static M_FILE *_m_file_open(FILE *fp,char *name,char *mode)
{
	int i,k;
	long ih,fp_n;
	char c,buf[270],*p;
	M_FILE *rmfp,*mfp,tfp;

	rmfp = NULL;
	if (!m_file) _akxa_file_new();
	fp_n = htonl((long)fp);
	k = akxcxtoc(&fp_n,sizeof(FILE *),buf);
	buf[k] = '.';
	memnzcpy(buf+k+1,name,strlen(name),sizeof(buf));
#if 1
	if ((ih=akxs_xhash2(xha,'S',buf,m_file+AKX_MFILE_FIXED_MAX_NO)) > 0) {
/*
printf("_m_file_open:S ih=%d\n",ih);
*/
	/*	xha->xha_xhix = ih;
		ih = akxs_xhash2(xha,'K',&fp,&rmfp);	*/
	/*	ih = akxs_xhash2(xha,'R',&fp,&rmfp);	*/
		ih = akxs_xhash2(xha,'R',buf,&rmfp);
/*
printf("_m_file_open:R ih=%d rmfp=%08x\n",ih,rmfp);
*/
		rmfp->m_fd = ih + AKX_MFILE_FIXED_MAX_NO;
		_m_file_set_mfp(rmfp,fp,buf,mode);
	}
#else
	i = gNextM_FILE;
	for (k=0;k<AKX_FP_SETSIZE;k++,i++) {
		if (i >= AKX_FP_SETSIZE) {
			i = 0;
			mfp = m_file;
		}
		mfp = m_file + i;
		if (!mfp->m_fp) {
			mfp->m_fd = i;
			rmfp = mfp;
			break;
		}
	}
	gNextM_FILE = i + 1;
#endif
	return rmfp;
}

/****************************************/
/*										*/
/****************************************/
static int _m_file_set_mfp(M_FILE *rmfp,FILE *fp,char *name,char *mode)
{
	int m;
	char c;
/*
printf("_m_file_set_mfp: rmfp=%08x fp=%08x name=[%s] mode=[%s]\n",rmfp,fp,name,mode);
*/
	rmfp->m_id[0] = 'M';
	rmfp->m_id[1] = 'F';
	rmfp->m_fp = fp;
	rmfp->m_name = Strdup(name);
	rmfp->m_mcat = NULL;
	if (mode) {
		m = 0;
		if (c = *mode++) {
			if (c == 'r') ;
			else if (c == 'w') m += 1;
			else if (c == 'a') m += 2;
			if (c = *mode++) {
				if (c == 'b') m += 0x10;
				else if (c == '+') m += 0x20;
				if (c = *mode++) {
					if (c == 'b') m += 0x10;
					else if (c == '+') m += 0x20;
				}
			}
		}
		rmfp->m_flag = m;
	}
/*
printf("_m_file_set_mfp: rmfp->m_flag=%08x\n",rmfp->m_flag);
*/
	return 0;
}

/****************************************/
/*										*/
/****************************************/
static int _m_file_close(M_FILE *mfp)
{
	int i,ret;
	long ih;
	M_FILE *rmfp;

	ret = 0;
	if (mfp) {
		i = mfp->m_fd;
/*
printf("_m_file_close i=%d\n",i);
*/
		if (i > AKX_MFILE_FIXED_MAX_NO) {
			if (mfp->m_fp) {
				ih = akxs_xhash2(xha,'D',mfp->m_name,&rmfp);
/*
printf("_m_file_close ih=%d\n",ih);
*/
				mfp->m_fp = NULL;
				mfp->m_mcat = NULL;
				mfp->m_flag = 0;
				Free(mfp->m_name);
				mfp->m_name = NULL;
			}
			else ret = -5;
		}
	}
	else ret = -1;
/*
printf("_m_file_close ret=%d\n",ret);
*/
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int m_file_init()
{
	return _akxa_file_new();
}

/****************************************/
/*										*/
/****************************************/
M_FILE *m_fopen(char *name,char *mode)
{
	FILE *fp;
	M_FILE *mfp;

	if (!name || !mode) return NULL;
#if 1
	if (fp = fopen(name,mode)) {
		mfp = _m_file_open(fp,name,mode);
	}
	else
		mfp = NULL;
#else
	mfp = _m_file_open();
	if (mfp) {
		if (fp = fopen(name,mode))
			_m_file_set_mfp(mfp,fp,name,mode);
		else
			mfp = NULL;
	}
#endif
	return mfp;
}

/****************************************/
/*										*/
/****************************************/
int m_file_valid(M_FILE *mfp)
{
	int ret,i;
	long ih;
	FILE *fp;
	M_FILE *rmfp;

	ret = 0;
	if (mfp) {
		if (!m_file) ret = -2;
		else if (mfp->m_id[0]=='M' && mfp->m_id[1]=='F') {
			if (fp = mfp->m_fp) {
				if ((i=mfp->m_fd)>=0 && i<=AKX_MFILE_FIXED_MAX_NO) {
					rmfp = m_file + i;
					if (mfp->m_fp != rmfp->m_fp) ret = -4;
				}
				else {
					rmfp = NULL;
				/*	ih = akxs_xhash2(xha,'R',&fp,&rmfp);	*/
					ih = akxs_xhash2(xha,'R',mfp->m_name,&rmfp);
					if (ih<=0 || mfp!=rmfp) ret = -4;
				}
			}
			else ret = -3;
		}
		else ret = -2;
	}
	else ret = -1;
/*
printf("m_file_valid ret=%d\n",ret);
*/
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int m_fclose(M_FILE *mfp)
{
	int ret;
/*
printf("m_fclose:Enter mfp=%08x\n",mfp);
*/
	if ((ret=m_file_valid(mfp)) >= 0) {
/*
printf("m_fclose: m_name=[%s] m_mcat=%08x\n",mfp->m_name,mfp->m_mcat);
*/
		if (!mfp->m_mcat) fclose(mfp->m_fp);
		_m_file_close(mfp);
		ret = 0;
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
M_FILE *m_popen(char *name,char *mode)
{
	FILE *fp;
	M_FILE *mfp;

	if (!name || !mode) return NULL;

#if 1
	if (fp = popen(name,mode)) {
		mfp = _m_file_open(fp,name,mode);
	}
	else
		mfp = NULL;
#else
	mfp = _m_file_open();
	if (mfp) {
		if (fp = popen(name,mode))
			_m_file_set_mfp(mfp,fp,name,mode);
		else
			mfp = NULL;
	}
#endif
	return mfp;
}

/****************************************/
/*										*/
/****************************************/
int m_pclose(M_FILE *mfp)
{
	int ret;

	if ((ret=m_file_valid(mfp)) >= 0) {
		pclose(mfp->m_fp);
		_m_file_close(mfp);
		ret = 0;
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
M_FILE *m_opendir(char *name)
{
	DIR *dp;
	M_FILE *mfp;

	if (!name) return NULL;

#if 1
	if (dp = opendir(name)) {
		mfp = _m_file_open((FILE *)dp,name,NULL);
	}
	else
		mfp = NULL;
#else
	mfp = _m_file_open();
	if (mfp) {
		if (dp = opendir(name))
			_m_file_set_mfp(mfp,(FILE *)dp,name,NULL);
		else
			mfp = NULL;
	}
#endif
	return mfp;
}

/****************************************/
/*										*/
/****************************************/
int m_closedir(M_FILE *mfp)
{
	int ret;

	if ((ret=m_file_valid(mfp)) >= 0) {
		closedir((DIR *)mfp->m_fp);
		_m_file_close(mfp);
		ret = 0;
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int m_fread(char *p1,int n,int size,M_FILE *mfp)
{
	int ret;

	if ((ret=m_file_valid(mfp)) >= 0) {
		ret = fread(p1,n,size,mfp->m_fp);
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int m_fwrite(char *p2,int len2,int n,M_FILE *mfp)
{
	int ret;

	if ((ret=m_file_valid(mfp)) >= 0)
		ret = fwrite(p2,len2,n,mfp->m_fp);
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int m_fileno(M_FILE *mfp)
{
	int ret;

	if ((ret=m_file_valid(mfp)) >= 0)
		ret = fileno(mfp->m_fp);
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int m_ferror(M_FILE *mfp)
{
	int ret;

	if ((ret=m_file_valid(mfp)) >= 0) {
		if (mfp->m_flag & AKX_MFILE_FLAG_HDOC) ret = 0;
		else ret = ferror(mfp->m_fp);
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
int m_fflush(M_FILE *mfp)
{
	int ret;

	if ((ret=m_file_valid(mfp)) >= 0) {
		ret = fflush(mfp->m_fp);
	}
	return ret;
}

/****************************************/
/*										*/
/****************************************/
M_FILE *m_heredoc_open(char *name)
{
	FILE *fp;
	M_FILE *mfp;
/*
printf("m_heredoc_open: name=[%s]\n",name);
*/
	if (name) {
		fp = stdin;
		mfp = _m_file_open(fp,name,"r");
		mfp->m_mcat = &mcat;
		mfp->m_flag = AKX_MFILE_FLAG_HDOC;
	}
	else mfp = NULL;
	return mfp;
}
