/*	
 *	clipprnt.c
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Tue May 20 06:00:00 JST 2003 Naoyuki Sawa
 *	- http://minix.technoir.org/src/lib/stdio/doprnt.cを基に改造しました。
 *	* Thu Jul 13 06:12:00 JST 2006 Naoyuki Sawa
 *	- snprintf(),vsnprintf()を追加しました。
 *	- snprintf(),vsnprintf()対応のために、既存のdoprnt()を改造しました。
 *	  doprnt()はsprintf(),vsprintf()が利用していたサブルーチンで、改造後も引き続き利用します。
 *	  sprintf(),vsprintf()に影響が出ないよう気をつけたつもりですが、しばらくの間は要注意です。
 *	* Wed Nov 16 02:21:10 JST 2011 Naoyuki Sawa
 *	- 型フィールド文字'g'(及び'G')に簡易対応しました。
 *	* Tue Jan 31 23:45:07 JST 2012 Naoyuki Sawa
 *	- f_print()の、絶対値が2147483648.0(=INT_MAX+1)以上の実数を表示すると文字化けするバグを修正しました。
 *	  絶対値が4294967296.0(=UINT_MAX+1)以上の実数を表示すると文字化けするバグ(制約？)は、まだ未修正です。
 *	* Thu Oct 02 01:02:39 JST 2014 Naoyuki Sawa
 *	- snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。
 *	  scprintf(),vscprintf(),asprintf(),vasprintf()を追加しました。
 *	* Sun Oct 12 15:49:27 JST 2014 Naoyuki Sawa
 *	- doprnt()関数に、以下の変更を行いました。
 *	- 当モジュールをVC++6.0でビルドする場合、OUTの定義がWindowsヘッダファイル「rpcdce.h」と衝突するため、OUTを予め定義解除しました。
 *	  当モジュールをVC++6.0でビルドする場合の対策が必要になった理由は、以下のとおりです。
 *	- これまでは、VC++6.0に含まれているprintf等で充分だったので、当モジュールをVC++6.0でビルドすることは考慮していなかったのですが、
 *	  snprintf(),vsnprintf()の戻り値の挙動変更や、scprintf(),vscprintf(),asprintf(),vasprintf()の追加に伴い (2014/10/02コメント参照)
 *	  VC++6.0用のプロジェクトにも当モジュールを含めてビルドし、P/ECE用プログラムと動作を共通化したいと思いました。
 *	  そのために、当モジュールをVC++6.0でビルドする場合も警告が出ないよう、対策しました。
 *	* Thu Jan 22 21:10:35 JST 2015 Naoyuki Sawa
 *	- 長さ修飾子'll'を仮対応しました。
 *	  長さ修飾子'll'が指定された場合、可変引数からの値の取得と、変換指定子'n'への値の格納を、64ビットで行うようにしただけです。
 *	  内部処理は32ビットのままであり、32ビットの範囲を超える64ビット値を指定すると、下位32ビット部分のみを解釈して表示します。	⇒{{2016/08/04コメント追記:32ビットの範囲を超える64ビット値の表示に正式対応しました。}}
 *	- 内部処理を32ビットのままにした理由は、稀なケースに対応するために性能が低下することを避けるためです。
 *	  long long型を使用するプログラムでも、ほとんどの場合、値は32ビットの範囲に収まると思います。
 *	  もし収まらなくても、表示がおかしくなるだけで、動作上は(おそらく)問題ありません。
 *	* Sun Aug 02 16:45:48 JST 2015 Naoyuki Sawa
 *	- fprintf(),printf(),vfprintf(),vprintf()を、clipio.c⇒clipprnt.cへ移動しました。
 *	  Win32プロジェクトでも、doprnt()を利用したprintf()等を利用したいからです。
 *	  clipio.cはP/ECEに依存しているのでWin32プロジェクトに含められませんが、clipprnt.cならばWin32プロジェクトに含められます。
 *	- 変換指定子'b'に対してもフラグ文字'#'が指定出来るようにしました。
 *	  '%#b'の場合'0b','%#B'の場合'0B'が先行します。
 *	  この動作はPerlのsprintf関数に互換です。
 *	* Wed Sep 16 21:59:48 JST 2015 Naoyuki Sawa
 *	- vasprintf()がva_listの使い方が正しくなかった点を修正しました。
 *	  P/ECE開発環境(GCC)とWindows(VC++6.0)での動作上は修正前のままでも問題無く動作するのですが、厳密さのために修正する事にしました。
 *	* Tue Feb 23 21:40:12 JST 2016 Naoyuki Sawa
 *	- 三桁区切りのフラグ文字「'」を対応しました。
 *	  □「Linux Programmer's Manual - PRINTF」(http://linuxjm.osdn.jp/html/LDP_man-pages/man3/printf.3.html)より引用:
 *	  │フラグ文字「'」
 *	  │10進数変換(i,d,u,f,F,g,G)において、ロケール情報に指定があれば1000単位の区切り文字を出力する。
 *	  │gccの多くのバージョンは、このオプションを解釈することができず、警告を出力することに注意せよ。
 *	- 上記の説明には、"10進数変換(i,d,u,f,F,g,G)において"とありますが、当実装では簡単のために、
 *	  フラグ文字「'」が指定されたら、10進数変換に限らず(たとえばもし16進数変換であっても)、整数部に三桁区切りを表示する事にしました。
 *	  呼び出し側で10進数変換以外とフラグ文字「'」を併用しない限り、この違いが問題になる事は無いと思います。
 *	- フラグ文字「'」のシンボル名は、FL_THOUSANDSとしました。このシンボル名は、自分で考えて付けました。
 *	  三桁区切りに対応している既存のライブラリのソースが、インターネット上で見つけられず、一般的なシンボル名が判らなかったからです。
 *	  もっともこれは、このソース内だけの小さな疑問点であり、特に気にする必要はありません。
 *	* Sat May 28 21:20:19 JST 2016 Naoyuki Sawa
 *	- snprintf(),vsnprintf()の引数cntの型をint⇒size_tに修正しました。
 *	  修正後の方が標準仕様に沿っています。VC++6.0ではコンパイラがvsnprintf()を持っていなかったので標準仕様と異なる引数型でもエラーは出なかったのですが、
 *	  VC++.NETではコンパイラがvsnprintf()を持っているので引数型が異なるとエラーになったからです。
 *	  今回の修正による動作の変化は有りません。今後、Visual C++ .NETへ移行するための準備です。
 *	* Sun May 29 21:54:56 JST 2016 Naoyuki Sawa
 *	- Visual C++ .NETでコンパイルした時に、vsprintf()等で警告C4028が表示される問題を回避しました。
 *	  詳細は、以下の通りです。
 *	- VC++2015で当ライブラリをコンパイルしてみた所、当ライブラリの実装で置き換えるための、vsprintf()等で警告C4028が表示されました。
 *	  原因は、VC++2015では、これらの関数のプロトタイプが、標準的なプロトタイプと異なっている事でした。
 *	  以下に、VC++2015での、vsprintf()の宣言を示します。(他の関数も同様です)
 *	  □c:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\stdio.h
 *	  │_CRT_STDIO_INLINE int __CRTDECL vsprintf(
 *	  │    _Pre_notnull_ _Post_z_        char*       const _Buffer,
 *	  │    _In_z_ _Printf_format_string_ char const* const _Format,
 *	  │                                  va_list           _ArgList
 *	  │    )
 *	  標準的なプロトタイプでは、第一引数は'char*',第二引数は'char const*'ですが、VC++2015では第一引数が'char* const',第二引数は'char const* const'になっています。
 *	  (ちなみに、MSDNの関数リファレンスでは前者になっており、VC++2015のヘッダファイルだけが後者の宣言であるようです。)
 *	- 対処する方法は、二種類考えられます。
 *	  ・一つは、Visual C++ .NETならば、当モジュール内の関数の引数型を変更して、Visual C++ .NETの関数プロトタイプに合わせる事です。
 *	  ・もう一つは、Visual C++ .NETならば、警告を無視する方法です。
 *	  本当は前者の方が安全なのでしょうけれど、今回は後者の方法を使う事にしました。
 *	  この問題は明らかにVisual C++ .NETだけの問題であり、この問題に対処するために多くの関数の定義を条件コンパイル分けしたりして、コードが複雑になるのは良くないと思ったからです。
 *	- 本日、clipprnt.cとclipscan.cに、同じ方法で対処を行いました。
 *	  もし今後、対処する方法を変更する場合は、両方について、変更する必要が有るかを検討して下さい。
 *	* Thu Aug 04 21:10:05 JST 2016 Naoyuki Sawa
 *	- __int64とlong longを条件コンパイルで使い分けていた個所を、int64_tで共通化しました。
 *	  当モジュールを作成した当時は、まだ/clip/include/stdint.hを作成していなかったので、__int64とlong longを条件コンパイルで使い分けていました。
 *	  現在では、int64_tを使用すれば__int64とlong longを条件コンパイルで使い分ける必要は無くなっているので、当モジュールもそのように修正しました。
 *	- 32ビットの範囲を超える64ビット値の表示に正式対応しました。
 *	  これまでは、内部処理は32ビットのままであり、32ビットの範囲を超える64ビット値を指定すると、下位32ビット部分のみを解釈して表示していました。
 *	  今後は、内部処理も64ビットで行い、32ビットの範囲を超える64ビット値(double,int64_t,uint64_t)も表示出来るようになりました。
 *	  これまで内部処理を32ビットにしていた理由は、性能の低下を避けるためだったですが、大きなdoubleの値が表示出来ないと困る事が有ったので、やっぱり内部処理を64ビット化する事にしました。
 *	  今回の変更により、printf系関数の速度低下と、常にframdi.sモジュールがリンクされる事によるコードサイズの増大が発生しますが、やむをえません。
 *	  尚、常にframdi.sモジュールがリンクされるようになったので、今後は、アプリケーションや他のモジュールにおいて、コードサイズ低減のために64ビット整数演算を避ける意味は無くなりました。
 *	* Sun Sep 04 21:41:17 JST 2016 Naoyuki Sawa
 *	- 「#pragma warning(disable:...)」～「#pragma warning(default:...)」を、「#pragma warning(push)」「#pragma warning(disable:...)」～「#pragma warning(pop)」に変更しました。
 *	  詳細は、clipstd.h の同日のコメントを参照して下さい。
 *	- 64ビット版では、変換指定子pを64ビット引数と解釈するようにしました。
 *	  32ビット版の動作には影響有りません。
 *	- 長さ修飾子j,z,tを対応しました。
 *	  長さ修飾子hhは未対応である事を明示的に示すためにエラー終了するようにしました。
 *	* Sun Oct 02 21:48:17 JST 2016 Naoyuki Sawa
 *	- doprnt()の32ビット版の処理において、長さ修飾子z,tを読み飛ばしていなかったバグを修正しました。
 *	* Tue Oct 18 21:19:07 JST 2016 Naoyuki Sawa
 *	- 0詰め,かつ,三桁区切りならば、0詰めにも三桁区切りを含めるようにしました。
 *	  詳細は、以下の通りです。
 *	- ゲームのスコア表示等を行う場合に、0詰めと三桁区切りを併用したいケースが時々有ります。
 *	  しかし、これまでは、0詰めと三桁区切りを併用すると、0詰めに三桁区切りが含まれず、見た目に不自然な出力になる問題が有りました。
 *	  【変更前】
 *	  │printf("$%'014d\n", 123456789);		//$000123,456,789
 *	  │printf("$%'020.5f\n", 12345678.90123);	//$000012,345,678.90123
 *	  一応、整数の場合は、出力幅指定ではなく、精度指定を用いることで、見た目に自然な出力にする事も可能ではあるのですが～
 *	  【変更前】
 *	  │printf("$%'.14d\n", 123456789);		//$00,000,123,456,789
 *	  ～整数の精度指定を用いるのは直観的でなく、一般的には出力幅指定と0詰めを用いる事の方が多いので、やはり問題でした。
 *	- そこで今回、0詰め,かつ,三桁区切りならば、0詰めにも三桁区切りを含めるようにしました。
 *	  変更後は、上記の例は、以下のような出力となります。
 *	  【変更後】
 *	  │printf("$%'014d\n", 123456789);		//$00,123,456,789
 *	  │printf("$%'020.5f\n", 12345678.90123);	//$00,012,345,678.90123
 *	  │printf("$%'.14d\n", 123456789);		//$00,000,123,456,789	これは'0詰め,かつ,三桁区切り'ではないので、今回の変更の影響は受けません。
 *	- 注意点として、0詰めと三桁区切りを併用する場合は、出力幅の指定に注意して下さい。
 *	  具体的には、整数部の出力幅が4の倍数であると、先頭に三桁区切りが置かれて、見た目に不自然な出力になってしまいます。
 *	  【変更後】
 *	  │printf("$%'016d\n", 123456789);		//$,000,123,456,789
 *	  │printf("$%'022.5f\n", 12345678.90123);	//$,000,012,345,678.90123
 *	  │printf("$%'017d\n", -123456789);		//$-,000,123,456,789
 *	  │printf("$%'023.5f\n", -12345678.90123);	//$-,000,012,345,678.90123
 *	  0詰めと三桁区切りを併用する場合は、整数部の出力幅が4の倍数にならないよう、アプリケーション側で注意して下さい。
 *	- 尚、手元に三桁区切りに対応した処理系が無い(VS2015やx86用のGCCも対応していないようです)ため、一般的にどのように出力されるかが不明です。
 *	  従って、上記の変更は、一般的な処理系の出力結果に合わせたのではなく、自分の感覚で自然な出力結果だと思う仕様にしたものです。
 *	  元々、三桁区切りはC標準ライブラリの仕様には含まれていない(?要確認)ので、自分の解釈で実装しても大きな問題は無いと思います。
 */
