static    char    sccsid[]="%Z% %M% %I% %E% %U%";
/*****************************************************/
/*                                                   */
/*     akxccvn  (rad, ss, len, pnum )                */
/*     akxccvd  (ss, len, pnum)                      */
/*     akxcgcvn ( s, n, pnum )                       */
/*                                                   */
/*****************************************************/
#include "akxcommon.h"
#include <math.h>

#if defined(_LP64)
#define D_CHK_X_OVER	0xf000000000000000
#define D_CHK_O_OVER	0xa000000000000000
#define D_CHK_B_OVER	0x8000000000000000
#else
#define D_CHK_X_OVER	0xf0000000
#define D_CHK_O_OVER	0xa0000000
#define D_CHK_B_OVER	0x80000000
#endif

static char *sep=" \t\n\r";

/********************************/
/*	akxqsign					*/
/********************************/
int akxqsign(char *s, int len_s, int parm[], char *sep, int opt)
{
	char *p,cc;
	int  sign,nzflag,lens,zero,at,i_sig,nsign,opt2;

	if (!s || !parm) return -1;
	if (!sep) sep = " \t";
	lens = len_s;
	p = s;
	at = zero = nsign = i_sig = 0;
	sign = nzflag = 1;
	opt2 = opt & AKX_CNVN_OPT_COMMA;
	while ((lens-- > 0) && (cc = *p++)) {
		at++;
		if (nzflag == 1) {
			if (cc == '-' || cc == '+') {
				if (cc == '-') sign = -sign;
				nsign++;
				if (nsign >= 2) i_sig = at;
			}
			else if (cc == '0') {
				zero++;
				nzflag = 0;
			}
		/*
			else if (opt2) {
				if (cc==',' && lens>=1 && (cc=*p)>='0' && cc<='9') ;
				else break;
			}
		*/
			else if (!strchr(sep,cc)) break;
		}
		else {
			if (cc != '0') break;
			zero++;
		}
	}
	parm[0] = sign;
	parm[1] = nsign;
	parm[2] = i_sig;
	parm[3] = zero;
	parm[4] = nzflag;
/*
printf("akxqsign: at=%d sign=%d nsign=%d i_sig=%d zero=%d nzflag=%d\n",
at,sign,nsign,i_sig,zero,nzflag);
*/
	return at;
}

/************************************************/
/*	ppos	: 少数点を除く数字以外が表れた位置	*/
/*	ret = 0 : 正常								*/
/*	     -1 : 数字がない						*/
/*	     -2 : radが不正							*/
/*	    > 0 : 少数点を含め数字以外が表れた位置	*/
/************************************************/
static int _cvl(rad,ss,len,pnum,ppos)
int rad,len,*ppos;
char *ss;
long *pnum;
{
	char c,*s;
	long num,num0,radm1,d;
	int i,sig,ret,parm[5],skip;

	if (ppos) *ppos = 0;
	if (pnum) *pnum = 0;
	if (!(s=ss)) return -1;
	if (rad<2 || rad>16) return -2;
#if 0	/* 2018.5.26 */
	i = akxqsign(ss,len,parm,sep,0);
	rc = parm[2];
	if (i>=len && !parm[3]) rc = -1;
	if (rc) return rc;
	s += i;
	sig = parm[0];
#else
	sig = 0;
	for (i=0;i<len;i++) {
		if ((c=*s) == '-') {
			if (sig) break;
			sig = -1;
		}
		else if (c == '+') {
			if (sig) break;
			sig = 1;
		}
		else if (!strchr(sep,c)) break;
		s++;
	}
	if (ppos) *ppos = i;
	if (i>=len) return -1;
#endif
	ret = 0;
	radm1 = rad - 1;
	num0 = num = 0;
	d = -1;
	skip = 0;
	for (;i<len;i++) {
		c = *s++;
	/*	if (c=='\0' || strchr(sep,c)) break;	*/
		if (c>='0' && c<='9') d = c - '0';
		else if (c=='.') {
			skip++;
			d = 0;
			if (!ret) ret = i + 1;
		}
		else if (rad>10) {
			if (c>='a' && c<='f') d = c - 'a' + 10;
			else if (c>='A' && c<='F') d = c - 'A' + 10;
			else d = -1;
		}
		else d = -1;
		if (d<0 || d>radm1) {
			if (!ret) ret = i + 1;
			break;
		}
		else if (skip > 1) break;
		if (!skip) {
			if (sig>=0) {
				num = num*rad + d;
				if (num<num0) {
					ret = -3;
					num = LONG_MAX;
					break;
				}
			}
			else {
				num = num*rad - d;
				if (num>num0) {
					ret = -3;
					num = LONG_MIN;
					break;
				}
			}
			num0 = num;
		}
	}
	if (pnum) *pnum = num;
	if (!ret && d<0) ret = -1;
	if (ppos) *ppos = i;
	return ret;
}

