//---------------------------------------------------------------------------------------------
// UTF8/SJIS対応文字/列関数群(他)
//---------------------------------------------------------------------------------------------

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "code2code.h"
#include "support.h"

// 参照
// http://ash.jp/code/unitbl21.htm
// 変換テーブルとCORE_DEBUG()はTwentyOneのソースから

// 処理の最適化はしてない

//---------------------------------------------------------------------------------------------

// SHIFT-JIS1バイト目の判定
// X68の範囲のみ
// 1/2角,1/4角文字も含む
int iskanji1Sjis(ULong code)
{
	if (code>=0x80 && code<=0x9f) return(YES);
	return (code>=0xe0 && code<=0xf3);
}

// SHIFT-JIS2バイト目として正しいコードかどうかの判定
// X68の範囲
// 1/2角,1/4角文字には対応しない
int iskanji2Sjis(ULong code)
{
	if (code<0x20) return (NO); // 通常は0x40
	switch (code) {
		case 0x7f:
		case 0xfd:
		case 0xfe:
		case 0xff:
			return (NO);
	}
	return (YES);
}
// 0x80xx 1/2角(半角ひらがな)
// 0xf0xx 1/4角上付きカタカナ
// 0xf1xx 1/4角上付きひらがな
// 0xf2xx 1/4角下付きカタカナ
// 0xf3xx 1/4角下付きひらがな
// 1/2角,1/4角文字は0x00〜0x1f(コントロールコード可視化),0x20〜0x7e(1/4のみ),0xa0〜0xdfである。

//---------------------------------------------------------------------------------------------
// バッファリング付き文字構築
//---------------------------------------------------------------------------------------------
// バイト単位の入力から、1文字が成立した時にそのコードを返す

/// SJIS文字取得
/// @return CODE_TOCHU = 途中
ULong chars2Sjis(UByte c)
{
static SLong cc=0; // ここに中間状態を保持
	if (cc==0) { // 1バイト目
		if (iskanji1Sjis(c)) {
			// SJIS1バイト目
			cc=c;
			return (CODE_TOCHU);
		}
		if (c==EOS) cc=0; // リセット
		// ASCIIまたは半角文字、または不正コードはそのまま出力
		return (c);
	}
	// SJIS2バイト目
	ULong c2=(cc<<8)|c;
	if (c==EOS) c2=EOS; // 2バイト目がEOSの時は1バイト目も消す
	cc=0; // 次は1バイト目
	return (c2);
}

/// UTF8文字取得
/// @return CODE_TOCHU = 途中
ULong chars2Utf8(UByte c)
{
	static ULong cc;
	static int needs=0; // 必要なコード数
	static int bytes=0; // 現在のコード数
	if (c==EOS) {
		// リセット
		cc=0;
		needs=0;
		bytes=0;
		return (c);
	}
	/* パターン
	 	~~1~~	+~~2~~	+~~3~~	+~~4~~	+~~5~~	+~~6~~
	 (1)c2～df			+80～bf
	 (2)e0～ef	+80～bf	+80～bf
	 (3)f0～f7	+80～bf	+80～bf	+80～bf
	 ---------------------------------------
	 (4)f8～fb	+80～bf	+80～bf	+80～bf	+80～bf 			┬─非サポート
	 (5)fc～fd	+80～bf	+80～bf	+80～bf	+80～bf	+80～bf	┘
	 だけど、X-BASIC'でサポートするのは4バイトコードまで(ULongまでなので)。
	 */
	switch (bytes) {
		case 0: // 1バイト目
			if (c<0x7f) return (c); // ASCIIはそのまま出力
			bytes++;
			cc=c;
			if (c>=0xc2 && c<=0xdf) {
				// (1)
				needs=2;
				return (CODE_TOCHU);
			}
			if (c>=0xe0 && c<=0xef) {
				// (2)
				needs=3;
				return (CODE_TOCHU);
			}
			if (c>=0xf0 && c<=0xf7) {
				// (3)
				needs=4;
				return (CODE_TOCHU);
			}
			// 非サポート範囲なので、そのまま出力
			// (4)(5)またはその他不正コード
			break;
		//
		case 1: // 2バイト目
			cc=(cc<<8)|c;
			bytes++;
			if (c>=0x80 && c<=0xbf) {
				switch (needs) {
					case 2: // (1)終了
						break;
					case 3: // (2)の途中
					case 4: // (3)の途中
						return (CODE_TOCHU);
				}
			}
			break;
		//
		case 2: // 3バイト目
			cc=(cc<<8)|c;
			bytes++;
			if (c>=0x80 && c<=0xbf) {
				switch (needs) {
					case 3: // (2)終了
						break;
					case 4: // (3)の途中
						return (CODE_TOCHU);
				}
			}
			break;
			//
		case 3: // 4バイト目
			cc=(cc<<8)|c;
			// 不正でも正常でもこれで返す
			break;
	} // switch
	bytes=0;
	return (cc);
}