#include "clip.h"

/****************************************************************************
 *
 ****************************************************************************/

					// ＝意味＝		＝例＝
#define FL_LJUST	(1 <<  0)	// 左詰め		%-5d
#define FL_ZEROFILL	(1 <<  1)	// 0詰め		%05d
#define FL_SIGN		(1 <<  2)	// +/-表示		%+5d
#define FL_SPACE	(1 <<  3)	// 空白/-表示		% 5d
#define FL_ALT		(1 <<  4)	// 0/0x/0X表示		%#x
#define FL_SHORT	(1 <<  5)	// ハーフワード引数	%hd
#define FL_LONG_LONG	(1 <<  6)	// 64ビット引数		%lld				//{{2015/01/22変更:長さ修飾子'll'を仮対応しました。}}
#define FL_PRECSPEC	(1 <<  7)	// 精度指定あり		%9.5f
#define FL_SIGNEDCONV	(1 <<  8)	// 符号あり		%d
#define FL_THOUSANDS	(1 <<  9)	// 三桁区切り		%'d				//{{2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。}}
#define FL_NOMORE	(1 << 31)	// （内部使用）

/* widthやprecisionを取得します。 */
static const char*
gnum(const char* fmt, int* ip, va_list* app)
{
	int i, c;

	if(*fmt == '*') {
		*ip = va_arg(*app, int);
		fmt++;
	} else {
		i = 0;
		for(;;) {
			c = *fmt;
			if(c < '0' || '9' < c) break;
			i = i * 10 + (c - '0');
			fmt++;
		}
		*ip = i;
	}

	return fmt;
}

//{{2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。
///* 整数値を表示します。 */
//static char*
//i_compute(unsigned val, int base, char* s, int precision)
//{
//	int c;
//
//	c = val % base;
//	val /= base;
//	if(val || precision > 1) s = i_compute(val, base, s, precision - 1);
//	*s++ = c < 10 ? '0' + c : 'a' + (c - 10);
//
//	return s;
//}
//↓2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。
/* 整数値を表示します。 */
//{{2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
//static char* i_compute(unsigned val, int base, char* s, int precision, int thousands) {
//↓2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
static char* i_compute(uint64_t val, int base, char* s, int precision, int thousands) {
//}}2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
	//現在の桁の値を求める。
	int c = val % base;
	//上位の桁の値を求める。
	val /= base;
	//上位の桁の値が残っているか,又は,precisionが残ってたら…
	// - precisionよりも値の桁数が大きかった場合、precisionは既に0以下になっている可能性も有る事に注意せよ。
	if(val || (precision > 1)) {
		//上位の桁について再帰する。
		s = i_compute(val, base, s, (precision - 1), (thousands + 1));
		//現在の桁が(3N+2)ならば、上位の桁(3N)と現在の桁(3N+2)の間に三桁区切りを出力する。
		// - ここで明示的に、三桁区切りのフラグ文字「'」が指定されたかどうかを判断する必要は無い。理由は以下の通りです。
		//   三桁区切りのフラグ文字「'」が指定されていない場合、thousandsの初期値はINT_MINであり、再帰中にプラス領域になる事は無い。
		//   マイナス領域のthousandsに対して(thousands%3)の結果はマイナスになり、((thousands%3)==2)が成立する事は無いからです。
		if((thousands % 3) == 2) { *s++ = ','; }
	}
	//現在の桁の値を出力する。
	*s++ = ((c < 10) ? '0' : ('a' - 10)) + c;
	//最後に格納した文字の次の位置を返す。
	return s;
}
//}}2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。

