static char sccsid[]="%Z% %M% %I% %E% %U%";
/************************************************/
/*												*/
/*	get arg parameter list						*/
/*												*/
/*		coded  by A.Kobayashi   2010.05.27		*/
/*												*/
/************************************************/

#include "akxcommon.h"

/************************************************/
/*												*/
/************************************************/
int akxa_get_line(line,linemax,fp,opt)
char *line;
int	 linemax;
FILE *fp;
int	 opt;
{
	int opt1,opt2,c,c2,i,cw,lmax,opt_csv,quot,opt_csv_SLF;
	char *p;

	if (!fp || !line || linemax<2) return -2;

	lmax = linemax - 1;
	p = line;
	opt1 = opt & 0x01;	/* 1: CRLF=>LF, CR=>LF */
	opt2 = opt & 0x02;	/* 1:suppress LF */
	if (opt & 0x08) opt |= 0x04;
	opt_csv = opt & 0x04;	/* 1:for csv */
	if (opt_csv) opt_csv_SLF = opt & (0x08/* | 0x02*/);	/* 1:for csv suppress LF in quot */
	else opt_csv_SLF = 0;
	if (opt2 | opt_csv_SLF) opt1 = 1;
	if (!(opt1+opt2)) lmax--;
	c = EOF;
	quot = 0;
	i = 0;
	while (i<lmax && (c=getc(fp))!=EOF) {
		if (opt_csv) {
			if (c == '"') {
				if (quot) {
					c2 = getc(fp);
					if (c2 == quot) {
						if (i < lmax) {
							*p++ = c;
							i++;
						}
					}
					else {
						ungetc(c2,fp);
						quot = 0;
					}
				}
				else quot = c;
			}
		}
		cw = c;
		if (c == '\r') {
			c2 = getc(fp);
			if (opt1) {
				if (c2 != '\n') ungetc(c2,fp);
				cw = c = '\n';
			}
			else {
				if (c2 == '\n') {
					*p++ = c;
					*p++ = c2;
					i+=2;
					break;
				}
				else {
					cw = '\n';
					ungetc(c2,fp);
				}
			}
		}
		if (cw == '\n') {
			if (!opt2 && !(opt_csv_SLF && quot)) {
				*p++ = c;
				i++;
			}
			if (!(opt_csv && quot)) break;
		}
		else {
			*p++ = c;
			i++;
		}
	}
	*p = '\0';
	if (!i && c==EOF) i = -1;
/*
printf("akxa_get_line: i=%d line=[%s]\n",i,line);
*/
	return i;
}

/************************************************************************/
/* 関数名	| int akxa_read_line_opt()									*/
/* 引き数	| buf	: 読み込み領域へのポインタ							*/
/*			| size	: bufサイズ(バイト)									*/
/*			| fp	: 読み込みファイルポインタ							*/
/*			| opt	: 0x01 	1: CRLF=>LF, CR=>LF							*/
/*			| 		: 0x02 	1: suppress LF, CR							*/
/* 返却値	| <0	読み込み終了										*/
/*			| >=0	読み込み長(バイト)									*/
/* 処理概要 |１行の長さが(size-1)byte以上の場合それ以上の文字列は		*/
/*			|読みとばす。最初の(size-1)byteをbufに格納する。NULL終端。	*/
/************************************************************************/
int akxa_read_line_opt(buf, size, fp, opt)
char	*buf;
int		size;
FILE	*fp;
int		opt;
{
	int		len,lw,opt1,opt2,optw;
	char	work[AKX_RECORD_BUFSIZE],c,c1,c2,wk[3],lwk;

	if (opt2 = opt & 0x02)	/* 2:suppress LF */
		 opt |= 0x01;
	opt1 = opt & 0x01;	/* 1: CRLF=>LF, CR=>LF */
	optw = opt & ~0x02;
/*
	if ((opt & (0x04 | 0x02)) == (0x04 | 0x02)) optw |= 0x08;
*/
	if ((len=akxa_get_line(buf,size,fp,optw)) >= 0) {
		if (!len) len = -1;
		else {
			if ((c=buf[len-1])!='\n' && c!='\r') {
				/* size byte以上の文字列を読みとばす */
				do {
					if ((lw=akxa_get_line(work,sizeof(work),fp,optw)) < 0) break;
				} while ((c2=work[lw-1])!='\n' && c2!='\r');
				if (lw>0 && !opt2) {
					if (opt1) {
						if (lw>0 && (c2=work[lw-1])=='\n') buf[len-1] = c2;
					}
					else {
						lwk=0;
						if (lw>1 && (c1=work[lw-2]) == '\r') wk[lwk++] = c1;
						if (lw>0 && ((c1=work[lw-1])=='\r' || c1=='\n')) wk[lwk++] = c1;
						wk[lwk]='\0';
						if (lwk>0) {
							len = X_MAX(len-lwk,size-1-lwk);
							strcpy(buf+len,wk);
							len += lwk;
						}
					}
				}
			}
			else if (opt2) {
				buf[--len] = '\0';
			}
		}
	}
	return len;
}