//---------------------------------------------------------------------------------------------

// テーブルの要素数を求める
// 巨大テーブルのためソースを分離をしたので、sizeof()が使えないので
int setTableSize(const U16SJIS *codeTable)
{
	DBG_Func();
	int i=0;
	while (codeTable[i].code1!=0) i++; // end of tableまで回す
	DBG_printf1("table 要素数=%d\n",i);
	return (i); // end of table分は含まない
}

void AllTableSize(void)
{
	if (U2STableSize==0) {
		U2STableSize=setTableSize(U2STable);
		CheckCodeTable(U2STable);
	}
	if (S2UTableSize==0) {
		S2UTableSize=setTableSize(S2UTable);
		CheckCodeTable(S2UTable);
	}
}

//---------------------------------------------------------------------------------------------

#ifdef CORE_DEBUG
// テーブル内のコード重複をチェックする
void CheckCodeTable(const U16SJIS *codeTable)
{
	DBG_Func();
	int i=0;
	U16SJIS bcode={0,0};
	while (codeTable[i].code1!=0) {
		if (bcode.code1==codeTable[i].code1) {
			DBG_printf("重複$%04x\n",codeTable[i].code1);
		}
		bcode=codeTable[i];
		i++;
	}
}
#endif

//---------------------------------------------------------------------------------------------

// code1->code2の変換
UWord u16Sjis( UWord code ,const U16SJIS *codeTable,int sizeOfTable)
{
	DBG2_Func();
	
	if (code<=0x7f||code==0xa0) return(code); // ASCII/SJIS/UTF8では、この範囲は変換する必要がない
	
	int dimsize =sizeOfTable;
	int idx = 1; // [0]は不一致コード
	int move = dimsize;
	int sub;
	UWord code1;
	// 2分法で検索する
	do {
		code1=codeTable[idx].code1;
#ifdef CORE_DEBUG
		DBG_printf( "%d : $%04x\n", idx ,code1);
#endif
		if ( idx >= dimsize ) { // 要素数を超えてしまった時は逆方向に変更
			sub = -1;
		} else {
			sub = code - code1;
			if ( sub == 0 ) {
				// 差分が0=文字一致で終了
				DBG_prints("<差分0");
				break;
			}
			if (sub<16 && sub>0) {
				// 近くにあるときはシリアルサーチする
				// code1はコード順に並んでいる
				int i;
				for (i=0;i<16;i++) {
					if (code==codeTable[idx+i].code1) {
						idx+=i;
						goto ENDCODE2CODE;
					}
				}
				// 近くにあるはずなのになかったときは不一致
				DBG_prints("近くにあるはずなのにない");
				idx=0; // テーブルの先頭に不一致時の変換コードを入れておく
				break;
			}
		}
		if ( move == 1 ) {
		//	idx=dimsize-1;
			// 文字不一致(だと思う)
			DBG_prints("<mode=1");
			idx=0; // テーブルの先頭に不一致時の変換コードを入れておく
			break;
		}
		move = (move+1)/2;
		idx = idx+ ( sub<0 ? -move : move );
	} while (1);
ENDCODE2CODE:;
	DBG_printsn("<");
	return ( codeTable[idx].code2);
}