/* 整数引数を表示します。 */
static char*
o_print(char* s, int flags, int nrdigits, int c, va_list* app)
{
//{{2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
//	unsigned val;
//↓2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
	int64_t val;
//}}2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
	int base;
	char *old_s = s;

	/* 値を取得。 */
	       if(flags & FL_LONG_LONG) {
//{{2016/08/04変更:__int64とlong longを条件コンパイルで使い分けていた個所を、int64_tで共通化しました。
//#ifdef  _MSC_VER
//		                            val = va_arg(*app, unsigned __int64  );		//{{2015/01/22変更:長さ修飾子'll'を仮対応しました。}}
//#else //_MSC_VER
//		                            val = va_arg(*app, unsigned long long);		//{{2015/01/22変更:長さ修飾子'll'を仮対応しました。}}
//#endif//_MSC_VER
//↓2016/08/04変更:__int64とlong longを条件コンパイルで使い分けていた個所を、int64_tで共通化しました。
		                            val = va_arg(*app, int64_t);
//}}2016/08/04変更:__int64とlong longを条件コンパイルで使い分けていた個所を、int64_tで共通化しました。
	} else if(flags & FL_SHORT    ) {
		if(flags & FL_SIGNEDCONV) { val = va_arg(*app,          short    ); }
		else                      { val = va_arg(*app, unsigned short    ); }
	} else {
//{{2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
//		                            val = va_arg(*app, unsigned          );
//↓2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
		if(flags & FL_SIGNEDCONV) { val = va_arg(*app,          int      ); }
		else                      { val = va_arg(*app, unsigned int      ); }
//}}2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
	}

	/* 符号表示。 */
	if(flags & FL_SIGNEDCONV) {
//{{2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
//		if((int)val < 0) {
//			*s++ = '-';
//			val = -(int)val;
//↓2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
		if(val < 0) {
			*s++ = '-';
			val = -val;
//}}2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
		} else if(flags & FL_SIGN) {
			*s++ = '+';
		} else if(flags & FL_SPACE) {
			*s++ = ' ';
		}
	}

	/* 基数表示。 */
	if(flags & FL_ALT) {
		switch(c) {
	    //{{2015/08/02追加:変換指定子'b'に対してもフラグ文字'#'が指定出来るようにしました。'%#b'の場合'0b','%#B'の場合'0B'が先行します。この動作はPerlのsprintf関数に互換です。
		case 'b':
		case 'B': *s++ = '0'; *s++ = 'b'; break;
	    //}}2015/08/02追加:変換指定子'b'に対してもフラグ文字'#'が指定出来るようにしました。'%#b'の場合'0b','%#B'の場合'0B'が先行します。この動作はPerlのsprintf関数に互換です。
		case 'o': *s++ = '0';             break;
		case 'p':
		case 'x':
		case 'X': *s++ = '0'; *s++ = 'x'; break;
		}
	}

	/* 値を表示。 */
	switch(c) {
	case 'b':
	case 'B': base =  2; break;
	case 'o': base =  8; break;
	case 'd':
	case 'i':
	case 'u': base = 10; break;
	case 'p':
	case 'x':
	case 'X': base = 16; break;
	default : base = -1; DIE();
	}
    //{{2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。
    //	s = i_compute(val, base, s, nrdigits);
    //↓2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。
	s = i_compute(val, base, s, nrdigits, (flags & FL_THOUSANDS) ? 0 : INT_MIN);	//三桁区切りのフラグ文字「'」が指定されていたらthousandsの初期値を0、指定されていなければthousandsの初期値をINT_MINとする。詳細はi_compute()のコメントを参照して下さい。
    //}}2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。
    //{{2015/08/02変更:変換指定子'b'に対してもフラグ文字'#'が指定出来るようにしました。'%#b'の場合'0b','%#B'の場合'0B'が先行します。この動作はPerlのsprintf関数に互換です。
    //	if(c == 'X') {
    //↓2015/08/02変更:変換指定子'b'に対してもフラグ文字'#'が指定出来るようにしました。'%#b'の場合'0b','%#B'の場合'0B'が先行します。この動作はPerlのsprintf関数に互換です。
	if(isupper(c)) {
    //}}2015/08/02変更:変換指定子'b'に対してもフラグ文字'#'が指定出来るようにしました。'%#b'の場合'0b','%#B'の場合'0B'が先行します。この動作はPerlのsprintf関数に互換です。
		while(old_s != s) {
			*old_s = toupper(*old_s);
			old_s++;
		}
	}

	return s;
}

/* 浮動小数引数を表示します。 */
static char*
f_print(char* s, int flags, int precision, va_list* app)
{
//{{2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
//	double val;
//	int c;
//↓2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
	double val, ival;
//}}2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。

	/* 値を取得。 */
	val = va_arg(*app, double);

	/* 符号表示。 */
	if(val < 0) {
		*s++ = '-';
		val = -val;
	} else if(flags & FL_SIGN) {
		*s++ = '+';
	} else if(flags & FL_SPACE) {
		*s++ = ' ';
	}

	/* 四捨五入用の+0.5or0.05or0.005... */
	val += pow(10, -precision) / 2;

	/* 整数部表示。 */
//{{2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
//	c = (int)val;
////{{2012/01/31:絶対値が2147483648.0(=INT_MAX+1)以上の実数を表示すると文字化けするバグを修正
////	val -= c;
////↓2012/01/31:絶対値が2147483648.0(=INT_MAX+1)以上の実数を表示すると文字化けするバグを修正
//	val -= (unsigned)c;
////}}2012/01/31:絶対値が2147483648.0(=INT_MAX+1)以上の実数を表示すると文字化けするバグを修正
//    //{{2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。
//    //	s = i_compute(c, 10, s, 1);
//    //↓2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。
//	s = i_compute(c, 10, s, 1, (flags & FL_THOUSANDS) ? 0 : INT_MIN);	//三桁区切りのフラグ文字「'」が指定されていたらthousandsの初期値を0、指定されていなければthousandsの初期値をINT_MINとする。詳細はi_compute()のコメントを参照して下さい。
//    //}}2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。
//↓2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
	val = modf(val, &ival);
	s = i_compute(ival, 10, s, 1, (flags & FL_THOUSANDS) ? 0 : INT_MIN);	//三桁区切りのフラグ文字「'」が指定されていたらthousandsの初期値を0、指定されていなければthousandsの初期値をINT_MINとする。詳細はi_compute()のコメントを参照して下さい。
//}}2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。

	/* 小数部表示。 */
	if(precision) {
		*s++ = '.';
		do {
//{{2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
//			val *= 10;
//			c = (int)val;
//			val -= c;
//			*s++ = '0' + c;
//↓2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
			val = modf(val * 10.0, &ival);
			*s++ = '0' + (int)ival;
//}}2016/08/04変更:32ビットの範囲を超える64ビット値の表示に正式対応しました。
		} while(--precision);
	}

	return s;
}