/************************************************************************/
/* 関数名	| int akxa_read_line()										*/
/* 引き数	| buf	: 読み込み領域へのポインタ							*/
/*			| size	: bufサイズ(バイト)									*/
/*			| fp	: 読み込みファイルポインタ							*/
/* 返却値	| =0	読み込み終了										*/
/*			| >0	読み込み長(バイト)									*/
/* 処理概要 |１行の長さが(size-1)byte以上の場合それ以上の文字列は		*/
/*			|読みとばす。最初の(size-1)byteをbufに格納する。NULL終端。	*/
/*			|改行コード(LF,CR)は削除する。								*/
/************************************************************************/
int akxa_read_line(buf, size, fp)
char	*buf;
int		size;
FILE	*fp;
{
	int len;

	if ((len=akxa_read_line_opt(buf, size, fp, 1)) < 0) len = 0;
	return len;
}

/********************************************************/
/*	pwd == NULL: wdに書き込まない						*/
/*	lmax >  0  : lmaxをチェックしながらwdに書き込む		*/
/*	lmax == 0  : wdに書き込まず、lmaxもチェックしない	*/
/*	lmax <  0  : wd書き込み時にlmaxをチェックしない		*/
/********************************************************/
int akxwdmax_chk(pwd,pattr,lmax,l,ch)
char **pwd;
uchar *pattr;
int  lmax,l;
char ch;
{
	char *wd=*pwd;

	if (lmax>0) {
		if (l<lmax-1) {
			if (wd) *wd++ = ch;
			l++;
		}
		else pattr[1] = 1;
	}
	else {
		if (lmax<0 && wd) *wd++ = ch;
		l++;
	}
	*pwd = wd;
	return l;
}

/************************************************/
/*												*/
/************************************************/
int akxwdmax_chk2(pwd,pattr,lmax,l,ch1,ch2)
char **pwd;
uchar *pattr;
int  lmax,l;
char ch1,ch2;
{
	char *wd=*pwd;

	if (lmax>0) {
		if (l<lmax-2) {
			if (wd) {
				*wd++ = ch1;
				*wd++ = ch2;
			}
			l += 2;
		}
		else pattr[1] = 1;
	}
	else {
		if (lmax<0 && wd) {
			*wd++ = ch1;
			*wd++ = ch2;
		}
		l += 2;
	}
	*pwd = wd;
	return l;
}

/************************************************/
/*												*/
/************************************************/
int akxwdmax_chkm(pwd,pattr,lmax,l,s,m)
char **pwd;
uchar *pattr,*s;
int  lmax,l,m;
{
	char *wd=*pwd;

	if (lmax>0) {
		if (l<lmax-m) {
			if (wd) {
				memcpy(wd,s,m);
				wd += m;
			}
			l += m;
		}
		else pattr[1] = 1;
	}
	else {
		if (lmax<0 && wd) {
			memcpy(wd,s,m);
			wd += m;
		}
		l += m;
	}
	*pwd = wd;
	return l;
}