//---------------------------------------------------------------------------------------------

// UTF16 -> UTF8
// http://ja.wikipedia.org/wiki/UTF-8 参照
// Unicodeは文字コードの総称で、UTF-16やUTF-8はその表現方法(エンコード)の種類、である。
// UTF16は本来UWord範囲である
ULong Utf16ToUtf8(ULong n)
{
	if (n<=0x7f) return(n); // ASCII互換
	if (n<=0x7ff) {
		// 8421 8421   8421 8421
		// 110x_xxxx | 10xx_xxxx
		return  w16( 												(0xc0|(n>>6))		 , (0x80|(n&0x3f)) );
	}
	if (n<=0xffff) {
		// 8421 8421   8421 8421   8421 8421
		// 1110_xxxx | 10xx_xxxx | 10xx_xxxx
		return	w24( 						(0xe0|((n>>12)&0x0f)) , (0x80|((n>>6)&0x3f)) , (0x80|(n&0x3f)) );
		
	}
	// n<=0x1fffff
	// 8421 8421   8421 8421   8421 8421   8421 8421
	// 1111_0xxx | 10xx_xxxx | 10xx xxxx | 10xx xxxx
	return	w32(	(0xf0|((n>>18)&0x07)) , (0x80|((n>>12)&0x3f)) , (0x80|((n>>6)&0x3f)) , (0x80|(n&0x3f)) );
	
	// 定義上はこれ以上もあるが、実在しないので省略
}

//---------------------------------------------------------------------------------------------

// UTF8 -> UTF16
// UTF16は本来UWord範囲である
ULong Utf8ToUtf16(ULong b)
{
	if (b<=0xff) return(b); // ASCII
	if (b<=0xffff) {
		return (						  (b16(b) & 0x1f) << 6) + (b8(b) & 0x3f);
	}
	return (	((b24(b) & 0xf) << 12) + ((b16(b) & 0x3f) << 6) + (b8(b) & 0x3f)	);
}

//---------------------------------------------------------------------------------------------

// UTF8文字列から1文字コードを得る
// 21bit UTF8(コードで32ビット以内)まで対応(リターン値はULongだが値はSLong範囲)
// https://ja.wikipedia.org/wiki/UTF-8参照
ULong getUtf8(UByte *(*src0))
{
	UByte *src=*src0;
	ULong c=*src++; // 1バイト目
	DBG2_printf1("%02x",(UByte)c);
	if (c>0x7f) {
		UByte c1=*src++; // 次の1バイト
		DBG2_printf1(".%02x",c1);
		if (c>=0xc2 && c<=0xdf) { // 11bit
			c=(c<<8)|c1;
		} else {
			UByte c2=*src++;
			DBG2_printf1(".%02x",c2);
			if (c>=0xe0 && c<=0xef) { // 16bit
				c=(c<<16)|(c1<<8)|c2;
			} else {
				UByte c3=*src++;
				DBG2_printf1(".%02x",c3);
				if (c>=0xf0 && c<=0xf7) { // 21bit
					c=(c<<24)|(c1<<16)|(c2<<8)|c3;
				} else {
					// このプログラム内では使えないコード
					UByte c4=*src++;
					DBG2_printf1(".%02x",c4);
					if (c4>=0xf8 && c4<=0xfb) { // 26bit
						c=0xE280BB; // ※;このプログラムの中では文字コードとしては使えないので
					} else {
						UByte c5=*src++;
						DBG2_printf1(".%02x",c5);
						if (c5>=0xfc && c5<=0xfd) { // 31bit
							c=0xE280BB; // ※;このプログラムの中では文字コードとしては使えないので
						}
					}
				}
			}
		}
	} // c<=0x7f
	//
	DBG2_printsn("");
	*src0=src;
	return (c);
}

//---------------------------------------------------------------------------------------------

// SJIS文字列から1文字コードを得る
ULong getSjis(UByte *(*src0))
{
	UByte *src=*src0;
	int c=*src++; // 1バイト目
	if (iskanji1Sjis(c)) c=(c<<8)|*src++;
	*src0=src;
	return (c);
}