static int
//doprnt(char* out, const char* fmt, va_list ap)
//×2006/07/13 snprintf(),vsnprintf()対応
//×
//×- snprintf(),vsnprintf()対応において、doprnt()の引数にバッファサイズ(cnt)を追加するのでなく、バッファ末尾のポインタ(end)を追加するよう設計した理由は、
//×  こうする方が、vsprintf()からの利用時に、無限バッファを表現するのが容易だったからです。(無限バッファの末尾のポインタは、((char*)-1)と表せます。)
//×  また、doprnt()の実装においても、残りバッファサイズを管理するよりも、次の出力位置(out)がバッファ末尾(end)を超えていないかを検査する方が簡単です。
//×
//×- snprintf()を以下のように呼び出した場合、
//×
//×	char buf[10];
//×	snprintf(buf, 10, fmt, ...);
//×
//×  doprnt()への引数out,endは、下図のような位置を指しています。
//×
//×	buf[0][1][2][3][4][5][6][7][8][9]
//×	    |                          |
//×	   out                        end
//×
//×  endは(バッファの末尾)であり、(バッファの末尾+1)ではないことに注意してください。
//×  終端のnulを含まない、有効な文字を格納できるのは、(out～end-1)の範囲となります。
//×
//×- 終端のnulを含まない有効な文字が(out～end-1)の範囲に収まった場合、直後にnulを格納し、nulを含まない文字数を返します。
//×  終端のnulを含まない有効な文字が(end-1)を超える場合、(end-1)以降を切り捨てて(end)にnulを格納し、結果(-1)を返します。
//×
//×- もし、snprintf()をバッファサイズ0で呼び出した場合、
//×
//×	snprintf(buf, 0, fmt, ...);
//×
//×  doprnt()への引数out,endは、endがoutよりも前を指しています。
//×
//×	buf[-1][0]
//×	    |   |
//×	   end out
//×
//×  この場合、終端のnulも格納せずに、結果(-1)を返します。
//×
//↓* Thu Oct 02 01:02:39 JST 2014 Naoyuki Sawa
//↓- snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。
//↓
//↓  それに伴い、doprnt()の引数endの仕様を、(バッファの末尾)⇒(バッファの末尾+1)に変更しました。
//↓  「snprintf(NULL,0,fmt,...)」から呼び出された場合に、(out=0x00000000,end=0xFFFFFFFF)になる問題を避けるためです。
//↓
//↓  OUT(C)マクロが、バッファ終端のnulを格納する位置まで、文字を格納してしまうことになりますが、最後にnulで上書きするので問題ありません。
//↓  「if(out<end)」の条件を「if(out<(end-1))」に変更しても良かったのですが、コードサイズが増えるので、行いませんでした。
//↓  前述のとおり、「if(out<end)」のままでも、結果は同じになるので問題ありません。
//↓
//↓  今後は、outとendの指す位置は、以下のようになります。
//↓
//↓- snprintf()を以下のように呼び出した場合、
//↓
//↓	char buf[10];
//↓	snprintf(buf, 10, fmt, ...);
//↓
//↓  doprnt()への引数out,endは、下図のような位置を指しています。
//↓
//↓	buf[0][1][2][3][4][5][6][7][8][9](10)
//↓	    |                             |
//↓	   out                           end
//↓
//↓- もし、snprintf()をバッファサイズ0で呼び出した場合、
//↓
//↓	snprintf(buf, 0, fmt, ...);
//↓
//↓  doprnt()への引数out,endは、どちらも同じ位置を指しています。
//↓
//↓	buf[0]
//↓	    |
//↓	 out,end 
//↓
doprnt(char* out, char* end, const char* fmt, va_list ap)
{
//{{2014/10/12追加:当モジュールをVC++6.0でビルドする場合、OUTの定義がWindowsヘッダファイル「rpcdce.h」と衝突するため、OUTを予め定義解除しました。
#ifdef  WIN32
#undef  OUT
#endif//WIN32
//}}2014/10/12追加:当モジュールをVC++6.0でビルドする場合、OUTの定義がWindowsヘッダファイル「rpcdce.h」と衝突するため、OUTを予め定義解除しました。
/*{{2006/07/13 snprintf(),vsnprintf()対応*/
#define OUT(C)				\
	do {				\
		char __c__ = (C);	\
		if(out < end) {		\
			*out = __c__;	\
		}			\
		out++;			\
	} while(0)
/*}}2006/07/13 snprintf(),vsnprintf()対応*/

	int c, pad, len, flags, width, precision, zfill;
	char buf[256];	/* 数値の出力幅や精度がこのサイズを超えると異常動作します。 */
	char *s, *old_s;
	char *old_out = out;

	/* 書式文字列を走査して… */
	while((c = *fmt++) != '\0') {
		/* 『%[flags][width][.precision][h|l]type』でなければそのまま表示。 */
		if(c != '%') {
			//*out++ = c;
			//↓2006/07/13 snprintf(),vsnprintf()対応
			OUT(c);
			continue;
		}

		/* [flags]取得。 */
		flags = 0;
		do {
			switch(*fmt) {
			case '-':  flags |= FL_LJUST;     break;	/* 左詰め */
			case '0':  flags |= FL_ZEROFILL;  break;	/* 0詰め */
			case '+':  flags |= FL_SIGN;      break;	/* +/-表示 */
			case ' ':  flags |= FL_SPACE;     break;	/* 空白/-表示 */
			case '#':  flags |= FL_ALT;       break;	/* 0/0x/0X表示 */
			case '\'': flags |= FL_THOUSANDS; break;	/* 三桁区切り */	//{{2016/02/23追加:三桁区切りのフラグ文字「'」を対応しました。}}
			default :  flags |= FL_NOMORE;    continue;
			}
			fmt++;
		} while(!(flags & FL_NOMORE));
		if((flags & FL_LJUST) && (flags & FL_ZEROFILL)) DIE();
		if((flags & FL_SIGN ) && (flags & FL_SPACE   )) DIE();

		/* [width]取得。 */
		fmt = gnum(fmt, &width, &ap);
		if(*fmt == '.') {
			fmt++;
			fmt = gnum(fmt, &precision, &ap);
			flags |= FL_PRECSPEC;
		}

//{{2016/09/04変更:長さ修飾子j,z,tを対応しました。長さ修飾子hhは未対応である事を明示的に示すためにエラー終了するようにしました。
//		/* [h|l]取得。 */
//		switch(*fmt) {
//		case 'h': flags |= FL_SHORT; fmt++; break;
//		case 'l': fmt++; if(*fmt == 'l') { flags |= FL_LONG_LONG; fmt++; } break;	//{{2015/01/22変更:長さ修飾子'll'を仮対応しました。}}
//		case 'L': DIE(); /* long double は未対応 */
//		}
//↓2016/09/04変更:長さ修飾子j,z,tを対応しました。長さ修飾子hhは未対応である事を明示的に示すためにエラー終了するようにしました。
		/* [h|l|ll|j|z|t]取得。 */
		switch(*fmt) {
		case 'h': flags |= FL_SHORT; fmt++; if(*fmt == 'h') { /* [un]signed charは未対応 */ DIE(); } break;
		case 'l': /** no job **/     fmt++; if(*fmt == 'l') { flags |= FL_LONG_LONG; fmt++; } break;
		case 'L': DIE(); /* long double は未対応 */
#ifndef _WIN64
		case 'j': //整数変換に対応する引き数がintmax_tかuintmax_tで、n変換に対応する引き数がintmax_tへのポインターであることを示す。
			flags |= FL_LONG_LONG; fmt++;
			break;
		case 'z': //整数変換に対応する引き数がsize_tかssize_tで、n変換に対応する引き数がsize_tへのポインターであることを示す。
		case 't': //整数変換に対応する引き数がptrdiff_tで、n変換に対応する引き数がptrdiff_tへのポインターであることを示す。
	//{{2016/10/02修正:doprnt()の32ビット版の処理において、長さ修飾子z,tを読み飛ばしていなかったバグを修正しました。
	//		/** no job **/
	//↓2016/10/02修正:doprnt()の32ビット版の処理において、長さ修飾子z,tを読み飛ばしていなかったバグを修正しました。
			fmt++;
	//}}2016/10/02修正:doprnt()の32ビット版の処理において、長さ修飾子z,tを読み飛ばしていなかったバグを修正しました。
			break;
#else //_WIN64
		case 'j': //整数変換に対応する引き数がintmax_tかuintmax_tで、n変換に対応する引き数がintmax_tへのポインターであることを示す。
		case 'z': //整数変換に対応する引き数がsize_tかssize_tで、n変換に対応する引き数がsize_tへのポインターであることを示す。
		case 't': //整数変換に対応する引き数がptrdiff_tで、n変換に対応する引き数がptrdiff_tへのポインターであることを示す。
			flags |= FL_LONG_LONG; fmt++;
			break;
#endif//_WIN64
		}
//}}2016/09/04変更:長さ修飾子j,z,tを対応しました。長さ修飾子hhは未対応である事を明示的に示すためにエラー終了するようにしました。

		s = old_s = buf;
		switch(c = *fmt++) {
		default:
			//*out++ = c;
			//↓2006/07/13 snprintf(),vsnprintf()対応
			OUT(c);
			continue;
		case 'n':
			       if(flags & FL_LONG_LONG) {
//{{2016/08/04変更:__int64とlong longを条件コンパイルで使い分けていた個所を、int64_tで共通化しました。
//#ifdef  _MSC_VER
//				*va_arg(ap, __int64  *) = (__int64  )(out - old_out);		//{{2015/01/22変更:長さ修飾子'll'を仮対応しました。}}
//#else //_MSC_VER
//				*va_arg(ap, long long*) = (long long)(out - old_out);		//{{2015/01/22変更:長さ修飾子'll'を仮対応しました。}}
//#endif//_MSC_VER
//↓2016/08/04変更:__int64とlong longを条件コンパイルで使い分けていた個所を、int64_tで共通化しました。
				*va_arg(ap, int64_t*) = (int64_t)(out - old_out);
//}}2016/08/04変更:__int64とlong longを条件コンパイルで使い分けていた個所を、int64_tで共通化しました。
			} else if(flags & FL_SHORT    ) {
				*va_arg(ap, short    *) = (short    )(out - old_out);
			} else {
				*va_arg(ap, int      *) = (int      )(out - old_out);
			}
			continue;
		case 'c':
			*s++ = va_arg(ap, int);
			break;
		case 's':
			old_s = va_arg(ap, char*);
			if(old_s == NULL) old_s = "(null)";
			s = old_s;
			while(*s != '\0') {
				if(flags & FL_PRECSPEC) {
					if(!precision) break;
					precision--;
				}
				s++;
			}
			break;
		case 'b':
		case 'B':
		case 'o':
		case 'u':
		case 'p':
		case 'x':
		case 'X':
//{{2016/09/04追加:64ビット版では、変換指定子pを64ビット引数と解釈するようにしました。32ビット版の動作には影響有りません。
#ifdef  _WIN64
			if(c == 'p') { flags |= FL_LONG_LONG; }
#endif//_WIN64
//}}2016/09/04追加:64ビット版では、変換指定子pを64ビット引数と解釈するようにしました。32ビット版の動作には影響有りません。
			if(!(flags & FL_PRECSPEC)) precision = 1;
			s = o_print(s, flags, precision, c, &ap);
			break;
		case 'd':
		case 'i':
			flags |= FL_SIGNEDCONV;
			if(!(flags & FL_PRECSPEC)) precision = 1;
			s = o_print(s, flags, precision, c, &ap);
			break;
		case 'f':
		case 'e': /* 1.2e3形式は未対応。'f'と同じ扱いとします。 */
		case 'E': /* 1.2e3形式は未対応。'f'と同じ扱いとします。 */
		case 'g': /* 1.2e3形式は未対応。'f'と同じ扱いとします。 */
		case 'G': /* 1.2e3形式は未対応。'f'と同じ扱いとします。 */
			flags |= FL_SIGNEDCONV;
			if(!(flags & FL_PRECSPEC)) precision = 6;
			s = f_print(s, flags, precision, &ap);
/*{{2011/11/16追加 'g'(及び'G')簡易対応*/
			/* * Wed Nov 16 02:21:10 JST 2011 Naoyuki Sawa
			 * - 型フィールド文字'g'(及び'G')に簡易対応しました。
			 * - 本来の、'g'(及び'G')の特徴は、以下のとおりです。
			 *   ① 数値によって、'f'又は'e'(又は'E')の書式を、自動選択する。
			 *   ② 精度は、小数部の桁数ではなく、整数部+小数部の桁数である。
			 *   ③ 小数部の末尾にある'0'(全て'0'ならば'.'も)を、表示しない。
			 * - 'g'(及び'G')を用いる理由は、③の目的が主であるようです。
			 *   そこで今回は、①②は対応せず、③のみを簡易対応しました。
			 * - 'g'(及び'G')の使用例としては、LUA言語が'g'を使用しています。
			 *   LUA言語は全ての数値が実数ですが、'g'を使用して数値を表示しているため、小数部の無い数値は、あたかも整数であるかのように表示されるのです。
			 */
			if((c == 'g') || (c == 'G')) {
				/* 精度が0でなければ、f_print()の処理で、'.'と少なくとも一桁の小数部が、sに格納されているはず。 */
				if(precision) {
					/* sに格納された文字列から、小数部末尾の'0'と、全て'0'ならば'.'も取り除く。 */
					for(;;) {
						/* 一文字前が'.'ならば、'.'を取り除いて、抜ける。 */
						       if(*(s - 1) == '.') {
							s--;
							break;
						/* 一文字前が'0'ならば、'0'を取り除いて、継続する。 */
						} else if(*(s - 1) == '0') {
							s--;
						/* 一文字前が'1'～'9'ならば、取り除かずに、抜ける。 */
						} else {
							break;
						}
					}
				}
			}
/*}}2011/11/16追加 'g'(及び'G')簡易対応*/
			break;
		}

		zfill = (flags & FL_ZEROFILL) ? '0' : ' ';
		len = s - old_s;
		pad = width - len;
		if(pad > 0) {
			if(!(flags & FL_LJUST)) {
				/* 符号(+/-/空白)と基数(0/0x/0X)は0詰めに先行します。 */
				if(flags & FL_ZEROFILL) {
					if(flags & FL_SIGNEDCONV) {
						switch(*old_s) {
						case '+':
						case '-':
						case ' ':
							//*out++ = *old_s++;
							//↓2006/07/13 snprintf(),vsnprintf()対応
							OUT(*old_s++);
							len--;
							break;
						}
					}
					if(flags & FL_ALT) {
						//switch(c) {
						//case 'o':
						//	*out++ = *old_s++;
						//	len--;
						//	break;
						//case 'p':
						//case 'x':
						//case 'X':
						//	*out++ = *old_s++;
						//	*out++ = *old_s++;
						//	len -= 2;
						//	break;
						//}
						//↓2006/07/13 snprintf(),vsnprintf()対応
						switch(c) {
					    //{{2015/08/02追加:変換指定子'b'に対してもフラグ文字'#'が指定出来るようにしました。'%#b'の場合'0b','%#B'の場合'0B'が先行します。この動作はPerlのsprintf関数に互換です。
						case 'b':
						case 'B':
					    //}}2015/08/02追加:変換指定子'b'に対してもフラグ文字'#'が指定出来るようにしました。'%#b'の場合'0b','%#B'の場合'0B'が先行します。この動作はPerlのsprintf関数に互換です。
						case 'p':
						case 'x':
						case 'X':
							OUT(*old_s++);
							len--;
							/* FALLTHRU */
						case 'o':
							OUT(*old_s++);
							len--;
							break;
						}
					}
				}
//{{2016/10/18変更:0詰め,かつ,三桁区切りならば、0詰めにも三桁区切りを含めるようにしました。
//				/* 空白または0詰め。 */
//				while(pad > 0) {
//					//*out++ = zfill;
//					//↓2006/07/13 snprintf(),vsnprintf()対応
//					OUT(zfill);
//					pad--;
//				}
//↓2016/10/18変更:0詰め,かつ,三桁区切りならば、0詰めにも三桁区切りを含めるようにしました。
				/* 空白または0詰め。 */
				if(pad > 0) {
					//0詰め,かつ,三桁区切りならば、0詰めにも三桁区切りを含める。
					if((flags & FL_ZEROFILL) && (flags & FL_THOUSANDS)) {
						//0詰めの直後から、最初の三桁区切り,又は,小数点,又は,出力文字列の終端までに、何文字有るかを数える。
						// - 要するに、0詰めの直後から表示する出力文字列の先頭部分に、三桁区切りの端数桁が、何桁有るかを数える。
						// - 万一、"%'09s"のような不正な指定がされた場合もこの処理を通るが、遅くとも出力文字列の終端で抜けるので安全である。
						//   '%s'の対象となる文字列の途中に','や'.'が含まれていた場合は意図しない出力になるが、元々'%s'と三桁区切りを併用するのが間違いなので仕方が無い。
						//   この場合出力結果が不正になるのはアプリケーション側の問題であり、当関数の処理としてはメモリ破壊やプログラムが停止しなければ問題無い。
						int thousands;
						for(thousands = 0; thousands < len; thousands++) {
							if((old_s[thousands] == ',') ||
							   (old_s[thousands] == '.')) { break; }
						}
						do {
							//上記の処理で求めた桁数と、残りの0詰め文字数を足して、4の倍数ならば、三桁区切りを表示する。
							//それ以外ならば、0を表示する。
							if((thousands + pad) % (3 + 1/*','*/)) {
								OUT('0');
							} else {
								OUT(',');
							}
						} while(--pad);
					//0詰め,かつ,三桁区切りでなければ、通常の0詰め,又は,空白詰めを行う。
					} else {
						do {
							OUT(zfill);
						} while(--pad);
					}
				}
//}}2016/10/18変更:0詰め,かつ,三桁区切りならば、0詰めにも三桁区切りを含めるようにしました。
			}
		}
		while(len > 0) {
			//*out++ = *old_s++;
			//↓2006/07/13 snprintf(),vsnprintf()対応
			OUT(*old_s++);
			len--;
		}
		while(pad > 0) {
			//*out++ = zfill;
			//↓2006/07/13 snprintf(),vsnprintf()対応
			OUT(zfill);
			pad--;
		}
	}

//{{2014/10/02変更:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。
//	//*out = '\0'; /* 終端のNUL忘れずに! */
//	//return out - old_out;
//	//↓2006/07/13 snprintf(),vsnprintf()対応
//	if(out <= end) {
//		*out = '\0';
//		return out - old_out;
//	} else {
//		if(end >= old_out) {
//			*end = '\0';
//		} else {
//			/* バッファサイズが0以下の場合は、nulも格納しない。 */
//		}
//		return -1;
//	}
//↓2014/10/02変更:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。
	if(out < end) {
		*out = '\0';
	} else {
		if(end > old_out) {
			*(end - 1) = '\0';
		} else {
			/* バッファサイズが0以下の場合は、nulも格納しない。 */
		}
	}
	return out - old_out;	//バッファ不足時は(-1)でなく「もし十分なスペースがあれば書き込まれたであろう文字の個数」を返します。
//}}2014/10/02変更:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。

/*{{2006/07/13 snprintf(),vsnprintf()対応*/
#undef OUT
/*}}2006/07/13 snprintf(),vsnprintf()対応*/
}