int akxccvl(rad,ss,len,pnum)
int rad,len;
char *ss;
long *pnum;
{
	return _cvl(rad,ss,len,pnum,NULL);
}

int akxccvn(rad,ss,len,pnum)
int rad,len;
char *ss;
int *pnum;
{
	return akxccvn2(rad,ss,len,pnum,NULL);
}

#if 1	/* 2020.5.24 */
static int _chk_int_over(lnum,pnum)
long lnum;
int  *pnum;
{
	int ret,num;

	ret = 0;
	if (lnum > INT_MAX) {
		num = INT_MAX;
		ret = -3;
	}
	else if (lnum <INT_MIN) {
		num = INT_MIN;
		ret = -3;
	}
	else num = lnum;
	if (pnum) *pnum = num;
	return ret;
}
#endif
int akxccvn2(rad,ss,len,pnum,ppos)
int rad,len;
char *ss;
int *pnum,*ppos;
{
#if defined(_LP64)
	int rc,ret,num;
	long lnum;

	ret = _cvl(rad,ss,len,&lnum,ppos);
#if 1	/* 2020.5.24 */
	if (rc = _chk_int_over(lnum,pnum)) ret = rc;
#else
	if (lnum > INT_MAX) {
		num = INT_MAX;
		ret = -3;
	}
	else if (lnum <INT_MIN) {
		num = INT_MIN;
		ret = -3;
	}
	else num = lnum;
	if (pnum) *pnum = num;
#endif
	return ret;
#else
	return _cvl(rad,ss,len,pnum,ppos);
#endif
}

static int _cvnd(ss,len,dpnum)
char *ss;
int  len;
double *dpnum;
{
	char c,*s;
	int i,d,sig,rc,parm[5];
	double dnum;

	if (dpnum) *dpnum = 0.0;
	if (!(s=ss)) return -1;
#if 0	/* 2018.5.26 */
	i = akxqsign(ss,len,parm,sep,0);
	rc = parm[2];
	if (i>=len && !parm[3]) rc = -1;
	if (rc) return rc;
	s += i;
	sig = parm[0];
#else
	sig = 0;
	for (i=0;i<len;i++) {
		if ((c=*s) == '-') {
			if (sig) break;
			sig = -1;
		}
		else if (c == '+') {
			if (sig) break;
			sig = 1;
		}
		else if (!strchr(sep,c)) break;
		s++;
	}
	if (i>=len) return -1;
#endif
	rc = 0;
	dnum = 0.0;
	d = -1;
	for (;i<len;i++) {
		c = *s++;
	/*	if (c=='\0' || strchr(sep,c)) break;
		else */if (c>='0' && c<='9') d = c - '0';
		else {
			d = -1;
			rc = i + 1;
			break;
		}
		dnum = dnum*10.0 + d;
	}
	if (dpnum) {
		if (sig<0) dnum = -dnum;
		*dpnum = dnum;
	}
	if (!rc && d<0) rc = -1;
	return rc;
}

int akxccvd(ss,len,dpnum)
char *ss;
int  len;
double *dpnum;
{
	int rc,i,n,sig,iexp,nflg,ns;
	double dNum;
	char c,*s;

	if (dpnum) *dpnum = 0.0;
	if (!(s=ss)) return -1;
	i = nflg = sig = ns = 0;
	dNum = 0.0;
	if (*s != '.') {
		rc = _cvnd(s,len,&dNum);
		if (rc < 0) return rc;
		else if (!rc) {
			if (dpnum) *dpnum = dNum;
			return 0;
		}
		if (dNum < 0.0) {
			sig = -1;
			dNum = -dNum;
		}
		s += --rc;
		i = rc;
		nflg = 1;
	}
	rc = 0;
	if (*s == '.') {
		for (++i,++s;i<len;i++,s++) {
			if ((c=(*s - '0'))<0 || c>9) break;
			dNum = dNum*10.0 + c;
			ns++;
			nflg = 1;
		}
	}
	if (!nflg) return -1;
	iexp = 0;
	if (i < len) {
		if ((c=akxcupper(*s++))=='E' || c=='D') {
			i++;
			if (c=='D' && (i>=len || (i<len && strchr(sep,*s)))) ;
			else {
				if ((rc = akxccvn(10,s,len-i,&iexp)) < 0) rc -= 10*i;
				else if (rc > 0) rc += i;
			}
		}
		else {
			if (c=='F') {
				if (i+1 < len) c = akxcupper(*s);
				else c = '\0';
			}
			if (c=='\0' || strchr(sep,c)) ;
			else rc = i + 1;
		}
	}
	if (dNum) {
		if (iexp -= ns) dNum *= pow(10.0,(double)iexp);
		if (sig) dNum = -dNum;
	}
	if (dpnum) *dpnum = dNum;
	return rc;
}