// SJIS文字列から1文字コードを得る
// X68専用の1/2,1/4角文字は普通のASCIIに変換
ULong getSjisNoX68(UByte *(*src0))
{
	UByte *src=*src0;
	ULong c=*src++; // 1バイト目
	switch (c) {
		case 0x80: // 1/2
		case 0xf0: // 上付き１／４角（片仮名）
		case 0xf1: // 上付き１／４角（平仮名）
		case 0xf2: // 下付き１／４角（片仮名）
		case 0xf3: // 下付き１／４角（平仮名）
			// 1/2,1/4角文字は普通のASCIIに変換
			c=*src++;
			if (c<' ') c=' '; // 変換結果としてコントロールコードになると問題を起こすのでスペースにする
			break;
		default:
			if (iskanji1Sjis(c)) c=(c<<8)|*src++;
			break;
	}
	*src0=src;
	return (c);
}

ULong getSjisOrUtf8(UByte *(*src0),int fsjis)
{
	ULong c;
	if (fsjis) { // SHIFT-JIS
		c=getSjis(src0);
	} else { // UTF-8/ASCII
		c=getUtf8(src0);
	}
	DBG_printf1("1文字=$%x\n",(int)c);
	return (c);
}

//---------------------------------------------------------------------------------------------

// UTF8で文字数を数える
int utf8Len(UByte *str)
{
	int len=0;
	ULong c;
	while ((c=getUtf8(&str))!=EOS) {
		len++;
	}
	return (len);
}

// SHIFT-JISで文字数を数える
int sjisLen(UByte *str)
{
	int len=0;
	ULong c;
	while ((c=*str++)!=EOS) {
		if (iskanji1Sjis(c)) str++;
		len++;
	}
	return (len);
}

//---------------------------------------------------------------------------------------------

// cを書き込むのに必要なサイズを返す
int calcLongSize(ULong c)
{
	int len=1;	// 最低限1バイトは必要
	if (c>=0x1000000) { // 4バイト
		len++;
	}
	if (c>=0x10000) { // 3バイト
		len++;
	}
	if (c>=0x100) { // 2バイト
		len++;
	}
	//
	return (len);
}

// UTF8/SJIS/ASCIIの1文字をワークに書き込む
UByte *storeUtf8(UByte *des,ULong c)
{
	// UTF-8では1～4バイトになり得る
	if (c>=0x1000000) { // 4バイト
		*des++=b32(c);
	}
	if (c>=0x10000) { // 3バイト
		*des++=b24(c);
	}
	if (c>=0x100) { // 2バイト
		*des++=b16(c);
	}
	*des++=b8(c);
	//
	return (des);
}

// SJISの1文字をワークに書き込む
UByte *storeSjis(UByte *des,ULong c)
{
	if (c>=0x100) { // 2バイト
		*des++=b16(c);
	}
	*des++=b8(c);
	//
	return (des);
}

UByte *storeSjisOrUtf8(UByte *des,ULong c,int fsjis)
{
	DBG_printf2("%p～<-$%x",des,(int)c);
	if (fsjis) {
		return (storeSjis(des,c));
	}
	return (storeUtf8(des,c));
}

//---------------------------------------------------------------------------------------------

// 指定文字目(0～)=mojis,の先頭からのバイト数を得る
// UTF8コード専用
int utf8Position(UByte *str,int mojis)
{
	DBG_Func();
	DBG_printf2("str=%s,mojis=%d\n",str,mojis);
	UByte *str0=str;
	while (mojis-->0) {
		getUtf8(&str);
	}
	return ((int)(str-str0));
}

// 指定文字目(0～)=mojis,の先頭からのバイト数を得る
// SJISコード専用
int sjisPosition(UByte *str,int mojis)
{
	DBG_Func();
	DBG_printf2("str=%s,mojis=%d\n",str,mojis);
	UByte *str0=str;
	while (mojis-->0) {
		getSjis(&str);
	}
	return ((int)(str-str0));
}