/****************************************************************************
 *
 ****************************************************************************/
//{{2016/05/29追加:Visual C++ .NETでコンパイルした時に、警告C4028が表示される問題を回避しました。
// * Sun May 29 21:54:56 JST 2016 Naoyuki Sawa
// - Visual C++ .NETでコンパイルした時に、vsprintf()等で警告C4028が表示される問題を回避しました。
//   詳細は、以下の通りです。
// - VC++2015で当ライブラリをコンパイルしてみた所、当ライブラリの実装で置き換えるための、vsprintf()等で警告C4028が表示されました。
//   原因は、VC++2015では、これらの関数のプロトタイプが、標準的なプロトタイプと異なっている事でした。
//   以下に、VC++2015での、vsprintf()の宣言を示します。(他の関数も同様です)
//   □c:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\stdio.h
//   │_CRT_STDIO_INLINE int __CRTDECL vsprintf(
//   │    _Pre_notnull_ _Post_z_        char*       const _Buffer,
//   │    _In_z_ _Printf_format_string_ char const* const _Format,
//   │                                  va_list           _ArgList
//   │    )
//   標準的なプロトタイプでは、第一引数は'char*',第二引数は'char const*'ですが、VC++2015では第一引数が'char* const',第二引数は'char const* const'になっています。
//   (ちなみに、MSDNの関数リファレンスでは前者になっており、VC++2015のヘッダファイルだけが後者の宣言であるようです。)
// - 対処する方法は、二種類考えられます。
//   ・一つは、Visual C++ .NETならば、当モジュール内の関数の引数型を変更して、Visual C++ .NETの関数プロトタイプに合わせる事です。
//   ・もう一つは、Visual C++ .NETならば、警告を無視する方法です。
//   本当は前者の方が安全なのでしょうけれど、今回は後者の方法を使う事にしました。
//   この問題は明らかにVisual C++ .NETだけの問題であり、この問題に対処するために多くの関数の定義を条件コンパイル分けしたりして、コードが複雑になるのは良くないと思ったからです。
// - 本日、clipprnt.cとclipscan.cに、同じ方法で対処を行いました。
//   もし今後、対処する方法を変更する場合は、両方について、変更する必要が有るかを検討して下さい。
#if     (defined(_MSC_VER) && (_MSC_VER > 1200))
//{{2016/09/04変更:「#pragma warning(disable:...)」～「#pragma warning(default:...)」を、「#pragma warning(push)」「#pragma warning(disable:...)」～「#pragma warning(pop)」に変更しました。
//#pragma warning(disable: 4028)	//Visual C++ .NETならば、この範囲で警告C4028を抑制します。↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//↓2016/09/04変更:「#pragma warning(disable:...)」～「#pragma warning(default:...)」を、「#pragma warning(push)」「#pragma warning(disable:...)」～「#pragma warning(pop)」に変更しました。
#pragma warning(push)
#pragma warning(disable: 4028)		//Visual C++ .NETならば、この範囲で警告C4028を抑制します。↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//}}2016/09/04変更:「#pragma warning(disable:...)」～「#pragma warning(default:...)」を、「#pragma warning(push)」「#pragma warning(disable:...)」～「#pragma warning(pop)」に変更しました。
#endif//(defined(_MSC_VER) && (_MSC_VER > 1200))
//}}2016/05/29追加:Visual C++ .NETでコンパイルした時に、警告C4028が表示される問題を回避しました。
/****************************************************************************
 *
 ****************************************************************************/