int akxcgcvl(wd0,len0,pnum)
char *wd0;
int  len0;
long *pnum;
{
	int n31w=0,rc,i,len,len1,len2,s,skip,iLONG;
	char ch,*wd,*wd1,*wd2;
	long lnum;

	rc = s = 0;
	iLONG = 1;
	wd  = wd0;
	len = len0;
	skip = akxnskipin(wd,len," \t");
	wd += skip;
	len = akxnrskipin(wd,len-skip,sep);
	if (len<=0) rc = -1;
	else if (len >= 3) {
		wd1  = wd;
		len1 = len;
		if ((ch = *wd1)=='+' || ch=='-') {
			if (ch == '-') s = -1;
			len1--;
			wd1++;
		}
		if (*wd1 == '0') {
			iLONG = 0;
			wd2  = wd1  + 2;
			len2 = len1 - 2;
			skip += 2;
			switch (wd1[1]) {
				case 'D':
				case 'd':
					rc = akxccvl(10,wd,len,&lnum);
					break;
				case 'X':
				case 'x':
					rc = akxccvlx(wd2,len2,&lnum);
					break;
				case 'B':
				case 'b':
					rc = akxccvlb(wd2,len2,&lnum);
					break;
				case 'O':
				case 'o':
					rc = akxccvlo(wd2,len2,&lnum);
					break;
				default:
					skip -= 2;
					s = 0;
					iLONG = 1;
			}
#if 1	/* 2020.5.24 */
			if (rc == -3) {
				if (s) lnum = LONG_MIN;
				else lnum = LONG_MAX;
			}
			else if (s) lnum = -lnum;
#else
			if (rc == -3) {
				if (s) n31w = INT_MIN;
				else n31w = INT_MAX;
			}
			else if (s) n31w = -n31w;
			lnum = n31w;
#endif
		}
	}
	if (iLONG) {
		rc = akxccvl(10,wd,len,&lnum);
	}
#if 1	/* 2020.5.24 */
	if (pnum) *pnum = lnum;
#else
	if (pnum) memcpy(pnum,&lnum,sizeof(long));
#endif
	if (rc > 0) rc += skip;
	return rc;
}

int akxcgcvn(wd0,len0,pnum)
char *wd0;
int len0;
int *pnum;
{
#if defined(_LP64)
	int rc,ret,num;
	long lnum;

	ret = akxcgcvl(wd0,len0,&lnum);
#if 1	/* 2020.5.24 */
	if (rc = _chk_int_over(lnum,pnum)) ret = rc;
#else
	if (lnum > INT_MAX) {
		num = INT_MAX;
		ret = -3;
	}
	else if (lnum <INT_MIN) {
		num = INT_MIN;
		ret = -3;
	}
	else num = lnum;
	if (pnum) *pnum = num;
#endif
	return ret;
#else
	return akxcgcvl(wd0,len0,pnum);
#endif
}

int akxccvx(wd0,len0,pnum)
char *wd0;
int len0;
uint *pnum;
{
#if defined(_LP64)
	int ret;
	long lnum;

	ret = akxccvx(wd0,len0,&lnum);
	if (pnum) *pnum = lnum;
	return ret;
#else
	return akxccvx(wd0,len0,pnum);
#endif
}

int akxccvlx(wd0,len0,pnum)
char *wd0;
int len0;
ulong *pnum;
{
	int rc,i,len;
	ulong uVal, n;
	char c,*wd;

	wd  = wd0;
	len = len0;
	uVal = rc = 0;
	if (len <= 0) return -1;
	for (i=0;i<len;i++,wd++) {
		if (uVal & D_CHK_X_OVER) {
			rc = -3;
			break;
		}
		if ((c = *wd)>='0' && c<='9') n = c - '0';
		else if (c>='a' && c<='f') n = c - 'a' + 10;
		else if (c>='A' && c<='F') n = c - 'A' + 10;
		else {
			rc = i + 1;
			break;
		}
		uVal <<= 4;
		uVal |= n;
	}
	*pnum = uVal;

	return rc;
}

