/*	
 *	cliplibc.c
 *
 *	標準Ｃライブラリの補助
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015 Naoyuki Sawa
 *
 *	* Wed Jan 07 21:18:08 JST 2015 Naoyuki Sawa
 *	- 新規作成。
 *	- errnoを、clippce.c⇒cliplibc.cへ移動しました。
 *	- 「下位レベル関数/ダミー関数 : 標準Ｃライブラリ」の実装を、clippce.c⇒cliplibc.cへ移動しました。
 *	- 「EPSONライブラリの置き換え」の実装を、clippce.c⇒cliplibc.cへ移動しました。
 *	- 「標準Ｃライブラリの補助」の実装を、clippce.c⇒cliplibc.cへ移動しました。具体的には、clippce.hの2015/01/07の下記コメントに相当します:
 *	  │ - strdup(),strcasecmp(),strncasecmp()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  │   strcasecmp(),strncasecmp()は本当はstrings.hで宣言すべきなのですが、P/ECEにはstrings.hが無いのでinclude/string.hで宣言することにしました。
 *	  │ - strnlen(),strndup()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  │ - ismbblead(),ismbbtrail(),iscsym(),iscsymf(),isblank()の宣言をclippce.h⇒include/ctype.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  │   ismbblead(),ismbbtrail()は本当はmbctype.hで宣言すべきなのですが、P/ECEにはmbctype.hが無いのでinclude/ctype.hで宣言することにしました。
 *	  │ - strupr(),strlwr()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  │ - splitpath(),makepath()の宣言をclippce.h⇒include/stdlib.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  │ - ffs()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  │   ffs()は本当はstrings.hで宣言すべきなのですが、P/ECEにはstrings.hが無いのでinclude/string.hで宣言することにしました。
 *	  │ - fileno(),isatty()の宣言を、clippce.h⇒include/stdio.hへ移動しました。実装はclipio.cにあります。
 *	  │   isatty()は本当はio.hかunistd.hで宣言すべきなのですが、P/ECEにはio.hもunistd.hも無いのでinclude/stdio.hで宣言することにしました。
 *	* Wed Jan 07 21:29:51 JST 2015 Naoyuki Sawa
 *	- Visual C++ 6.0でビルドする時にエラーになる箇所を、条件コンパイルディレクティブで除外するようにしました。
 *	  今回の変更は、P/ECE開発環境でビルドする場合には、影響有りません。
 *	* Wed Mar 18 22:26:03 JST 2015 Naoyuki Sawa
 *	- ダミーのread()の実装を削除しました。
 *	  ダミーのread()はEPSONライブラリのsscanf()のために定義していた物で、だいぶん前にsscanf()を独自実装した時点で不要になっていた事にこれまで気付かず無駄にコード容量を消費していました。
 *	  ダミーのread()を削除した事により、コード容量が12バイト少なくなりました。
 *	* Tue Mar 24 21:38:35 JST 2015 Naoyuki Sawa
 *	- EPSONライブラリのbsearch()を置き換えました。
 *	  EPSONライブラリのbsearch()のままでも問題無いのですが、C言語で実装されていて生成されるコードに少し無駄が有ります。
 *	  アセンブラ化する事によって、68バイト⇒60バイトになり、8バイトのサイズ節約になりました。
 *	  アセンブラ化による高速化の効果は、比較関数の処理時間を含めなければ、約15%の高速化です。
 *	* Wed Apr 29 14:30:43 JST 2015 Naoyuki Sawa
 *	- memccpy(),mempcpy(),strncpy(),stpncpy(),strcpy(),stpcpy()を追加しました。
 *	  宣言は、include/string.hに追加しました。
 *	- strncpy()とstrcpy()は、P/ECE開発環境のEPSONライブラリにも含まれていますが、自分で再実装しました。
 *	  stpncpy()とstpcpy()と共通化できる部分が多く、まとめて実装する方がコードサイズ節約できるからです。
 *	* Sun May 31 13:54:55 JST 2015 Naoyuki Sawa
 *	- strcpy()とstrcat()はVisual C++ 6.0でReleaseビルドすると「error C2169: 組み込み関数は定義できません。」になるので除外しました。
 *	* Sat Jul 25 17:20:54 JST 2015 Naoyuki Sawa
 *	- log2()を追加しました。宣言は、include/math.h に有ります。log2()は、C99で追加された関数です。「Lua 5.3.1」が、使用しています。
 *	  EPSONライブラリにも、Visual C++ 6.0にも、log2()は含まれていません。
 */
#include "clip.h"

/*****************************************************************************
 *	グローバル変数
 *****************************************************************************/

#ifdef  PIECE
/* S1C33 Family Cコンパイラパッケージでは、errnoはアプリケーション側で定義する必要があります。
 * [S5U1C33000C_J.pdf p.140] */
int errno;
#endif//PIECE

/*****************************************************************************
 *	下位レベル関数/ダミー関数 : 標準Ｃライブラリ
 *****************************************************************************/

/* 下位レベル関数：	標準ライブラリ内部から呼ばれるもの。
 *			アプリケーションから直接使うことはありません。
 * ダミー関数：		標準ライブラリのヘッダで宣言されているが、
 *			実装されていない（ライブラリ内に存在しない）。
 * 従って、これらの関数を clippce.h で宣言する必要はありません。
 */

#ifdef  PIECE
/* exit(),abort()から呼ばれます。 */
void
_exit()
{
	pceAppReqExit(0); /* 終了要求を発行して、 */
	yield();          /* システムに制御を返す */
	/* もう、yield()は制御を返しません。      */
}
#endif//PIECE

//{{2015/03/18削除:ダミーのread()の実装を削除しました。ダミーのread()はEPSONライブラリのsscanf()のために定義していた物で、だいぶん前にsscanf()を独自実装した時点で不要になっていた事にこれまで気付かず無駄にコード容量を消費していました。ダミーのread()を削除した事により、コード容量が12バイト少なくなりました。
//#ifdef  PIECE
///* * EPSONライブラリの標準入出力用下位レベル関数です。
// *   EPSONライブラリのsscanf()を使うために定義しました。
// * - sscanf()はread()を使っていませんが、sscanf()が呼び出す_doscan()がscanf()と共用になっていて、
// *   _doscan()がscanf()から呼ばれた場合にread()を使っているため、read()のシンボル解決が要求されてしまいます。
// *   リンクエラーを回避するため、ダミーのread()関数を定義することにしました。
// * - sscanf()を使うだけならread()が呼ばれることはありません。
// */
//int
//read(int fd, char* buf, int nbytes)
//{
//	DIE();
//}
//#endif//PIECE
//}}2015/03/18削除:ダミーのread()の実装を削除しました。ダミーのread()はEPSONライブラリのsscanf()のために定義していた物で、だいぶん前にsscanf()を独自実装した時点で不要になっていた事にこれまで気付かず無駄にコード容量を消費していました。ダミーのread()を削除した事により、コード容量が12バイト少なくなりました。

/*****************************************************************************
 *	EPSONライブラリの置き換え
 *****************************************************************************/

#ifdef  PIECE
/* * Thu Jun 17 05:14:00 JST 2004 Naoyuki Sawa 追記
 * - メモリ管理を、EPSONライブラリmalloc()から、P/ECE API pceHeapAlloc()に変更しました。
 *   本モジュールにてmalloc()/calloc()/realloc()/free()を再定義し、EPSONライブラリ内の同名関数をオーバーライドします。
 */
void*
malloc(size_t size)
{
	return pceHeapAlloc(size);
}
void
free(void* ptr)
{
	/* pceHeapFree()はfree()と違ってNULLポインタを無視せず、開放しようとして失敗するので、まず明示的に検査します。
	 * メモリブロックの開放に失敗した場合、たぶんアプリケーションプログラムのバグなので、DIE()することにしました。
	 */
	int retval;

	if(ptr) {
		retval = pceHeapFree(ptr);
		if(retval != 0) DIE();
	}
}
void*
realloc(void* oldptr, size_t newsize)
{
	/* pceHeapRealloc()とrealloc()は、かなり仕様が異なります。
	 * pceHeapRealloc()はメモリブロックを移動させません。
	 * その場所のまま、サイズ拡張または縮小を行おうとします。(縮小は必ず成功するはずです)
	 * realloc()の場合、その場所でサイズ拡張に失敗した場合、別のメモリブロックを確保して元の内容をコピーしますが、
	 * pceHeapRealloc()はこの動作を行わず、ただちに失敗を返します。
	 * →* Thu Jun 17 07:27:00 JST 2004 Naoyuki Sawa 追記
	 * →  PieceSystem 1.20 現在のpceHeapRealloc()にはバグがあることがわかりました。
	 * →  詳しくは、後述のコメントを参照してください。
	 * →* Mon Mar 30 19:21:12 JST 2009 Naoyuki Sawa
	 * →- PieceSystem1.20現在のpceHeapRealloc()バグ修正パッチを適用しました。
	 * →  詳しくは、後述のコメントを参照してください。
	 */
	int retval;
	int oldsize;
	void* newptr;
	HEAPMEM* phm;

	/* * realloc(NULL, newsize)は、malloc(newsize)と等価です。(realloc仕様)
	 *   realloc(oldptr, 0)は、free(oldptr)と等価です。(realloc仕様)
	 * * realloc(NULL, 0)の動作は、標準Cライブラリ仕様では未定義のようです。(※要確認)
	 *   2004/06/17現在の実装は、{ free(NULL); return NULL; } の動作としてあります。
	 */
	if(!newsize) {
		free(oldptr);
		return NULL;
	}
	if(!oldptr) {
		return malloc(newsize);
	}

	///* まず、その場でサイズ変更してみます。
	// * 縮小の場合は、必ず成功するはずです。
	// */
	//retval = pceHeapRealloc(oldptr, newsize);
	//if(retval == 0) return oldptr;
	//→* Thu Jun 17 07:27:00 JST 2004 Naoyuki Sawa
	//→  PieceSystem1.20現在のpceHeapRealloc()にはバグがあります。
	//→  /usr/PIECE/system/pcekn/heapman.c 195行目の
	//→	oldsize = (unsigned long)phm->chain - (unsigned long)phm;
	//→  は間違いで、正しくは
	//→	oldsize = (unsigned long)phm->chain - ((unsigned long)phm + sizeof(HEAPMEM));
	//→  としなければいけないはずです。
	//→  pceHeapRealloc()を呼ぶと、ヒープが破壊されたり、アドレス不整例外が発生したりします。
	//→  仕方が無いので、常にメモリブロックの再割り当てを行うことにしました。
	//→  サイズ縮小時は旧いメモリブロックをそのまま使うという手段もありますが、
	//→  不要に大きなメモリブロックがいつまでも残ってしまうことを避けるために、
	//→  常に要求されたサイズのメモリブロックを再割り当てすることにしました。
	//----------------------------------------------------------------------------------------
	// * Mon Mar 30 19:21:12 JST 2009 Naoyuki Sawa
	// - PieceSystem1.20のpceHeapRealloc()バグに対する、上述の修正方法は誤りでした。
	//   上述の修正方法では、元々不正だったHeapを増やすバグが治る代わりに、元々正しかったHeapを減らす処理が不正になってしまいます。
	//   正しい修正方法は、/usr/PIECE/system/pcekn/heapman.cの195行目は変更せず、202行目と203行目の間に次の一行を追加することです。
	//     if ( phm2->owner ) return 2; // 失敗(後ろに空きがない)
	//     if(n < sizeof(HEAPMEM)) n = sizeof(HEAPMEM); // ←この一行を追加!!
	//     n2 = (unsigned long)phm2->chain - (unsigned long)phm2;
	// - PieceSystem1.20における、pceHeapRealloc()のバグを再現する方法は、以下のとおりです。
	//     p = pceHeapAlloc(4);
	//     pceHeapRealloc(p, 8); // ←ここでアドレス不正例外が発生します。
	//   バグの原因は、204行目のAllocHEAPMEM()呼び出しにおいて、第二引数nに後続の空きブロックから取り込むバイト数を指定しています。
	//   AllocHEAPMEM()の第二引数には、HEAPMEM構造体を含めた割り当てサイズを指定するのですが、上記のバグ再現コードのように、
	//   4バイトだけ拡張する場合、HEAPMEM構造体のサイズ(8バイト)未満の新規メモリブロックを作成しようとしてしまいます。
	//   AllocHEAPMEM()の中で、phm1の4バイト後にphm2を作成してしまい、phm1のchainフィールドを破壊してしまいます。
	//   この問題を修正するには、拡張するバイト数がHEAPMEM構造体のサイズ(8バイト)未満の場合は、8バイトとすることです。
	// - 以上の修正方法によって、pceHeapRealloc()が正しく動作するようになります。
	//   なお、Heapを減らす処理(208行目)は元々正しいので、前述の修正方法ならばHeapを減らす処理には影響を与えません。
	// - 以上を踏まえて、本ライブラリの初期化処理に、pceHeapRealloc()の修正パッチを組み込むことにしました。
	//   具体的には、pceAppInit()とpceAppExit()に追加した、bugfix_pceHeapRealloc()呼び出しを参照してください。
	//   pceHeapRealloc()修正パッチに伴い、上で"Thu Jun 17 07:27:00 JST 2004"にコメントアウトしていたコードを復元しました。
	//   これまでは、realloc()は常にメモリを移動していましたが、今後は、pceHeapRealloc()が成功すればメモリを移動しなくなりました。
	retval = pceHeapRealloc(oldptr, newsize);
	if(retval == 0) return oldptr;

	/* 新しいメモリブロックを確保します。
	 * 新しいメモリブロックが確保できなかった場合は、元のメモリブロックを開放せずに、NULLを返します。(relloc仕様)
	 */
	newptr = malloc(newsize);
	if(!newptr) return NULL;

	/* 元のメモリブロックの内容を、新しいメモリブロックにコピーします。
	 *
	 *	|              |
	 *	+--------------+ --- phm = oldptr - sizeof(HEAPMEM)
	 *	|    HEAPMEM   |
	 *	+--------------+ --- oldptr
	 *	|              |  |
	 *	| memory block |  |  oldsize = phm->chain - oldptr
	 *	|              |  |
	 *	+--------------+ --- phm->chain
	 *	| next HEAPMEM |
	 *	+--------------+
	 *	|              |
	 */
	phm = (HEAPMEM*)((unsigned char*)oldptr - sizeof(HEAPMEM));
	if(phm->mark != HEAPMEMMK) DIE();
	oldsize = (unsigned char*)phm->chain - (unsigned char*)oldptr;
	memcpy(newptr, oldptr, oldsize < newsize ? oldsize : newsize);

	/* 元のメモリブロックを開放します。 */
	free(oldptr);

	return newptr;
}
#endif//PIECE