/* 「#include <piece.h>」の前に「#define NOPCESPRINTF」を忘れずに！ */

/* P/ECEカーネルまたはEPSONライブラリ内の関数を置き換えます。 */
int
vsprintf(char* out, const char* fmt, va_list ap)
{
	//return doprnt(out, fmt, ap);
	//↓2006/07/13 snprintf(),vsnprintf()対応
	return doprnt(out, (char*)-1/*無限バッファの末尾*/, fmt, ap);	//⇒{{2014/10/02備考:厳密には左記の指定では無限バッファに[0xFFFFFFFF]が含まれません。本当に[0xFFFFFFFF]を含む事は考えられないので実質問題ありません。}}
}

/* P/ECEカーネルまたはEPSONライブラリ内の関数を置き換えます。 */
int
sprintf(char* out, const char* fmt, ...)
{
	int n;
	va_list ap;
	va_start(ap, fmt);
	n = vsprintf(out, fmt, ap);
	va_end(ap);
	return n;
}

/*{{2006/07/13 snprintf(),vsnprintf()対応*/

/* * Thu Jul 13 06:12:00 JST 2006 Naoyuki Sawa
 * - vsnprintf()を追加しました。
 *   P/ECE開発環境のライブラリには、vsnprintf()が含まれていません。
 * - vsnprintf()は、C99にて正式に追加された関数です。
 *   C99に準拠していないコンパイラでは、vsnprintf()をサポートしていなかったり、挙動が違っている場合があります。
 *   たとえばVC++6.0の_vsnprintf()は、出力文字数が(n-1)を超える場合の挙動が違っています。
 *   出力文字数が(n-1)を超える場合、C99の仕様では、(n-1)文字まで文字を出力し、(n)文字目にnulを格納します。
 *   それに対してVC++6.0の仕様では、(n)文字まで文字を出力し、nulを格納しません。(strncpy()に似た挙動です。)
 *   C99の仕様の方が、出力文字列が確実にnul終端されるので、使い易いと思います。
 *   今回の実装は、C99の仕様に従いました。
 * - C99とVC++6.0の挙動の違いを示すサンプルコードを、以下に示します。
 *   以下のサンプルコードはsnprintf()の例ですが、vsnprintf()も同様です。
 *
 *	main() {
 *	    char buf[] = "0123456789";
 *	    snprintf(buf, 5, "ABCDEFG");     // C99の挙動…
 *	    printf("<%s>\n", buf);           //   結果「ABCD」
 *	    _snprintf(buf, 5, "ABCDEFG");    // VC++6.0の挙動…
 *	    printf("<%s>\n", buf);           //   結果「ABCDE56789」
 *	}
 *
 * - 参考資料「プログラミング言語 C の新機能 (http://seclan.dll.jp/c99d/c99d08.htm#dt19991115)」より
 *	┌───┬───────────────────────────────────────────────────┐
 *	│名前	│int vsnprintf(char * restrict s, size_t n, const char * restrict format, va_list arg);		│
 *	├───┼───────────────────────────────────────────────────┤
 *	│ヘッダ│stdio.h												│
 *	├───┼───────────────────────────────────────────────────┤
 *	│引数	│s      : 出力先バッファ										│
 *	│	│n      : 出力先バッファの文字数									│
 *	│	│format : 書式												│
 *	│	│arg    : va_start で初期化した値									│
 *	├───┼───────────────────────────────────────────────────┤
 *	│戻り値│出力した文字数。終端のヌル文字は含まない。エラー時は負の値。						│	⇒{{2014/10/02変更:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。バッファ不足時は(-1)でなく「もし十分なスペースがあれば書き込まれたであろう文字の個数」を返します。エラーが発生することは無いので実質(-1)が返ることは有りません。詳細は「Thu Oct 02 01:02:39 JST 2014」のコメントを参照してください。}}
 *	├───┼───────────────────────────────────────────────────┤
 *	│解説	│vsprintf の 出力文字数対応版。format に従い文字を書式化して s に最大 n - 1 文字出力する。		│
 *	│	│n - 1 文字以上出力された場合は破棄される。s の終端にはヌル文字が付加される。				│
 *	│	│参考 : wchar_t を受け付ける関数 vswprintf があり、これはバッファ文字数を指定できる仕様になっている。	│
 *	└───┴───────────────────────────────────────────────────┘
 */
int
//{{2016/05/28変更:snprintf(),vsnprintf()の引数cntの型をint⇒size_tに修正しました。修正後の方が標準仕様に沿っています。VC++6.0ではコンパイラがvsnprintf()を持っていなかったので標準仕様と異なる引数型でもエラーは出なかったのですが、VC++.NETではコンパイラがvsnprintf()を持っているので引数型が異なるとエラーになったからです。今回の修正による動作の変化は有りません。今後、Visual C++ .NETへ移行するための準備です。
//vsnprintf(char* out, int cnt, const char* fmt, va_list ap)
//↓2016/05/28変更:snprintf(),vsnprintf()の引数cntの型をint⇒size_tに修正しました。修正後の方が標準仕様に沿っています。VC++6.0ではコンパイラがvsnprintf()を持っていなかったので標準仕様と異なる引数型でもエラーは出なかったのですが、VC++.NETではコンパイラがvsnprintf()を持っているので引数型が異なるとエラーになったからです。今回の修正による動作の変化は有りません。今後、Visual C++ .NETへ移行するための準備です。
vsnprintf(char* out, size_t cnt, const char* fmt, va_list ap)
//}}2016/05/28変更:snprintf(),vsnprintf()の引数cntの型をint⇒size_tに修正しました。修正後の方が標準仕様に沿っています。VC++6.0ではコンパイラがvsnprintf()を持っていなかったので標準仕様と異なる引数型でもエラーは出なかったのですが、VC++.NETではコンパイラがvsnprintf()を持っているので引数型が異なるとエラーになったからです。今回の修正による動作の変化は有りません。今後、Visual C++ .NETへ移行するための準備です。
{
//{{2014/10/02変更:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。
//	return doprnt(out, out + cnt - 1/*バッファの末尾*/, fmt, ap);
//↓2014/10/02変更:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。
	return doprnt(out, (out + cnt)/*バッファの末尾+1*/, fmt, ap);
//}}2014/10/02変更:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。
}

/* * Thu Jul 13 06:12:00 JST 2006 Naoyuki Sawa
 * - snprintf()を追加しました。
 *   P/ECE開発環境のライブラリには、snprintf()が含まれていません。
 * - VC++6.0の_snprintf()との挙動の違いについては、vsnprintf()と同様です。
 *   vsnprintf()のコメントを参照してください。
 *
 * - 参考資料「プログラミング言語 C の新機能 (http://seclan.dll.jp/c99d/c99d08.htm#dt19991115)」より
 *	┌───┬───────────────────────────────────────────────────┐
 *	│名前	│int snprintf(char * restrict s, size_t n, const char * restrict format, ...);				│
 *	├───┼───────────────────────────────────────────────────┤
 *	│ヘッダ│stdio.h												│
 *	├───┼───────────────────────────────────────────────────┤
 *	│引数	│s      : 出力先バッファ										│
 *	│	│n      : 出力先バッファの文字数									│
 *	│	│format : 書式												│
 *	│	│...    : 書式で指定した値										│
 *	├───┼───────────────────────────────────────────────────┤
 *	│戻り値│出力した文字数。終端のヌル文字は含まない。エラー時は負の値。						│	⇒{{2014/10/02変更:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。バッファ不足時は(-1)でなく「もし十分なスペースがあれば書き込まれたであろう文字の個数」を返します。エラーが発生することは無いので実質(-1)が返ることは有りません。詳細は「Thu Oct 02 01:02:39 JST 2014」のコメントを参照してください。}}
 *	├───┼───────────────────────────────────────────────────┤
 *	│解説	│sprintf の出力文字数指定版。format に従い文字を書式化して s に最大 n - 1 文字出力する。		│
 *	│	│n - 1 文字以上出力された場合は破棄される。s の終端にはヌル文字が付加される。				│
 *	│	│参考 : wchar_t を受け付ける関数 swprintf があり、これはバッファ文字数を指定できる仕様になっている。	│
 *	└───┴───────────────────────────────────────────────────┘
 */
