/*	
 *	clipprnt.c
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2018 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標準ライブラリの仕様には含まれていない(?要確認)ので、自分の解釈で実装しても大きな問題は無いと思います。
 *	* Wed Dec 14 21:49:23 JST 2016 Naoyuki Sawa
 *	- フラグ文字'#'が指定されても、数値が0ならば基数表示を行わないように修正しました。
 *	  これまでは、「printf("%#x",0)」が、誤って"0x0"を出力してしまっていました。
 *	  実際にそれが問題になるケースは少ないのですが、厳密にはフラグ文字'#'が指定されても数値が0ならば基数表示を行わないのが正しい仕様でした。
 *	  そこで今回、「printf("%#x",0)」は、正しく"0"を出力するように修正しました。
 *	* Tue Aug 29 21:30:25 JST 2017 Naoyuki Sawa
 *	- doprnt.cをclipprnt.cに統合しました。
 *	  詳細は、以下の通りです。
 *	- 2012/01/20に、P/ECEカーネルのpceFontPrintf()のバグ修正対策を行った時に、/clip/doprnt.cを作成しました。
 *	  /clip/doprnt.cは、'\usr\PIECE\sysdev\pcekn\doprnt.c'をコピーして少し変更したものであり、pceFontPrintf()をリンク時にで置き換えるものでした。
 *	  動作上はそれで問題無いのですが、/clip/doprnt.cと、当モジュール(clipprnt.c)に、同じ役割をするdoprnt()関数が重複して含まれているという問題が有りました。
 *	  2012/01/20の修正対策時は、極力、エンバグの危険を減らしたかったので、'\usr\PIECE\sysdev\pcekn\doprnt.c'を最小限の変更で、そのまま使う事にしたからです。
 *	  なぜ、2012/01/20の時点では、clipprnt.cのdoprnt()に統合しなかったかと言うと、'\usr\PIECE\sysdev\pcekn\doprnt.c'のdoprnt()には、OUTBF構造体を介してバッファを巻き戻して出力する機能が有るからです。
 *	  これは、RAM使用量低減を重視するP/ECEカーネルAPIならではの仕様であり、汎用性を重視しているclipprnt.cのdoprnt()にはその時点では実装していない機能でした。
 *	  上記の点を除けば、clipprnt.cのdoprnt()の機能は、'\usr\PIECE\sysdev\pcekn\doprnt.c'のdoprnt()の機能を包括しています。
 *	  そこで今回、clipprnt.cのdoprnt()に、OUTBF構造体を介してバッファを巻き戻して出力する機能を実装し、doprnt.cをclipprnt.cに統合してコードサイズを低減する事にしました。
 *	  OUTBF構造体を介してバッファを巻き戻して出力する仕組みは、既存の/clip/doprnt.cと同じ方法で移植しました。
 *	  ちなみに、実際にこの機能を使うのは、pceFontPrintf()から呼び出された場合だけであり、P/ECE環境以外では無駄なのですが、Windows環境等で多少オーバーヘッドが増えても、全体への影響は小さいと思います。
 *	- 今回の統合による、メモリ節約効果は、以下の通りです。
 *	  【変更前】
 *	  │clipprnt.o 3328バイト┬合計 5076バイト┐
 *	  │doprnt.o   1748バイト┘               │
 *	  【変更後】                              │
 *	  │clipprnt.o 3664バイト┬合計 3664バイト┴ 1412バイト削減
 *	  │doprnt.o      0バイト┘
 *	* Wed Aug 30 23:30:03 JST 2017 Naoyuki Sawa
 *	- P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
 *	  詳細は、「P/ECE研究記録 - gcc33.exeがswitch～caseを無駄に大きなジャンプテーブルに展開する」(http://piece-me.org/piece-lab/piece-lab-2017.txt)の記事を参照して下さい。
 *	- 今回の変更による、メモリ節約効果は、以下の通りです。
 *	  【変更前】clipprnt.o 3664バイト┐
 *	  【変更後】clipprnt.o 2836バイト┴ 828バイト削減
 *	* Sun Feb 11 23:59:59 JST 2018 Naoyuki Sawa
 *	- 長さ修飾子'hh'を対応しました。
 */
#include "clip.h"