int akxccvo(wd0,len0,pnum)
char *wd0;
int len0;
uint *pnum;
{
#if defined(_LP64)
	int ret;
	long lnum;

	ret = akxccvx(wd0,len0,&lnum);
	if (pnum) *pnum = lnum;
	return ret;
#else
	return akxccvo(wd0,len0,pnum);
#endif
}

int akxccvlo(wd0,len0,pnum)
char *wd0;
int len0;
ulong *pnum;
{
	int rc,i,len;
	ulong uVal,n;
	char *wd;

	wd  = wd0;
	len = len0;
	uVal = rc = 0;
	if (len <= 0) return -1;
	for (i=0;i<len;i++,wd++) {
		if (uVal & D_CHK_O_OVER) {
			rc = -3;
			break;
		}
		n = *wd - '0';
		if (n>=0 && n<=7) {
			uVal <<= 3;
			uVal |= n;
		}
		else {
			rc = i + 1;
			break;
		}
	}
	*pnum = uVal;

	return rc;
}

int akxccvb(wd0,len0,pnum)
char *wd0;
int len0;
uint *pnum;
{
#if defined(_LP64)
	int ret;
	long lnum;

	ret = akxccvx(wd0,len0,&lnum);
	if (pnum) *pnum = lnum;
	return ret;
#else
	return akxccvb(wd0,len0,pnum);
#endif
}

int akxccvlb(wd0,len0,pnum)
char *wd0;
int len0;
ulong *pnum;
{
	int rc,i,len;
	ulong uVal,n;
	char *wd;

	wd  = wd0;
	len = len0;
	uVal = rc = 0;
	if (len <= 0) return -1;
	for (i=0;i<len;i++,wd++) {
		if (uVal & D_CHK_B_OVER) {
			rc = -3;
			break;
		}
		n = *wd - '0';
		if (!n) {
			uVal <<= 1;
		}
		else if (n == 1) {
			uVal <<= 1;
			uVal |= 1;
		}
		else {
			rc = i + 1;
			break;
		}
	}
	*pnum = uVal;

	return rc;
}

/********************************************************************/
/*  機能 : intの値を文字列に変換する								*/
/*  引数 : IN : value   : サーチ対象文字列ポインタ配列				*/
/*				str     : 文字列を出力するエリアへのポインタ		*/
/*				radix   : 進数 (2,8,10,16)							*/
/*				str_len : strの長さ(バイト)							*/
/*						  ・負符号とNULL終端文字を含めた長さ		*/
/*						  ・長さが足りないときは、負符号が付いて、	*/
/*						  　上位が削られる							*/
/*						  <0 のときは、長さチェックなし				*/
/*  返却 : = -1 : str == NULL										*/
/*		   = -2 : radix が不正										*/
/*		   >= 0 : 文字列長 (バイト)									*/
/********************************************************************/
int akxcitoa(value,str,radix,str_len)
int value;
char *str;
int radix,str_len;
{
	long lval=value;

	return akxcltoa(lval,str,radix,str_len);
}

int akxcltoa(value,str,radix,str_len)
long value;
char *str;
int radix,str_len;
{
	int i,sign,m;
	char *p,c;

	if (!(p=str)) return -1;
	if (!(radix==2 || radix==8 || radix==10 || radix==16)) return -2;

	if (str_len > 0) str_len--;

	if ((sign = value) < 0) {
		value = -value;
		if (str_len > 0) str_len--;
	}
	i = 0;
	do {
		if (str_len >= 0) {
			if (i >= str_len) break;
		}
		i++;
		m = value % radix;
		c = m + '0';
		if (radix==16 && m>=10) c = m - 10 + 'a';
		*p++ = c;
	} while ((value /= radix) > 0);

	if (sign < 0) {
		*p++ = '-';
		i++;
	}
	*p = '\0';

	return akxtreverse(str,i);
}

int akxtreverse(str,len)
char *str;
int len;
{
	int c,i,j;

	for (i=0,j=len-1;i<j;i++,j--) {
		c = str[i];
		str[i] = str[j];
		str[j] = c;
	}
	return len;
}