int
//{{2016/05/28変更:snprintf(),vsnprintf()の引数cntの型をint⇒size_tに修正しました。修正後の方が標準仕様に沿っています。VC++6.0ではコンパイラがvsnprintf()を持っていなかったので標準仕様と異なる引数型でもエラーは出なかったのですが、VC++.NETではコンパイラがvsnprintf()を持っているので引数型が異なるとエラーになったからです。今回の修正による動作の変化は有りません。今後、Visual C++ .NETへ移行するための準備です。
//snprintf(char* out, int cnt, const char* fmt, ...)
//↓2016/05/28変更:snprintf(),vsnprintf()の引数cntの型をint⇒size_tに修正しました。修正後の方が標準仕様に沿っています。VC++6.0ではコンパイラがvsnprintf()を持っていなかったので標準仕様と異なる引数型でもエラーは出なかったのですが、VC++.NETではコンパイラがvsnprintf()を持っているので引数型が異なるとエラーになったからです。今回の修正による動作の変化は有りません。今後、Visual C++ .NETへ移行するための準備です。
snprintf(char* out, size_t cnt, const char* fmt, ...)
//}}2016/05/28変更:snprintf(),vsnprintf()の引数cntの型をint⇒size_tに修正しました。修正後の方が標準仕様に沿っています。VC++6.0ではコンパイラがvsnprintf()を持っていなかったので標準仕様と異なる引数型でもエラーは出なかったのですが、VC++.NETではコンパイラがvsnprintf()を持っているので引数型が異なるとエラーになったからです。今回の修正による動作の変化は有りません。今後、Visual C++ .NETへ移行するための準備です。
{
	int n;
	va_list ap;
	va_start(ap, fmt);
	n = vsnprintf(out, cnt, fmt, ap);
	va_end(ap);
	return n;
}
/*}}2006/07/13 snprintf(),vsnprintf()対応*/

/****************************************************************************
 *
 ****************************************************************************/

//{{2014/10/02追加:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。scprintf(),vscprintf(),asprintf(),vasprintf()を追加しました。

//	* Thu Oct 02 01:02:39 JST 2014 Naoyuki Sawa
//	- snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。
//	  scprintf(),vscprintf(),asprintf(),vasprintf()を追加しました。
//	  詳細は、以下の項目を参照してください。
//	- これまで、終端のnulの挙動についてはC99準拠にしていたのですが、snprintfのバッファ不足時の戻り値の挙動がVC++6.0の挙動になってしまっていました。
//	  C99(及びGCC)は「もし十分なスペースがあれば書き込まれたであろう文字の個数」を返します。VC++6.0は「負の値(実際には-1)」を返します。…参考資料①
//	  snprintfのバッファ不足時の戻り値の挙動も、C99準拠の方が便利であるため、C99準拠に変更することにしました。
//	- この変更が、既存のプログラムに影響する可能性があるため、注意してください。
//	  当ライブラリ内では、cliptime.cのstrftime()に影響が有ったため、strftime()を修正しました。
//	  今後は、snprintfの戻り値からバッファ不足かを判断するには、「retval<0」ではなく「(unsigned)retval>=(unsigned)cnt」としてください。
//	- VC++環境でも、_vscprintfを使用することで、C99準拠の挙動をシミュレートすることができます。…参考資料②
//	  ただし、VC++6.0には_vscprintfは有りません。(Visual Studio 2005以降で追加されたようです。)
//	  _vscprintfは、それ単独でも便利そうなので、P/ECE環境やVC++6.0環境でも使用できるよう、当ライブラリ内で実装することにしました。
//	- _vscprintfとメモリ確保を併用すると、フォーマット文字列を展開するバッファの確保が行えます。…参考資料③
//	  GCCには、上記をまとめて行う関数として、asprintfが有ります。…参考資料④
//	  便利なので、P/ECE環境やVC++6.0環境でも使用できるよう、当ライブラリ内で実装することにしました。
//	  なお、エラーが生じた時のstrpの挙動は、FreeBSDの実装に互換とし、エラーの際にはstrpをNULLにセットすることにしました。
//	- asprintfを使うと、二つの文字列を連結して、新しいメモリブロックを作成することができます。
//	  strdup()とstrcat()を同時に行うような感じです。…参考資料⑤
//	
//	■参考資料①「Stack Overflow」(http://stackoverflow.com/)の、『snprintf and Visual Studio 2010』(http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010)のページより引用:
//	┃Microsoft says its customers aren't pressuring enough for C99 support. But with snprintf part of C++11, you're likely to see it implemented by 2014.
//	┃Until then, you can simulate (v)snprintf like this:
//	┃│#ifdef  _MSC_VER
//	┃│#define snprintf c99_snprintf
//	┃│inline int c99_snprintf(char* str, size_t size, const char* format, ...) {
//	┃│  int count;
//	┃│  va_list ap;
//	┃│  va_start(ap, format);
//	┃│  count = c99_vsnprintf(str, size, format, ap);
//	┃│  va_end(ap);
//	┃│  return count;
//	┃│}
//	┃│inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) {
//	┃│    int count = -1;
//	┃│    if(size != 0)
//	┃│      count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
//	┃│    if(count == -1)
//	┃│      count = _vscprintf(format, ap);
//	┃│    return count;
//	┃│}
//	┃│#endif//_MSC_VER
//	┃As mentioned in the standard:
//	┃・at most size bytes get written (including terminating '\0')
//	┃・if output was truncated, the return value is the number of characters (excluding terminating '\0') that would have been written
//	┃───────────────────────────────────────────────────────────────────────────
//	┃This will not always terminate the string with a 0 which is required on a overflow.
//	┃The second if in c99_vsnprintf must be: if (count == -1) { if (size > 0) str[size - 1] = 0; count = _vscprintf(format, ap); }
//	
//	■参考資料②「Microsoft Developer Network」(http://msdn.microsoft.com/)の、『_vscprintf、_vscprintf_l、_vscwprintf、_vscwprintf_l』(http://msdn.microsoft.com/ja-jp/library/w05tbk72.aspx)のページより引用:
//	┃引数リストへのポインターを使用して書式指定された文字列の文字数を返します。
//	┃              int _vscprintf(const char* format, va_list argptr);
//	┃              int _vscprintf_l(const char* format, locale_t locale, va_list argptr);
//	┃              int _vscwprintf(const wchar_t* format, va_list argptr);
//	┃              int _vscwprintf_l(const wchar_t* format, locale_t locale, va_list argptr);
//	┃パラメーター  format 書式指定文字列。
//	┃              argptr 引数リストへのポインター。
//	┃              locale 使用するロケール。
//	┃戻り値        _vscprintf関数は、引数リストが指す文字列が、指定の書式化コードを使用して出力されるか、またはファイルやバッファーに送信された場合に生成される文字数を返します。
//	┃              返される値には、終端のNULL文字は含まれません。ワイド文字の場合は、_vscwprintfが同じ機能を実行します。
//	┃              _lサフィックスが付いているこれらの関数の各バージョンは、現在のスレッドロケールの代わりに渡されたロケールパラメーターを使用する点を除いて同じです。
//	┃              formatがnullポインターの場合は、「パラメーターの検証」に説明されているように、無効なパラメーターハンドラーが呼び出されます。
//	┃              実行の継続が許可された場合、関数は-1を返し、errnoをEINVALに設定します。
//	┃解説          各argumentはformatの対応する書式指定に従って(存在する場合)に変換されます。formatは通常の文字で構成し、その形式と機能はprintf関数のformatと同じです。
//			
//	■参考資料③「jianji-production」(http://jianji.noor.jp/)さんの、『フォーマット文字列を展開するバッファの確保』(http://jianji.noor.jp/wiki/index.cgi?page=%A5%D5%A5%A9%A1%BC%A5%DE%A5%C3%A5%C8%CA%B8%BB%FA%CE%F3%A4%F2%C5%B8%B3%AB%A4%B9%A4%EB%A5%D0%A5%C3%A5%D5%A5%A1%A4%CE%B3%CE%CA%DD)のページより引用:
//	┃コンパイル環境によって分かれるもよう。
//	┃□GNU拡張の場合
//	┃vasprintfでバッファの確保とコピーを同時に行う。
//	┃│void MyPrintf(const char* format, ...) {
//	┃│  va_list argptr;
//	┃│  va_start(argptr, format);
//	┃│  char* buf_ = NULL;
//	┃│  vasprintf(&buf_, format, argptr);
//	┃│  MyPrintString(buf_);
//	┃│  free(buf_);
//	┃│  va_end(argptr);
//	┃│}
//	┃□VC拡張の場合
//	┃_vscprintfで展開後の文字列長を取得し、それに+1した長さのバッファを用意する。
//	┃│void MyPrintf(const char* format, ...) {
//	┃│  va_list argptr;
//	┃│  va_start(argptr, format);
//	┃│  int length = _vscprintf(format, argptr);
//	┃│  char* buf_ = new char [length + 1];
//	┃│  vsprintf(buf_, format, argptr);
//	┃│  MyPrintString(buf_);
//	┃│  delete[] buf_;
//	┃│  va_end(argptr);
//	┃│}
//	┃VC拡張はメモリ確保を外部化できるので、より柔軟な印象。
//	
//	■参考資料④「JM Project」(http://linuxjm.sourceforge.jp/)の、『Man page of ASPRINTF』(http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/asprintf.3.html)のページより引用:
//	┃名前          asprintf, vasprintf - 文字列を割り当ててそれに出力する
//	┃書式          #define _GNU_SOURCE /* feature_test_macros(7) 参照 */
//	┃              #include <stdio.h>
//	┃              int asprintf(char** strp, const char* fmt, ...);
//	┃              int vasprintf(char** strp, const char* fmt, va_list ap);
//	┃説明          asprintf()関数とvasprintf()関数とは、それぞれsprintf(3)関数とvsprintf(3)関数とに似ているが、
//	┃              出力文字列を(終端のヌルバイト('\0')も含めて)保持するのに十分な大きさのメモリを確保し、最初の引数にその文字列へのポインタを返す。
//	┃              このポインタは、不要になったらfree(3)に渡し、割り当てられた記憶領域を解放すべきである。
//	┃返り値        成功すると、これらの関数は出力されたバイト数を(sprintf(3)のように)返す。
//	┃              メモリの割り当てができなかったり、その他エラーが生じると、これらの関数は-1を返し、strpの内容は未定義となる。
//	┃準拠          これらの関数はGNUの拡張であり、CやPOSIXのものではない。これらは*BSDでも利用できる。
//	┃              FreeBSDの実装では、エラーの際にはstrpをNULLにセットする。
//	
//	■参考資料⑤「Stack Overflow」(http://stackoverflow.com/)の、『Is there a neat way to do strdup() followed by strcat()?』(http://stackoverflow.com/questions/12591074/is-there-a-neat-way-to-do-strdup-followed-by-strcat)のページより引用:
//	┃Say I wanted to duplicate a string then concatenate a value to it.
//	┃Using stl std::string, it's:
//	┃│string s = "hello";
//	┃│string s2 = s + " there"; //effectively dup/cat
//	┃in C:
//	┃│char* s = "hello";
//	┃│char* s2 = strdup(s);
//	┃│strcat(s2, " there"); //s2 is too short for this operation
//	┃The only way I know to do this in C is:
//	┃│char* s = "hello";
//	┃│char* s2 = (char*)malloc(strlen(s) + strlen(" there") + 1); //allocate enough space
//	┃│strcpy(s2, s);
//	┃│strcat(s2, " there");
//	┃Is there a more elegant way to do this in C?
//	┃───────────────────────────────────────────────────────────────────────────
//	┃A GNU extension is asprintf() that allocates the required buffer:
//	┃│char* s2;
//	┃│if(-1 != asprintf(&s2, "%s%s", "hello", " there") {
//	┃│  free(s2);
//	┃│}