#ifdef  PIECE
/* S1C33 Family Cコンパイラパッケージのcalloc()には問題があります。
 * calloc(～, 1)の形式で使ったときに、必要量の4倍ものメモリを確保しようとします。
 * おそらく、次のような実装になっているものと思われます。
 * 	void* calloc(size_t num, size_t size) {
 * 		int n;
 * 		void* p;
 * 		size = size + 3 & ~3;		// 要素サイズを4バイト単位に切り上げ
 * 		n = num * size;			// 割り当てバイト数を計算
 * 		p = malloc(n);			// 割り当てを行ってみる
 * 		if(p != NULL) memset(p, 0, n);	// 成功ならゼロクリア
 * 		return p;
 * 	}
 * これでは無駄が多すぎます。
 * 自前でcalloc()を用意し、ライブラリ内のcalloc()を置き換えることにします。
 * 参考文献：P.J.プラウガー著「標準Ｃライブラリ ANSI/ISO/JIS C規格」（トッパン）
 * 　　　　　初版 432ページ 図13.30 calloc.c
 *
 * * Thu Jun 17 05:14:00 JST 2004 Naoyuki Sawa 追記
 * - メモリ管理を、EPSONライブラリmalloc()から、P/ECE API pceHeapAlloc()に変更しました。
 *   EPSONライブラリ内のcalloc()をオーバーライドするために、引き続きここでcalloc()を定義しておきます。
 */
void*
calloc(size_t num, size_t size)
{
	size_t n = num * size;
	void* p = malloc(n);
	if(p) memset(p, 0, n);
	return p;
}
#endif//PIECE

#ifdef  PIECE
/* S1C33 Family Cコンパイラパッケージのstrtok()は完全にバグってます。
 * s1に与えた文字列の終端の'\0'を突き抜けて走査してしまいます。
 * 例えば次のコードを実行すると：
 *	char* s1 = "a/b/c\0d/e/f";
 *	char* p;
 *	p = strtok(s1, "/");
 *	while(p != NULL) {
 *		pceFontPrintf("(%s)", p);
 *		p = strtok(NULL, "/");
 *	}
 * 「(a)(b)(c)」ではなく、「(a)(b)(c)(d)(e)(f)」と表示されてしまいます。
 * 文字列s1が「c」の後の「\0」で終わっているのを認識できていません。
 * この例では「f」で止まっていますが、たまたま「f」の後ろに「\0\0...」と
 * ヌル文字が連続していただけで、そうでなっていなければ永遠に終わりません。
 * （S1C33のstrtok()は、「\0」が二個以上連続していないと終わらないようです。）
 * これはさすがに論外です。
 * 自前でstrtok()を用意し、ライブラリ内のstrtok()を置き換えることにします。
 * 参考文献：P.J.プラウガー著「標準Ｃライブラリ ANSI/ISO/JIS C規格」（トッパン）
 * 　　　　　初版 467ページ 図14.20 strtok.c
 */
char*
strtok(char* s1, const char* s2)
{ /* find next token in s1[] delimited by s2[] */
	static char* ssave = ""; /* for safety */
	char *sbegin, *send;

	sbegin = s1 ? s1 : ssave;
	sbegin += strspn(sbegin, s2);
	if(*sbegin == '\0') { /* end of scan */
		ssave = ""; /* for safety */
		return NULL;
	}

	send = sbegin + strcspn(sbegin, s2);
	if(*send != '\0') *send++ = '\0';
	ssave = send;
	return sbegin;
}
#endif//PIECE

/* * Tue Jul 11 17:50:40 JST 2006 Naoyuki Sawa
 * - P/ECE開発環境付属のstrstr()には不具合があり、誤った結果を返します。
 *   不具合を再現するプログラム例を、以下に示します。
 *
 *	char dst1[] = { 'a', '\0', 'a', 'b', '\0' }; // 比較先文字列1
 *	char dst2[] = {       'a', 'a', 'b', '\0' }; // 比較先文字列2
 *	char src [] = {            'a', 'b', '\0' }; // 比較元文字列
 *	char* p1 = dstdst(dst1, "ab"); // NULLを返すべきだが、dst1[2]へのポインタを返してしまう
 *	char* p2 = dstdst(dst2, "ab"); // dst2[1]へのポインタを返すべきだが、NULLを返してしまう
 *
 *    誤りのパターンは二種類あります。以下、それぞれについて説明します。
 *
 *    1. マッチしてはいけないのにマッチしてしまう誤りの例:
 *
 *	dst1[]は、文字列として見ると、一文字目の"a"だけで終わっています。
 *	従って、
 *		strstr(dst1, src);
 *	は、
 *		strstr("a", "ab");
 *	と等価であり、結果はNULLになるはずです。
 *	しかし、P/ECE開発環境付属のstrstr()は誤って'\0'を突き抜け、
 *	三文字目～の"ab"にマッチして、三文字目の'a'へのポインタを返してしまいます。
 *
 *    2. マッチしなければいけないのにマッチしない誤りの例
 *
 *	dst2[]は、文字列として見ると、"aab"であり、二文字目～に"ab"を含んでいます。
 *	従って、
 *		strstr(dst2, src);
 *	は、二文字目の'a'へのポインタを返すはずです。
 *	しかし、P/ECE開発環境付属のstrstr()は誤ってNULLを返してしまいます。
 *	P/ECEのstrstr()は、まず、dst2[0～1]とsrc[0～1]の比較を行い、マッチしていないと判断した後、
 *	dst2[]側の走査位置をdst[1]に戻すのを忘れて、dst[2]から比較継続してしまっているみたいです。
 *
 * - P/ECE開発環境付属のstrstr()の不具合を回避するため、自前でstrstr()を用意しました。
 *   速度が要求される場面でstrstr()を使うことは無いと思うので、ごく単純な実装としました。
 *   ※要確認: strstr()の正式な仕様は、s1,s2が必ずヌル終端されていることを前提として良いのでしょうか?	┐
 *   もし、s1のどこかにs2が存在することが確実な場合に、s1がヌル終端されていないことを許す仕様ならば、	│2014/10/12追記
 *   以下の実装では正しく動作しません。(最初に行っているstrlen()が、どこまで行くか予測できないから。)	│strstr()がs1がヌル終端されていなくても動作するように修正しました。
 *   strstr()の正式な仕様を確認する必要があります。							┘
 */
//{{2014/10/12変更:strstr()がs1がヌル終端されていなくても動作するように修正しました。
//char*
//strstr(const char* s1, const char* s2)
//{
//	int n1 = strlen(s1);
//	int n2 = strlen(s2);
//
//	n1 -= n2;
//	while(n1 >= 0) {
//		if(!memcmp(s1, s2, n2)) {
//			return (char*)s1;
//		}
//		s1++;
//		n1--;
//	}
//	return NULL;
//}
//↓2014/10/12変更:strstr()がs1がヌル終端されていなくても動作するように修正しました。
/* * Sun Oct 12 18:49:43 JST 2014 Naoyuki Sawa
 * - strstr()がs1がヌル終端されていなくても動作するように修正しました。s2はヌル終端されていなければなりません。
 * - strcasestr()を追加しました。宣言はinclude/string.hに追加しました。strcasestr()はGNU拡張です。
 */