/*
*	ret =	 0 : 下記以外
*			 2 : 整数
*			 3 : 2進浮動小数点  (f,F,e,d,D)
*			 4 : 10進浮動小数点 (E)
*			 8 : 小数点がある数字列
*			10 : 0x,0o,0b形式
*			-1 : buf==NULL or buf_len<0
*			-2 : 空白
*			-3 : 符号のみ
*			-4 : 0x,0o,0b 形式エラー
*			-5 : 整数または小数点がある数字列エラー
*			-6 : E,F,D 形式エラー
*/
int akxqnumber(buf,buf_len,opt,iParm)
char *buf;
int  buf_len,opt,iParm[];
{
	int i,i0,ol,fu,i_p,disp,ret,dat_len,len1,m,i_e,atr;
	char *p,*p1,c,cc;

	if (iParm) mem_set_int(iParm,0,2);
	if (!buf || buf_len<0) return -1;
	i0 = akxnskipin(buf,buf_len," \t");
/*
printf("akxqnumber: i0=%d\n",i0);
*/
	dat_len = buf_len - i0;
	p = buf + i0;
	dat_len = akxnrskipin(p,dat_len," \t");
/*
printf("akxqnumber: dat_len=%d\n",dat_len);
*/
	if (!dat_len) return -2;
	i_p = fu = 0;
	for (i=i0;i<dat_len;i++,p++) {
		c = *p;
		if (c==' ' || c=='\t') ;
		else if (c=='-' || c=='+') fu++;
		else {
			i_p = i + 1;
			break;
		}
	}
/*
printf("akxqnumber: i_p=%d\n",i_p);
*/
	ret = m = i_e = atr = 0;
	if (!i_p) {
		ret =  -3;
		i_e = i;
	}
	if (!ret && c=='0') {
		cc = akxcupper(*(p+1));
		if (cc=='X' || cc=='O' || cc=='B') {
			atr = 10;
			p1 = p + 2;
			len1 = dat_len - i_p - 1;
			if (cc=='X') {
				if ((i_e=akx_skip_opt(p1,len1,"01234567890ABCDEF",1)) < len1) ret = -4;
			}
			else if (cc=='O') {
				if ((i_e=akx_skip_opt(p1,len1,"01234567",0)) < len1) ret = -4;
			}
			else {
				if ((i_e=akx_skip_opt(p1,len1,"01",0)) < len1) ret = -4;
			}
			if (i_e > 0) i_e += i_p + 1;
		}
	}
	if (!ret && !atr) {
		if (c=='.' || (c>='0' && c<='9')) {
			if (c=='.') {
				disp = 2;
				ret = -3;
				i_e = i_p;
				atr = 8;
			}
			else {
				disp = 1;
				if (c != '0') m++;
				atr = 2;
			}
			p = buf + i_p++;
			for (i=i_p;i<=dat_len;i++) {
				c = *p++;
				cc = akxcupper(c);
				if (disp <= 2) {
					if (c == '.') {
						if (disp == 2) ret = -5;
						else atr = 8;
					}
					else if (c>='0' && c<='9') {
						if (ret < 0) ret = 0;
						if (m) m++;
					}
					else if (cc == 'F') {
						if (ret<0 || i<dat_len) ret = -6;
						else atr = 3;
					}
					else if (cc=='E' || cc=='D') {
						atr = 3;
						if (ret < 0) ret = -6;
						else if (cc=='E' && i==dat_len) ret = -6;
						else if (c=='E') atr = 4;
						disp = 3;
					}
					else ret = -5;
				}
				else if (disp == 3) {
					if (c=='-' || c=='+') {
						if (i == dat_len) ret = -6;
					}
					else if (c>='0' && c<='9') disp = 4;
					else ret = -6;
				}
				else if (disp == 4) {
					if (c<'0' || c>'9') ret = -6;
				}
				if (ret < 0) {
					i_e = i;
					break;
				}
			}
		}
	}
	if (iParm) {
		iParm[0] = atr;
		iParm[1] = m;
		iParm[2] = i_e;
	}
	if (!ret) ret = atr;
	return ret;
}

int akxccvdotn(ss,len,pnum)
char *ss;
int len;
int *pnum;
{
	int nn,v,v1,m,pos;
	char *pp;

	if (pnum) *pnum = 0;
	if (!(pp=ss)) return -1;

	nn = len;
	v = 0;
	while (nn > 0) {
		pos = instrchar(pp,'.');
printf("akxccvdotn: pos=%d nn=%d v=%08x pp=[%s]\n",pos,nn,v,pp);
		if (pos > 0) m = pos - 1;
		else m = nn;
		akxcgcvn(pp,m,&v1);
		v <<= 8;
		v |= v1 & 0xff;
		if (pos > 0) {
			pp += pos;
			nn -= pos;
		}
		else break;
	}
	if (pos > 0) v <<= 8;
	if (pnum) *pnum = v;
	return 0;
}