//---------------------------------------------------------------------------------------------
// 1文字/文字列変換
//---------------------------------------------------------------------------------------------

// SHIFT-JIS → UTF16
ULong sjisToUtf16(ULong c)
{
	return u16Sjis((UWord)c,S2UTable,S2UTableSize);
}

// UTF16 → SHIFT-JIS
ULong utf16ToSjis(ULong c)
{
	return u16Sjis((UWord)c,U2STable,U2STableSize);
}

// SJIS→UTF8 1文字変換
ULong sjisToUtf8(ULong c)
{
	DBG2_printf1("[SJIS:%04lx→",c);
	switch (c&0xff00) {
		case 0x8000: // 1/2
		case 0xf000: // 上付き１／４角（片仮名）
		case 0xf100: // 上付き１／４角（平仮名）
		case 0xf200: // 下付き１／４角（片仮名）
		case 0xf300: // 下付き１／４角（平仮名）
			// 普通文字に変換
			c&=0x00ff;
			break;
		default:
			c=u16Sjis((UWord)c,S2UTable,S2UTableSize);	// SHIFT-JIS → UTF16
			DBG2_printf1("UTF16:%04lx→",c);
			// UTF-8では1～4バイトになり得る
			c=Utf16ToUtf8(c);							// UTF16 → UTF8
			break;
	}
	DBG2_printf1("UTF8:%04lx]\n",c);
	return (c);
}

// UTF8→SJIS 1文字変換
ULong utf8ToSjis(ULong c)
{
	DBG2_printf1("[UTF8:%04lx→",c);
	c=Utf8ToUtf16(c);							// UTF8  → UTF16
	DBG2_printf1("UTF16:%04lx→",c);
	c=u16Sjis((UWord)c,U2STable,U2STableSize);	// UTF16 → SHIFT-JIS
	DBG2_printf1("SJIS:%04lx]\n",c);
	return (c);
}

// 文字列のSHIFT-JIS → UTF8変換
// source <- bp
UByte *sjisToUtf8S(UByte *source,UByte *bp)
{
	nslog(@"sjisToUtf8S");
	ULong c;
	int keta=0;
	while ((c=getSjisNoX68(&bp))!=EOS) {
		if (c==TAB) {
			// TAB->SPACE変換
			// UTF8ではバイト数と幅が位置しないのでずれる可能性があるが、面倒なので無視
			int tb=TABWIDTH-(keta%4);
			while (tb-->0) {
				*source++=' ';
				keta++;
			}
		} else {
			keta=keta+(1+(c>=0x100));
			c=sjisToUtf8(c);
			source=storeUtf8(source,c);
		}
	}
	*source=EOS;
	return (source); // リターン値はEOSの位置
}

// 文字列のUTF8 → SHIFT-JIS変換
// source <- bp
UByte *utf8ToSjisS(UByte *source,UByte *bp)
{
	nslog(@"utf8ToSjisS");
	ULong c;
	int keta=0;
	while ((c=getUtf8(&bp))!=EOS) {
		if (c==TAB) {
			// TAB->SPACE変換
			// UTF8ではバイト数と幅が位置しないのでずれる可能性があるが、面倒なので無視
			int tb=TABWIDTH-(keta%4);
			while (tb-->0) {
				*source++=' ';
				keta++;
			}
		} else {
			keta=keta+(1+(c>=0x100));
			c=utf8ToSjis(c);
			source=storeSjis(source,c);
		}
	}
	*source=EOS;
	return (source);
}

//---------------------------------------------------------------------------------------------
// TABの数を数える
//---------------------------------------------------------------------------------------------
// UITextViewではTABを処理できないので、予めスペースに置き換える必要がある。
// 現在TABはTABWIDTH固定
// まず、ワーク確保のため、TABの数を数える

// あらかじめ"r"でopenしておくこと
int countTabsInFile(FILE *fp)
{
	int tabs=0;
	int c;
	while ((c=fgetc(fp))!=EOF) {
		if (c==0x1a) break; // EOT
		if (c==TAB) tabs++;
	}
	rewind(fp); // ファイル先頭に戻しておく
	nslog(@"タブの数=%d",tabs);
	return (tabs);
}