int scprintf(const char* fmt, ...) {
	int n;
	va_list ap;
	va_start(ap, fmt);
	n = vscprintf(fmt, ap);
	va_end(ap);
	return n;
}
int vscprintf(const char* fmt, va_list ap) {
	return doprnt(NULL, NULL, fmt, ap);
}

int asprintf(char** strp, const char* fmt, ...) {
	int n;
	va_list ap;
	va_start(ap, fmt);
	n = vasprintf(strp, fmt, ap);
	va_end(ap);
	return n;
}
//{{2015/09/16変更:vasprintf()がva_listの使い方が正しくなかった点を修正しました。P/ECE開発環境(GCC)とWindows(VC++6.0)での動作上は修正前のままでも問題無く動作するのですが、厳密さのために修正する事にしました。
//int vasprintf(char** strp, const char* fmt, va_list ap) {
//	if(!(*strp = malloc(vscprintf(fmt, ap) + 1/*nul*/))) { return -1; }
//	return vsprintf(*strp, fmt, ap);
//}
//↓2015/09/16変更:vasprintf()がva_listの使い方が正しくなかった点を修正しました。P/ECE開発環境(GCC)とWindows(VC++6.0)での動作上は修正前のままでも問題無く動作するのですが、厳密さのために修正する事にしました。
int vasprintf(char** strp, const char* fmt, va_list ap) {
	va_list ap2;
	va_copy(ap2, ap);					//apをap2にコピーする。
	*strp = malloc(vscprintf(fmt, ap2) + 1/*nul*/);		//ap2はvscprintf()によって変更されるので、このあとvsprintf()に渡してはいけない。	P/ECE開発環境(GCC)とWindows(VC++6.0)では値渡しなので問題無いのだが、処理系依存であり厳密にはこのように処理する必要が有る。
	va_end(ap2);						//ap2の使用を終了する。
	if(!*strp) { return -1; }
	return vsprintf(*strp, fmt, ap);			//変更していない元のapをvsprintf()に渡す。
}
//}}2015/09/16変更:vasprintf()がva_listの使い方が正しくなかった点を修正しました。P/ECE開発環境(GCC)とWindows(VC++6.0)での動作上は修正前のままでも問題無く動作するのですが、厳密さのために修正する事にしました。

//}}2014/10/02追加:snprintf(),vsnprintf()の戻り値の挙動をVC++6.0準拠⇒C99準拠に変更しました。scprintf(),vscprintf(),asprintf(),vasprintf()を追加しました。

/****************************************************************************
 *
 ****************************************************************************/

//{{2015/08/02追加:fprintf(),printf(),vfprintf(),vprintf()を、clipio.c⇒clipprnt.cへ移動しました。Win32プロジェクトでも、doprnt()を利用したprintf()等を利用したいからです。clipio.cはP/ECEに依存しているのでWin32プロジェクトに含められませんが、clipprnt.cならばWin32プロジェクトに含められます。

/* * Sun Aug 02 16:45:48 JST 2015 Naoyuki Sawa
 * - fprintf(),printf(),vfprintf(),vprintf()を、clipio.c⇒clipprnt.cへ移動しました。
 *   Win32プロジェクトでも、doprnt()を利用したprintf()等を利用したいからです。
 *   clipio.cはP/ECEに依存しているのでWin32プロジェクトに含められませんが、clipprnt.cならばWin32プロジェクトに含められます。
 */
int fprintf(FILE* stream, const char* format, ...) {
	int retval;
	va_list argptr;
	va_start(argptr, format);
	retval = vfprintf(stream, format, argptr);
	va_end(argptr);
	return retval;
}
int printf(const char* format, ...) {
	int retval;
	va_list argptr;
	va_start(argptr, format);
	retval = vprintf(format, argptr);
	va_end(argptr);
	return retval;
}
int vfprintf(FILE* stream, const char* format, va_list argptr) {
   //{{2015/05/01変更:vfprintf()が_def_vbuff[]を利用するのをやめて、代りにvasprintf()を利用するように変更しました。
   //	//文字列展開バッファとして_def_vbuff[]を利用しています。
   //	return fwrite(_def_vbuff, 1, vsprintf(_def_vbuff, format, argptr), stream);
   //↓2015/05/01変更:vfprintf()が_def_vbuff[]を利用するのをやめて、代りにvasprintf()を利用するように変更しました。
	char* s;
	int n = vasprintf(&s, format, argptr);
	if(n < 0) { DIE(); }
	n = fwrite(s, 1, n, stream);
	free(s);
	return n;
   //}}2015/05/01変更:vfprintf()が_def_vbuff[]を利用するのをやめて、代りにvasprintf()を利用するように変更しました。
}
int vprintf(const char* format, va_list argptr) {
	return vfprintf(stdout, format, argptr);
}

//}}2015/08/02追加:fprintf(),printf(),vfprintf(),vprintf()を、clipio.c⇒clipprnt.cへ移動しました。Win32プロジェクトでも、doprnt()を利用したprintf()等を利用したいからです。clipio.cはP/ECEに依存しているのでWin32プロジェクトに含められませんが、clipprnt.cならばWin32プロジェクトに含められます。

/****************************************************************************
 *
 ****************************************************************************/
//{{2016/05/29追加:Visual C++ .NETでコンパイルした時に、警告C4028が表示される問題を回避しました。
#if     (defined(_MSC_VER) && (_MSC_VER > 1200))
//{{2016/09/04変更:「#pragma warning(disable:...)」～「#pragma warning(default:...)」を、「#pragma warning(push)」「#pragma warning(disable:...)」～「#pragma warning(pop)」に変更しました。
//#pragma warning(default: 4028)	//Visual C++ .NETならば、この範囲で警告C4028を抑制します。↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
//↓2016/09/04変更:「#pragma warning(disable:...)」～「#pragma warning(default:...)」を、「#pragma warning(push)」「#pragma warning(disable:...)」～「#pragma warning(pop)」に変更しました。
#pragma warning(pop)			//Visual C++ .NETならば、この範囲で警告C4028を抑制します。↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
//}}2016/09/04変更:「#pragma warning(disable:...)」～「#pragma warning(default:...)」を、「#pragma warning(push)」「#pragma warning(disable:...)」～「#pragma warning(pop)」に変更しました。
#endif//(defined(_MSC_VER) && (_MSC_VER > 1200))
//}}2016/05/29追加:Visual C++ .NETでコンパイルした時に、警告C4028が表示される問題を回避しました。
/****************************************************************************
 *
 ****************************************************************************/