#ifndef PIECE
static char* strstr_sub(const char* s1, const char* s2, int (*fn)(const char*, const char*, size_t));
char* strstr(const char* s1, const char* s2) {
	return strstr_sub(s1, s2, strncmp);
}
char* strcasestr(const char* s1, const char* s2) {
	return strstr_sub(s1, s2, strncasecmp);
}
static char* strstr_sub(const char* s1, const char* s2, int (*fn)(const char*, const char*, size_t)) {
	/* 部分文字列の文字数を求める。(s2="")でも構わない。 */
	int n = strlen(s2);
	/* 文字列の先頭から検索を開始する。
	 * - (s1="")の場合も、一回目のループは実行する。
	 *   (s2="")の場合は、s1の内容にかかわらず((s1="")であってもなくても)常に一致するからです。 */
	do {
		/* 文字列の現在位置から、部分文字列の文字数分比較を行い、一致したら現在位置を返す。
		 * - (s2="")だった場合、s1の内容にかかわらず((s1="")であってもなくても)、一致する。
		 * - (s1="")だった場合、(s2="")でなければ、一致しない。 */
		if(!(*fn)(s1, s2, n)) { return (char*)s1; }
	/* 文字列の終端でなければ、位置を次へ進める。
	 * - (s1="")だった場合は、一回目で抜けることになる。 */
	} while(*s1++);
	/* 文字列の終端における比較でも一致しなければ、NULLを返す。 */
	return NULL;
}
#else /*PIECE*/
char* strstr(const char* s1, const char* s2);
char* strcasestr(const char* s1, const char* s2);
asm("
		.code
		.align		1
		.global		strstr
		.global		strcasestr
strstr:
		xld.w		%r14, strncmp			;//%r14 := fn = strncmp
		jp		strstr_sub
strcasestr:
		xld.w		%r14, strncasecmp		;//%r14 := fn = strncasecmp
strstr_sub:
		pushn		%r3
		ld.w		%r0, %r12			;//%r0  := s1
		ld.w		%r1, %r13			;//%r1  := s2
		ld.w		%r2, %r14			;//%r2  := fn
		xcall.d		strlen				;//%r10 := n = strlen(s2)
		ld.w		%r12, %r1			;//%r12 :=            s2		*delay*
		ld.w		%r3, %r10			;//%r3  := n
strstr_sub_L10:							;//do {
		ld.w		%r12, %r0			;//%r12 :=                s1
		ld.w		%r13, %r1			;//%r13 :=                   s2
		call.d		%r2				;//%r10 := retval = (*fn)(s1,s2,n)
		ld.w		%r14, %r3			;//%r14 :=                      n	*delay*
		cmp		%r10, 0				;//if(!retval) { return s1 }
		jreq.d		strstr_sub_L20
		ld.w		%r10, %r0			;//%r10 :=              s1		*delay*
		ld.b		%r10, [%r0]+			;//%r10 := c = *s1++
		cmp		%r10, 0				;//} while(c)
		jrne		strstr_sub_L10
strstr_sub_L20:
		popn		%r3
		ret
");
#endif/*PIECE*/
//}}2014/10/12変更:strstr()がs1がヌル終端されていなくても動作するように修正しました。

#ifndef _MSC_VER	//Visual C++ 6.0ではリリースビルド時に「error C2169: 'pow' : 組み込み関数は定義できません。」になるため除外した。
/* S1C33 Family C Compiler Package の pow() には不具合があり、間違った値を返すことがあります。
 * 例えば pow(1.25, 1.0) の結果が 0.0 になることがあります。まだ原因は究明できていません。
 * pow(1.0～1.5, 0.0以外) あたりが危ないようですが、微妙なコーディングの違いによって発症しないこともあります。
 * 現在、二種類の回避方法が発見されています。
 * ・pow()を呼ぶだけのラッピング関数pow_wrap()を用意し、常にpow_wrap()を経由してpow()を呼び出す。
 *   確かに回避できるのですが、なぜこれだけで回避できるのか全くわからないのが不安なところです。
 * ・pow()をexp()とlog()に展開し、pow()を使わないようにします。
 *   もしも不具合の原因がpow()単体の問題であったならば、この方法で確実に回避できるはずです。
 *   ただし、算術関数の呼び出しが増えるため、プログラムが遅くなってしまう欠点があります。
 * いずれにせよ、もともとの原因がわかっていないので、どちらの方法でも確実に回避できるとは言い切れません。
 */
//double
//pow(double x, double y)
//{
//	return exp(log(x) * y);
//}
//---------------------------------------------------------------------------
//↓* Sun Apr 22 21:28:18 JST 2007 Naoyuki Sawa
//↓- 上の実装では、xが負の場合に対応できていなかったので、以下のように修正しました。
//↓  以下の処理手順は、前述のように不具合のあるEPSONライブラリ版pow()とほぼ同じものですが、なぜか不具合を回避できるようです。
//↓  EPSONライブラリ版pow()の不具合は、処理手順そのものではなく、精度のために複雑な処理をしている部分に原因があるみたいです。
//↓- 不要なexp()やlog()が毎回リンクされてしまうのを避けるために、pow()を別モジュールに分離することも検討しましたが、
//↓  clipprnt.cがpow()を使っていて、結果的にほとんどのアプリケーションにリンク必要なので、分離する必要は無いと判断しました。
double
pow(double x, double y)
{
	double z;

	if(x > 0.0) {
		/* xが正ならば、そのまま計算します。
		 */
		z = exp(y * log(x));
	} else if(x < 0.0) {
		/* xが負ならば...
		 * 1. yが整数でなければ、エラーです。(負のn乗根を含むため)
		 * 2. xを正にして、計算します。
		 * 3. yが奇数ならば、結果を負にします。
		 */
		if((int)y != y) {
			DIE();
		}
		x = -x;
		z = exp(y * log(x));
		if((int)y & 1) {
			z = -z;
		}
	} else { /* (x == 0.0) */
		/* xが零ならば...
		 * 1. yが正ならば、結果は0.0です。
		 * 2. yが負ならば、エラーです。(ゼロ除算になるため)
		 * 3. yが零ならば、結果は1.0です。
		 */
		if(y > 0.0) {
			z = 0.0;
		} else if(y < 0.0) {
			DIE();
		} else { /* (y == 0.0) */
			z = 1.0;
		}
	}

	return z;
}
#endif//_MSC_VER	//Visual C++ 6.0ではリリースビルド時に「error C2169: 'pow' : 組み込み関数は定義できません。」になるため除外した。

/* * Thu Oct 25 14:45:01 JST 2007 Naoyuki Sawa
 * - Aquaplus版よりも高速な、memcpy()を作成しました。
 * - P/ECE開発環境のmemcpy()は、EPSON版よりも高速な、Aquaplus版を使っています。
 *   今回、Aquaplus版を基にして、もっと高速で省サイズな、CLiP版を作成しました。
 * - コピーのループを工夫して、遅延スロットを最大限に活用しました。
 *   高速化の効果は、以下のとおりです。(TURBO=-1で計測)
 *	コピー処理 (×100回)               | Aquaplus版 | CLiP版    | 高速化
 *	-----------------------------------+------------+-----------+-------
 *	memcpy(0xc00000,0xd00000,0x100000) | 21140[ms]  | 18915[ms] | 約10%
 *	memcpy(0xc00002,0xd00002,0x100000) | 33379[ms]  | 28929[ms] | 約13%
 *	memcpy(0xc00001,0xd00001,0x100000) | 66757[ms]  | 57856[ms] | 約13%
 * - 終了判断を、memcpy_BYTEの一箇所にまとめて、コードサイズを削減しました。
 *   コードサイズ削減の効果は、以下のとおりです。
 *	Aquaplus版=68[byte] → CLiP版=64[byte]
 * * Tue Jan 08 14:58:19 JST 2008 Naoyuki Sawa
 * - memcpy()を、ベクタ領域のFRAMに転送して実行するために、clipidiv.sへ移動しました。
 *   ベクタ領域に収まるように、並べ替えを行いましたが、コード内容は変更していません。
 */
//{{2008/01/08:削除(clipidiv.sへ移動)
//asm("
//	.code
//	.align	1
//	.global	memcpy
//memcpy:
//	;// %r12 := dst
//	;// %r13 := src
//	;// %r14 := cnt
//	cmp	%r14, 3		; if(cnt<=3) memcpy_BYTE
//	jrule.d	memcpy_BYTE
//	ld.w	%r10, %r12	; %r10 := dst (戻り値)			*delay*
//	ld.w	%r9, %r12	; %r9  := dst
//	or	%r9, %r13	; %r9  := dst|src
//	and	%r9, 3		; %r9  := (dst|src)&3
//	jreq	memcpy_WORD	; if(!((dst|src)&3)) memcpy_WORD
//	and	%r9, 1		; %r9  := (dst|src)&1
//	jreq	memcpy_HALF	; if(!((dst|src)&1)) memcpy_HALF
//	;-----------------------;
//memcpy_BYTE:
//	sub	%r14, 1		; %r14 := (cnt-1) ------+
//	jrult	memcpy_RET	; if((cnt-1)<0) return  |
//	 ld.b	%r9, [%r13]+	;   byte = *src++       |
//	 ld.b	[%r12]+, %r9	;   *dst++ = byte       |
//	jrugt.d	-2		; while((cnt-1)>0) <----+ フラグ影響
//	sub	%r14, 1		; %r14 := (cnt-1) -= 1 -+		*delay*
//memcpy_RET:
//	ret
//	;-----------------------;
//memcpy_HALF:
//	xsub	%r15, %r14, 3	; %r15 := (cnt-3) ------+
//	 ld.h	%r9, [%r13]+	;   half = *src++       |
//	 ld.h	[%r12]+, %r9	;   *dst++ = half       |
//	jrugt.d	-2		; while((cnt-3)>0) <----+ フラグ影響
//	sub	%r15, 2		; %r15 := (cnt-3) -= 2 -+		*delay*
//	jp.d	memcpy_BYTE
//	and	%r14, 1		; %r14 := cnt &= 1			*delay*
//	;-----------------------;
//memcpy_WORD:
//	xsub	%r15, %r14, 7	; %r15 := (cnt-7) ------+
//	 ld.w	%r9, [%r13]+	;   word = *src++       |
//	 ld.w	[%r12]+, %r9	;   *dst++ = word       |
//	jrugt.d	-2		; while((cnt-7)>0) <----+ フラグ影響
//	sub	%r15, 4		; %r15 := (cnt-7) -= 4 -+		*delay*
//	jp.d	memcpy_BYTE
//	and	%r14, 3		; %r14 := cnt &= 3			*delay*
//");
//}}2008/01/08:削除(clipidiv.sへ移動)

/* * Thu Oct 25 14:45:01 JST 2007 Naoyuki Sawa
 * - Aquaplus版よりも高速な、memset()を作成しました。
 * - P/ECE開発環境のmemset()は、EPSON版よりも高速な、Aquaplus版を使っています。
 *   今回、Aquaplus版を基にして、もっと高速で省サイズな、CLiP版を作成しました。
 * - フィルのループを工夫して、遅延スロットを最大限に活用しました。
 *   高速化の効果は、以下のとおりです。(TURBO=-1で計測)
 *	フィル処理 (×100回)        | Aquaplus版 | CLiP版    | 高速化
 *	----------------------------+------------+-----------+-------
 *	memset(0xc00000,0,0x100000) | 13352[ms]  | 11127[ms] | 約16%
 *	memset(0xc00002,0,0x100000) | 22252[ms]  | 17802[ms] | 約20%
 *	memset(0xc00001,0,0x100000) | 44505[ms]  | 35604[ms] | 約20%
 * - memset_WORDとmemset_HALFのための、フィル値拡張処理を一部共通化、および、
 *   終了判断を、memset_BYTEの一箇所にまとめて、コードサイズを削減しました。
 *   コードサイズ削減の効果は、以下のとおりです。
 *	Aquaplus版=80[byte] → CLiP版=68[byte]
 * * Tue Jan 08 14:58:19 JST 2008 Naoyuki Sawa
 * - memset()を、ベクタ領域のFRAMに転送して実行するために、clipidiv.sへ移動しました。
 *   ベクタ領域に収まるように、並べ替えを行いましたが、コード内容は変更していません。
 */
//{{2008/01/08:削除(clipidiv.sへ移動)
//asm("
//	.code
//	.align	1
//	.global	memset
//memset:
//	;// %r12 := dst
//	;// %r13 := v,?,?,?
//	;// %r14 := cnt
//	cmp	%r14, 3		; if(cnt<=3) memset_BYTE
//	jrule.d	memset_BYTE
//	ld.w	%r10, %r12	; %r10 := dst (戻り値)			*delay*
//	xand	%r9, %r12, 1	; %r9  := dst&1
//	jrne	memset_BYTE	; if(dst&1) memset_BYTE
//	ld.ub	%r15, %r13	; %r15 := v,0,0,0
//	sll	%r13, 8		; %r13 := 0,v,?,?
//;//	or	%r13, %r15	; %r13 := v,v,?,?-------+
//	xand	%r9, %r12, 2	; %r9  := dst&2         |
//	jrne.d	memset_HALF	; if(dst&2) memset_HALF |
//	or	%r13, %r15	; <---------------------+		*delay*
//	ld.uh	%r13, %r13	; %r13 := v,v,0,0
//	swap	%r15, %r13	; %r15 := 0,0,v,v
//	or	%r13, %r15	; %r13 := v,v,v,v
//	;-----------------------;
//memset_WORD:
//	xsub	%r15, %r14, 7	; %r15 := (cnt-7) ------+
//	 ld.w	[%r12]+, %r13	;   *dst++ = v,v,v,v    |
//	jrugt.d	-1		; while((cnt-7)>0) <----+ フラグ影響
//	sub	%r15, 4		; %r15 := (cnt-7) -= 4 -+		*delay*
//	jp.d	memset_BYTE
//	and	%r14, 3		; %r14 := cnt &= 3			*delay*
//	;-----------------------;
//memset_HALF:
//	xsub	%r15, %r14, 3	; %r15 := (cnt-3) ------+
//	 ld.h	[%r12]+, %r13	;   *dst++ = v,v        |
//	jrugt.d	-1		; while((cnt-3)>0) <----+ フラグ影響
//	sub	%r15, 2		; %r15 := (cnt-3) -= 2 -+		*delay*
//	and	%r14, 1		; %r14 := cnt &= 1
//	;-----------------------;
//memset_BYTE:
//	sub	%r14, 1		; %r14 := (cnt-1) ------+
//	jrult	memset_RET	; if((cnt-1)<0) return  |
//	 ld.b	[%r12]+, %r13	;   *dst++ = v          |
//	jrugt.d	-1		; while((cnt-1)>0) <----+ フラグ影響
//	sub	%r14, 1		; %r14 := (cnt-1) -= 1 -+		*delay*
//memset_RET:
//	ret
//");
//}}2008/01/08:削除(clipidiv.sへ移動)

#ifdef  PIECE
;// * Sun Mar 11 22:22:46 JST 2012 Naoyuki Sawa
;// - EPSONライブラリのmemmoveを置き換えました。
;// - EPSONライブラリのmemmoveも正しく動作はしますが、以下の問題があります。
;//   ・memcpyを利用できる場合は、memcpyを利用する方が効率が良い。
;//	memcpyの方が、ワード単位コピーで最適化されており、高速だからである。
;//	しかし、EPSONライブラリのmemmoveは、内部でバイト単位コピーを行ってしまい、低速である。
;//   ・前方コピーの場合は、常にmemcpyを利用できる。
;//	従って、memmove内部に、前方コピーの実装を含める必要は無い。
;//	しかし、EPSONライブラリのmemmoveは、前方コピーを含んでしまっており、容量の無駄である。
;//   ・EPSONライブラリのmemmoveは、後方コピーのループ終端判断を、ループの先頭で行っています。
;//	ループ終端判断を、ループの末尾で行う方が、高速化できます。
;// - 今回は、上記三点を改善した、memmoveを実装しました。
;//
;//-----------------------------------------------------------------------------------------------------------------------------
;//
;//	((dest <= src) || (dest >= src+count)) が成立する場合、memcpyを利用できる
;//
;//		○memcpyを利用できる
;//
;//			dest
;//			├───────────┐
;//			└───────────┘	┌───────────┐
;//							├───────────┤
;//							src			src+count
;//
;//		○memcpyを利用できる
;//
;//					dest
;//					├───────────┐
;//					└───────┬───┴───────┐
;//							├───────────┤
;//							src			src+count
;//
;//		○memcpyを利用できる
;//
;//							dest			
;//							├───────────┐
;//							├───────────┤
;//							├───────────┤
;//							src			src+count
;//
;//		×memcpyを利用できない
;//
;//									dest
;//									├───────────┐
;//							┌───────┴───┬───────┘
;//							├───────────┤
;//							src			src+count
;//
;//		○memcpyを利用できる
;//
;//										dest
;//										├───────────┐
;//							┌───────────┼───────────┘
;//							├───────────┤
;//							src			src+count
;//
;//		○memcpyを利用できる
;//
;//											dest
;//											├───────────┐
;//							┌───────────┐	└───────────┘
;//							├───────────┤
;//							src			src+count
;//
;//-----------------------------------------------------------------------------------------------------------------------------
;//
;//	(count == 0) が成立する場合も、memcpyを利用できる。その場合、
;//		((dest <= src) || (dest >= src+count))　⇒　((dest <= src) || (dest >= src))　⇒　常に成立
;//	となるので、明示的に判断する必要は無い。
;//
;//		○memcpyを利用できる
;//
;//			dest
;//			│
;//			│				
;//							│
;//							│
;//							src(=src+count)
;//
;//		○memcpyを利用できる
;//
;//							dest
;//							│
;//							│
;//							│
;//							│
;//							src(=src+count)
;//
;//		○memcpyを利用できる
;//
;//											dest
;//											│
;//											│
;//							│
;//							│
;//							src(=src+count)
;//
;//-----------------------------------------------------------------------------------------------------------------------------
;//
;//	((dest <= src) || (dest >= src+count)) を効率良く判断する方法は、両辺からsrcを引いて、
;//		((dest-src <= src-src) || (dest-src >= src-src+count))　⇒　((dest-src <= 0) || (dest-src >= count))
;//	(dest-src) がマイナス値になる場合は、符号無し比較を用いれば (マイナス値 > count) が成立するから、
;//	(dest-src >= count) に集約でき、(dest-src) が0になる場合だけを判断すれば良い。従って、
;//		((dest-src == 0) || (dest-src >= count))
;//	で判断できる。
;//
;//-----------------------------------------------------------------------------------------------------------------------------
void* memmove(void* dest, const void* src, size_t count);
asm("
		.code
		.align		1
		.global		memmove
memmove:
		sub		%r12, %r13		;// %r12 := dest-src
		jreq		2			;// if((dest-src == 0) ||	//jreq条件が成立しているので、xjrugeで必ず分岐する
		cmp		%r12, %r14		;//    (dest-src >= count))
		xjruge.d	memcpy			;//       return memcpy(dest, src, count)
		add		%r12, %r13		;// %r12 := dest			*delay*
		;//
		add		%r12, %r14		;// %r12 := dest += count
		add		%r13, %r14		;// %r13 := src  += count
		;//
		sub		%r13, 1			;// <---------------------------+
memmove_LOOP:						;// do {			|
;//		sub		%r13, 1			;//   %r13 := src--	--------+
		ld.b		%r9, [%r13]		;//   %r9  := c = *src		|
		sub		%r12, 1			;//   %r12 := dest--		|	*anti-interlock*
		ld.b		[%r12], %r9		;//   *dest = c			|
		sub		%r14, 1			;//   %r14 := count--		|
		jrne.d		memmove_LOOP		;// } while(count != 0)		|
		sub		%r13, 1			;// <---------------------------+	*delay*
		ret.d					;// return  dest
		ld.w		%r10, %r12		;// %r10 := dest			*delay*
");
#endif//PIECE

/*****************************************************************************
 *	標準Ｃライブラリの補助
 *****************************************************************************/

#ifndef PIECE
#ifndef _MSC_VER	//Visual C++ 6.0ではリリースビルド時に「error C2169: 'strlen' : 組み込み関数は定義できません。」になるため除外した。
size_t strlen(const char* string) {
	return strnlen(string, SIZE_MAX);
}
#endif//_MSC_VER	//Visual C++ 6.0ではリリースビルド時に「error C2169: 'strlen' : 組み込み関数は定義できません。」になるため除外した。
/* strnlen()関数は、stringが指す文字列の長さを、バイト数で返す。
 * 長さには、終端の'\0'は含まない。
 * 長さは最大で、nまでである。
 * strnlen()関数は、stringの最初のnバイトのみを検査し、string+nより先を検査することはない。
 */
size_t strnlen(const char* string, size_t n) {
	size_t len = 0;
	while((n--) && (*string++)) {
		len++;
	}
	return len;
}
#else /*PIECE*/
asm("
		.code
		.align		1
		.global		strlen
		.global		strnlen
strlen:
		ld.w		%r13, -1		;// %r13 := n = SIZE_MAX
strnlen:
		ld.w		%r10, -1		;// %r10 := len = -1	最後のループで余分に+1するので、予め-1しておく
		sub		%r13, 1			;// %r13 := n--				<---------------+
		jrult		4			;// if(n == -1) { return len + 1 }	--------+	|
		ld.b		%r9, [%r12]+		;// %r9  := c = *string++			|	|
		cmp		%r9, 0			;// if(c ==  0) { return len + 1 }		|	|
		jrne.d		-4			;//					--------|-------+
		add		%r10, 1			;// %r10 := len++			<-------+		*delay*
		ret
");
#endif/*PIECE*/

#ifndef PIECE
#ifndef GC_LEAK_DETECTOR_H	//Boehm GCのleak_detector.hをインクルードしている場合は、定義が重複するのでここでは定義しない。
char* strdup(const char* string) {
	return strndup(string, SIZE_MAX);
}
/* strndup()関数は、strdup()と同様であるが、最大でnバイトだけを複製する。
 * stringがnよりも長い場合は、nバイトだけを複製し、終端の'\0'を追加する。
 */
char* strndup(const char* string, size_t n) {
	size_t len = strnlen(string, n);
	char* p =  malloc(len + 1/*終端の'\0'の分、忘れずに!*/);
	if(p != NULL) {
		p[len] = '\0';
		memcpy(p, string, len);
	}
	return p;
}
#endif//GC_LEAK_DETECTOR_H	//Boehm GCのleak_detector.hをインクルードしている場合は、定義が重複するのでここでは定義しない。
#else /*PIECE*/
asm("
		.code
		.align		1
		.global		strdup
		.global		strndup
strdup:
		ld.w		%r13, -1		;// %r13 := n = SIZE_MAX
strndup:
		pushn		%r1
		;// %r12 := string
		;// %r13 := n
		xcall.d		strnlen			;// %r10 := len = strnlen(string, n)
		ld.w		%r0, %r12		;// %r0  :=               string	*delay*
		ld.w		%r1, %r10		;// %r1  := len
		;// %r0  := string
		;// %r1  := len
		ld.w		%r12, %r1		;// %r12 :=             len
		xcall.d		malloc			;// %r10 := p =  malloc(len + 1)
		add		%r12, 1			;// %r12 :=             len + 1		*delay*
		cmp		%r10, 0			;// if(p != NULL) {
		jreq		strndup_RET
		;// %r0  := string
		;// %r1  := len
		;// %r10 := p
		ld.w		%r12, %r10		;//   %r12 :=            p
		add		%r10, %r1		;//   %r10 := p + len
		ld.b		[%r10], %r8		;//         *(p + len) = '￥0'		■注1■
		ld.w		%r13, %r0		;//   %r13 :=               string
		xcall.d		memcpy			;//   %r10 := p = memcpy(p, string, len)
		ld.w		%r14, %r1		;//   %r14 :=                       len	*delay*
strndup_RET:	;// %r10 := p				;// }
		popn		%r1
		ret					;// return p
");
//■注1■
// - asmブロック内のコメントに、半角「\」を使用しないよう、注意してください。
// - たとえば、上記コメント内の「*(p+len)='￥0'」を「*(p+len)='\0'」とすると、そこでasmブロックが終了してしまいます。
//   なぜなら、コンパイラはasmブロックを文字列リテラルとして扱い、'\0' をエスケープシーケンスとして展開するからです。
// - 上記コードの場合は、たまたま、strndup_RET の未定義エラーとなり、リンク時に発見できます。
//   しかし、常にビルド時のエラーとして発見できるとは限らず、見つけ辛いバグの原因となります。
#endif/*PIECE*/

/*--------------------------------------------------------------------------*/

#ifndef PIECE
int strcasecmp(const char* s1, const char* s2) {
	int c1, c2;
	do {
		c1 = tolower(*s1++ & 0xff);
		c2 = tolower(*s2++ & 0xff);
	} while(c1 != '\0' && c1 == c2);
	return c1 - c2;
}
int strncasecmp(const char* s1, const char* s2, size_t n) {
	int c1, c2;
	do {
		if(n-- == 0) return 0;
		c1 = tolower(*s1++ & 0xff);
		c2 = tolower(*s2++ & 0xff);
	} while(c1 != '\0' && c1 == c2);
	return c1 - c2;
}
#else /*PIECE*/
/* * Fri Apr 20 11:09:47 JST 2012 Naoyuki Sawa
 * - strcasecmp()とstrncasecmp()をアセンブラ化しました。
 */
asm("
		.code
		.align		1
		.global		strcasecmp
		.global		strncasecmp
strcasecmp:
		ld.w		%r14, -1		;// %r14 := n = UINT_MAX
strncasecmp:
		pushn		%r3
		ld.w		%r1, %r12		;// %r1  := s1
		ld.w		%r2, %r13		;// %r2  := s2
		ld.w		%r3, %r14		;// %r3  := n
		sub		%r3, 1			;// <-------------------------------------------+
strncasecmp_LOOP:					;//						|
;//		sub		%r3, 1			;// %r3  := n--	--------------------------------+
		jrult		strncasecmp_RET0	;// if(n < 0) return 0				|
		;//					;//						|
		ld.ub		%r12, [%r2]+		;// %r12 := c2 = (unsigned char)*s2++		|
		xcall		tolower			;// %r10 := c2 = tolower(c2)			|
;//		ld.w		%r0, %r10		;// %r0  := c2	------------------------+	|
		;//					;//					|	|
		ld.ub		%r12, [%r1]+		;// %r12 := c1 = (unsigned char)*s1++	|	|
		xcall.d		tolower			;// %r10 := c1 = tolower(c1)		|	|
		ld.w		%r0, %r10		;// <-----------------------------------+	|	*delay*
		;//					;//						|
		cmp		%r10, 0			;// if(c1 ==  0) return (c1 - c2)		|
		jreq.d		strncasecmp_EXIT	;//						|
		sub		%r10, %r0		;// %r10 :=             (c1 - c2)		|	*delay*
		jreq.d		strncasecmp_LOOP	;// if(c1 != c2) return (c1 - c2)		|
		sub		%r3, 1			;// <-------------------------------------------+	*delay*
strncasecmp_EXIT:
		popn		%r3
		ret
strncasecmp_RET0:
		jp.d		strncasecmp_EXIT
		ld.w		%r10, 0			;// %r10 := 0						*delay*
");
#endif /*PIECE*/

/*--------------------------------------------------------------------------*/

/* * Sat Dec 15 14:14:55 JST 2012 Naoyuki Sawa
 * - strcmp()とstrncmp()は、P/ECE開発環境のEPSONライブラリにも含まれていますが、自分で再実装しました。
 *   EPSON版は、strcmp()とstrncmp()が個別に実装されていますが、まとめて実装し、少し省メモリになりました。
 * - 実際には、本モジュールに含めると、必要の無い場合も必ずリンクされてしまい、却ってメモリ消費が増えます。
 *   アプリケーションが、strcmp()とstrncmp()を両方使用している場合のみ、省メモリになったと考えてください。
 */
#ifndef PIECE
#ifndef _MSC_VER	//Visual C++ 6.0ではリリースビルド時に「error C2169: 'strcmp' : 組み込み関数は定義できません。」になるため除外した。
int strcmp(const char* s1, const char* s2) {
	return strncmp(s1, s2, SIZE_MAX);
}
#endif//_MSC_VER	//Visual C++ 6.0ではリリースビルド時に「error C2169: 'strcmp' : 組み込み関数は定義できません。」になるため除外した。
int strncmp(const char* s1, const char* s2, size_t n) {
	int t = 0; /* 引数nに0が指定された場合に戻り値を0とするため、(t=0)に初期化しておく。 */
	for(;;) {
		int c1, c2;
		if((int)--n == -1) {
			break; /* この位置では必ず(t==0)である。従って"return 0"に相当する。 */
		}
		c1 = *(unsigned char*)s1++;
		c2 = *(unsigned char*)s2++;
		if((t = c1 - c2) != 0) {
			break;
		}
		if(c2 == 0) {
			break; /* この位置では必ず(t==0)である。従って"return 0"に相当する。 */
		}
	}
	return t;
}
#else /*PIECE*/
int  strcmp(const char* s1, const char* s2);
int strncmp(const char* s1, const char* s2, size_t n);
asm("
		.code
		.align		1
		.global		strcmp
		.global		strncmp
;//---------------------------------------------;//
strcmp:						;//
		ld.w		%r14, -1	;// %r14 := n = SIZE_MAX
;//---------------------------------------------;//
strncmp:					;//
		ld.w		%r10, 0		;// %r10 := t = 0
strncmp_LOOP:					;// for(;;) {
		sub		%r14, 1		;//   if((int)--n == -1)
		jrult		strncmp_RET	;//     break
		ld.ub		%r10, [%r12]+	;//   %r10 := c1 = *(unsigned char*)s1++
		ld.ub		%r11, [%r13]+	;//   %r11 := c2 = *(unsigned char*)s2++
		sub		%r10, %r11	;//   %r10 := t  = c1 - c2
		jrne		strncmp_RET	;//   if(t  != 0) break
		cmp		%r11, 0		;//   if(c2 == 0)
		jrne		strncmp_LOOP	;//     break
strncmp_RET:					;// }
		ret
;//---------------------------------------------;//
");
#endif /*PIECE*/

/*--------------------------------------------------------------------------*/

/* * Sat Dec 15 14:14:55 JST 2012 Naoyuki Sawa
 * - strchr()とstrrchr()は、P/ECE開発環境のEPSONライブラリにも含まれていますが、自分で再実装しました。
 *   EPSON版のstrchr()とstrrchr()で処理に無駄がある点を改善し、今回の実装の方が少し省メモリになりました。
 * - 実際には、本モジュールに含めると、必要の無い場合も必ずリンクされてしまい、却ってメモリ消費が増えます。
 *   アプリケーションが、strchr()とstrrchr()を両方使用している場合のみ、省メモリになったと考えてください。
 */
#ifndef PIECE
char* strchr(const char* s, int c) {
	int tmp;
	do {
		if((tmp = *(unsigned char*)s) == c) {
			return (char*)s; /* 文字列s中に最初に文字cが現れた位置へのポインタを返す。 */
		}
		s++;
	} while(tmp != 0);
	return NULL; /* 文字列s中に文字cが見つからない場合はNULLを返す。 */
}
char* strrchr(const char* s, int c) {
	char* result = NULL; /* 文字列s中に最後に文字cが現れた位置へのポインタ。文字列s中に文字cが見つからない場合はNULLを返す。 */
	int tmp;
	do {
		if((tmp = *(unsigned char*)s) == c) {
			result = (char*)s; /* 文字列s中に最後に文字cが現れた位置へのポインタを更新する。 */
		}
		s++;
	} while(tmp != 0);
	return result; /* 文字列s中に最後に文字cが現れた位置へのポインタを返す。文字列s中に文字cが見つからない場合はNULLを返す。 */
}
#else /*PIECE*/
char*  strchr(const char* s, int c);
char* strrchr(const char* s, int c);
asm("
		.code
		.align		1
		.global		strchr
		.global		strrchr
;//---------------------------------------------;//
;// strchr()関数は、文字列s中に最初に文字cが現れた位置へのポインタを返す。
;// 文字列s中に文字cが見つからない場合はNULLを返す。
;// 終端のnulは文字列の一部と見なされ、cにnulが指定された場合は終端のnulへのポインタを返す。←←←要注意!!
;//---------------------------------------------;//
strchr:						;// do {
		ld.ub		%r10, [%r12]	;//   %r10 := tmp = *(unsigned char*)s
		cmp		%r10, %r13	;//   if(tmp == c)			!INTERLOCK!
		jreq		strchr_RET	;//     goto strchr_RET
		cmp		%r10, 0		;//   
		jrne.d		strchr		;// } while(tmp != 0)
		add		%r12, 1		;//   %r12 := s++			*delay*
		ret				;// return  0
strchr_RET:					;//
		ret.d				;// return  s
		ld.w		%r10, %r12	;// %r10 := s				*delay*
;//---------------------------------------------;//
;// strrchr()関数は、文字列s中に最後に文字cが現れた位置へのポインタを返す。
;// 文字列s中に文字cが見つからない場合はNULLを返す。
;// 終端のnulは文字列の一部と見なされ、cにnulが指定された場合は終端のnulへのポインタを返す。←←←要注意!!
;//---------------------------------------------;//
strrchr:					;//
		ld.w		%r10, 0		;// %r10 := result = 0
strrchr_LOOP:					;// do {
		ld.ub		%r9, [%r12]	;//   %r9  := tmp = *(unsigned char*)s
		cmp		%r9, %r13	;//   					!INTERLOCK!
		jrne.d		3		;//   if(tmp == c)
		cmp		%r9, 0		;//   <-------------------------+	*delay*
		 ld.w		%r10, %r12	;//     %r10 := result = s	|
;//		cmp		%r9, 0		;//   --------------------------+
		jrne.d		strrchr_LOOP	;// } while(tmp != 0)
		add		%r12, 1		;//   %r12 := s++			*delay*
		ret				;// return result
;//---------------------------------------------;//
");
#endif /*PIECE*/

/*--------------------------------------------------------------------------*/

/* * Tue Dec 18 21:23:57 JST 2012 Naoyuki Sawa
 * - memchr()とmemcmp()は、P/ECE開発環境のEPSONライブラリにも含まれていますが、自分で再実装しました。
 *   EPSON版のmemchr()とmemcmp()で処理に無駄がある点を改善し、今回の実装の方が4バイト省メモリになりました。
 * - 本モジュールに含めると、必要の無い場合も必ずリンクされ、却ってメモリ消費が増える恐れがあります
 *   しかし、memchr()はdoprnt.cモジュールから,memcmp()はclippce.cから参照されているので、元々必ず必要です。
 *   従って、無駄は生じません。
 */
#ifndef PIECE
void* memchr(const void* _s, int c, size_t n) {
	unsigned char* s      = (unsigned char*)_s;
	unsigned char* result = (unsigned char*) 1;
	int tmp;
	for(;;) {
		if((int)--n == -1) {
			break; /* この位置では必ず(result==1)である。 */
		}
		if((tmp = *s++) == c) {
			result = s; /* ポインタsは文字cを見つけた位置よりも+1進んでいる。 */
			break;
		}
	}
	return result - 1; /* どちらのbreakで抜けた場合も(result-1)が正しい戻り値となる。 */
}
#ifndef _MSC_VER	//Visual C++ 6.0ではリリースビルド時に「error C2169: 'memcmp' : 組み込み関数は定義できません。」になるため除外した。
int memcmp(const void* _s1, const void* _s2, size_t n) {
	const unsigned char* s1 = _s1;
	const unsigned char* s2 = _s2;
	int c1, c2, t;
	for(;;) {
		if((int)--n == -1) {
			break;
		}
		c1 = *s1++;
		c2 = *s2++;
		if((t = c1 - c2) != 0) {
			return t;
		}
	}
	return 0;
}
#endif//_MSC_VER	//Visual C++ 6.0ではリリースビルド時に「error C2169: 'memcmp' : 組み込み関数は定義できません。」になるため除外した。
#else /*PIECE*/
void* memchr(const void* _s, int c, size_t n);
int memcmp(const void* _s1, const void* _s2, size_t n);
asm("
		.code
		.align		1
		.global		memchr
		.global		memcmp
;//---------------------------------------------;//
memchr:						;//
		ld.w		%r10, 1		;// %r10 := result = 1
memchr_LOOP:					;// for(;;) {
		sub		%r14, 1		;//   if((int)--n == -1)
		jrult		memchr_RET	;//     break
		ld.ub		%r9, [%r12]+	;//   %r9  := tmp = *s++
		cmp		%r9, %r13	;//   if(tmp == c) {
		jrne		memchr_LOOP	;//     %r10 := result = s
		ld.w		%r10, %r12	;//     break }
memchr_RET:					;// }
		ret.d				;// return  result
		sub		%r10, 1		;// %r10 := result--	*delay*
;//---------------------------------------------;//
memcmp:						;// for(;;) {
		sub		%r14, 1		;//   if((int)--n == -1)
		jrult		memcmp_RET0	;//     break
		ld.ub		%r10, [%r12]+	;//   %r10 := c1 = *(unsigned char*)s1++
		ld.ub		%r11, [%r13]+	;//   %r11 := c2 = *(unsigned char*)s2++
		sub		%r10, %r11	;//   %r10 := t  = c1 - c2
		jreq		memcmp		;//   if(t != 0)
		ret				;//     return t
memcmp_RET0:					;// }
		ret.d				;// return  0
		ld.w		%r10, 0		;// %r10 := 0		*delay*
;//---------------------------------------------;//
");
#endif /*PIECE*/

/*--------------------------------------------------------------------------*/

/* * Fri Dec 21 00:22:01 JST 2012 Naoyuki Sawa
 * - strspn()とstrcspn()は、P/ECE開発環境のEPSONライブラリにも含まれていますが、自分で再実装しました。
 *   EPSON版のmemchr()とmemcmp()で処理に無駄がある点を改善し、今回の実装の方が4命令分省メモリになりました。
 * - 本モジュールに含めると、必要の無い場合も必ずリンクされ、却ってメモリ消費が増える恐れがあります
 *   しかし、strspn()とstrcspn()は、clippce.c内で再実装したstrtok()から参照しているので、元々必ず必要です。
 *   従って、無駄は生じません。
 */
#ifndef PIECE
size_t  strspn(const char* s1, const char* s2) {
	int result = -1;
	int c1, c2, c;
	const char* p;
	c2 = 0;					//異なるのはこの二行だけ
	for(;;) {
		c1 = *(unsigned char*)s1++;	//異なるのはこの二行だけ
		//{{--- strspn_strcspn ---
		result++;
		if(c1 == c2) { return result; }
		p = s2;
		for(;;) {
			c = *(unsigned char*)p++;
			if(c == c1) { break; }
			if(c == c2) { return result; }
		}
		//}}--- strspn_strcspn ---
	}
}
size_t strcspn(const char* s1, const char* s2) {
	int result = -1;
	int c1, c2, c;
	const char* p;
	c1 = 0;					//異なるのはこの二行だけ
	for(;;) {
		c2 = *(unsigned char*)s1++;	//異なるのはこの二行だけ
		//{{--- strspn_strcspn ---
		result++;
		if(c1 == c2) { return result; }
		p = s2;
		for(;;) {
			c = *(unsigned char*)p++;
			if(c == c1) { break; }
			if(c == c2) { return result; }
		}
		//}}--- strspn_strcspn ---
	}
}
#else /*PIECE*/
size_t  strspn(const char* s1, const char* s2);
size_t strcspn(const char* s1, const char* s2);
asm("
		.code
		.align		1
		.global		strspn
		.global		strcspn
strspn:
		ld.w		%r10, -1		;// %r10 := result = -1
		ld.w		%r5, 0			;// %r5  := c2 = 0
		;//					;// for(;;) {
		ld.ub		%r4, [%r12]+		;//   %r4  := c1 = *(unsigned char*)s1++
		call		strspn_strcspn		;//   %r10 := result++
		jp		-2			;// }
		;//-------------------------------------;//
strcspn:
		ld.w		%r10, -1		;// %r10 := result = -1
		ld.w		%r4, 0			;// %r4  := c1 = 0
		;//					;// for(;;) {
		ld.ub		%r5, [%r12]+		;//   %r5  := c2 = *(unsigned char*)s1++
		call		strspn_strcspn		;//   %r10 := result++
		jp		-2			;// }
		;//-------------------------------------;//
strspn_strcspn:
		cmp		%r4, %r5		;// if(c1 == c2)
		jreq.d		8			;//   return result	--------------------------------+	strspn又はstrcspnへ戻らず、その呼び出し元へ戻る
		add		%r10, 1			;// %r10 := result++	*delay*				|
		ld.w		%r6, %r13		;// %r6  := p = s2					|
		;//					;// for(;;) {						|
		ld.ub		%r7, [%r6]+		;//   %r7  := c = *(unsigned char*)p++	<-------+	|
		cmp		%r7, %r4		;//   if(c == c1)				|	|
		jreq		4			;//     return result	----------------+	|	|	strspn又はstrcspnへ戻る
		cmp		%r7, %r5		;//   if(c != c2)			|	|	|
		jrne		-4			;//     continue	----------------|-------+	|
		add		%sp, 1			;//   else		<---------------|---------------+
		ret					;//     return result	<---------------+			strspn又はstrcspnへ戻らず、その呼び出し元へ戻る
							;// }
");
#endif /*PIECE*/

/*--------------------------------------------------------------------------*/

/* * Wed Mar 27 20:21:54 JST 2013 Naoyuki Sawa
 * - strsep()を追加しました。宣言は、include/string.hに追加しました。
 *   strsep()は、EPSONライブラリには含まれておらず、また、C言語標準関数ではありませんが、UNIX環境では一般的な関数です。
 *   strtok()と較べて、空のフィールドを扱えること，リエントラントであることの利点があり、便利なのでP/ECEにも追加することにしました。
 * - strpbrk()は、P/ECE開発環境のEPSONライブラリにも含まれていますが、自分で再実装しました。
 *   strpbrk()は、EPSONライブラリの実装のままでも、充分にコンパクトで高速です。
 *   しかし、strsep()と一緒に実装することで、一部のレジスタの退避を省略してよりコンパクトで高速にできるので、strpbrk()も実装することにしました。
 *   実際には、strpbrk()を使用しないアプリケーションにもリンクされてしまう欠点を勘案すると、必ずしも効率的とは言えないのですけれど、
 *   EPSONライブラリ版よりも良いアセンブラ化ができた(と思う)ので、せっかくなので含めることにしました(^^;
 */
#ifndef PIECE
/* strsep()関数は、*stringpにより参照される文字列の中で、文字列delim中のいずれかの文字(または終端の'\0')のうちで最初に出現する文字の位置を探し、その箇所を'\0'で置き換えます。
 * 区切り文字の次の文字の位置(または文字列の末尾に達した場合はNULL)が、*stringpに格納されます。
 * *stringpの元の値が、戻り値となります。
 * 「空」のフィールド、すなわち、2つの隣接する区切り文字によって生じたフィールドは、*stringpの中に返されたポインタが参照する位置を'\0'と比較することで検出可能です。
 * *stringpが最初からNULLである場合は、strsep()はNULLを返します。
 */
char* strsep(char** stringp, const char* delim) {
	char* begin = *stringp;
	if(begin) {
		char* end = strpbrk(begin, delim);
		if(end) { *end++ = '\0'; }
		*stringp = end;
	}
	return begin;
}
char* strpbrk(const char* s, const char* accept) {
	const char* p;
	for(;;) {
		int c = *s++;
		if(!c) { return NULL; }
		p = accept;
		for(;;) {
			int t = *p++;
			if(!t) { break; }
			if(t == c) { return (char*)(s - 1); }
		}
	}
}
#else /*PIECE*/
char* strsep(char** stringp, const char* delim);
char* strpbrk(const char* s, const char* accept);
asm("
		.code
		.align		1
		;//=====================================;//
		.global		strsep
strsep:
		ld.w		%r14, [%r12]		;// %r14 := begin = *stringp
		cmp		%r14, 0			;// if(begin) {
		jreq		strsep_RET
		ld.w		%r15, %r12		;//   %r15 := stringp
		call.d		strpbrk			;//   %r10 := end = strpbrk(begin, delim)
		ld.w		%r12, %r14		;//   %r12 :=               begin		*delay*
		cmp		%r10, 0			;//   if(end) {
		jreq		2			;//     *end++ = '￥0'		--------+
		ld.b		[%r10]+, %r8		;//   }					|
		ld.w		[%r15], %r10		;//   *stringp = end		<-------+
strsep_RET:	;//					;// }
		ret.d
		ld.w		%r10, %r14		;// %r10 := begin				*delay*
		;//=====================================;//
		.global		strpbrk
strpbrk:						;// for(;;) {
		ld.b		%r10, [%r12]+		;//   %r10 := c = *s++		<-------+
		cmp		%r10, 0			;//   if(!c)				|
		jreq		strpbrk_RET		;//     return NULL			|
		ld.w		%r11, %r13		;//   %r11 := p = accept		|
		;//					;//   for(;;) {				|
		ld.b		%r9, [%r11]+		;//     %r9  := t = *p++	<-------|-------+
		cmp		%r9, 0			;//     if(!t)				|	|
		jreq		strpbrk			;//       break			--------+	|
		cmp		%r9, %r10		;//     if(t == c) return s - 1			|
		jrne		-4			;//   }				----------------+
		sub		%r12, 1			;// %r12 := s - 1
		ld.w		%r10, %r12		;// %r10 := s - 1
strpbrk_RET:	;//					;// }
		ret
");
#endif/*PIECE*/

/*--------------------------------------------------------------------------*/

/* * Thu Oct 09 22:33:48 JST 2014 Naoyuki Sawa
 * - strcat()とstrncat()は、P/ECE開発環境のEPSONライブラリにも含まれていますが、自分で再実装しました。
 *   EPSON版は、strcat()とstrncat()が個別に実装されていますが、まとめて実装し、少し省メモリになりました。
 * - 実際には、本モジュールに含めると、必要の無い場合も必ずリンクされてしまい、却ってメモリ消費が増えます。
 *   アプリケーションが、strcat()とstrncat()を両方使用している場合のみ、省メモリになったと考えてください。
 * - 省メモリの効果は、以下の通りです。
 *   □EPSON版
 *   │strcat  10命令┐
 *   │strncat 16命令┴26命令
 *   □自作版            ↓…12命令節約
 *   │strcat＋strncat 14命令
 */
#ifndef PIECE
/* □「Linux Programmer's Manual - STRCAT」(http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/strcat.3.html)より引用:
 * │strcat()関数は、dest文字列の後にsrc文字列を付け加える。
 * │その際に、destの最後にある終端のヌルバイト('\0')は上書きされ、新たに生成された文字列の末尾に終端のヌルバイトが付与される。
 * │二つの文字列srcとdestは重なってはならない。
 * │また、文字列destは、連結後の結果を格納するのに十分な大きさでなければならない。
 * │destが十分な大きさでない場合、プログラムがどのような動作をするか分からない。
 * │バッファオーバーランはセキュアなプログラムを攻撃する際に好んで使われる方法である。
 * │strncat()も同様だが、以下の点が異なる。
 * │- srcのうち最大nバイトが使用される。
 * │- srcがnバイト以上の場合、srcはヌル終端されている必要はない。
 * │strcat()と同じく、destに格納される結果の文字列は常にヌル終端される。
 * │srcがnバイト以上の場合、strncat()はdestにn+1バイトを書き込む(srcからのnバイトと終端のヌルバイトである)。
 * │したがって、destの大きさは最低でもstrlen(dest)+n+1でなければならない。 */
#ifndef _MSC_VER	//{{2015/05/31:Visual C++ 6.0でReleaseビルドすると「error C2169: 'strcat' : 組み込み関数は定義できません。」になるので除外しました。
char* strcat(char* dest, const char* src) {
	return strncat(dest, src, SIZE_MAX);
}
#endif//_MSC_VER	//}}2015/05/31:Visual C++ 6.0でReleaseビルドすると「error C2169: 'strcat' : 組み込み関数は定義できません。」になるので除外しました。
char* strncat(char* dest, const char* src, size_t n) {
	char* p = dest;
	while(*p++) { /** no job **/ }
	p--;
	while(n--) { if(!(*p++ = *src++)) { return (char*)dest; } }
	*p++ = '\0';
	return (char*)dest;
}
#else /*PIECE*/
char* strcat(char* dest, const char* src);
char* strncat(char* dest, const char* src, size_t n);
//素直なバージョン(15命令)と、1命令節約バージョン(14命令)を作成しました。サイズを優先して後者を使用することにしました。
//strcat()やstrncat()を使用するような処理は、速度があまり重要でないことが多く、少しでも小さい方が良いと思ったからです。
#if 0
//ほぼC言語どおり素直に実装したバージョンです。
asm("
		.code
		.align		1
		.global		strcat
		.global		strncat
strcat:
		ld.w		%r14, -1		;//%r14 := n = SIZE_MAX
strncat:
		ld.w		%r10, %r12		;//%r12 := p = dest
		ld.b		%r9, [%r12]+		;//while(*p++) { /** no job **/ }
		 cmp		%r9, 0
		jrne		-2
		sub		%r12, 1			;//%r12 := p--
strncat_LOOP:
		sub		%r14, 1			;//while(n--) {
		jrult		strncat_TERM
		ld.b		%r9, [%r13]+
		ld.b		[%r12]+, %r9		;//  if(!(*p++ = *src++)) { return dest }
		cmp		%r9, 0
		jrne		strncat_LOOP
		ret					;//}
strncat_TERM:
		ld.b		[%r12], %r8		;//*p = '￥0'
		ret					;//return dest
");
#else
//1命令節約したバージョン。ただし少し低速です。
asm("
		.code
		.align		1
		.global		strcat
		.global		strncat
strcat:
		ld.w		%r14, -1		;//%r14 := n = SIZE_MAX
strncat:
		ld.w		%r10, %r12		;//%r12 := p = dest
		ld.b		%r9, [%r12]		;//while(*p) { p++ }
		 cmp		%r8, %r9		;//					%psr(C) := %r9 ? 1 : 0
		jrne.d		-2
strncat_LOOP:						;//for(;;) {
		adc		%r12, %r8		;//  if(!初回) { p++ }			上のループ中は+1。上のループ抜け時のみ+0。下のループ中は+1。	*delay*
		sub		%r14, 1			;//  if(!n--) { break }
		jrult		strncat_TERM
		ld.b		%r9, [%r13]+		;//  if(!(*p = *src++)) { break }
		ld.b		[%r12], %r9
		cmp		%r8, %r9		;//					%psr(C) := %r9 ? 1 : 0
		jrne		strncat_LOOP		;//}
strncat_TERM:
		ld.b		[%r12], %r8		;//*p = '￥0'				下のループから降りて来た場合は、2回nulを格納することになるが問題無い。
		ret					;//return dest
");
#endif
#endif/*PIECE*/

/*--------------------------------------------------------------------------*/

/* * Fri Oct 31 00:45:36 JST 2014 Naoyuki Sawa
 * - strlcpy()を追加しました。宣言は、include/string.hに追加しました。
 * □「Linux Programmer's Manual - STRCPY」(http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/strcpy.3.html)より引用:
 * │いくつかのシステム(BSD、Solarisなど)では以下の関数が提供されている。
 * │    size_t strlcpy(char *dest, const char *src, size_t size); 
 * │この関数はstrncpy()と同様だが、最大でもsize-1バイトしかdestにコピーをせず、末尾への終端のヌルバイトの追加が必ず行われ、宛先バッファ(の未使用部分)へのヌルバイトの書き込みが行われない。
 * │この関数ではstrcpy()やstrncpy()の持つ問題のいくつかが修正されているが、sizeが小さすぎた場合にはデータが失われる問題には、依然として呼び出し側で対処する必要がある。
 * │この関数の返り値はsrcの長さである。これにより、末尾の切り詰めが行われたかを簡単に検出することができる。返り値がsize以上の場合には、末尾の切り詰めが発生している。
 * │データロスが問題となる場合は、呼び出し側で、呼び出し前に引き数をチェックするか、この関数の返り値を検査するかのいずれかをしなければならない。
 * │strlcpy()はglibcには存在せず、POSIXによる標準化もされていないが、Linuxではlibbsdライブラリ経由で利用できる。 */
#ifndef PIECE
size_t strlcpy(char* dst, const char* src, size_t size) {
	size_t len = strlen(src);			//転送元の文字列の長さを求める。
	if(size--) {					//バッファサイズを1減らす。1減らす前のバッファサイズが0でなければ…
		if(size > len) { size = len; }		//転送する文字列の長さを求める。
		memcpy(dst, src, size);			//文字列を転送する。
		dst[size] = '\0';			//文字列をヌル終端する。
	}
	return len;					//転送元の文字列の長さを返す。
}
#else /*PIECE*/
size_t strlcpy(char* dst, const char* src, size_t size);
asm("
		.code
		.align		1
		.global		strlcpy
strlcpy:
		pushn		%r2
		ld.w		%r0, %r12		;//%r0  := dst
		ld.w		%r1, %r13		;//%r1  := src
		ld.w		%r2, %r14		;//%r2  := size
		xcall.d		strlen			;//%r10 := len = strlen(src)
		ld.w		%r12, %r1		;//%r12 :=              src			*delay*
		sub		%r2, 1			;//%r2  := size--
		jrult		strlcpy_RET		;//if(size >= 0) {
		ld.w		%r12, %r0		;//  %r12 :=              dst
		ld.w		%r0, %r10		;//  %r0  := len
		cmp		%r2, %r0		;//  if(size > len) {
		jrule.d		3			;//
		 ld.w		%r13, %r1		;//  %r13 :=                   src		*delay*
		 ld.w		%r2, %r0		;//     size = len  }
		xcall.d		memcpy			;//  %r10 := dst = memcpy(dst, src, size)
		ld.w		%r14, %r2		;//  %r14 :=                        size	*delay*
		add		%r10, %r2		;//  %r10 := &dst[size]
		ld.b		[%r10], %r8		;//           dst[size] = '￥０'
		ld.w		%r10, %r0		;//  %r10 := len
strlcpy_RET:						;//}
		popn		%r2
		ret
");
#endif/*PIECE*/

/* * Fri Oct 31 00:45:36 JST 2014 Naoyuki Sawa
 * - strlcat()を追加しました。宣言は、include/string.hに追加しました。
 * □「Linux Programmer's Manual - STRCAT」(http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/strcat.3.html)より引用:
 * │いくつかのシステム(BSD、Solarisなど)では以下の関数が提供されている。
 * │    size_t strlcat(char *dest, const char *src, size_t size); 
 * │この関数は、ヌル終端された文字列srcを文字列destに追加する。
 * │具体例には、sizeがstrlen(dest)より大きい場合には最大でsize-strlen(dest)-1バイトをsrcからコピーし、結果の末尾に終端のヌルバイトを追加する。
 * │この関数ではstrcat()のバッファオーバーランが発生するという問題が修正されているが、sizeが小さすぎた場合にはデータが失われる問題には、依然として呼び出し側で対処する必要がある。
 * │この関数はstrlcat()が作成しようとした文字列の長さを返す。返り値がsize以上の場合、データロスが発生している。
 * │データロスが問題となる場合は、呼び出し側で、呼び出し前に引き数をチェックするか、この関数の返り値を検査するかのいずれかをしなければならない。
 * │strlcat()はglibcには存在せず、POSIXによる標準化もされていないが、Linuxではlibbsdライブラリ経由で利用できる。 */
#ifndef PIECE
size_t strlcat(char* dst, const char* src, size_t size) {
	size_t dlen = strlen(dst);			//転送先の文字列の長さを求める。
	size_t slen = strlen(src);			//転送元の文字列の長さを求める。
	size_t tlen = dlen + slen;			//文字列の長さの合計を求める。
	if(size > dlen) {				//転送先の文字列がバッファ内でヌル終端されていたら…
		size -= dlen;				//(バッファ内に追加可能な文字数+1)を求める。
		if(slen >= size) { slen = size - 1; }	//追加する文字列の長さを求める。
		dst += dlen;				//文字列を追加する位置を求める。
		memcpy(dst, src, slen);			//文字列を追加する。
		dst[slen] = '\0';			//文字列をヌル終端する。
	}
	return tlen;					//文字列の長さの合計を返す。
}
#else /*PIECE*/
size_t strlcat(char* dst, const char* src, size_t size);
asm("
		.code
		.align		1
		.global		strlcat
strlcat:
		pushn		%r3
		ld.w		%r0, %r12		;//%r0  := dst
		ld.w		%r1, %r13		;//%r1  := src
		xcall.d		strlen			;//%r10 := dlen = strlen(dst)
		ld.w		%r2, %r14		;//%r2  := size					*delay*
		add		%r0, %r10		;//%r0  := dst += dlen
		ld.w		%r3, %r10		;//%r3  := dlen
		xcall.d		strlen			;//%r10 := slen = strlen(src)
		ld.w		%r12, %r1		;//%r12 :=               src			*delay*
		sub		%r2, %r3		;//%r2  := size -= dlen
		jrule.d		strlcat_RET		;//if(size > 0) {
		add		%r3, %r10		;//%r3  := tlen = dlen + slen			*delay*
		cmp		%r10, %r2		;//  if(slen >= size) {
		jrult.d		4			;//
		 ld.w		%r12, %r0		;//  %r12 :=        dst				*delay*
		 ld.w		%r10, %r2		;//    %r10 := slen = size - 1
		 sub		%r10, 1			;//  }
		ld.w		%r13, %r1		;//  %r13 :=             src
		ld.w		%r14, %r10		;//  %r14 :=                  slen
		xcall.d		memcpy			;//  %r10 := memcpy(dst, src, slen)
		add		%r0, %r10		;//  %r0  := &dst[slen]				*delay*
		ld.b		[%r0], %r8		;//           dst[slen] = '￥０'
strlcat_RET:						;//}
		ld.w		%r10, %r3		;//%r10 := tlen
		popn		%r3
		ret
");
#endif/*PIECE*/

/*--------------------------------------------------------------------------*/

int
ismbblead(int c)
{
	c &= 0xff; /* bit31-8は無視（VC++の_ismbblead()もそうなってます） */
	return (0x81 <= c && c <= 0x9f) ||
	       (0xe0 <= c && c <= 0xfc);
}

int
ismbbtrail(int c)
{
	c &= 0xff; /* bit31-8は無視（VC++の_ismbbtrail()もそうなってます） */
	return (0x40 <= c && c <= 0x7e) ||
	       (0x80 <= c && c <= /*0xec*/0xfc);
	/* 2002/12/12: VC++6.0付属のMSDNの、_ismbbtrail()の説明はうそです。 */
	/* 後半0x80～0xecでは、「ん」(0x82f1)の二バイト目が判定できません。 */
}

/*--------------------------------------------------------------------------*/

#ifndef PIECE
#ifndef _MSC_VER	//Visual C++ 6.0のCTYPE.Hは、iscsym,iscsymfをマクロ定義しており、定義が重複するのでここでは定義しない。
int iscsym(int c) {
	return isalnum(c) || (c == '_');
}
int iscsymf(int c) {
	return isalpha(c) || (c == '_');
}
#endif//_MSC_VER	//Visual C++ 6.0のCTYPE.Hは、iscsym,iscsymfをマクロ定義しており、定義が重複するのでここでは定義しない。
#else /*PIECE*/
/* * Fri Apr 20 11:09:47 JST 2012 Naoyuki Sawa
 * - iscsym()とiscsymf()をアセンブラ化しました。
 */
asm("
		.code
		.align		1
		.global		iscsym
		.global		iscsymf
iscsym:
		xcmp		%r12, 95	;// if(c != '_')
		xjrne		isalnum		;//   return isalnum(c)
		ret.d				;// else
		ld.w		%r10, 1		;//   return 1	*delay*
iscsymf:
		xcmp		%r12, 95	;// if(c != '_')
		xjrne		isalpha		;//   return isalpha(c)
		ret.d				;// else
		ld.w		%r10, 1		;//   return 1	*delay*
");
#endif /*PIECE*/

/*--------------------------------------------------------------------------*/

#ifndef PIECE
int isblank(int c) {
	return (c == ' ') || (c == '\t');
}
#else /*PIECE*/
asm("
		.code
		.align		1
		.global		isblank
isblank:
		;// xcmpで比較すると、' 'の比較時に、ext拡張が必要になります。
		;// subとaddを使うと、ext拡張が不要で、1命令分高速化できます。
		sub		%r12, 32	;// if((c -=  ' '        ) == 0) { %psr[Z] = 1 } else
		jreq		2
		 add		%r12, 23	;// if((c += (' ' - '\t')) == 0) { %psr[Z] = 1 } else { %psr[Z] = 0 }
		ld.w		%r10, %psr	;// %r10[1] := %psr[Z]
		ret.d
		and		%r10, 2		;// return     %r10[1] … 0 or 2	*delay*		戻り値が(0|1)でなく(0|2)となることに注意。isblank()の仕様には反しない。
");
#endif /*PIECE*/

/*--------------------------------------------------------------------------*/

//{{2014/01/13削除:lfind()とlsearch()の実装を、clippce.c⇒clipsrch.cへ分離しました。
///* * Sat Jul 04 21:25:58 JST 2009 Naoyuki Sawa
// * - POSIX標準のリニアサーチ関数です。
// *   やや新しい標準のようで、P/ECE開発環境のEPSONライブラリには含まれていなかったので、ここで実装しました。
// *   単純な処理ですが、未ソートの配列をリニアサーチしたい(=bsearch()は使えない)場合は結構有るので、便利だと思います。
// * - 関数仕様は、Web上の資料や、MSDNなどを参照してください。(Visual C++ 6.0のMSDNにも載っています。)
// *   lfind()の引数で、numがポインタ渡しなのが無駄に見えますが、おそらく、lsearch()と引数型を一致させたためだと思います。
// *   また、base引数が、lfind()はconst、lsearch()は非constである違いに注意してください。
// *   lfind()は配列を変更せず、lsearch()は見つからなかったときに配列に要素を追加することを、明示するためだと思います。
// *   (その割には、lfind()の戻り値の型は非constになっている点が、一貫性がありませんが…)
// * - lsearch()を使って、簡単に、重複の無いセットを作成することができます。
// *   以下に、使用例を示します。
// *	<例>
// *		static int compare(const void* elem1, const void* elem2) {
// *			char* str1 = *(char**)elem1;
// *			char* str2 = *(char**)elem2;
// *			return strcmp(str1, str2);
// *		}
// *		void sample() {
// *			char* set[10];
// *			int num = 0;
// *			char* key;
// *			int i;
// *			if(num < 10) key = "One";   lsearch(&key, set, &num, sizeof set[0], compare);
// *			if(num < 10) key = "Two";   lsearch(&key, set, &num, sizeof set[0], compare);
// *			if(num < 10) key = "One";   lsearch(&key, set, &num, sizeof set[0], compare);
// *			if(num < 10) key = "Three"; lsearch(&key, set, &num, sizeof set[0], compare);
// *			if(num < 10) key = "Two";   lsearch(&key, set, &num, sizeof set[0], compare);
// *			if(num < 10) key = "Four";  lsearch(&key, set, &num, sizeof set[0], compare);
// *			for(i = 0; i < num; i++) { printf("%d: %s\n", i, set[i]); }
// *		}
// *	<結果>
// *		0: One
// *		1: Two
// *		2: Three
// *		3: Four
// */
//void*
//lfind(const void* key, const void* base, size_t* num, size_t width, int (*compare)(const void* elem1, const void* elem2))
//{
//	int i = *num;
//	while(i) {
//		if(!(*compare)(key, base)) {
//			return (void*)base;
//		}
//		base = (char*)base + width;
//		i--;
//	}
//	return NULL;
//}
//void*
//lsearch(const void* key, void* base, size_t* num, size_t width, int (*compare)(const void* elem1, const void* elem2))
//{
//	void* ptr = lfind(key, base, num, width, compare);
//	if(!ptr) {
//		ptr = memcpy((char*)base + ((*num)++ * width), key, width);
//	}
//	return ptr;
//}
//}}2014/01/13削除:lfind()とlsearch()の実装を、clippce.c⇒clipsrch.cへ分離しました。

/* * Sat Jul 04 21:25:58 JST 2009 Naoyuki Sawa
 * - 勉強のため自分で実装してみましたが、bsearch()はP/ECE開発環境のEPSONライブラリにも含まれており、以下のコードと全く同じ実装です。
 *   以下のコードをclippce.cに含めておくと、アプリケーションに常にリンクされてコードサイズが無駄になるので、コメントアウトしました。
 *   なお、Visual C++ 6.0にもbsearch()のソースが含まれており、参考にできますが、EPSONライブラリ(=以下のコードと同じ)の方が簡潔です。
 */
//	void*
//	bsearch(const void* key, const void* base, size_t num, size_t width, int (*compare)(const void* elem1, const void* elem2))
//	{
//		while(num) {
//			char* mid = (char*)base + ((num >> 1) * width);
//			int retval = (*compare)(key, mid);
//			if(retval >= 0) {
//				if(!retval) {
//					return mid;
//				}
//				base = mid + width;
//				num--;
//			}
//			num >>= 1;
//		}
//		return NULL;
//	}

/*--------------------------------------------------------------------------*/

/* * Mon Jul 06 23:33:17 JST 2009 Naoyuki Sawa
 * - strupr()とstrlwr()は、標準関数かどうかよくわからず、VC++特有なのかも知れません。
 *   Web上の資料から推測すると、Unix環境のライブラリには含まれていない(?)ようです。
 *   P/ECE開発環境のEPSONライブラリにも、strupr()とstrlwr()は、含まれていません。
 *   便利なので、定義しておくことにしました。
 * - strupr()とstrlwr()のコードは小さいので、無駄なコードサイズ増の影響は僅かです。
 *   tolower()を呼び出していますが、tolower()は既に本モジュールで使用しているので、新たなコード増は生じません。
 *   toupper()を呼び出していますが、toupper()は必須のclipprnt.cで使用しているので、新たなコード増は生じません。
 */
//#ifndef PIECE
//char* strupr(char* string) {
//	int c;
//	char* p = string;
//	while((c = *p)) {
//		*p++ = toupper(c);
//	}
//	return string;
//}
//char* strlwr(char* string) {
//	int c;
//	char* p = string;
//	while((c = *p)) {
//		*p++ = tolower(c);
//	}
//	return string;
//}
//#else /*PIECE*/
//char* strupr(char* string);
//char* strlwr(char* string);
//asm("
//		.code
//		.align		1
//		.global		strupr
//		.global		strlwr
//strupr:
//		xld.w		%r13, toupper		;// %r13 := fn = toupper
//		jp		strupr_strlwr
//strlwr:
//		xld.w		%r13, tolower		;// %r13 := fn = tolower
//strupr_strlwr:
//		pushn		%r2
//		ld.w		%r0, %r12		;// %r0  := string
//		ld.w		%r1, %r12		;// %r1  := p
//		ld.w		%r2, %r13		;// %r2  := fn
//strupr_strlwr_LOOP:					;// for(;;) {
//		ld.b		%r12, [%r1]		;//   %r12 := c = *p
//		cmp		%r12, 0			;//   if(!c)
//		jreq		strupr_strlwr_RET	;//     break
//		call		%r2			;//   %r10 := c = fn(c)
//		ld.b		[%r1]+, %r10		;//   *p++ := c
//		jp		strupr_strlwr_LOOP	;// }
//strupr_strlwr_RET:
//		ld.w		%r10, %r0		;// %r10 := string
//		popn		%r2
//		ret
//");
//#endif /*PIECE*/
//↓---------------------------------------------------------------------------------------------------------------------
//↓ * Sat Dec 25 12:48:38 JST 2010 Naoyuki Sawa
//↓ - strupr()やstrlwr()で、全角文字を含む文字列を変換すると、文字化けすることがある問題を修正しました。
//↓ - これまでの版では、たとえば「テキスト」という文字列を、toupper()で変換すると「ウキスエ」になってしまっていました。
//↓   「テ」の2バイト目を「e」と見なして「E」に、「ト」の2バイト目を「g」と見なして「E」に変換してしまっていたためです。
//↓ - 今回の修正によって、全角文字を含む文字列も、strupr()やstrlwr()で正しく変換できるようになりました。
//↓ - なお、strupr()やstrlwr()で全角文字が化ける問題は、Visual C++ 6.0や、Borland C++ 5.5.1のライブラリでも発生します。
//↓   Windowsプログラミングの際には、気をつけてください。
//↓   回避策の一つは、MFCのCString::MakeUpper()を使うことです。Visual C++ 6.0のMFCで、文字化けしないことを確認しました。
//↓---------------------------------------------------------------------------------------------------------------------
#ifndef PIECE
char* strupr(char* string) {
	char* p = string;
	for(;;) {
		/* 全角文字ならば、変換せずに飛ばす。
		 * - 1バイト目がismbblead()でtrueならば、2バイト目を調べなくても全角文字と判断できるのですが、
		 *   壊れた文字列で2バイト目がnulだった場合に、バッファオーバーランするおそれがあるため、
		 *   安全を期して、2バイト目がismbbtrail()でtrueであることも確認することにしました。
		 */
		if(ismbblead(p[0]) && ismbbtrail(p[1])) {
			p += 2;
		/* 半角文字ならば、変換する。終端だったら抜ける。
		 * - toupper()はnulを変換しないので、終端チェックはtoupper()より先に行っても後に行っても同じです。
		 *   toupper()よりも後で行う方が、Asm化した時に条件ループを組み易いため、後で行うことにしました。
		 */
		} else {
			if(!(*p = toupper(*p))) break;
			p += 1;
		}
	}
	return string;
}
char* strlwr(char* string) {
	char* p = string;
	for(;;) {
		/* 全角文字ならば、変換せずに飛ばす。
		 * - 1バイト目がismbblead()でtrueならば、2バイト目を調べなくても全角文字と判断できるのですが、
		 *   壊れた文字列で2バイト目がnulだった場合に、バッファオーバーランするおそれがあるため、
		 *   安全を期して、2バイト目がismbbtrail()でtrueであることも確認することにしました。
		 */
		if(ismbblead(p[0]) && ismbbtrail(p[1])) {
			p += 2;
		/* 半角文字ならば、変換する。終端だったら抜ける。 */
		} else {
			if(!(*p = tolower(*p))) break;
			p += 1;
		}
	}
	return string;
}
#else /*PIECE*/
char* strupr(char* string);
char* strlwr(char* string);
asm("
		.code
		.align		1
		.global		strupr
		.global		strlwr
strupr:
		xld.w		%r13, toupper		;// %r13 := fn = toupper
		jp		strupr_strlwr
strlwr:
		xld.w		%r13, tolower		;// %r13 := fn = tolower
strupr_strlwr:
		pushn		%r2
		ld.w		%r0, %r12		;// %r0  := string
		ld.w		%r1, %r12		;// %r1  := p
		ld.w		%r2, %r13		;// %r2  := fn
		;//-------------------------------------;//
strupr_strlwr_LOOP:					;// for(;;) {
		xld.b		%r12, [%r1+0]		;//   %r12 :=        p[0]
		xcall		ismbblead		;//   if(!ismbblead (p[0])) goto SINGLE
		cmp		%r10, 0
		jreq		strupr_strlwr_SINGLE
		;//
		xld.b		%r12, [%r1+1]		;//   %r12 :=        p[1]
		xcall		ismbbtrail		;//   if(!ismbbtrail(p[1])) goto SINGLE
		cmp		%r10, 0
		jreq		strupr_strlwr_SINGLE
		;//
		jp.d		strupr_strlwr_LOOP	;//   continue
		add		%r1, 2			;//   p += 2	*delay*
strupr_strlwr_SINGLE:
		ld.b		%r12, [%r1]		;//   %r12 :=    *p
		call		%r2			;//   %r10 := fn(*p)
		ld.b		[%r1]+, %r10		;//   *p   := fn(*p)
		;//
		cmp		%r10, 0			;//   if(!*p) break
		jrne		strupr_strlwr_LOOP
		;//-------------------------------------;//
strupr_strlwr_RET:					;// }
		ld.w		%r10, %r0		;// %r10 := string
		popn		%r2
		ret
");
#endif /*PIECE*/

/*--------------------------------------------------------------------------*/

/* * Wed Apr 29 14:30:43 JST 2015 Naoyuki Sawa
 *  - memccpy(),mempcpy(),strncpy(),stpncpy(),strcpy(),stpcpy()を追加しました。
 *    宣言は、include/string.hに追加しました。
 *  - strncpy()とstrcpy()は、P/ECE開発環境のEPSONライブラリにも含まれていますが、自分で再実装しました。
 *    stpncpy()とstpcpy()と共通化できる部分が多く、まとめて実装する方がコードサイズ節約できるからです。
 */

//■「Linux Programmer's Manual (3) - MEMCCPY」(http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/memccpy.3.html)より引用:
//□名前
//│memccpy - メモリー領域をコピーする
//□説明
//│memccpy()は、メモリー領域srcからメモリー領域destに最大でnバイトのコピーを行う。
//│nバイトコピーする前に文字cが見つかると、そこでコピーを中止する。
//│コピー元とコピー先のメモリー領域が重なっている場合、結果は不定である。
//□返り値
//│memccpy()は、dest中に見つかったcの次にあるキャラクター型の変数を指すポインターを返す。
//│見つからなかった場合、NULLを返す。
//□準拠
//│SVr4,4.3BSD,POSIX.1-2001.
#ifndef PIECE
void* memccpy(void* dest, const void* src, int c, size_t n) {
	      unsigned char* d = dest;
	const unsigned char* s = src;
	do {
		if(!n--) { return NULL; }
	} while((*d++ = *s++) != c);
	return d;
}
#else //PIECE
void* memccpy(void* dest, const void* src, int c, size_t n);
asm("
		.code
		.align		1
		.global		memccpy
memccpy:
		ld.w		%r10, 0			;//%r10 := NULL
memccpy_LOOP:						;//do {
		sub		%r15, 1			;//  %r15 := n--
		jrult		memccpy_RET		;//  if(n < 0) { return NULL }
		ld.ub		%r9, [%r13]+		;//  %r9  := t = *src++
		ld.b		[%r12]+, %r9		;//  *dest++ = t
		cmp		%r9, %r14		;//} while(t != c)
		jrne		memccpy_LOOP		;//
		ld.w		%r10, %r12		;//%r10 := dest
memccpy_RET:						;//
		ret					;//return  dest
");
#endif//PIECE

//■「Linux Programmer's Manual (3) - MEMPCPY」(http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/mempcpy.3.html)より引用:
//□名前
//│mempcpy - メモリー領域をコピーする
//□説明
//│mempcpy()関数はmemcpy()関数とほぼ同一である。
//│この関数は、srcで始まるオブジェクトからnバイトを、destで指されるオブジェクトにコピーする。
//│ただしdestの値を返すのではなく、最後に書き込まれたバイトの後に続くバイトへのポインターを返す。
//│この関数はいくつかのオブジェクトが連続的なメモリーの場所にコピーされるような状況で役に立つ。
//□返り値
//│dest+n.
//□準拠
//│この関数はGNUによる拡張である。
#ifndef PIECE
void* mempcpy(void* dest, const void* src, size_t n) {
	return (char*)memcpy(dest, src, n) + n;
}
#else //PIECE
void* mempcpy(void* dest, const void* src, size_t n);
asm("
		.code
		.align		1
		.global		mempcpy
mempcpy:
		pushn		%r0			;//
		xcall.d		memcpy			;//%r10 := dest = memcpy(dest, src, n)
		ld.w		%r0, %r14		;//%r0  := n				*delay*
		add		%r10, %r0		;//%r10 := dest + n
		popn		%r0			;//
		ret					;//return  dest + n
");
#endif//PIECE

//■「Linux Programmer's Manual (3) - STPNCPY」(http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/stpncpy.3.html)より引用:
//□名前
//│stpncpy - 固定長の文字列をコピーして、その最後へのポインターを返す
//□説明
//│stpncpy()関数はsrcが指している文字列から終端のヌルバイト('\0')を含めて最大nバイトをdestにコピーする。
//│長さstrlen(src)がnより小さい場合にはdestの残りの部分にはヌルバイト('\0')文字が埋められる。
//│長さstrlen(src)がn以上ならば、destが指す文字列はヌルで終端されていない。
//│二つの文字列は重なってはならない。
//│プログラマーはdestに少なくともnバイトの空きがあることを保証しなければならない。
//□返り値
//│stpncpy()はdestの終端のヌルバイトを指すポインターを返すか、destがヌルバイトで終端されていない場合にはdest+nを返す。
//□準拠
//│この関数はPOSIX.1-2008に追加された。
//│それ以前はGNUによる拡張であった。
//│この関数は1993年にGNU Cライブラリのバージョン1.07で初めて登場した。
#ifndef PIECE
char* strncpy(char* dest, const char* src, size_t n) {
	char*  save_dest = dest;
	stpncpy(dest, src, n);
	return save_dest;
}
char* stpncpy(char* dest, const char* src, size_t n) {
	char* save_dest;
	do {
		if(!n--) { return dest; }
	} while((*dest++ = *src++));
	save_dest = dest - 1;
	goto L_START;
	do {
		*dest++ = '\0';
L_START:	;
	} while(n--);
	return save_dest;
}
#else //PIECE
char* strncpy(char* dest, const char* src, size_t n);
char* stpncpy(char* dest, const char* src, size_t n);
asm("
		.code
		.align		1
		.global		strncpy
		.global		stpncpy
strncpy:
		call		stpncpy			;//%r12 := save_dest = dest
		ret.d					;//return  save_dest		┐
stpncpy:						;//				│
		ld.w		%r10, %r12		;//%r10 := dest			┘	*delay*
stpncpy_LOOP:						;//do {
		sub		%r14, 1			;//  %r14 := n--
		jrult		stpncpy_RET		;//  if(n < 0) { return dest }
		ld.ub		%r9, [%r13]+		;//  %r9  := c = *src++
		ld.b		[%r10]+, %r9		;//  *dest++ = c
		cmp		%r9, 0			;//  
		jrne		stpncpy_LOOP		;//} while(c)
		ld.w		%r9, %r10		;//%r9  := dest
		jp.d		stpncpy_START		;//goto L_START
		sub		%r10, 1			;//%r10 := save_dest = dest - 1		*delay*
stpncpy_FILL:						;//do {
		ld.b		[%r9]+, %r8		;//  *dest++ = '￥0'
stpncpy_START:						;//L_START:
		sub		%r14, 1			;//  %r14 := n--
		jruge		stpncpy_FILL		;//} while(  n)
stpncpy_RET:						;//
		ret					;//return  save_dest
");
#endif//PIECE

//■「Linux Programmer's Manual (3) - STPCPY」(http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/stpcpy.3.html)より引用:
//□名前
//│stpcpy - 文字列をコピーし、コピーした文字列の終りへのポインターを返す
//□説明
//│stpcpy()関数は、srcで指された文字列を(文字列を終端するヌルバイト('\0')を含めて)destで指された配列にコピーする。
//│文字列は重複してはならず、コピー先の文字列destはコピーを受け取るのに十分大きくなくてはならない。
//□返り値
//│stpcpy()は、文字列destの始まりではなく終りを指すポインター(すなわち、文字列を終端するヌルバイト)を返す。
//□準拠
//│この関数はPOSIX.1-2008に追加された。
//│それ以前は、この関数はCやPOSIX.1標準の一部でもUNIXシステムの慣習的なものでもなかった。
//│この関数はLatticeCAmigaDOSコンパイラで初めて登場し、それは少なくとも1986年時点ではそうであった。
//│その後、1989年にGNUfileutilsとGNU textutilsに登場し、1992年までにはGNU Cライブラリにも存在していた。
//│この関数はBSD系にも存在する。
#ifndef PIECE
#ifndef _MSC_VER	//{{2015/05/31:Visual C++ 6.0でReleaseビルドすると「error C2169: 'strcpy' : 組み込み関数は定義できません。」になるので除外しました。
char* strcpy(char* dest, const char* src) {
	char*  save_dest = dest;
	stpcpy(dest, src);
	return save_dest;
}
#endif//_MSC_VER	//}}2015/05/31:Visual C++ 6.0でReleaseビルドすると「error C2169: 'strcpy' : 組み込み関数は定義できません。」になるので除外しました。
char* stpcpy(char* dest, const char* src) {
	do { /** no job **/ } while((*dest++ = *src++));
	return dest - 1;
}
#else //PIECE
char* strcpy(char* dest, const char* src);
char* stpcpy(char* dest, const char* src);
asm("
		.code
		.align		1
		.global		strcpy
		.global		stpcpy
strcpy:
		call		stpcpy			;//%r12 := save_dest = dest
		ret.d					;//return  save_dest		┐
stpcpy:							;//				│
		ld.w		%r10, %r12		;//%r10 := dest			┘	*delay*
stpcpy_LOOP:						;//do {
		ld.ub		%r9, [%r13]+		;//  %r9  := c = *src++
		ld.b		[%r10]+, %r9		;//  *dest++ = c
		cmp		%r9, 0			;//} while(c)
		jrne		stpcpy_LOOP		;//
		ret.d					;//return  dest - 1
		sub		%r10, 1			;//%r12 := dest - 1			*delay*
");
#endif//PIECE

/*--------------------------------------------------------------------------*/

/* * Thu Jul 09 00:22:54 JST 2009 Naoyuki Sawa
 * - VC++6.0の_splitpath()を、ほぼそのまま移植しました。
 */
void
splitpath(const char* path, char drive[/*MAX_DRIVE*/], char dir[/*MAX_DIR*/], char fname[/*MAX_FNAME*/], char ext[/*MAX_EXT*/])
{
	const char* sep;
	const char* dot;
	const char* p;
	int len;

	/* パス名が2文字以上で、2文字目が':'ならば、最初の2文字がドライブ名。 */
	if((path[0] != '\0') && (path[1] == ':')) {
		if(drive) {
			memcpy(drive, path, 2);
			drive[2] = '\0';
		}
		path += 2; /* pathをドライブ名の次へ進める */
	} else {
		if(drive) {
			drive[0] = '\0';
		}
	}

	/* 最後の区切り文字の次の位置と、最後のドット文字の位置を検索します。 */
	sep = dot = NULL;
	for(p = path; *p; p++) {
		if((*p == '/') || (*p == '\\')) {
			sep = p + 1; /* 区切り文字の次の位置 */
		} else if(*p == '.') {
			dot = p;     /* ドット文字の位置 */
		}
	}

	/* 区切り文字が有れば、最後の区切り文字も含めてディレクトリ名を格納。 */
	if(sep) {
		if(dir) {
			len = sep - path;
			if(len > (MAX_DIR - 1)) {
				len = (MAX_DIR - 1);
			}
			memcpy(dir, path, len);
			dir[len] = '\0';
		}
		path = sep; /* pathをファイル名の先頭へ進める */
	} else {
		if(dir) {
			dir[0] = '\0';
		}
	}

	/* ファイル名の先頭よりも後ろに、ドット文字が有れば… */
	if(dot >= path) { /* この条件で !dot も除外できます。 */
		/* ドット文字の前まで、ファイル名として格納。 */
		if(fname) {
			len = dot - path;
			if(len > (MAX_FNAME - 1)) {
				len = (MAX_FNAME - 1);
			}
			memcpy(fname, path, len);
			fname[len] = '\0';
		}
		/* ドット文字から最後まで、拡張子として格納。 */
		if(ext) {
			len = p/*末端*/ - dot;
			if(len > (MAX_EXT - 1)) {
				len = (MAX_EXT - 1);
			}
			memcpy(ext, dot, len);
			ext[len] = '\0';
		}
	} else {
		/* 残りの文字をすべて、ファイル名として格納。 */
		if(fname) {
			len = p/*末端*/ - path;
			if(len > (MAX_FNAME - 1)) {
				len = (MAX_FNAME - 1);
			}
			memcpy(fname, path, len);
			fname[len] = '\0';
		}
		if(ext) {
			ext[0] = '\0';
		}
	}
}

/* * Thu Jul 09 00:22:54 JST 2009 Naoyuki Sawa
 * - VC++6.0の_makepath()を、少し変更して移植しました。
 *   VC++6.0の_makepath()は、path[MAX_PATH]への格納文字数をチェックしておらず、MAX_PATH文字を超えても格納してしまいます。
 *   以下のコードは、path[MAX_PATH]への格納文字数を、終端の'\0'を除いて(MAX_PATH-1)文字以下に切り詰めるよう変更しました。
 */
void
makepath(char path[/*MAX_PATH*/], const char* drive, const char* dir, const char* fname, const char* ext)
{
	char* path_end = &path[MAX_PATH - 1];

	/* ドライブ名が1文字以上指定されていたら、ドライブ名を格納。 */
	if(drive && *drive) {
		*path++ = *drive;
		//if(path == path_end) goto L_EXIT; /* 有り得ない */
		*path++ = ':'; /* 2文字目は':'固定 */
		//if(path == path_end) goto L_EXIT; /* 有り得ない */
	}

	/* ディレクトリ名が1文字以上指定されていたら、ディレクトリ名を格納。 */
	if(dir && *dir) {
		do {
			*path++ = *dir++;
			if(path == path_end) goto L_EXIT;
		} while(*dir);
		/* 末尾の区切り文字が省略されていたら、区切り文字を補う。
		 * - ディレクトリ名に空文字列が指定された場合(dir="")は、区切り文字を補わないことに注意。
		 *   もし空文字列(dir="")に対して区切り文字を補ってしまうと、以下のようなバグが発生する。
		 *     splitpath("xxx.yyy", drive, dir, fname, ext); -> drive = "", dir = "", fname = "xxx", ext = ".yyy"
		 *     makepath(path, drive, dir, fname, ext);       -> path = "\xxx.yyy" (元のpathに無い'\'が増えるバグ)
		 */
		if((*(path - 1) != '/') && (*(path - 1) != '\\')) {
			*path++ = '\\';
			if(path == path_end) goto L_EXIT;
		}
	}

	/* ファイル名を格納。 */
	if(fname) {
		while(*fname) {
			*path++ = *fname++;
			if(path == path_end) goto L_EXIT;
		}
	}

	/* 拡張子を格納。 */
	if(ext) {
		if(*ext != '.') {
			*path++ = '.'; /* 先頭のドット文字が省略されていたら、ドット文字を補う */
			if(path == path_end) goto L_EXIT;
		}
		while(*ext) {
			*path++ = *ext++;
			if(path == path_end) goto L_EXIT;
		}
	}
L_EXIT:
	*path = '\0'; /* 終端 */
}

/*--------------------------------------------------------------------------*/

/* ワードの中で最初にセットされている最下位ビットの位置を返します。(Find first set)
 * [in]
 *	i	ワード
 * [out]
 *	戻り値	(i = ???????? ???????? ???????? ???????1 の時) ⇒  1 … 最下位ビットは 1
 *		(i = ???????? ???????? ???????? ??????10 の時) ⇒  2
 *		(i = ???????? ???????? ???????? ?????100 の時) ⇒  3
 *		                  ( 中 略 )
 *		(i = ?1000000 00000000 00000000 00000000 の時) ⇒ 31
 *		(i = 10000000 00000000 00000000 00000000 の時) ⇒ 32 … 最上位ビットは32
 *		(i = 00000000 00000000 00000000 00000000 の時) ⇒  0 … ワードが0ならば0
 * [note]
 *	- 本関数は、ffs(): 4.3BSD, POSIX.1-2001. 準拠です。
 *	  参照: Linux Programmer's Manual (3) FFS
 *	        http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/ffs.3.html
 *	- P/ECEのコンパイラgcc33は、__builtin_ffsを認識しますが、インライン展開しません。
 *	  gcc33は、__builtin_ffsを見つけると、ffs関数を呼び出すコードを生成するようです。
 *	  つまり、プログラム中で__builtin_ffsを使うのとffsを使うのは、等価です。
 */
#ifndef PIECE
//----------------------------------------------------------------------------
//C言語版
//----------------------------------------------------------------------------
int ffs(int i) {
	int n;
	for(n = 1; n <= 32; n++) {
		if((i & 1) != 0) {
			return n;
		}
		i >>= 1;
	}
	return 0;
}
#else /*PIECE*/
//----------------------------------------------------------------------------
//アセンブラ版①
//高速ですが、ややコードサイズが大きな実装です。
//----------------------------------------------------------------------------
//asm("
//		.code
//		.align		1
//		.global		ffs
//ffs:
//		swap		%r12, %r12	;//          +-- 反転後の値で､1が最上位ビットに有る時                                             反転後の値で､1が最下位ビットに有る時 --+   +-- 1が無い時
//		mirror		%r12, %r12	;//          |                                                                                                                           |   |
//		scan1		%r10, %r12	;// %r10 :=  0   1   2   3   4   5   6   7   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8
//		sll		%r12, %r10
//		scan1		%r11, %r12	;// %r11 :=  0   0   0   0   0   0   0   0   0   1   2   3   4   5   6   7   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8   8
//		sll		%r12, %r11
//		add		%r10, %r11	;// %r10 :=  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  16  16  16  16  16  16  16  16  16  16  16  16  16  16  16  16
//		scan1		%r11, %r12	;// %r11 :=  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   2   3   4   5   6   7   8   8   8   8   8   8   8   8   8
//		sll		%r12, %r11
//		add		%r10, %r11	;// %r10 :=  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  24  24  24  24  24  24  24  24
//		scan1		%r11, %r12	;// %r11 :=  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   1   2   3   4   5   6   7   8
//		jruge.d		3
//		 add		%r10, %r11	;// %r10 :=  0   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32	*delay*
//		 ld.w		%r10, -1
//		ret.d
//		add		%r10, 1		;// %r10 :=  1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32   0
//");
//----------------------------------------------------------------------------
//アセンブラ版②
//低速で、省メモリな実装です。
//ffs()は使用頻度が低く、実行速度は重要でないので、こちらの方が良いです。
//----------------------------------------------------------------------------
//asm("
//		.code
//		.align		1
//		.global		ffs
//ffs:
//		cmp		%r12, 0		;// if(i != 0) {
//		jreq.d		7
//		 ld.w		%r10, 0		;// %r10 := n = 0						*delay*
//		 swap		%r12, %r12	;//   %r12 := i = 反転(i)
//		 mirror		%r12, %r12
//		  add		%r12, %r12	;//   do { %psr(C) := i[31], %r12 := i <<= 1, %r10 := n++
//		 jruge.d	-1		;//   } while(%psr(C) == 0)
//		 add		%r10, 1		;// }								*delay*
//		ret				;// return n
//");
//----------------------------------------------------------------------------
//アセンブラ版③
//さらに低速で、さらに省メモリな実装です。
//処理方法を工夫して、一命令節約しました。
//----------------------------------------------------------------------------
asm("
		.code
		.align		1
		.global		ffs
ffs:
		cmp		%r12, 0		;// if(i != 0) {
		jreq.d		6
		 ld.w		%r10, 0		;// %r10 := n = 0			*delay*
		  sll		%r12, 1		;//   do { %r12 := i <<= 1, %r10 := n++
		 jrne.d		-1		;//   } while(i != 0)
		 sub		%r10, 1		;//					*delay*
		 add		%r10, 33	;// %r10 := n += 33  (-1～-32)⇒(32～1)
		ret				;// return n
");
#endif/*PIECE*/

/*--------------------------------------------------------------------------*/

#ifdef  PIECE
//{{2014/09/29追加:malloc_usable_size()を追加しました。
size_t malloc_usable_size(void* ptr) {
	//                              |               |
	//  (((HEAPMEM*)ptr)-1)         +===============+
	//                              | mark  | owner |
	//                              +---------------|
	//                              |     chain     |
	//              ptr             +---------------+
	//               A              |///////////////|
	//               |              |///////////////|
	//               |size          |///////////////|
	//               |              |///////////////|
	//               V              |///////////////|
	// ((((HEAPMEM*)ptr)-1)->chain) +===============+
	//                              | mark  | owner |
	//                              +---------------|
	//                              |     chain     |
	//                              +---------------+
	//                              |               |
	return ptr ? ((int)((((HEAPMEM*)ptr)-1)->chain) - (int)ptr) : 0;
}
//}}2014/09/29追加:malloc_usable_size()を追加しました。
#else //PIECE
#ifdef  GC_H
size_t malloc_usable_size(void* ptr) {	//Visual C++ 6.0 with Boehm GC
	//Boehm GCを使用すると、malloc()はメモリブロックの途中(=管理情報の後)のポインタを返す。
	//GC_size()は、メモリブロックの途中が指定されても、メモリブロックの全体のサイズを返す。
	//malloc()が返したポインタ以降のサイズを得るには、以下のように計算しなくてはならない。(実験より推測)
	return ptr ? (GC_size(ptr) - ((int)ptr - (int)GC_base(ptr))) : 0;
}
#else //GC_H
size_t malloc_usable_size(void* ptr) {	//Visual C++ 6.0 without Boehm GC
	return ptr ? _msize(ptr) : 0;
}
#endif//GC_H
#endif//PIECE

/*--------------------------------------------------------------------------*/

// * Tue Mar 24 21:38:35 JST 2015 Naoyuki Sawa
// - EPSONライブラリのbsearch()を置き換えました。
//   EPSONライブラリのbsearch()のままでも問題無いのですが、C言語で実装されていて生成されるコードに少し無駄が有ります。
//   アセンブラ化する事によって、68バイト⇒60バイトになり、8バイトのサイズ節約になりました。
//   アセンブラ化による高速化の効果は、比較関数の処理時間を含めなければ、約15%の高速化です。
#ifndef PIECE
void* bsearch(const void* key, const void* _base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)) {
	const unsigned char* base = _base;
	goto L_START;
	do {
		const unsigned char* mid = base + ((nmemb >> 1) * size);
		int retVal = (*compar)(key, mid);
		if(retVal == 0) { return (void*)mid; }
		if(retVal >  0) {
			base = mid + size;
			nmemb--;
		}
		nmemb >>= 1;
L_START:	;
	} while(nmemb);
	return NULL;
}
#else //PIECE
void* bsearch(const void* key, const void* _base, size_t nmemb, size_t size, int (*compar)(const void*, const void*));
asm("
		.code
		.align		1
		.global		bsearch
bsearch:
		pushn		%r3
		xsub		%sp, %sp, 4
		ld.w		[%sp+0], %r12		;//[%sp+0] := key
		ld.w		%r0, %r13		;//%r0     := base
		ld.w		%r1, %r14		;//%r1     := nmemb
		ld.w		%r2, %r15		;//%r2     := size
		jp.d		bsearch_START		;//goto L_START
		cmp		%r1, 0			;//%psr(Z) := !nmemb			────┐	*delay*
bsearch_LOOP:						;//do {						│
		;//%r0      := base									│
		;//%r1      := nmemb									│
		;//%r2      := size									│
		;//%r10     := nmemb>>1									│
		;//[%sp+ 0] := key									│
		;//[%sp+ 4] := %r0									│
		;//[%sp+ 8] := %r1									│
		;//[%sp+12] := %r2									│
		;//[%sp+16] := %r3									│
		;//[%sp+20] := %pc									│
		;//[%sp+24] := compar									│
		mlt.w		%r10, %r2		;//  %alr :=             (nmemb>>1)*size	│
		ld.w		%r3, %alr		;//  %r3  :=             (nmemb>>1)*size	│
		add		%r3, %r0		;//  %r3  := mid = base+((nmemb>>1)*size)	│
		xld.w		%r9, [%sp+24]		;//  %r9  := compar				│
		xld.w		%r12, [%sp+0]		;//  %r12 := key				│
		call.d		%r9			;//  %r10 := retVal = (*compar)(key, mid)	│
		ld.w		%r13, %r3		;//  %r13 :=                         mid	│	*delay*
		cmp		%r10, 0			;//  						│
		jreq		bsearch_FOUND		;//  if(retVal == 0) { return mid }		│
		jrlt		4			;//  if(retVal >  0) {				│
		 ld.w		%r0, %r3		;//    %r0  :=        mid			│
		 add		%r0, %r2		;//    %r0  := base = mid + size		│
		 sub		%r1, 1			;//    %r1  := nmemb-- }			│
		srl		%r1, 1			;//  %r1  := nmemb >>= 1		────┤
bsearch_START:						;//  						│
		ld.w		%r10, %r1		;//  %r10 :=              nmemb			│
		jrne.d		bsearch_LOOP		;//} while(nmemb)			←───┘
		srl		%r10, 1			;//  %r10 :=              nmemb>>1			*delay*
bsearch_RET:						;//
		xadd		%sp, %sp, 4
		popn		%r3
		ret
bsearch_FOUND:
		jp.d		bsearch_RET		;//return  mid
		ld.w		%r10, %r3		;//%r10 := mid						*delay*
");
#endif//PIECE

/*--------------------------------------------------------------------------*/

// * Sat Jul 25 17:20:54 JST 2015 Naoyuki Sawa
// - log2()を追加しました。宣言は、include/math.h に有ります。log2()は、C99で追加された関数です。「Lua 5.3.1」が、使用しています。
//   EPSONライブラリにも、Visual C++ 6.0にも、log2()は含まれていません。
double log2(double x) {
	return log(x) / 0.69314718055994530941723212145818/*=log(2)*/;
}