/************************************************/
/*												*/
/************************************************/
int akxtgetwnspl(p, len, sspl, opt)
char   *p;
int     len;
SSPL_S *sspl;
int     opt;
{
	char *wd,*ps,*ps1,sep[16];
	uchar *pattr;
	int  *ppos;
	int  lmax;
	int  opt1,opt2,opt3,opt5,opt20,opt_q,opt_sep,opt_not_csv;
	char ch, quot, cw, csep, QUOT1, QUOT2;
	int  l = 0, pos, lmax1, m;

	wd = sspl->wd;
	ppos = &(sspl->sp);
	pattr = &(sspl->attr[0]);
	lmax = sspl->wdmax;
	pattr[0] = 0;
	pattr[1] = 0;

	lmax1 = lmax - 1;
	pos = *ppos;
	p += pos;

	while((pos<len)&&(((ch=*p)=='\n')||(ch==' ')||(ch=='\t')||(ch=='\r'))) {
		p++;
		pos++;
	}
	if (pos>=len || !ch) {
		if (wd && (lmax != 0)) *wd = '\0';
		*ppos = pos;
		return -1;
	}

	if (opt_not_csv = !(opt & AKX_ARGV_FOR_CSV)) {
 		QUOT1 = '\'';
		QUOT2 = '"';
 	}
	else {
 		QUOT1 = QUOT2 = '"';
	}
	opt20 = opt & 0x20;	/* IPV6 */
	if ((pos<len) && (ch==QUOT1 || ch==QUOT2 || (opt20 && ch=='['))) {
		opt_q = opt & AKX_ARGV_NOT_CUT_QUOT;
		if (ch=='[') {
			*pattr = 6;
			quot = ']';
		}
		else {
			if (ch==QUOT2) *pattr = 6;
			else           *pattr = 5;
			quot = ch;
			if (opt_q) l = akxwdmax_chk(&wd,pattr,lmax,l,ch);
		}
		p++;
		pos++;
		while((pos<len)&&((ch = *p)!='\0')) {
			if ((pos+1<len)&&(m=akxqiskanji(p))) {
				l = akxwdmax_chkm(&wd,pattr,lmax,l,p,m);
				p+=m;
				pos+=m;
			}
			else {
				if (opt_not_csv && ((ch=='\n')||(ch=='\r'))) break;
				if (ch==quot) {
					if (opt_q) l = akxwdmax_chk(&wd,pattr,lmax,l,ch);
					p++;
					pos++;
					if ((pos >= len) || (*p != quot)) break;
				}
				l = akxwdmax_chk(&wd,pattr,lmax,l,ch);
				p++;
				pos++;
			}
		}
		if (wd && (lmax != 0)) *wd = '\0';
		*ppos = pos;
		return(l);
	}
	ps = sep;
	*ps++ = '\n';
	*ps++ = '\r';
	opt1 = opt & 0x01;	/* # */
	opt2 = opt & 0x02;	/* = */
	opt3 = opt & 0x04;	/* , */
	opt5 = opt & 0x10;	/* : or := */
	if (opt_sep = opt & AKX_ARGV_USE_ATTR2_SEP) {
		if (!(csep = pattr[2])) opt_sep = 0;
	}
	if (opt_sep) {
		*ps++ = csep;
		ps1 = ps;
	}
	else {
		*ps++ = ' ';
		*ps++ = '\t';
		*ps++ = QUOT1;
		*ps++ = QUOT2;
		if (opt20) *ps++ = '[';
		if (opt1) *ps++ = '#';
		if (opt3) *ps++ = ',';
		ps1 = ps;
		if (opt2) *ps++ = '=';
		if (opt5) *ps++ = ':';
	}
	*ps = '\0';
	if ((opt1 && ch=='#')||(opt2 && ch=='=')||(opt5 && ch==':')||
	    (opt3 && ch==',')||(opt_sep && ch==csep)) {
		l = akxwdmax_chk(&wd,pattr,lmax,l,ch);
		*pattr = ch;
		if (wd && (lmax != 0)) *wd = '\0';
		if (ch==':' && (pos<len) && *(p+1)=='=') {
			l = akxwdmax_chk(&wd,pattr,lmax,l,'=');
			if (wd && (lmax != 0)) *wd = '\0';
			pos++;
		}
		*ppos = pos + 1;
		return l;
	}
	if (opt & 0x08) *ps1 = '\0';
	while((pos<len)&&((ch=*p)!='\0')) {
		if ((pos+1<len)&&(m=akxqiskanji(p))) {
			l = akxwdmax_chkm(&wd,pattr,lmax,l,p,m);
			p+=m;
			pos+=m;
		}
		else {
			if ((pos+1==len) && akxqiskanji1(*p)) {
				pos++;
				break;
			}
			ps = sep;
			while (csep = *ps++) {
				if (ch == csep) break;
			}
			if (csep) break;
			l = akxwdmax_chk(&wd,pattr,lmax,l,ch);
			p++;
			pos++;
		}
		*pattr = 1;
	}
	if (wd && (lmax != 0)) *wd = '\0';
	*ppos = pos;
	return l;
}

/************************************************/
/*												*/
/************************************************/
int akxtgetwn3(p, len, ppos, wd, lmax, pattr, opt)
char *p, *wd;
int   *ppos;
uchar *pattr;
int   len,lmax, opt;
{
	SSPL_S sspl;
	int ret;

	sspl.sp = *ppos;
	sspl.wd = wd;
	sspl.wdmax = lmax;
	memcpy(sspl.attr+2,pattr+2,2);
	ret =  akxtgetwnspl(p, len, &sspl, opt);
	memcpy(pattr,sspl.attr,4);
	*ppos  = sspl.sp;
	return ret;
}

/************************************************/
/*												*/
/************************************************/
int akxtgetw3(p, ppos, wd, lmax, pattr, opt)
char *p, *wd;
int	*ppos;
uchar *pattr;
int	lmax, opt;
{
	return akxtgetwn3(p, INT_MAX, ppos, wd, lmax, pattr, opt);
}

/************************************************/
/*												*/
/************************************************/
int akxtgetw(p, ppos, wd, lmax)
char	*p, *wd;
int	*ppos;
int	lmax;
{
	int   rc;
	uchar attr[4];

	if (lmax <= 0) return -2;
	return akxtgetwn3(p, INT_MAX, ppos, wd, lmax, attr, 0);
}