//---------------------------------------------------------------------------------------------
// ファイル変換関数
//---------------------------------------------------------------------------------------------

// 指定ファイルのSJIS/UTF8を判別する
// fLineNo : 行番号が付いているかどうか
// あらかじめ"r"でopenしておくこと
// SJISファイルはX68のソースしか想定していない
CODETYPE checkFileSjisUtf8(FILE *fp,int *fLineNo)
{
	CODETYPE cType=FILE_ASCII; // とりあえず
	*fLineNo=NO; // とりあえず
	
	int ffileTop=YES; // ファイル先頭の印
	int c;
	while ((c=fgetc(fp))!=EOF) {
		if (c==0x1a) break; // EOT
		if (c<=0x7f) {
			// ASCII範囲は識別に使えない
			// 行番号判定
			if (ffileTop) {
				nslog(@"ファイル先頭:c=$%02x",c);
				while (c==' '||c=='\t') { // 先頭にスペース/TABがある場合は読み飛ばす(V2.5)
					if ((c=fgetc(fp))==EOF) goto CF1;
				}
				if (isdigit(c)) {
					// ファイル先頭から数字がある場合は行番号ありと見なす
					// 行ではなくファイル先頭からdim={複数行}のデータ群がくることはない
					nslog(@"行番号あり");
					*fLineNo=YES;
				}
				nslog(*fLineNo? @"行番号あり":@"行番号なし");
				ffileTop=NO;
			}
			continue;
		}
		// c>=0x80
		// この先はSJISまたはUTF8でしか出てこない
		cType=FILE_SJIS; // とりあえず
		if (c>=0x80 && c<=0x9f) { // 漢字前半の第1バイトが出てきた
			// UTF8でこれらがいきなり出てくることはない
			break; // SJIS;判別できたらそこで終了
		}
		if (c>=0xa0 && c<=0xc1) { // 半角カタカナが出てきた
			break; // SJIS;判別できたらそこで終了
		}
		// c>=0xc2～:この先はUTF8の可能性あり
		// パターンはchars2Utf8()を参照
		int c2=fgetc(fp); // 次の1バイト
		if (c2==-1) break; // EOF
		if (c2<0x80||c2>0xbf) { // どの並びにおいてもUTF8に含まれない文字が出てきたとき
			break; // SJIS;判別できたらそこで終了
		}
		// ↑(1)は終了
		if (c>=0xe0 && c<=0xef) { // (2)
			if (c2<0x80 || c2>0xbf) {
				break; // SJIS;判別できたらそこで終了
			}
			cType=FILE_UTF8;
			break; // 判別できたらそこで終了
		}
		// (3)
		if (c>=0xf0 && c<=0xf3) { // 1/4角文字の可能性がある
			if (c2<0x80||c2>0xbf) {
				break; // SJIS;判別できたらそこで終了
			}
			// c2=80〜bf
			if (c2>=0xa0) { // 1/4角仮名の可能性あり
				int c3=fgetc(fp); // さらに次の1バイト
				if (c3==-1) break; // EOF
				if (c3>=0x80 && c3<=0xbf) {
					// 実際にはX68上のSJISでこの文字の組み合わせは出現しうるが、確率的にはほぼ0だといえるので
					cType=FILE_UTF8;
					break; // 判別できたらそこで終了
				}
				break; // SJIS;判別できたらそこで終了
			}
		}
		cType=FILE_UTF8;
		break; // 判別できたらそこで終了
	}
CF1:;
	// 最後まで読んだ
	#if 0	// ASCIIの可能性もあるので削除
	if (c==0x1a) {
		// EOTがあるときはSJISと見なす(Mac/Win上では基本的に付かないから)
		cType=FILE_SJIS;
	}
	#endif
	#ifdef CORE_DEBUG
	switch (cType) {
		case FILE_UTF8:
			DBG_printsn("UTF8 File");
			break;
		case FILE_SJIS:
			DBG_printsn("SJIS File");
			break;
		case FILE_ASCII:
			DBG_printsn("ASCII File");
			break;
	}
	#endif
	rewind(fp); // ファイル先頭に戻しておく
	return (cType);
}