//{{2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
#undef  NO_JUMP_TABLES	//まず確実に未定義にしておきます。
#ifdef  PIECE
#define NO_JUMP_TABLES	//NO_JUMP_TABLESシンボルを定義すると、P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避するために、各switch文にダミーの'case CHAR_MIN:'を追加します。P/ECE環境以外でもこの対策を行っても害は有りませんが無意味なので、P/ECE環境でのみこの対策を行う事にしました。
#endif//PIECE
//}}2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。

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

					// ＝意味＝		＝例＝
#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_CHAR		(1 <<  5)	// バイト引数		%hhd				//{{2018/02/11追加:長さ修飾子'hh'を対応しました。}}
#define FL_SHORT	(1 <<  6)	// ハーフワード引数	%hd
#define FL_LONG_LONG	(1 <<  7)	// 64ビット引数		%lld				//{{2015/01/22追加:長さ修飾子'll'を仮対応しました。}}
#define FL_PRECSPEC	(1 <<  8)	// 精度指定あり		%9.5f
#define FL_SIGNEDCONV	(1 <<  9)	// 符号あり		%d
#define FL_THOUSANDS	(1 << 10)	// 三桁区切り		%'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    ); }
//{{2018/02/11追加:長さ修飾子'hh'を対応しました。
	} else if(flags & FL_CHAR     ) {
		if(flags & FL_SIGNEDCONV) { val = va_arg(*app,          char     ); }
		else                      { val = va_arg(*app, unsigned char     ); }
//}}2018/02/11追加:長さ修飾子'hh'を対応しました。
	} 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++ = ' ';
		}
	}

	/* 基数表示。 */
//{{2016/12/14変更:フラグ文字'#'が指定されても、数値が0ならば基数表示を行わないように修正しました。
//	if(flags & FL_ALT) {
//↓2016/12/14変更:フラグ文字'#'が指定されても、数値が0ならば基数表示を行わないように修正しました。
	if((flags & FL_ALT) && (val != 0)) {
//}}2016/12/14変更:フラグ文字'#'が指定されても、数値が0ならば基数表示を行わないように修正しました。
		switch(c) {
//{{2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
#ifdef  NO_JUMP_TABLES
		case CHAR_MIN: /* FALLTHRU */	//おまじない
#endif//NO_JUMP_TABLES
//}}2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
		default: /** no job **/ break;
	    //{{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) {
//{{2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
#ifdef  NO_JUMP_TABLES
	case CHAR_MIN: /* FALLTHRU */	//おまじない
#endif//NO_JUMP_TABLES
//}}2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
	default:DIE();
	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;
	}
    //{{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;
}