/************************************************/
/*												*/
/************************************************/
int akxtgetargvns2(buf,buflen,argv,maxargcs,parm,len,sep,opt)
char *buf,**argv,*parm,*sep;
int  buflen,maxargcs,len, opt;
{
	char *wd;
	int   argc=0,lw,pos,opt1,opt2,opt3,opt7,opt8,skip,maxargc,opt_sep;
	uchar attr[4], battr, csep;
/*
printf("akxtgetargvns2: buf=[%s] buflen=%d\n",buf,buflen);
*/
	maxargc = maxargcs;
	if (maxargc < 0) maxargc = -maxargc;
	if (len<0) return -2;
	else if (!maxargc) return 0;
	else if (len <= 1 || !buf || !parm) return -1;
	opt1 = opt & 0x01;	/* # */
#if 1
	if (sep) csep = (uchar)*sep;
	else csep = '\0';
	attr[2] = csep;
	if (csep) {
		opt &= ~(0x12 | 0x04 | 0x40 | 0x80);
		opt |= AKX_ARGV_USE_ATTR2_SEP;
		battr = csep;
	}
	else {
		opt &= ~AKX_ARGV_USE_ATTR2_SEP;
		battr = '\0';
	}
	opt2 = opt & 0x12;	/* = */
	opt3 = opt & 0x04;	/* , */
	opt7 = opt & 0x40;	/*  */
	opt8 = opt & 0x80;	/* ,=, */
	opt_sep = opt & AKX_ARGV_USE_ATTR2_SEP;
	if (opt3) battr = ',';
#else
	opt2 = opt & 0x12;	/* = */
	opt3 = opt & 0x04;	/* , */
	opt7 = opt & 0x40;	/*  */
	opt8 = opt & 0x80;	/* ,=, */
	if (opt3) battr = ',';
	else battr = '\0';
	if (sep) attr[2] = (uchar)*sep;
	else attr[2] = '\0';
	if (opt_sep = opt & AKX_ARGV_USE_ATTR2_SEP) {
		if (csep = attr[2]) {
			/*if (!battr) */battr = csep;
			opt2 = opt3 = opt7 = opt8 = 0;
		}
		else opt_sep = 0;
	}
#endif
/*
printf("akxtgetargvns2: battr=[%c] opt_sep=%08x csep=[%c]\n",battr,opt_sep,csep);
*/
	pos = 0;
	wd = parm;
	for (;;) {
		if (argv && maxargcs>0 && maxargc<=0) break;
		lw = akxtgetwn3(buf,buflen,&pos,wd,len,attr,opt);
		if (lw == -1 || (opt1 && attr[0] == '#')) {
			*wd = '\0';
			if (argv) {
				while (maxargc-- > 0) *argv++ = wd;
			}
			break;
		}
		if (attr[1]) return -10;
		skip = 0;
/*
printf("akxtgetargvns2: attr[0]=[%c] attr[1]=%02x\n",attr[0],attr[1]);
*/
		if (opt3 && attr[0]==',') {
			if (opt2 && !opt8) {
				opt &= ~opt2;
				opt2 = 0;
			}
#if 1
			if (battr==',') {
#else
			if (battr==',' || (opt_sep && battr == csep)) {
#endif
				lw = 0;
				*wd = '\0';
			}
			else skip = 1;
		}
		else if (opt_sep && attr[0]==csep) {
#if 1
			if (battr==csep) {
#else
			if (battr==csep || (opt3 && battr==',')) {
#endif
				lw = 0;
				*wd = '\0';
			}
			else skip = 1;
		}
		battr = attr[0];
		if (!skip) {
			if (opt2) {
				if (argc==0 && !opt7 && (attr[0]=='=' || attr[0]==':')) {
					*wd = '\0';
					lw = 0;
				}
				else if (argc == 1) {
					opt &= ~opt2;
					opt2 = 0;
					if ((attr[0]=='=' || attr[0]==':')) continue;
				}
			}
			if (argv && maxargc>0) {
				*argv++ = wd;
				maxargc--;
			}
			if (lw >= 0) {
				argc++;
				len -= lw;
				len--;
				if ((len<=0 && !argv) || (len<=0 && maxargc>0)) return -10;
				if (opt_sep && attr[0]!=5 && attr[0]!=6) lw = akxtsapb(1,wd,lw);
														/* 0-->1 2017.11.03 */
				wd += ++lw;
			}
			if (opt2) opt |= 0x08;	/* ２ワード目が、=,:,:=で始まらないときは
			                    ワードの途中の=,:,:=で区切られないようにする */
		}
	}
	return argc;
}

/************************************************/
/*												*/
/************************************************/
int akxtgetargvn2(buf,buflen,argv,maxargcs,parm,len,opt)
char *buf,**argv,*parm;
int  buflen,maxargcs,len, opt;
{
	return akxtgetargvns2(buf,buflen,argv,maxargcs,parm,len,NULL,opt);
}

/************************************************/
/*												*/
/************************************************/
int akxtgetargv2(buf,argv,maxargcs,parm,len,opt)
char *buf,**argv,*parm;
int  maxargcs,len, opt;
{
	return akxtgetargvns2(buf,INT_MAX,argv,maxargcs,parm,len,NULL,opt);
}

/************************************************/
/*												*/
/************************************************/
int akxtgetargv(buf,argv,maxargc,parm,len)
char *buf,**argv,*parm;
int  maxargc,len;
{
	return akxtgetargvns2(buf,INT_MAX,argv,maxargc,parm,len,NULL,0);
}

/************************************************/
/*												*/
/************************************************/
int akxagetstplix(file,colm,name,argv,maxargc,parm,len,opt)
char *file,*name,**argv,*parm;
int  colm,maxargc,len,opt;
{
	FILE *fp;
	char buf[AKX_RECORD_BUFSIZE];
	int n,colm1;

	if (colm<=0 || colm>maxargc) return -1;
	if (colm==1) return akxagetstplx(file,name,argv,maxargc,parm,len,opt);
	colm1 = colm - 1;
	if (!(fp = fopen(file,"r"))) return -1;
	while (akxa_read_line(buf,sizeof(buf),fp)) {
		if (*buf == '#')
			continue;
		if ((n=akxtgetargv2(buf,argv,colm,parm,len,opt))>=colm) {
			if (!akxs_opt_strcmp(name,argv[colm1],opt & ~0xf)) {
				n = akxtgetargv2(buf,argv,maxargc,parm,len,opt);
				fclose(fp);
				return n;
			}
		}
		else if (n < 0) return n;
	}
	fclose(fp);
	return 0;
}

/************************************************/
/*												*/
/************************************************/
int akxagetstpli(file,colm,name,argv,maxargc,parm,len)
char *file,*name,**argv,*parm;
int  colm,maxargc,len;
{
	return akxagetstplix(file,colm,name,argv,maxargc,parm,len,3);
}

/************************************************/
/*												*/
/************************************************/
int akxagetstplx(file,name,argv,maxargc,parm,len,opt)
char *file,*name,**argv,*parm;
int  maxargc,len,opt;
{
	FILE *fp;
	char buf[AKX_RECORD_BUFSIZE],*wd;
	int argc=0,lw,pos,i;
	uchar attr[4];

	if (maxargc<0 || len<0) return -2;
	else if (maxargc==0) return 0;
	else if (!argv || !parm || len<1) return -1;

	if (!(fp = fopen(file,"r"))) return -1;
	while (akxa_read_line(buf,sizeof(buf),fp)) {
		argc = 0;
		if (*buf == '#') continue;
		pos = 0;
		wd = parm;
		lw = akxtgetw3(buf, &pos, wd, len, attr, opt);
		if (attr[0] == '#') continue;
		if (attr[1]) {
			fclose (fp);
			return -10;
		}
		if (akxs_opt_strcmp(name,wd,opt & ~0xf)) continue;
		argc = akxtgetargv2(buf,argv,maxargc,parm,len,opt);
		break;
	}
	fclose (fp);
	if (!argc) {
		*parm = '\0';
		for (i=0;i<maxargc;i++) {
			argv[i] = parm;
		}
	}
	return argc;
}

/************************************************/
/*												*/
/************************************************/
int akxagetstpl(file,name,argv,maxargc,parm,len)
char *file,*name,**argv,*parm;
int  maxargc,len;
{
	return akxagetstplx(file,name,argv,maxargc,parm,len,3);
}

/************************************************/
/*												*/
/************************************************/
int akxa_gs_stplix(file,block,colm,name,argv,maxargc,parm,len,opt)
char *file,*block,*name,**argv,*parm;
int  maxargc,len,colm,opt;
{
	FILE *fp;
	char buf[AKX_RECORD_BUFSIZE],c,*wd;
	int argc=0,lw,pos;
	uchar attr[4];
	int n,match,colm1,i,ret[2];

	if (colm<=0 || colm>maxargc) return (-1);
	if (!block || !*block)
		return akxagetstplix(file,colm,name,argv,maxargc,parm,len,opt);

	colm1 = colm - 1;

	if (maxargc<0 || len<0) return -2;
	else if (maxargc==0) return 0;
	else if (!name || !*name || !argv || !parm || len<1) return -1;

	argc = 0;
	if (!(fp = akxa_gs_fopen(file,block,NULL,0,NULL,0,opt,ret))) {
		if (ret[0] == 100) goto LB1;
		return -1;
	}
	while (akxa_read_line(buf,sizeof(buf),fp)) {
		if ((c=*buf) == '#' || !c || c == '\n') continue;
		else if (c == '[') break;

		if ((n=akxtgetargv2(buf,argv,colm,parm,len,opt))>=colm) {
			if (!akxs_opt_strcmp(name,argv[colm1],opt & ~0xf)) {
				n = akxtgetargv2(buf,argv,maxargc,parm,len,opt);
				fclose(fp);
				return n;
			}
		}
		else if (n < 0) {
			fclose(fp);
			return n;
		}
	}
 LB0:
	fclose(fp);
 LB1:
	if (!argc) {
		*parm = '\0';
		for (i=0;i<maxargc;i++) argv[i] = parm;
	}
	return argc;
}

/************************************************/
/*												*/
/************************************************/
int akxtget2vsep(buf,argv,parm,parmlen,sep,opt)
char *buf,**argv,*parm,sep;
int  parmlen, opt;
{
	char *p,sepa[2];
	int  len,ret;
	
	if (!argv) return -1;
	if (!parm || parmlen<=0) {
		if (!(p = buf)) return -1;
	}
	else {
		if (!(p = parm)) return -1;
		if (buf) {
			len = strlen(buf);
			if (len >= parmlen) return -2;
			memcpy(parm,buf,len+1);
		}
	}
	sepa[0] = sep;
	sepa[1] = '\0';
	ret = akxtgetnvsep(p,argv,2,sepa,opt|0x02);
	return ret;
}

/************************************************/
/*												*/
/************************************************/
int akxtgetnvsep(buf,argv,maxargc,sep,opt)
char *buf,**argv,*sep;
int  maxargc, opt;
{
	char *p,c;
	int  i,len,argc,buf_len,opt2,opt4,opt8,level;
	
	if (!buf || (maxargc>0 && !argv) || !sep) return -1;
	if ((len = strlen(sep)) <= 0) return -2;
	opt2 = opt & 0x02;
	opt4 = opt & 0x04;	/* for IPv6 Host Addr */
	opt8 = opt & 0x08;	/* \ escape */
	p = buf;
	level = argc = 0;
	if (argc < maxargc) argv[argc] = p;
	if (opt & 0x01) {
		buf_len = strlen(buf);
		p = buf + buf_len - 1;
		while (buf_len-- > 0) {
			if (buf_len>0 && akxqiskanji(p-1)) {
				p -= 2;
				buf_len--;
			}
			else {
				c = *p;
				if (opt4) {
					if (c == ']') level++;
					else if (level>0 && c=='[') level--;
				}
				if (!level) {
					if (memchr(sep,c,len)) {
						*p = '\0';
						argc++;
						if (argc < maxargc) argv[argc] = p + 1;
						if (opt2 && argc+1>=maxargc) break;
					}
				}
				p--;
			}
		}
		p = buf + buf_len;
	}
	else {
		while (c = *p) {
			if (akxqiskanji(p)) {
				p += 2;
			}
			else {
				if (opt8) {
					if (c=='\\') {
						if (!*(++p)) break;
						if (!(c = *(++p))) break;
					}
				}
				if (opt4) {
					if (c == '[') level++;
					else if (level>0 && c==']') level--;
				}
				if (!level) {
					if (memchr(sep,c,len)) {
						*p = '\0';
						argc++;
						if (argc < maxargc) argv[argc] = p + 1;
						if (opt2 && argc+1>=maxargc) break;
					}
				}
				p++;
			}
		}
	}
	for (i=argc+1;i<maxargc;i++) argv[i] = p;

	return argc;
}

/************************************************/
/*												*/
/************************************************/
int akxtgetvseps(string,argv,seps,opt)
char *string,*argv[],*seps;
int opt;
{
	char *p;
	int ret=0,ret2;

	if (!string || !argv || !seps) return -1;
	if (*(p=seps+1)) {
		if ((ret=akxtgetvseps(string,argv+1,p,opt)) < 0) return ret;
	}
	if ((ret2=akxtget2vsep(string,argv,NULL,0,*seps,opt)) < 0) return ret2;
	return ret2 + ret;
}

/************************************************/
/*												*/
/************************************************/
typedef struct tdtSect {
	char *section;
	int  pos;
	struct tdtSect *nextSect;
} tdtSect;

typedef struct tdtFopenCache {
	char *file;
	tdtSect *nextSect;
	struct tdtFopenCache *nextFile;
} tdtFopenCache;

static tdtFopenCache *gtpFopenCache=NULL;

static int _fopen_cache(cmnd,file,section,pret)
char cmnd,*file,*section;
int  pret[];
{
	tdtFopenCache *nF,*nFu,*nFp;
	tdtSect *nS,*nSu,*nSp,*nSpu;

	nF = gtpFopenCache;
	switch (cmnd) {
	case 'i':
		pret[0] = 0;
		while (nF) {
			if (!strcmp(nF->file,file)) {
				nS = nF->nextSect;
				while (nS) {
					nS->section[0] = '\0';
					nS = nS->nextSect;
				}
				break;
			}
			nF = nF->nextFile;
		}
		break;
	case 'r':
		pret[0] = 0;
		nFp = NULL;
		nSp = NULL;
		while (nF) {
			if (!strcmp(nF->file,file)) {
				nS = nF->nextSect;
				while (nS) {
					if (!strcmp(nS->section,section)) {
						pret[0] = nS->pos;
						goto L_found;
					}
					nSp = nS;
					nS = nS->nextSect;
				}
			}
			nFp = nF;
			nF = nF->nextFile;
		}
		break;
	case 's':
		nFp = nFu = NULL;
		nSp = NULL;
		while (nF) {
			if (*nF->file) {
				if (!strcmp(nF->file,file)) break;
			}
			else nFu = nF;
			nFp = nF;
			nF = nF->nextFile;
		}
		if (nF) {	/* ファイル名登録済み */
			nS = nF->nextSect;
			nSpu = nSp = nSu = NULL;
			while (nS) {
				if (*nS->section) {
					if (!strcmp(nS->section,section)) break;
				}
				else {
					nSu = nS;
					nSpu = nSp;
				}
				nSp = nS;
				nS = nS->nextSect;
			}
			if (nS) {	/* Section名登録済み */
				nS->pos = pret[0];
			}
			else if (nSu) {	/* 空きがある */
				if (nSu->section) Free(nSu->section);
				nSu->section  = Strdup(section);
				nSu->pos      = pret[0];
				nS = nSu;
				nSp = nSpu;
			}
			else {	/* 空きがない */
				if (!(nS=(tdtSect *)Malloc(sizeof(tdtSect)))) return -1;
				nS->section  = Strdup(section);
				nS->pos      = pret[0];
				nS->nextSect = NULL;
				if (nSp) nSp->nextSect = nS;
				else nF->nextSect = nS;
			}
			goto L_found;
		}
		else if (nFu) {	/* 空きがある */
			if (nFu->file) Free(nFu->file);
			nFu->file     = Strdup(file);
			return _fopen_cache(cmnd,file,section,pret);
		}
		else {	/* 空きがない */
			if (!(nF=(tdtFopenCache *)Malloc(sizeof(tdtFopenCache)))) return -1;
			nF->file     = Strdup(file);
			nF->nextSect = NULL;
			nF->nextFile = NULL;
			if (nFp) nFp->nextFile = nF;
			else gtpFopenCache = nF;
			return _fopen_cache(cmnd,file,section,pret);
		}
		break;
	default:
		return -1;
	}
	return 0;

 L_found:
	if (nSp && (nF->nextSect != nS)) {
		nF->nextSect = nS;
		nSp->nextSect = nS->nextSect;
		nS->nextSect = nSp;
	}
	if (nFp) {
		gtpFopenCache = nF;
		nFp->nextFile = nF->nextFile;
		nF->nextFile = nFp;
	}
	return 1;
}

FILE *akxa_gs_fopen(file,section,argv,maxargc,parm,len,opt,pret)
char *file,*section,**argv,*parm;
int  maxargc,len,opt,pret[];
{
	FILE *fp;
	char buf[AKX_RECORD_BUFSIZE],c,*wd,work[AKX_RECORD_BUFSIZE];
	int argc=0,lw,pos,l,opt1,seek_pos,ret[2],found,opt2;
	uchar attr[4];
	int n,match,i,sectlen,iend,iRc;


	if (pret) {
		pret[0] = pret[1] = 0;
	}
	if (!file || !*file || !section || !*section || !pret) {
		if (pret) pret[0] = -1;
		return NULL;
	}
	sectlen = strlen(section);
	
	if (maxargc<=0 || len<1 || !argv || !parm) maxargc = 0;

	if (!(fp = fopen(file,"r"))) {
		pret[0] = -2;
		return NULL;
	}

	opt2 = !(opt & AKX_GSFOPEN_NO_CACHE);
	seek_pos = found = 0;
	if (opt2) {
		if (opt & AKX_GSFOPEN_CACHE_INVALID) _fopen_cache('i',file,0,ret);
		else {
			if ((found=_fopen_cache('r',file,section,ret)) > 0) {
				seek_pos = ret[0];
				fseek(fp,seek_pos,SEEK_SET);
			}
		}
	}

	argc = match = iend = 0;
	while (l=akxa_read_line(buf,sizeof(buf),fp)) {
		if ((c=*buf) == '[') {
			wd = buf + 1;
			if (l>sectlen && !memcmp(section,wd,sectlen)) {
				if ((c = *(wd+sectlen))==']' || c==' ' || c=='\n') {
					match = 1;
					pos = 1;
					if (c == ']') {
						if (opt2 && found <= 0) {
							ret[0] = seek_pos;
							_fopen_cache('s',file,section,ret);
						}
						return fp;
					}
					break;
				}
			}
		}
		seek_pos += l;
	}
	if (!match) {
		iRc = 100;
		goto LB0;
	}

	if (opt2 && found <= 0) {
		ret[0] = seek_pos;
		_fopen_cache('s',file,section,ret);
	}

	opt1 = opt & 0x01;	/* # */
	for (;;) {
		wd = buf + pos;
		while ((lw=akxtgetw3(buf,&pos,work,sizeof(work),attr,opt)) >= 0) {
			lw--;
			if (lw>=0 && attr[0]==1 && work[lw]==']') {
				*(buf+pos-1)='\0';
				iend = 1;
				break;
			}
			if (opt1 && attr[0] == '#') {
				break;
			}
		}
		if (maxargc>0 && len>1) {
			n = akxtgetargv2(wd,argv,maxargc,parm,len,opt);
			if (n < 0) maxargc = 0;
			else if (n > 0) {
				argc += n;
				argv += n;
				maxargc -= n;
				for (i=0;i<n;i++) {
					lw = strlen(parm) + 1;
					parm += lw;
					len  -= lw;
				}
			}
		}
		if (iend) break;
		for (;;) {
			if (!(l=akxa_read_line(buf,sizeof(buf),fp))) {
				iRc = -3;
				goto LB0;
			}
			if ((c=*buf) != '#' && c) break;
		}
		if (*buf == '[') {
			iRc = -4;
			goto LB0;
		}
		pos = 0;
	}
	pret[1] = argc;
	return fp;
 LB0:
	pret[0] = iRc;
	pret[1] = argc;
	fclose (fp);
	return NULL;
}

/************************************************/
/*												*/
/************************************************/
int akxa_gs_fopen_free()
{
	tdtFopenCache *nF,*nFn;
	tdtSect *nS,*nSn;
	char *p;

	nF = gtpFopenCache;
	while (nF) {
		nS = nF->nextSect;
		while (nS) {
			if (p=nS->section) Free(p);
			nSn = nS->nextSect;
			Free(nS);
			nS = nSn;
		}
		if (p=nF->file) Free(p);
		nFn = nF->nextFile;
		Free(nF);
		nF = nFn;
	}
	gtpFopenCache = NULL;
	return 0;
}

/************************************************/
/*												*/
/************************************************/
int akxtgetstplx(mem,memlen,name,argv,maxargc,parm,len,opt)
char *mem,*name,**argv,*parm;
int  memlen,maxargc,len,opt;
{
	char *buf,*wd;
	int argc=0,lw,pos,i,reclen;
	uchar attr[4];
	SSP_S ssp;

	if (memlen<0 || maxargc<0 || len<0) return -2;
	else if (maxargc==0) return 0;
	else if (!mem || !argv || !parm || len<1) return -1;

	ssp.sp = 0;
	while ((reclen=akxtmgetline(mem,memlen,&ssp))>=0) {
		buf = ssp.wd;
		argc = 0;
		if (*buf == '#') continue;
		pos = 0;
		wd = parm;
		lw = akxtgetwn3(buf,reclen,&pos,wd,len,attr,opt);
		if (attr[0] == '#') continue;
		if (attr[1]) return -10;
		if (akxs_opt_strcmp(name,wd,opt & ~0xf)) continue;
		argc = akxtgetargvn2(buf,reclen,argv,maxargc,parm,len,opt);
		break;
	}
	if (!argc) {
		*parm = '\0';
		for (i=0;i<maxargc;i++) {
			argv[i] = parm;
		}
	}
	return argc;
}

/************************************************/
/*												*/
/************************************************/
int akxs_opt_memcmp(s1,s2,len,opt)
char *s1,*s2;
int len,opt;
{
	int ret;

	if (opt & AKX_ARGV_USE_ICMP) ret = memicmp(s1,s2,len);
	else if (opt & AKX_ARGV_USE_AKXICMP) ret = akxmemicmp(s1,s2,len);
	else ret = memcmp(s1,s2,len);

	return ret;
}

/************************************************/
/*												*/
/************************************************/
int akxs_opt_strcmp(s1,s2,opt)
char *s1,*s2;
int opt;
{
	int ret;

	if (opt & (AKX_ARGV_USE_ICMP | 0x01)) ret = stricmp(s1,s2);
	else if (opt & (AKX_ARGV_USE_AKXICMP | 0x02)) ret = akxstricmp(s1,s2);
	else ret = strcmp(s1,s2);

	return ret;
}

/************************************************/
/*												*/
/************************************************/
int akxtmgetline(cpMem, iMemLen, ssp)
char *cpMem;
int  iMemLen;
SSP_S *ssp;
{
	char *p;
	int i,len;

	len = 0;
	i = ssp->sp;
	ssp->wd = p = cpMem + i;
	if (i>=iMemLen) return -1;
	while ((i < iMemLen) && (*p != '\n') && (*p != '\r') && (*p != '\0')) {
		i++;
		p++;
	}
	len = i - ssp->sp;
	if (i < iMemLen) {
		if (*p == '\r') {
			i++;
			if ((i<iMemLen) && (*(p+1)=='\n')) i++;
		}
		else if ((*p == '\n') || (*p == '\0')) i++;
	}
	ssp->sp = i;
	return len;
}

/************************************************/
/*												*/
/************************************************/
int akxa_fw_getc(buf,max,fp,pos,sap)
char *buf;
int pos,max,sap;
FILE *fp;
{
	int i,c,len;
	char *s,*d;
/*
printf("max=%d pos=%d sap=%d\n",max,pos,sap);
*/
	if (!buf || !fp) return -1;
	if (max<=0 || pos<0 || sap<0 /* || pos>max */) return -2;

	d = buf;
	if (sap > 0) {
		if ((pos -= sap) < 0) return -3;
		else if (pos > 0) {
			s = buf + sap;
			for (i=0;i<pos;i++) *d++ = *s++;
		}
	}
	else d += pos;

	for (i=pos;i<max;i++) {
		c = getc(fp);
		if (c == EOF) break;
		*d++ = c;
/*
printf("c=%08x\n",c);
*/
	}
	return i;
}