// 文字コード変換しながらソースファイルを指定領域に読み込む
// TABも桁に合わせてスペースに変換する。ただし文字幅は固定とみなす（故にプロポーショナルフォントでは桁がずれて見える）。
// また、表示桁数も、ASCII文字は半角、ほかは全角とみなす。
// End of text(0x1a)を見つけた場合、そこで終了する。
// codeType : FILE_ASCII=無変換
//			  FILE_SJIS =SJIS→UTF8
//			  FILE_UTF8 =UTF8→SJIS
// fcutLineNo : 行番号を削除する；予め行番号があることを確認しておくこと
// crlf : !=0で、改行コードをそのコードに置き換える（CR/LF/CRLFのみ）
// あらかじめU2STableSize/S2UTableSizeを設定しておくこと
UByte *loadSourceFileWithCodeConvert(FILE *fp,CODETYPE codeType,UByte *source,int fcutLineNo,UByte crlf)
{
	printFunc();
	nslog(@"fcutLineNo=%d",fcutLineNo);
	nslog(@"crlf=$%x",crlf);
	
	DBG_printf1("codeType=%d\n",codeType);
	AllTableSize();
	UByte buff[MAX_SOUREC1LINE*2],*bp; // 念のため2倍のバッファーを用意しておく(落ちないように)
	int llen;
	do {
		// 1行分読み込む
		// V3.00までのCRファイル読み込み異常はfgets()がCRのみを改行とみなさないため。だからMAX_SOUREC1LINEで区切られていた
		// V3.01ではfgets2()にすることで解決した
		llen=fgets2(buff,MAX_SOUREC1LINE,fp); // fgets2()は改行コードを消してくる,line[EOF/EOT]ではllen=-1になる,EOTは入ってこない
		nslog(@"行(%d)=%s",llen,buff); // 文字コード変換前の行
		bp=buff;
		if (fcutLineNo) {
			// 行番号を削除
			// 先頭からの一連の数字群を消す
			nslog(@"行番号削除:%p～",bp);
			UByte c;
			while (c=*bp,c==' '||c=='\t') bp++; // 行番号の前にスペースが有る場合はそれも削除する(v2.5)
			while (c=*bp,isdigit(c)) bp++;
			if (c==' '||c==TAB) bp++; // 直後にスペースかTABがあるときはそれも飛ばす(字下げを維持するため、1つだけ)
			nslog(@"〜%p",bp-1);
			nslog(@"行=%@",@((char *)bp)); // 文字コード変換前の行
		}
		
		// 改行コードの再付加
		{
		int len=(int)bstrlen(bp);
		UByte *bp2=bp+len;
		*bp2++=crlf; // 改行コードを入れる
		*bp2=EOS;
		}
		
		// 文字コード変換処理
		int c,keta=0;
		switch (codeType) {
			case FILE_ASCII: // 無変換
				nslog(@"無変換");
				// ASCIIのみ、またはSJIS->SJIS,UTF8->UTF8も含む
				do {
					c=*bp++;
					if (c==TAB) {
						// TAB->SPACE変換
						// UTF8ではバイト数と幅が位置しないのでずれる可能性があるが、面倒なので無視
						int tb=TABWIDTH-(keta%TABWIDTH);
						while (tb-->0) {
							*source++=' ';
							keta++;
						}
					} else {
						*source++=c;
						keta++;
					}
				} while (c!=EOS);
				source--; // EOSを消す(下で入れるから)
				break;
			//
			case FILE_UTF8: // UTF8→SJIS
				source=utf8ToSjisS(source,bp);
				break;
			//
			case FILE_SJIS: // SJIS→UTF8
				source=sjisToUtf8S(source,bp);
				break;
		}
	} while(llen>=0);
	*source=EOS;
	return (source);
}

//---------------------------------------------------------------------------------------------