//{{2017/08/29追加:doprnt.cをclipprnt.cに統合しました。
typedef struct tagOUTBF {
	char*	outp;				//バッファの出力アドレス。バッファが足りて出力した時に進める。flushを呼ぶとflushにて巻き戻す。全角文字がバッファを跨いだ場合の処理が必要なので_OUT()では巻き戻せない。
	char*	topp;				//バッファの先頭アドレス。変更しない。
	char*	endp;				//バッファの終端アドレス(+1)。変更しない。
	void (*flush)(struct tagOUTBF* pob);	//出力アドレスが終端アドレスに到達した瞬間に呼び出す関数。NULL可。
} OUTBF;
#undef  OUT	//Windowsヘッダファイル「rpcdce.h」と衝突するので未定義に戻す。Windows環境以外では衝突しないかも知れないが確実に未定義に戻しても害は無い。
#undef _OUT	//これもありがちな名前なので確実に未定義に戻しておく。衝突していないかも知れないが確実に未定義に戻しておいて害は無いしその方が安心である。
#define OUT(c) do { _OUT(       pob,    (c)); cnt++; } while(0)
static void         _OUT(OUTBF* pob, int c) {
	if(pob->outp < pob->endp) {			//出力アドレスが終端アドレスに到達していなければ…
		*pob->outp++ = c;			//バッファに格納する。
		if(pob->outp >= pob->endp) {		//出力アドレスが終端アドレスに到達したら…
			if(pob->flush) {		//フラッシュ関数が有れば…
				(*pob->flush)(pob);	//フラッシュ関数を呼び出す。
			}
		}
	}
}
//}}2017/08/29追加:doprnt.cをclipprnt.cに統合しました。

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 
//↓
//{{2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
//doprnt(char* out, char* end, const char* fmt, va_list ap)
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
doprnt(OUTBF* pob, const char* fmt, va_list ap)
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
{
//{{2017/08/29削除:doprnt.cをclipprnt.cに統合しました。
////{{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()対応*/
//}}2017/08/29削除:doprnt.cをclipprnt.cに統合しました。

	int c, pad, len, flags, width, precision, zfill;
	char buf[256];	/* 数値の出力幅や精度がこのサイズを超えると異常動作します。 */
	char *s, *old_s;
//{{2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
//	char *old_out = out;
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
	int cnt = 0;
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。

	/* 書式文字列を走査して… */
	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) {
//{{2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
#ifdef  NO_JUMP_TABLES
			case CHAR_MIN: /* FALLTHRU */	//おまじない
#endif//NO_JUMP_TABLES
//}}2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
			default:   flags |= FL_NOMORE;    continue;
			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追加:三桁区切りのフラグ文字「'」を対応しました。}}
			}
			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) {
//{{2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
#ifdef  NO_JUMP_TABLES
		case CHAR_MIN: /* FALLTHRU */	//おまじない
#endif//NO_JUMP_TABLES
//}}2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
		default: /** no job **/ break;
	//{{2018/02/11変更:長さ修飾子'hh'を対応しました。
	//	case 'h': flags |= FL_SHORT; fmt++; if(*fmt == 'h') { /* [un]signed charは未対応 */ DIE(); } break;
	//↓2018/02/11変更:長さ修飾子'hh'を対応しました。
		case 'h': fmt++; if(*fmt == 'h') { fmt++; flags |= FL_CHAR; } else { flags |= FL_SHORT; } break;
	//}}2018/02/11変更:長さ修飾子'hh'を対応しました。
		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++) {
//{{2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
#ifdef  NO_JUMP_TABLES
		case CHAR_MIN: /* FALLTHRU */	//おまじない
#endif//NO_JUMP_TABLES
//}}2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
		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);
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
				*va_arg(ap, int64_t  *) = cnt;	//右辺のキャストは不要でした。右辺をキャストしても害はないがうっかり間違って左辺よりも小さな型にキャストするとバグの元になるので右辺はキャストしない方が安全です。
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
//{{2018/02/11追加:長さ修飾子'hh'を対応しました。
			} else if(flags & FL_CHAR     ) {
				*va_arg(ap, char     *) = cnt;	//右辺のキャストは不要でした。右辺をキャストしても害はないがうっかり間違って左辺よりも小さな型にキャストするとバグの元になるので右辺はキャストしない方が安全です。
//}}2018/02/11追加:長さ修飾子'hh'を対応しました。
			} else if(flags & FL_SHORT    ) {
//{{2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
//				*va_arg(ap, short    *) = (short    )(out - old_out);
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
				*va_arg(ap, short    *) = cnt;	//右辺のキャストは不要でした。右辺をキャストしても害はないがうっかり間違って左辺よりも小さな型にキャストするとバグの元になるので右辺はキャストしない方が安全です。
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
			} else {
//{{2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
//				*va_arg(ap, int      *) = (int      )(out - old_out);
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
				*va_arg(ap, int      *) = cnt;	//右辺のキャストは不要でした。右辺をキャストしても害はないがうっかり間違って左辺よりも小さな型にキャストするとバグの元になるので右辺はキャストしない方が安全です。
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
			}
			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) {
//{{2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
#ifdef  NO_JUMP_TABLES
						case CHAR_MIN: /* FALLTHRU */	//おまじない
#endif//NO_JUMP_TABLES
//}}2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
						default: /** no job **/ break;
						case '+':
						case '-':
						case ' ':
							//*out++ = *old_s++;
							//↓2006/07/13 snprintf(),vsnprintf()対応
							OUT(*old_s++);
							len--;
							break;
						}
					}
