//
//	cliplibc.cs
//
//	標準Ｃライブラリの補助
//
//	CLiP - Common Library for P/ECE
//	Copyright (C) 2017 Naoyuki Sawa
//
//	* Wed Mar 15 22:06:35 JST 2017 Naoyuki Sawa
//	- 1st リリース。
//
using System;
namespace org.piece_me {
	public static partial class libclip {
		//*****************************************************************************
		//	標準Ｃライブラリの補助
		//*****************************************************************************
		public static int strcmp(StringPtr s1, StringPtr s2) {
			return strncmp(s1, s2, -1);
		}
		public static int strncmp(StringPtr s1, StringPtr s2, int n) {
			int t = 0;	//引数nに0が指定された場合に戻り値を0とするため、(t=0)に初期化しておく。
			for(;;) {
				int c1, c2;
				if(--n == -1) {
					break;	//この位置では必ず(t==0)である。従って"return 0"に相当する。
				}
				c1 = s1.Read();
				c2 = s2.Read();
				if((t = c1 - c2) != 0) {
					break;
				}
				if(c2 == 0) {
					break;	//この位置では必ず(t==0)である。従って"return 0"に相当する。
				}
			}
			return t;
		}
		//-----------------------------------------------------------------------------
		public static int  strspn(StringPtr s1, StringPtr s2) {
			int result = -1;
			int c1, c2, c;
			StringPtr p;
			c2 = 0;					//異なるのはこの二行だけ
			for(;;) {
				c1 = s1.Read();			//異なるのはこの二行だけ
				//{{--- strspn_strcspn ---
				result++;
				if(c1 == c2) { return result; }
				p = s2;
				for(;;) {
					c = p.Read();
					if(c == c1) { break; }
					if(c == c2) { return result; }
				}
				//}}--- strspn_strcspn ---
			}
		}
		public static int strcspn(StringPtr s1, StringPtr s2) {
			int result = -1;
			int c1, c2, c;
			StringPtr p;
			c1 = 0;					//異なるのはこの二行だけ
			for(;;) {
				c2 = s1.Read();			//異なるのはこの二行だけ
				//{{--- strspn_strcspn ---
				result++;
				if(c1 == c2) { return result; }
				p = s2;
				for(;;) {
					c = p.Read();
					if(c == c1) { break; }
					if(c == c2) { return result; }
				}
				//}}--- strspn_strcspn ---
			}
		}
		//-----------------------------------------------------------------------------
		public static int strtol(StringPtr nptr, int _base) {
			StringPtr endptr;
			return strtol(nptr, out endptr, _base);
		}
		public static int strtol(StringPtr nptr, out StringPtr endptr, int _base) {
			return (int)strtoul(nptr, out endptr, _base);
		}
		public static uint strtoul(StringPtr nptr, int _base) {
			StringPtr endptr;
			return strtoul(nptr, out endptr, _base);
		}
		public static uint strtoul(StringPtr nptr, out StringPtr endptr, int _base) {
			StringPtr eptr = nptr;					//文字列に有効な数字がひとつ現れるまで、eptrは文字列の先頭位置を維持する。
			int c, sign, sum;
			//基数が0,又は,2～36である事を確認する。
			if((_base == 1) || ((uint)_base > 36)) { throw new ApplicationException(); }	//【P/ECE開発環境のバグ情報】EPSONライブラリのstrtoul()は(base=1)も含めて許容しており正しくない。
			//空白を読み飛ばす。
			do { c = nptr.Read(); } while(isspace(c));		//【P/ECE開発環境のバグ情報】EPSONライブラリのstrtoul()はisspace()を使わずに' 'だけを読み飛ばしており正しくない。
		//不要	nptr--;							//空白ではなかった文字の位置へ戻す。			←┐
			//符号を判定する。												　├この二つの処理は相殺出来るので不要です。
		//不要	c = nptr.Read();					//符号(かも知れない)文字を読み出して、位置を進める。	←┘
			sign = -1;						//仮に、符号を負としておく。
			if(c != '-') {						//符号(かも知れない)文字が、'-'でなければ…
				sign = 1;					//符号を正とする。
				if(c != '+') {					//符号(かも知れない)文字が、'+'でなければ…
					nptr--;					//符号ではなかった文字の位置へ戻す。
				}
			}
			//基数が0,又は,16ならば…
			if((_base & ~16) == 0) {				//「if(!base || (base == 16)) {」と等価です。
				c = nptr[0];					//'0'(かも知れない)文字を読み出す。位置は進めない。
				//"0x",又は,"0X"が有れば…
				if((c == '0') && (toupper(nptr[1]) == 'X')) {
					_base = 16;				//基数を16とする。元から(base=16)だった場合はダミー処理です。
					nptr += 2;				//"0x"を読み飛ばす。
				//"0x",又は,"0X"が無く、基数が0ならば…
				} else if(_base == 0) {
					_base = 10;				//仮に、基数を10としておく。
					//"0"が有れば…
					if(c == '0') {
						_base = 8;			//基数を8とする。
					//不可	nptr++;				//【注意】16進数の"0x"は読み飛ばす必要が有りますが、8進数の"0"は読み飛ばしてはいけません。16進数の"0x"の直後に不正な文字が現れた場合は文字列に有効な数字が一つも無いと見なすべきですが、8進数の"0"の直後に不正な文字が現れた場合は"0"単独で有効な数字だと見なすべきだからです。もしここで"0"を読み飛ばしてしまうと、例えば「strtoul("0",&p,0)」の結果、正しくはpが文字列の終端のnulを指すべきなのに、(間違って)文字列に有効な数字がひとつもないと判断してしまい、pが文字列の先頭を指してしまうというバグが生じます。
					}
				}
			}
			//不正な文字,又は,終端のnulが現れるまで…
			sum = 0;
			for(;;) {
				c = nptr.Read();				//次の文字を読み出して、位置を進める。
				//'0'～'9'ならば…
				if(isdigit(c)) {
					c -= '0';				//0～9に変換する。
				//'A'～'Z',又は,'a'～'z'ならば…
				} else if(isalpha(c)) {
					c = toupper(c) - ('A' - 10);		//10～35に変換する。
				//不正な文字,又は,終端のnulならば…
				} else {
					break;					//変換を終了する。
				}
				//基数の範囲外ならば、変換を終了する。
				if(c >= _base) { break; }
				//変換した値を、結果の値に含める。
				// - 正しくはここでオーバーフロー検査を行うべきですが、当実装ではオーバーフローを無視して強行します。
				//   尚、strtol()とstrtoul()の仕様上の違いはオーバーフロー検査の範囲だけであり、当実装ではオーバーフローを無視するので、結果的にstrtol()とstrtoul()は同じ処理となります。
				//   strtoul()は(名前から受ける印象とは違い)、'-'を不正な文字と見なす*のではない*事に注意して下さい。(そういう仕様です。)
				sum = (sum * _base) + c;
				//今変換した文字の次の位置を、eptrに記憶する。
				// - もし次の位置で変換出来なくなった場合は、endptrに次の位置を返すためです。
				//   尚、初回にここへ到達するまでは、eptrは文字列の先頭位置を維持しています。
				//   文字列に有効な数字がひとつもなければ、空白や符号や"0x"を読み飛ばす前の、文字列の先頭位置をendptrに返します。
				eptr = nptr;
			}
			//最初に不正な文字が現れたアドレス,又は,文字列に有効な数字がひとつもなければnptrの元の値を*endptrに代入する。
			endptr = eptr;
			//結果の値に符号を掛け合わせて返す。
			return (uint)(sum * sign);
		}
	}
}