//{{2016/12/14変更:フラグ文字'#'が指定されても、数値が0ならば基数表示を行わないように修正しました。
//					if(flags & FL_ALT) {
//↓2016/12/14変更:フラグ文字'#'が指定されても、数値が0ならば基数表示を行わないように修正しました。
					if((flags & FL_ALT) && (len >= 2)) {	//この場所では、数値が0だったかどうかを直接的に判定出来ないので、o_print()の出力文字数によって判定する事にした。もし数値が0だったならば、FL_ALTが指定されていてもo_print()の出力結果は"0"となり、(len == 1)となっているはず。従ってこの場所では、(len >= 2)を判定する事によって、数値が0だったケースを除外出来る。
//}}2016/12/14変更:フラグ文字'#'が指定されても、数値が0ならば基数表示を行わないように修正しました。
						//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) {
//{{2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
#ifdef  NO_JUMP_TABLES
						case CHAR_MIN: /* FALLTHRU */	//おまじない
#endif//NO_JUMP_TABLES
//}}2017/08/30追加:P/ECE環境でswitch～caseが無駄に大きなジャンプテーブルに展開される問題を回避しました。
						default: /** no job **/ break;
					    //{{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)でなく「もし十分なスペースがあれば書き込まれたであろう文字の個数」を返します。
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
	if(pob->outp < pob->endp) {
		*pob->outp = '\0';
	} else {
		if(pob->endp > pob->topp) {
			*(pob->endp - 1) = '\0';
		} else {
			/* バッファサイズが0以下の場合は、nulも格納しない。 */
		}
	}
	return cnt;	//バッファ不足時は(-1)でなく「もし十分なスペースがあれば書き込まれたであろう文字の個数」を返します。
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。

//{{2017/08/29削除:doprnt.cをclipprnt.cに統合しました。
///*{{2006/07/13 snprintf(),vsnprintf()対応*/
//#undef OUT
///*}}2006/07/13 snprintf(),vsnprintf()対応*/
//}}2017/08/29削除:doprnt.cをclipprnt.cに統合しました。
}

//{{2017/08/29追加:doprnt.cをclipprnt.cに統合しました。
#undef  OUT	//doprnt()関数の上で定義したマクロを、doprnt()関数以外では使用しないはずなので、安全のため未定義に戻しておく。
#undef _OUT	//doprnt()関数の上で定義したマクロを、doprnt()関数以外では使用しないはずなので、安全のため未定義に戻しておく。
#ifdef  PIECE
static void OutFont(OUTBF* pob) {
	int c;
	*pob->outp = '\0';
	c = pceFontPutStr(pob->topp);	//全角文字がバッファを跨いでいたら…
	pob->outp = pob->topp;
	if(c) { *pob->outp++ = c; }	//…次回のバッファの先頭に格納する。
}
int pceFontPrintf(const char* fmt, ...) {
	char buff[31/*調整可*/ + 1/*nul*/];
	OUTBF b;
	va_list ap;
	int cnt;
	b.outp  = buff;
	b.topp  = buff;
	b.endp  = buff + (sizeof buff) - 1/*nul*/;
	b.flush = OutFont;
	va_start(ap, fmt);
	cnt = doprnt(&b, fmt, ap);
	va_end(ap);
	OutFont(&b);	//最後に残っている(かも知れない)バッファに対しては、doprnt()は自動的にフラッシュ関数を呼び出さないので、呼び出し側(ここ)で明示的にフラッシュする必要が有る事に注意せよ。
	return cnt;
}
#endif//PIECE
//}}2017/08/29追加:doprnt.cをclipprnt.cに統合しました。

/****************************************************************************
 *
 ****************************************************************************/
//{{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)
{
//{{2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
//	//return doprnt(out, fmt, ap);
//	//↓2006/07/13 snprintf(),vsnprintf()対応
//	return doprnt(out, (char*)-1/*無限バッファの末尾*/, fmt, ap);	//⇒{{2014/10/02備考:厳密には左記の指定では無限バッファに[0xFFFFFFFF]が含まれません。本当に[0xFFFFFFFF]を含む事は考えられないので実質問題ありません。}}
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
	OUTBF b;
	b.outp  = out;
	b.topp  = out;
	b.endp  = (char*)-1/*無限バッファの末尾*/;			//⇒{{2014/10/02備考:厳密には左記の指定では無限バッファに[0xFFFFFFFF]が含まれません。本当に[0xFFFFFFFF]を含む事は考えられないので実質問題ありません。}}
	b.flush = NULL;
	return doprnt(&b, fmt, ap);
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
}

/* 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);
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
	OUTBF b;
	b.outp  = out;
	b.topp  = out;
	b.endp  = (out + cnt)/*バッファの末尾+1*/;
	b.flush = NULL;
	return doprnt(&b, fmt, ap);
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
}

/* * 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) {
//{{2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
//	return doprnt(NULL, NULL, fmt, ap);
//↓2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
	OUTBF b;
	b.outp  = NULL;
	b.topp  = NULL;
	b.endp  = NULL;
	b.flush = NULL;
	return doprnt(&b, fmt, ap);
//}}2017/08/29変更:doprnt.cをclipprnt.cに統合しました。
}

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が表示される問題を回避しました。
/****************************************************************************
 *
 ****************************************************************************/
