/*
 *	clipprp.c
 *
 *	プロパティテーブル
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2017 Naoyuki Sawa
 *
 *	* Wed Sep 23 21:05:13 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Fri Sep 25 21:29:30 JST 2015 Naoyuki Sawa
 *	- ユーティリティ関数を追加しました。
 *	* Fri Sep 25 22:44:36 JST 2015 Naoyuki Sawa
 *	- PrpTbl_dump(),PrpHdr_dump()を追加しました。
 *	* Sun Sep 27 21:17:06 JST 2015 Naoyuki Sawa
 *	- 組み込み'Double'型を追加しました。
 *	- 大きな数を格納する場合、ほとんどの場合は既存のプリミティブ整数型'var'で足りると思うのですが、
 *	  もっと大きな値や小数も格納したい場合のために、64ビット浮動小数点数も格納出来るようにしました。
 *	  使用頻度は低いと思うので、速度効率やメモリ効率よりも、実装を単純にしておく方が重要だと考えて、
 *	  新たなプリミティブ小数型を追加するのではなく、内部的にはテーブルを使って実装する事にしました。
 *	* Wed Sep 30 21:54:03 JST 2015 Naoyuki Sawa
 *	- 静的なプロパティテーブルを定義するユーティリティマクロPrpTbl_def(),PrpHdr_def()を追加しました。
 *	  これらのマクロを使用する事は必須ではありません。
 *	* Thu Oct 01 21:01:01 JST 2015 Naoyuki Sawa
 *	- PrpTbl_incr_l(),PrpTbl_incr_a(),PrpTbl_incr_v(),PrpTbl_decr_l(),PrpTbl_decr_a(),PrpTbl_decr_v()を追加しました。
 *	  PrpHdr_incr_l(),PrpHdr_incr_a(),PrpHdr_incr_v(),PrpHdr_decr_l(),PrpHdr_decr_a(),PrpHdr_decr_v()を追加しました。
 *	- これらの機能は、アプリケーションが既存のPrpTbl_get_l(),PrpTbl_set_l()を使っても実現出来るのですが、
 *	  当モジュール内で実行する方が読み書きの回数が少なく効率が良いので、当モジュールの機能として提供する事にしました。
 *	- 範囲型の変数に対するdecrは、min値で飽和します。範囲型の変数に対するincrは、max値で飽和します。
 *	  列挙型の変数に対するdecrは、先頭の列挙値で飽和します。列挙型の変数に対するincrは、末尾の列挙値で飽和します。
 *	  'var'型の変数に対するdecr,incrは、飽和せずにラップアラウンドします。
 *	  どの型の変数に対するdecr,incrも、結果の値を返します。
 *	* Thu Oct 08 21:07:24 JST 2015 Naoyuki Sawa
 *	- レジストリ構造を変更しました。具体的には、以下の通りです。
 *	  ・範囲型のタイプ定義において、これまではPrp_rangeキーの下にminとmaxの値を格納していましたが、
 *	    変更後はPrp_rangeをBLOBとしてminとmaxを格納するようにしました。
 *	  ・列挙型のタイプ定義において、これまではPrp_enumキーの下にPrp_for及びPrp_revサブキーを作成しその中に順方向と逆方向の変換辞書を格納していましたが、
 *	    変更後はPrp_enumをBLOBとして列挙値を配列として格納しました。
 *	    辞書ではなくリニアサーチで変換するようになったため、列挙値が多いと性能低下しますが、大抵は列挙値は10個程度以下だと思うので問題無いと思います。
 *	  ・配列変数の定義において、これまではPrp_dimキーの下に各次元の(要素数-1)を格納していましたが、
 *	    変更後は変更後はPrp_dimをBLOBとして各次元の(要素数-1)を格納するようにしました。
 *	  以上のように変更した理由は、プロパティテーブルの読み書き時のレジストリ検索回数を減らして、高速化するためです。
 *	* Sun Oct 11 16:11:49 JST 2015 Naoyuki Sawa
 *	- USE_PRP_SEHシンボルを定義すると、clipprp.c内のDIE()を全て、SEH_throw(PrpException)に置き換えるようにしました。
 *	  当モジュールの関数は、呼び出し側のバグ(引数不正など)で失敗する事が多いので、即エラー停止でなく、呼び出し側で捕捉出来る方が便利だと思ったからです。
 *	  例えば、以下のように処理して下さい。
 *	  │SEH_try {
 *	  │  PrpHdr_set_l(phApp,123,PrpVar_x,1,2,3,-1);
 *	  │} SEH_catch(PrpException) {
 *	  │  SEH_DIE();
 *	  │} SEH_end
 *	  又は、ユーティリティマクロを使って、以下のように書く事も出来ます。
 *	  │SEH_VERIFY(PrpHdr_set_l(phApp,123,PrpVar_x,1,2,3,-1));
 *	  尚、個別の呼び出し位置で捕捉しなければ、あらかじめSEH_init()を実行した位置で捕捉されます。
 *	- USE_PRP_SEHシンボルを定義しなければ、これまで通りclipprp.c内のDIE()はそのままで、即エラー停止します。
 *	  特に、コードサイズを低減する事が要求される実行環境の場合は、USE_PRP_SEHシンボルを定義しないで下さい。
 *	* Mon Oct 12 13:35:44 JST 2015 Naoyuki Sawa
 *	- アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_get_*()とPrpHdr_set_*()を呼び出した時の処理を変更しました。
 *	  変更前は、エラー停止していました。
 *	  変更後は、PrpHdr_get_*()は整数部を返し、PrpHdr_set_*()は指定された整数値を浮動小数値に変換して設定するようになりました。
 *	  <例>
 *	   │table App
 *	   │      Double x
 *	   │end
 *	   ①PrpHdr_fset_l(pPrpHdr, 12.34, PrpVar_x, -1);	//12.34を設定する。
 *	   　PrpHdr_get_l(pPrpHdr, PrpVar_x, -1);		//12を返す。		←サービス
 *	   ②PrpHdr_set_l(pPrpHdr, 1234, PrpVar_x, -1);		//1234.0を設定する。	←サービス
 *	   　PrpHdr_fget_l(pPrpHdr, PrpVar_x, -1);		//1234.0を返す。
 *	- 上記はあくまでもサービスであり、組み込み'Double'型の変数に対して整数用の関数(PrpHdr_get_*()とPrpHdr_set_*())を呼び出す事は、望ましくはありません。
 *	  このサービスの濫用は避けて、組み込み'Double'型の変数に対しては明示的に浮動小数用の関数(PrpHdr_fget_*()とPrpHdr_fset_*())を呼び出すの望ましいです。
 *	  このサービスは却ってアプリケーションプログラムが変数型を間違えた場合のバグ発見を遅らせる恐れも有り、有害と判断したらこのブロックを削除して下さい。
 *	- アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_incr_*(),PrpHdr_decr_*()を呼び出した場合は、変更後も変更前と同じでエラーになります。
 *	  アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_init_*()を呼び出す事は、変更前も合法でした。変更後も変わらず合法で正しく動作します。
 *	* Wed Oct 14 21:50:46 JST 2015 Naoyuki Sawa
 *	- clipseh.hにてSEH_info構造体に'msg'フィールドを追加した事に伴い、当モジュールのPrpTbl_throw()の実装も変更しました。
 *	* Mon Oct 19 21:21:27 JST 2015 Naoyuki Sawa
 *	- PrpTbl_init_attr(),PrpHdr_init_attr()を追加し、特定の属性を持つ変数だけを再初期化出来るようにしました。
 *	  使用方法と注意点は、PrpTbl_init_attr()の関数内のコメントを参照して下さい。
 *	- 属性の追加に伴い、レジストリ構造を変更しました。
 *	  今回の変更は、属性を利用しなければ、メモリコストも計算コストも生じません。
 *	* Mon Oct 19 22:16:02 JST 2015 Naoyuki Sawa
 *	- PrpTbl_copy_attr(),PrpHdr_copy_attr()を追加し、特定の属性を持つ変数だけをコピー出来るようにしました。
 *	  全体をコピーしたい場合は単純にメモリコピーすれば良いので、全体をコピーする関数は用意していません。
 *	* Mon Oct 19 22:41:11 JST 2015 Naoyuki Sawa
 *	- レジストリ構造を変更しました。
 *	  これまでは、PrpTblキーの下にtypeサブキーとtableサブキーを設け、タイプ定義とテーブル定義をそれぞれに格納していました。
 *	  しかし、良く考えると、タイプとテーブルはキーの名前の範囲が異なるので、サブキーに分ける必要は無く、PrpTblキーの直下に共存出来る事に気付きました。
 *	  そこで、PrpTblキーの下にtypeサブキーとtableサブキーを削除し、PrpTblキーの直下に、タイプ定義のキーとテーブル定義のキーが共存させるようにしました。
 *	  この変更によって、キーを辿る階層が一階層減り、少しですがコードサイズの削減,及び,高速化が出来たと思います。
 *	* Sat Nov 28 21:08:17 JST 2015 Naoyuki Sawa
 *	- PrpTbl_list(),PrpHdr_list()を追加しました。
 *	- PrpTbl_dump(),PrpTbl_dump_indent()の内部処理を変更し、PrpTbl_list()を利用して動作するようにしました。
 *	  アプリケーションから見た、PrpTbl_dump()とPrpHdr_dump()の動作は、これまでと変わりません。
 *	* Sun Nov 29 21:58:15 JST 2015 Naoyuki Sawa
 *	- PrpTbl_path_f(),PrpTbl_path_g(),PrpTbl_path_p(),PrpHdr_path_f(),PrpHdr_path_g(),PrpHdr_path_p()を追加しました。
 *	- PrpTbl_init_f(),PrpTbl_init_g(),PrpTbl_init_p(),PrpTbl_set_f(),PrpTbl_set_g(),PrpTbl_set_p(),PrpTbl_get_f(),PrpTbl_get_g(),PrpTbl_get_p(),
 *	  PrpTbl_incr_f(),PrpTbl_incr_g(),PrpTbl_incr_p(),PrpTbl_decr_f(),PrpTbl_decr_g(),PrpTbl_decr_p(),
 *	  PrpTbl_fset_f(),PrpTbl_fset_g(),PrpTbl_fset_p(),PrpTbl_fget_f(),PrpTbl_fget_g(),PrpTbl_fget_p()を追加しました。
 *	- PrpHdr_init_f(),PrpHdr_init_g(),PrpHdr_init_p(),PrpHdr_set_f(),PrpHdr_set_g(),PrpHdr_set_p(),PrpHdr_get_f(),PrpHdr_get_g(),PrpHdr_get_p(),
 *	  PrpHdr_incr_f(),PrpHdr_incr_g(),PrpHdr_incr_p(),PrpHdr_decr_f(),PrpHdr_decr_g(),PrpHdr_decr_p(),
 *	  PrpHdr_fset_f(),PrpHdr_fset_g(),PrpHdr_fset_p(),PrpHdr_fget_f(),PrpHdr_fget_g(),PrpHdr_fget_p()を追加しました。
 *	- PrpTbl_dump_abs(),PrpHdr_dump_abs()を追加しました。
 *	* Mon Nov 30 21:58:52 JST 2015 Naoyuki Sawa
 *	- PrpTbl_name_l(),PrpTbl_name_a(),PrpTbl_name_v(),PrpTbl_name_f(),PrpTbl_name_g(),PrpTbl_name_p(),
 *	  PrpTbl_desc_l(),PrpTbl_desc_a(),PrpTbl_desc_v(),PrpTbl_desc_f(),PrpTbl_desc_g(),PrpTbl_desc_p()を追加しました。
 *	- PrpHdr_name_l(),PrpHdr_name_a(),PrpHdr_name_v(),PrpHdr_name_f(),PrpHdr_name_g(),PrpHdr_name_p(),
 *	  PrpHdr_desc_l(),PrpHdr_desc_a(),PrpHdr_desc_v(),PrpHdr_desc_f(),PrpHdr_desc_g(),PrpHdr_desc_p()を追加しました。
 *	- PrpTbl_dump(),PrpTbl_dump_abs(),PrpHdr_dump(),PrpHdr_dump_abs()が、説明文も表示するようにしました。
 *	* Tue Dec 01 21:56:21 JST 2015 Naoyuki Sawa
 *	- PrpTbl_path_p()等が、配列変数のインデクスを全て省略したパス名にも、マッチ出来るようにしました。
 *	  詳細は、PrpTbl_list_subr()内のコメントを参照して下さい。
 *	* Mon Dec 07 21:18:38 JST 2015 Naoyuki Sawa
 *	- 書式指定を対応しました。
 *	  詳細は、PrpTbl_dump()の実装を参照して下さい。
 *	  アプリケーションプログラムからも、同様の方法で、書式を利用する事が出来ます。
 *	  PrpTbl_dump()の引数に指定する(*fnVarFmt)形式のアプリケーション定義の関数は、PrpTbl_dump()以外にも様々な場面で共通に利用出来ると思います。
 *	  下記の関数にfnVarFmtを引き渡すと、任意の変数を統一された方法で、文字列化する事が出来ます。
 *	- PrpTbl_fmt_l(),PrpTbl_fmt_a(),PrpTbl_fmt_v(),PrpTbl_fmt_f(),PrpTbl_fmt_g(),PrpTbl_fmt_p(),
 *	  PrpHdr_fmt_l(),PrpHdr_fmt_a(),PrpHdr_fmt_v(),PrpHdr_fmt_f(),PrpHdr_fmt_g(),PrpHdr_fmt_p()を追加しました。
 *	  PrpTbl_ffmt_l(),PrpTbl_ffmt_a(),PrpTbl_ffmt_v(),PrpTbl_ffmt_f(),PrpTbl_ffmt_g(),PrpTbl_ffmt_p(),
 *	  PrpHdr_ffmt_l(),PrpHdr_ffmt_a(),PrpHdr_ffmt_v(),PrpHdr_ffmt_f(),PrpHdr_ffmt_g(),PrpHdr_ffmt_p()を追加しました。
 *	- PrpTbl_name_l()とPrpTbl_desc_l()の機能,及び,今回追加した書式情報を取得する機能を統合して、PrpTbl_inf_l()にしました。(PrpHdr_～,及び,～_l以外についても同様)
 *	  統合した理由は、取得できる情報が増える度に、それぞれの関数を増やすと、コードサイズが大きくなり、また、今後の保守もし辛いと思ったからです。
 *	- PrpTbl_dump()とPrpTbl_dump_abs()を統合し、PrpTbl_dump()の引数指定で使い分けるように変更しました。
 *	* Thu Dec 10 21:13:28 JST 2015 Naoyuki Sawa
 *	- ST_PrpInf構造体に、iTypeとiBitPosを追加しました。
 *	  PrpTbl_inf_l()等が、上記のフィールドも格納するようにしました。
 *	- PrpTbl_dump()のオプション指定を拡張しました。
 *	  PrpDmp_Vbsオプションを指定すると、各行の先頭の二列に、変数のビット位置と変数の型を出力します。
 *	  これは、プロパティテーブルのメモリマップと見なす事が出来ます。
 *	- Windows環境で、PrpTbl_path_p()を高速化しました。
 *	  詳細は、PrpTbl_path_p()関数内のコメントを参照して下さい。
 *	* Fri Dec 11 21:38:17 JST 2015 Naoyuki Sawa
 *	- PrpTbl_list()に、(aName=NULL),及び,(sPath=NULL)を指定出来るようにしました。
 *	  NULLが指定されたら、関数内の固定サイズのバッファを使います。
 *	- 上記の変更を行った理由は、利便性のためです。
 *	  元々、PrpTbl_list()が使うバッファを、アプリケーション側で指定するようにしていた理由は、以下の二つの理由でした。
 *	  │① コールバックが中断した時に、その時点でのバッファの内容を参照する。PrpTbl_path_p()がこのケースに相当します。
 *	  │② プロパティツリーの階層の深さが想定できないので、階層の深さに応じた容量のバッファを指定出来るようにするため。
 *	  ①は必須ですので、PrpTbl_list()のaName,sPath引数指定自体を削除する事は出来ません。
 *	  しかし、②については、よほど階層が深くない限り、ライブラリ側で用意したバッファを使っても良いと思いました。
 *	  なぜなら、他の多くの関数で、aName[(15+1)],sPath[256]のような固定サイズのバッファを使用しており、PrpTbl_list()だけ柔軟性を持たせてもあまり効果が無いからです。
 *	  それよりも、PrpTbl_list()を呼び出す度に、アプリケーション側で(①の用途でなくても)バッファを用意しなければいけない煩わしさを回避したいと思いました。
 *	  そこで、PrpTbl_list()に、(aName=NULL),及び,(sPath=NULL)を指定出来るようにし、NULLが指定されたら、関数内の固定サイズのバッファを使う事にしました。
 *	- 今回の変更によって、PrpTbl_list()に(aName=NULL),及び,(sPath=NULL)を指定してもしなくても、常に、PrpTbl_list()のスタック消費量が多くなります。
 *	  NULLが指定された場合だけmalloc()で確保する方法も検討しましたが、動的メモリ割り当てが使えない環境に対応出来なくなるので、そうしませんでした。
 *	  万一、今後、PrpTbl_list()のスタック消費量増加が問題になった場合は、再検討して下さい。
 *	* Sat Dec 12 21:52:40 JST 2015 Naoyuki Sawa
 *	- プロパティエディタの関数群を追加しました。
 *	  Windows環境で、curses.hをインクルードしている場合のみ、clipprp.c内での関数定義が有効になります。
 *	  なお、curses.hをインクルードしていなくても、clipprp.hでの関数宣言は常に有効になってしまいます。
 *	  一般的にclipprp.hより後でcurses.hをインクルードするので、clipprp.hではまだ判断出来ないからです。
 *	- 使用方法は、clipprp.cの実装部の上のコメントの、使用例を参照して下さい。
 *	* Sun Dec 13 21:20:57 JST 2015 Naoyuki Sawa
 *	- プロパティエディタを、組み込み'Double'型に対応しました。
 *	* Thu Dec 24 01:13:06 JST 2015 Naoyuki Sawa
 *	- PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
 *	- これまでは、'特定の属性を持つ変数'という条件しか指定出来ず、'複数の属性が含まれている'事や、'指定した属性が含まれていない'事を、条件で表現出来ませんでした。
 *	  今回の変更により、可変引数で2つのリスト(1個目の終端までが必須属性リスト,2個目の終端までが拒否属性リスト)を指定して、柔軟な条件を指定出来るようになりました。
 *	  <例> 属性A,Bを含み、属性C,Dを含まない変数だけを再初期化する:
 *	   │  PrpHdr_init_attr_l(pPrpHdr, PrpAtr_A,PrpAtr_B,-1, PrpAtr_C,PrpAtr_D,-1);
 *	   │                              ~~~~~~~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~~~~~~~
 *	   │                                 必須属性リスト        拒否属性リスト   
 *	  <例> 属性Eを含まない変数だけをコピーする:
 *	   │  PrpHdr_copy_attr_l(pPrpHdrDst, pPrpHdrSrc, -1, PrpAtr_E,-1);
 *	   │                                             ~~  ~~~~~~~~~~~
 *	   │                             必須属性リスト(空)  拒否属性リスト
 *	- 変更前のPrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()に互換な機能も、マクロとして実装しました。
 *	  変更前のPrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を使用しているアプリケーションも、修正不要です。
 *	* Mon Dec 28 19:36:37 JST 2015 Naoyuki Sawa
 *	- ST_PrpInf.nDim,pDimを追加しました。
 *	  PrpTbl_inf_*(),PrpHdr_inf_*()が、上記のフィールドを格納するようにしました。
 *	- ST_PrpInf.nDim,pDimの意味は、clipprp.hのST_PrpInf構造体定義のコメントを参照して下さい。
 *	  特に、ST_PrpInf.pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意して下さい。
 *	- ST_PrpInf.nDim,pDimを追加した目的は、アプリケーションが動的に配列変数のサイズを取得出来るようにするためです。
 *	  <例>
 *	   │□PrpTbl.txt
 *	   ││App
 *	   ││  ary[2,3]
 *	   ││end
 *	   │□sample.c
 *	   ││void sample(){
 *	   ││  ST_PrpInf inf;
 *	   ││  int i,j;
 *	   ││  PrpHdr_inf_f(phApp,&inf,"ary");
 *	   ││  if(inf.nDim!=2){DIE();}
 *	   ││  for(i=0;i<=inf.pDim[0];i++){
 *	   ││    for(j=0;j<=inf.pDim[1];j++){
 *	   ││      PrpHdr_set_f(phApp,i*10+j,"ary[%d,%d]",i,j);
 *	   ││    }
 *	   ││  }
 *	   ││}
 *	   │尚、配列変数の全ての要素に同じ値を設定する場合は「PrpHdr_set_f(phApp,123,"ary")」,配列変数の全ての要素を初期値に戻す場合は「PrpHdr_init_f(phApp,"ary")」でも充分です。
 *	* Tue Dec 29 21:41:52 JST 2015 Naoyuki Sawa
 *	- range型,及び,enum型の値の範囲を、これまでは符号無し16ビット(0～UINT16_MAX)でしたが、符号付き16ビット(INT16_MIN～INT16_MAX)に変更しました。
 *	  詳細は、dPrpTblC/dPrpTblC.exeの同日のコメントを参照して下さい。
 *	* Sat Jan 02 21:26:28 JST 2016 Naoyuki Sawa
 *	- <"書式文字列">と<書式番号>の同時指定は不可としました。
 *	  2016/1/1以前は同時指定も可能だったのですが、変数フォーマッタに書式文字列と書式番号を渡しても、実質、書式文字列の使い道が無く無駄でした。
 *	  変数フォーマッタの仕様を単純にするために、<"書式文字列">と<書式番号>の同時指定は不可とする事にしました。
 *	  詳細は、PrpTbl_fmt_v()の実装を参照して下さい。
 *	- 尚、組み込み'Double'型の変数に対して設定出来る書式指定は、これまで通り<"書式文字列">のみです。
 *	  詳細は、PrpTbl_ffmt_v()の実装を参照して下さい。
 *	* Tue Jan 05 21:29:01 JST 2016 Naoyuki Sawa
 *	- PrpEdt_new()の中でwclear()を呼び出すようにしました。
 *	  標準出力とCursesが混在している場合に確実にゴミを消しておくためです。
 *	- ユーティリティ関数 PrpEdt_run()を追加しました。
 *	  詳細は、clipprp.cのPrpEdt_run()実装箇所のコメントを参照して下さい。
 *	* Tue Jan 19 21:44:45 JST 2016 Naoyuki Sawa
 *	- PRPEDT_NARROW_KATAKANAシンボルを定義すると、値と説明文の中の全角かな文字(,及び,全角句読点等)を、半角文字に変換して表示するようにしました。
 *	  詳細は、PrpEdt_draw()実装箇所のコメントを参照して下さい。
 *	* Sun Jan 24 21:46:18 JST 2016 Naoyuki Sawa
 *	- incr,decrを廃止し、accに統合しました。
 *	* Sat Feb 27 21:21:24 JST 2016 Naoyuki Sawa
 *	- ユーティリティマクロPrpHdr_load(),PrpHdr_save()を追加しました。
 *	  詳細は、clipprp.hの、マクロ定義個所の<使用例>を参照して下さい。
 *	* Sun Feb 28 21:22:03 JST 2016 Naoyuki Sawa
 *	- ユーティリティマクロPrpHdr_fload(),PrpHdr_fsave()を追加しました。
 *	* Sun Feb 28 23:18:54 JST 2016 Naoyuki Sawa
 *	- range型の範囲の制限を緩和しました。
 *	  変更前は、最小値,最大値共に(-32768～32767)である必要がありました。
 *	  変更後は、最小値が(-32768～32767)で、最大値は(最小値+0～最小値+65535)となりました。
 *	- 今回の変更により、以下のようなrange型の定義が可能になりました。
 *	  ○range -32768,32767 //変更前も変更後もok
 *	  ○range      0,32767 //変更前も変更後もok
 *	  ○range      0,65535 //変更前はNG、変更後はok
 *	  ○range  32767,98302 //変更前はNG、変更後はok(使う事は無いと思いますが…)
 *	  ×range -65535,0     //変更前も変更後もNG。変更後の仕様でも最小値は(-32768～32767)でなければならない事に注意して下さい。
 *	  ×range     -1,65535 //変更前も変更後もNG。変更後の仕様でも(最大値－最小値≦65535)でなければならない事に注意して下さい。
 *	- 上記の変更のために、Prp_rangeのBLOBの構造を変更しました。
 *	  変更前: Prp_range = {minL,minH,maxL,maxH}
 *	  変更後: Prp_range = {minL,minH,(max-min)L,(max-min)H}
 *	- 上記のPrp_rangeのBLOBの構造を変更した事に伴い、PrpTbl_op_v()の処理を変更しました。
 *	  これまでは、Prp_rangeのBLOBからiMaxをint16_tとして直接読み出していましたが、変更後は、uint16_tとして読み出しiMinに加算するようにしました。
 *	  今回の変更に伴う当モジュールの変更はその個所だけであり、エンバグの危険性は低いと思います。
 *	  ツール側の変更については、/clip/tool/dPrpTblC/winapp.h,及び,/clip/tool/dPrpTblD/app.c の同日のコメントを参照して下さい。
 *	* Fri May 13 21:43:38 JST 2016 Naoyuki Sawa
 *	- PrpTbl_path_p()の実装を大幅に変更しました。
 *	  結果は変わりません。
 *	  変更した理由は、以下の通りです。
 *	- 変更前のPrpTbl_path_p()は、実装の単純さを優先して、極端に効率の悪い方法で処理していました。
 *	  具体的には、指定されたプロパティテーブル以下の全ての変数をパス名に変換して、引数のパス名と比較し、一致したらその変数が指定されたと判断していました。
 *	  PrpTbl_list()を呼び出すだけで実現出来るので、実装が単純であり、コードサイズが小さくて済む利点は有るのですが、直観的に判る通り、非常に低速です。
 *	  特に配列変数に対しては、配列要素ひとつひとつに対して、パス名に変換して引数のパス名と比較する処理を行うので、配列変数の要素数が多いと極端に低速です。
 *	  この低速さを緩和するために、Windows環境では、一度判断したパスをキャッシュして、次からは上記の処理を行わないようにする対策も行っていたのですが、
 *	  それはそれで問題が有り、無制限にキャッシュを行ってしまうので、キャッシュ容量が肥大化する問題が有りました。
 *	  バケットリミットを設ける方法も有るとは思うのですが、キャッシュミスした時の速度的なペナルティが大き過ぎるため、バケットリミットは設けていませんでした。
 *	  また、P/ECE環境ではメモリ制限のためにキャッシュは設けられないので、毎回全て比較しており、実用的な速度ではありませんでした。
 *	  (現実的には、P/ECE環境では、パス名によるアクセス(PrpTbl_get_p()等)は使用せず、名前配列によるアクセス(PrpTbl_get_l()等)を使うと思うので、
 *	   P/ECE環境ではPrpTbl_path_p()が呼び出される事も少なく、あまり問題にはならないとは思いますが…)
 *	- 上記の問題を改善するために、変更後のPrpTbl_path_p()は、引数のパス名を分解して、普通にプロパティーテーブルのルートから辿って行く方法にしました。
 *	  最近、clipyaml.cのyaml_path_get_node()で同様の処理を作成していたので、そのコードを一部流用しました。
 *	  変更後の方法ならば、PrpTbl_path_p()の処理時間は、プロパティーテーブルのネストの深さだけに依存し、実用的な時間で完了します。
 *	  変更後の方法ならば、キャッシュは不要だと思ったので、キャッシュは無くしました。
 *	  毎回、上記の方法で、プロパティーテーブルのルートから辿って行きます。
 *	  (変更後の方法ならば、キャッシュ無しでも実用的な速度で動作するので、P/ECE環境でもパス名によるアクセス(PrpTbl_get_p()等)を使って構わないと思います。)
 *	  とは言え、getの直後に同じ変数に対してsetする頻度が高い事を考慮すると、Windows環境ではバケットリミットを設定した小さなキャッシュを設けておく方が良いかも知れません。
 *	  今後、対応する予定です。	⇒{{2016/05/13追記:対応しました。}}
 *	- 変更後のPrpTbl_path_p()で、一応動作確認は行いましたが、まだ確認が不十分です。
 *	  変更前のPrpTbl_path_p()はこれまで半年間問題無く動作していた実績が有るので、しばらくは変更前のPrpTbl_path_p()のコードも残しておく事にしました。
 *	  USE_PRPTBL_PATH_P_NEWVERシンボルを定義しなければ、変更前のPrpTbl_path_p()を使って、ライブラリがビルドされます。
 *	  USE_PRPTBL_PATH_P_NEWVERシンボルを定義ずれば、変更後のPrpTbl_path_p()を使って、ライブラリがビルドされます。
 *	  2016/05/13現在は、USE_PRPTBL_PATH_P_NEWVERシンボルを定義しており、変更後のPrpTbl_path_p()を使うようにしてあります。
 *	  もし不具合が発生したら、USE_PRPTBL_PATH_P_NEWVERシンボルの定義をコメントアウトして、変更前のPrpTbl_path_p()に戻し、動作を比較して検証して下さい。
 *	  今後、変更後のPrpTbl_path_p()が十分に安定したら、変更前のPrpTbl_path_p()のコードと、USE_PRPTBL_PATH_P_NEWVERシンボルによって切り分ける仕組みを削除して構いません。
 *	* Fri May 13 23:35:50 JST 2016 Naoyuki Sawa
 *	- PrpTbl_path_p()に、Windows環境ではバケットリミットを設定した小さなキャッシュを設けました。
 *	  バケットリミットを設定した小さなキャッシュを設けた理由は、上記のコメントを参照して下さい。
 *	- USE_PRPTBL_PATH_STATISTICSシンボルを定義すると、キャッシュの統計情報を記録するようにしました。
 *	  グローバル変数st_PrpTbl_path_Statisticsを、アプリケーションから直接参照して下さい。
 *	* Thu Jun 09 21:26:53 JST 2016 Naoyuki Sawa
 *	- プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
 *	  その他に、ダブルクリック,又は,トリプルクリックで、編集開始になります。
 *	  詳細は、PrpEdt_exec()の実装を参照して下さい。
 *	* Sat Aug 27 21:24:43 JST 2016 Naoyuki Sawa
 *	- いつの間にか、マウスホイールでスクロール出来なくなっている事に気付きました。
 *	  少し調査してみた所、PDCursesの MOUSE_WHEEL_UP,MOUSE_WHEEL_DOWNのイベント自体が発生していないようです。
 *	  当モジュールは変更しておらず、最近行った変更としてはWindows 10をAnniversary Updateに更新した事ぐらいなので、もしかするとそれが影響しているのかも知れません。
 *	  とりあえずマウスホイールでスクロール出来ない事以外は問題なさそうなので、コードは変更せずに、しばらく様子を見る事にしました。	←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←←※要調査
 *	* Mon Sep 05 21:24:05 JST 2016 Naoyuki Sawa
 *	- 64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
 *	  setjmp()/longjmp()のパラメータは(int)であり、(void*)や(intptr_t)を使えないからです。
 *	  尚、32ビット版も64ビット版と共通に変更しても良いのですが、万一既存のコードに影響が生じる事を防ぐために、32ビット版はこれまで通りとしました。
 *	- 64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
 *	  変更点は、PrpTbl_op_v()の引数iValの型を(int)⇒(intptr_t)に変更した事と、
 *	  PrpTbl_inf_v()がPrpTbl_op_v()を呼び出す時に、ポインタを(int)にキャストせず(intptr_t)にキャストするようにした事の、二箇所のみです。
 *	  PrpTbl_op_v()の引数iValには、PrpTbl_inf_v()から呼び出される場合だけではありますが、ポインタを渡す事が有るので、上記の対応を行いました。
 *	- 既存の32ビット版の動作には、影響有りません。
 *	  従って、P/ECEのアセンブラ版のコードも、一切変更していません。
 *	* Fri Nov 25 22:46:52 JST 2016 Naoyuki Sawa
 *	- PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
 *	  変更した理由は、以下の通りです。(以下では、PrpTbl_init_attr_v()を例として説明しますが、他の関数も同様です。)
 *	- これまでは、PrpTbl_init_attr_v()は、テーブル変数の階層を辿っての、属性による限定を行っていませんでした。
 *	  属性による限定は、指定したテーブルの直下の変数に対してだけ適用し、それ以下の階層の属性は参照していませんでした。
 *	  そういう仕様にしていた理由は、もし階層を辿って属性による限定を適用する仕様にしてしまうと、
 *	  下位階層の細かなテーブルに対しても、上位階層での利用を意識して属性を付与する必要が生じてしまい、利用し辛くなってしまうと思ったからです。
 *	  しばらく実際に使っってみたところ、実用上は問題無かったのですが、やはり少々いびつな仕様であり、改善したいと思っていました。
 *	- 今回、属性の継承の概念を導入する事で、上記の問題は解決出来る事に気付きました。
 *	  テーブル変数が持つ属性がそのテーブル変数内の各変数にも継承すると見なせば、下位階層の細かなテーブルに対して上位階層での利用を意識して属性を付与する必要は生じません。
 *	  □<例>
 *	  │A
 *	  │  x
 *	  │  y attr3
 *	  │end
 *	  │B
 *	  │  a1 :A attr1	//a1.x,a1.yも属性attr1を持つと見なす。結果として、a1.xは{attr1}、a1.yは{attr1,attr3}の属性を持つ。
 *	  │  a2 :A attr2	//a2.x,a2.yも属性attr2を持つと見なす。結果として、a2.xは{attr2}、a2.yは{attr2,attr3}の属性を持つ。
 *	  │end
 *	  │---
 *	  │PrpHdr_def(B,b);
 *	  │PrpHdr_init(b,pPrpKey,PrpTbl_B);
 *	  │  ～
 *	  │PrpHdr_init_attr_l(b,PrpAtr_attr1,-1,PrpAtr_attr3,-1);
 *	  上記の例では、a1.xだけが処理対象となります。
 *	- 今回の変更によって、直観的で自然な仕様になったと思います。
 *	  関数インターフェイスは、変更前と変わっていません。
 *	  ただし、属性の解釈が上記のように変わったので、変更前の動作に依存しているアプリケーションは、修正が必要です。
 *	* Sun Mar 12 22:26:18 JST 2017 Naoyuki Sawa
 *	- PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
 *	  これまでは、PrpTbl_path_p_subr()のsPathに空文字列が指定されたら、エラー停止していました。
 *	  前述のように変更した理由は、以下の通りです。
 *	- 既存の「PrpTbl_～_v()」関数は、名前配列に空の配列を指定すれば、(テーブルに対しる操作が可能な処理ならば)引数のテーブルそのものを指すものとして動作します。
 *	  具体的には、PrpTbl_init_v()に対して空の名前配列を指定すれば、引数のテーブルそのものを初期化します。
 *	  しかしこれまで、PrpTbl_init_p()に対して空の文字列を指定すると、エラー停止してしまっていました。
 *	  PrpTbl_init_v()とPrpTbl_init_p()の整合性を考慮すると、名前配列で指定するのもパス文字列で指定するのも本質は同じですから、同じ動作をすべきです。
 *	  整合性を取るために、パス文字列を解析する関数であるPrpTbl_path_p_subr()にて、前述の変更を行う事にしました。
 *	  今後は、PrpTbl_init_p()のパス文字列に空文字列を指定した場合も、引数のテーブルそのものを指すようになって、PrpTbl_init_v()と整合性の有る動作となりました。
 *	  尚、元々空の名前配列に対して無効だった処理(PrpTbl_get_v()等)については、これまでと変わらずPrpTbl_get_p()等に空のパス文字列を指定するとエラーになります。
 *	- 今回の変更は、これまではエラーとなっていた処理がエラーにならなくなったという変更なので、既存のアプリケーションへの影響は有りません。
 *	  既存のアプリケーションの修正は不要です。
 */
#include "clip.h"
/****************************************************************************
 *	
 ****************************************************************************/
#ifdef  USE_PRP_SEH
//USE_PRP_SEHシンボルが定義されたら、clipprp.c内のDIE()を全て、SEH_throw(PrpException)に置き換えます。
#undef  DIE
#ifndef PIECE
  #define DIE() SEH_throw(PrpException)
#else //PIECE
  //P/ECEでも上のように定義しても良いのですが、メモリ節約のため下のように定義する事にしました。結果は同じになります。
  //以下の定義はclipseh.hのSEH_throw()の定義に依存しています。もし今後SEH_throw()を変更する時は以下も変更して下さい。
  #define DIE() do { PrpTbl_throw(__FILE__, __LINE__); } while(0)
  static void __attribute__((noreturn)) PrpTbl_throw(const char* file, int line) {
    SEH_info.file = file;
    SEH_info.line = line;
    SEH_info.msg  = NULL;
    SEH_longjmp((int)PrpException); }
#endif//PIECE
//{{2016/09/05変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
//const char PrpException[1/*dummy*/];
//↓2016/09/05変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
#ifndef _WIN64
const char PrpException[1/*dummy*/];	//32ビット版
#endif//_WIN64
//}}2016/09/05変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
#endif//USE_PRP_SEH
/****************************************************************************
 *	
 ****************************************************************************/
#define USE_PRPTBL_PATH_P_NEWVER	//このシンボルを定義すれば2016/05/13変更後のPrpTbl_path_p()を使用します。このシンボルを定義しなければ変更前のPrpTbl_path_p()を使用します。
/****************************************************************************
 *	ローカル関数
 ****************************************************************************/
//iOp = ┬ 0/*inf*/		iVal=(ST_PrpInf*),pPrpTbl=参照しない,iBitPos=0
//      │ 1/*init*/		iVal=参照しない
//      │ 2/*set*/		iVal=設定値
//      └ 3/*get/acc*/		iVal=0/*get*/,又は,増減値/*acc*/	'get'と'acc 0'は区別出来ないが問題無い。
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//static int PrpTbl_op_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iVal, const int* aName, int iOp) {
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
static int PrpTbl_op_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, intptr_t iVal, const int* aName, int iOp) {
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	const void* pTblKey;
	//テーブルキーを取得する。
	pTblKey = REG_open_key(pPrpKey, iTbl);
	if(!pTblKey) { DIE(); }
	for(;;) {
		int iName, iBitPos2, iArraySize, iOffset, nIndex, iType, iBitLen;
		const void* pVarKey;
		const uint16_t* pDim;
		//変数名を取得する。
		iName = *aName++;
		if(iName == -1) { DIE(); }
		//変数キーを取得する。
		pVarKey = REG_open_key(pTblKey, iName);
		if(!pVarKey) { DIE(); }
		//変数のビット位置を取得する。
		iBitPos2 = REG_get_value(pVarKey, Prp_pos);
		if(iBitPos2 == -1) { DIE(); }
		//テーブルのビット位置に、変数のビット位置を加算して、変数のビット位置とする。
		iBitPos += iBitPos2;
		//配列全体の要素数を1としておく。スカラー変数だった場合は1のままになる。
		iArraySize = 1;
		//配列オフセットを0としておく。
		iOffset = 0;
		//インデクスが指定された数を0としておく。
		nIndex = 0;
		//配列データを取得する。
		pDim = REG_get_blob(pVarKey, Prp_dim);
		//配列データが有れば…
		if(pDim) {
			int nDim, iBound, iIndex;
			//次元数を取得する。
			nDim = REG_get_blob_size(pDim);
			if(nDim & 1) { DIE(); }	//(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
			nDim >>= 1;		//配列データのバイト数⇒次元数に変換する。
			//各次元について…
			do {
				//この次元の(要素数-1)を取得する。
				iBound = *pDim++;	//このループ以降の処理でpDimを参照しないのでpDimを破壊して構わない。
				//(要素数-1)⇒(要素数)に補正する。
				iBound++;
				//配列全体の要素数に、この次元の要素数を乗算する。
				iArraySize *= iBound;
				//この次元のインデクスを取得する。
				iIndex = *aName++;
				//インデクスが指定されていたら…
				if(iIndex != -1) {
					if((unsigned)iIndex >= (unsigned)iBound) { DIE(); }
					//前の次元までの配列オフセットに、この次元の要素数を乗算する。
					iOffset *= iBound;
					//配列オフセットに、この次元のインデクスを加算する。
					iOffset += iIndex;
					//インデクスが指定された数を増やす。
					nIndex++;
				//インデクスが指定されていなければ…
				} else {
					if(nIndex) { DIE(); }	//全て指定するか,又は,全て省略のみ可。そうでなければ呼び出し側のバグです。
					//iArraySizeを求めるために、ポインタを戻して、処理を継続する。
					aName--;
				}
			} while(--nDim);
			//ここでnIndexは配列データの次元数に一致しているか,又は,0(=呼び出し側がインデクスを全て省略した場合)になっています。
			if(!nIndex && (iOp > 2/*set*/)) { DIE(); }	//'inf','init','set'以外(='get/acc')はインデクスの省略は不可。呼び出し側のバグです。
		}
		//タイプ名,又は,テーブル名を取得する。
		iType = REG_get_value(pVarKey, Prp_type);
		//タイプ名,又は,テーブル名が無ければ、'var'型と見なす。
		if(iType == -1) {
			//名前配列が終端でなければ、呼び出し側のバグです。
			if(*aName != -1) { DIE(); }
			//配列オフセットに、'var'型のビット数を乗算する。
			iOffset *= 32;
			//変数のビット位置に、配列オフセットを加算する。
			iBitPos += iOffset;
			switch(iOp) {
			default:DIE();
			case 0/*inf*/:
				{
					ST_PrpInf* pInf = (ST_PrpInf*)iVal;
					pInf->iType	= iType;						//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
					pInf->iBitPos	= iBitPos;						//変数のビット位置。(0ベースのオフセット)
					pInf->pDim	= nIndex ? NULL : REG_get_blob(pVarKey, Prp_dim);	//配列の各次元のインデクスの最大値。		┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
					pInf->nDim	= REG_get_blob_size(pInf->pDim) >> 1;			//配列の次元数。				┘上記以外の場合は、nDim=0,pDim=NULLを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=NULLが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
					pInf->pName	= REG_get_string(pVarKey, Prp_name);			//名前文字列が無ければ、NULLが格納される。
					pInf->pDesc	= REG_get_string(pVarKey, Prp_desc);			//説明文が無ければ、NULLが格納される。
					pInf->pFmt	= REG_get_string(pVarKey, Prp_fmt);			//書式文字列が無ければ、NULLが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
					pInf->iFmt	= REG_get_value( pVarKey, Prp_fmt);			//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
				}
				break;
			case 1/*init*/:
				//'var'型の変数を初期化する。
				iVal = 0;
				/* FALLTHRU */
			case 2/*set*/:
				//'var'型の変数を書き込む。
				// - 配列データが有り,かつ,呼び出し側がインデクスを全て省略した場合、配列全体に書き込む。
				//  それ以外ならば、一つの変数,又は,配列の一要素に書き込む。
				do {
					bitarray_lsb1st_set(pPrpTbl, iBitPos, 32, iVal);
					iBitPos += 32;
					if(nIndex) { break; }	//配列変数で,かつ,呼び出し側がインデクスを指定した場合は、ここで抜ける。
				} while(--iArraySize);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
				break;
			case 3/*get/acc*/:
				{
					const int iAcc = iVal;
					//'var'型の変数を読み出す。
					iVal = bitarray_lsb1st_get(pPrpTbl, iBitPos, 32);	//'get'の場合、これが戻り値となる。
					//'acc'ならば…											//┐
					if(iAcc) {											//│
						//数値を増減する。(ラップアラウンド演算)						//│
						iVal += iAcc;					//'acc'の場合、これが戻り値となる。	//├'get'の場合もこの処理を行っても構わないのだが、無駄であり性能低下するので避ける事にした。
						//'var'型の変数を書き込む。								//│
						bitarray_lsb1st_set(pPrpTbl, iBitPos, 32, iVal);					//│
					}												//┘
				}
				break;
			}
			break;	//ここまで
		//タイプ名,又は,テーブル名が、0x8000以上ならばタイプ名である。
		} else if(iType >= 0x8000) {
			const void* pTypKey;
		    //{{2015/12/29変更:range型,及び,enum型の値の範囲を、これまでは符号無し16ビット(0～UINT16_MAX)でしたが、符号付き16ビット(INT16_MIN～INT16_MAX)に変更しました。
		    //	const uint16_t *pRng, *pEnm;
		    //↓2015/12/29変更:range型,及び,enum型の値の範囲を、これまでは符号無し16ビット(0～UINT16_MAX)でしたが、符号付き16ビット(INT16_MIN～INT16_MAX)に変更しました。
			const int16_t *pRng, *pEnm;
		    //}}2015/12/29変更:range型,及び,enum型の値の範囲を、これまでは符号無し16ビット(0～UINT16_MAX)でしたが、符号付き16ビット(INT16_MIN～INT16_MAX)に変更しました。
			//名前配列が終端でなければ、呼び出し側のバグです。
			if(*aName != -1) { DIE(); }
			//タイプキーを取得する。
			pTypKey = REG_open_key(pPrpKey, iType);
			if(!pTypKey) { DIE(); }
			//このタイプの(ビット数-1)を取得する。
			iBitLen = REG_get_value(pTypKey, Prp_len);
		//不要	if(iBitLen == -1) { DIE(); }	この下の判定に含まれるので不要。
			//(ビット数-1)⇒(ビット数)に補正する。
			iBitLen++;
			if((iBitLen < 1) || (iBitLen > 16)) { DIE(); }
			//配列オフセットに、このタイプのビット数を乗算する。
			iOffset *= iBitLen;
			//変数のビット位置に、配列オフセットを加算する。
			iBitPos += iOffset;
			//範囲データ,又は,列挙データを取得する。
			pRng = REG_get_blob(pTypKey, Prp_range);
			pEnm = REG_get_blob(pTypKey, Prp_enum);
			//範囲型の変数ならば…
			if(pRng && !pEnm) {
				//最小値,最大値を取得する。
				const int iMin = *pRng++;
//{{2016/02/28変更:range型の範囲の制限を緩和しました。変更前は、最小値,最大値共に(-32768～32767)である必要がありました。変更後は、最小値が(-32768～32767)で、最大値は(最小値+0～最小値+65535)となりました。
//				const int iMax = *pRng++;
//				if(iMin > iMax) { DIE(); }	//データエラー
//↓2016/02/28変更:range型の範囲の制限を緩和しました。変更前は、最小値,最大値共に(-32768～32767)である必要がありました。変更後は、最小値が(-32768～32767)で、最大値は(最小値+0～最小値+65535)となりました。
				const int iMax = iMin + (uint16_t)*pRng++;
//}}2016/02/28変更:range型の範囲の制限を緩和しました。変更前は、最小値,最大値共に(-32768～32767)である必要がありました。変更後は、最小値が(-32768～32767)で、最大値は(最小値+0～最小値+65535)となりました。
				switch(iOp) {
				default:DIE();
				case 0/*inf*/:
					{
						ST_PrpInf* pInf = (ST_PrpInf*)iVal;
						pInf->iType	= iType;						//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
						pInf->iBitPos	= iBitPos;						//変数のビット位置。(0ベースのオフセット)
						pInf->pDim	= nIndex ? NULL : REG_get_blob(pVarKey, Prp_dim);	//配列の各次元のインデクスの最大値。		┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
						pInf->nDim	= REG_get_blob_size(pInf->pDim) >> 1;			//配列の次元数。				┘上記以外の場合は、nDim=0,pDim=NULLを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=NULLが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
						pInf->pName	= REG_get_string(pVarKey, Prp_name);			//名前文字列が無ければ、NULLが格納される。
						pInf->pDesc	= REG_get_string(pVarKey, Prp_desc);			//説明文が無ければ、NULLが格納される。
						pInf->pFmt	= REG_get_string(pVarKey, Prp_fmt);			//書式文字列が無ければ、NULLが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
						pInf->iFmt	= REG_get_value( pVarKey, Prp_fmt);			//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
						if(!pInf->pFmt && (pInf->iFmt == -1)) {					//値の書式が設定されていなければ、タイプに設定された書式を検索する。
							pInf->pFmt	= REG_get_string(pTypKey, Prp_fmt);		//書式文字列が無ければ、NULLが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
							pInf->iFmt	= REG_get_value( pTypKey, Prp_fmt);		//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
						}
					}
					break;
				case 1/*init*/:
					//範囲型の変数を初期化する。
					iVal = REG_get_value(pTypKey, Prp_init);
				//不要	if(iVal == -1) { DIE(); }	この下の判定に含まれるので不要。
					iVal += iMin;
					/* FALLTHRU */
				case 2/*set*/:
					//範囲型の変数を書き込む。
					// - 配列データが有り,かつ,呼び出し側がインデクスを全て省略した場合、配列全体に書き込む。
					//  それ以外ならば、一つの変数,又は,配列の一要素に書き込む。
					if((iVal < iMin) || (iVal > iMax)) { DIE(); }	//多分、呼び出し側のバグ。
					iVal -= iMin;
					do {
						bitarray_lsb1st_set(pPrpTbl, iBitPos, iBitLen, iVal);
						iBitPos += iBitLen;
						if(nIndex) { break; }	//配列変数で,かつ,呼び出し側がインデクスを指定した場合は、ここで抜ける。
					} while(--iArraySize);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
					break;
				case 3/*get/acc*/:
					{
						const int iAcc = iVal;
						//範囲型の変数を読み出す。
						iVal = bitarray_lsb1st_get(pPrpTbl, iBitPos, iBitLen);
						iVal += iMin;					//'get'の場合、これが戻り値となる。
						if((iVal < iMin) || (iVal > iMax)) { DIE(); }	//多分、当モジュールのバグ。
						//'acc'ならば…														//┐
						if(iAcc) {														//│
							//数値を増減する。(飽和演算)											//│
							iVal += iAcc;				//┐									//│
							if(iVal < iMin) { iVal = iMin; }	//├'acc'の場合、これが戻り値となる。					//├'get'の場合もこの処理を行っても構わないのだが、無駄であり性能低下するので避ける事にした。
							if(iVal > iMax) { iVal = iMax; }	//┘									//│
							//範囲型の変数を書き込む。											//│
							bitarray_lsb1st_set(pPrpTbl, iBitPos, iBitLen, iVal - iMin);	//iValは戻り値なので変化させないよう注意せよ。	//│
						}															//┘
					}
					break;
				}
			//列挙型の変数ならば…
			} else if(pEnm && !pRng) {
				int nEnm, iIdx = -1/*'init'と'set'を区別するための初期値*/;
				//列挙値の数を取得する。
				nEnm = REG_get_blob_size(pEnm);
				if(nEnm & 1) { DIE(); }	//列挙値は1個2バイトなので列挙データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
				nEnm >>= 1;		//列挙データのバイト数⇒列挙値の数に変換する。
				switch(iOp) {
				default:DIE();
				case 0/*inf*/:
					{
						ST_PrpInf* pInf = (ST_PrpInf*)iVal;
						pInf->iType	= iType;						//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
						pInf->iBitPos	= iBitPos;						//変数のビット位置。(0ベースのオフセット)
						pInf->pDim	= nIndex ? NULL : REG_get_blob(pVarKey, Prp_dim);	//配列の各次元のインデクスの最大値。		┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
						pInf->nDim	= REG_get_blob_size(pInf->pDim) >> 1;			//配列の次元数。				┘上記以外の場合は、nDim=0,pDim=NULLを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=NULLが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
						pInf->pName	= REG_get_string(pVarKey, Prp_name);			//名前文字列が無ければ、NULLが格納される。
						pInf->pDesc	= REG_get_string(pVarKey, Prp_desc);			//説明文が無ければ、NULLが格納される。
						pInf->pFmt	= REG_get_string(pVarKey, Prp_fmt);			//書式文字列が無ければ、NULLが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
						pInf->iFmt	= REG_get_value( pVarKey, Prp_fmt);			//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
						if(!pInf->pFmt && (pInf->iFmt == -1)) {					//値の書式が設定されていなければ、タイプに設定された書式を検索する。
							pInf->pFmt	= REG_get_string(pTypKey, Prp_fmt);		//書式文字列が無ければ、NULLが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
							pInf->iFmt	= REG_get_value( pTypKey, Prp_fmt);		//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
						}
					}
					break;
				case 1/*init*/:
					//列挙型の変数を初期化する。
					iIdx = REG_get_value(pTypKey, Prp_init);
				//不要	if(iIdx == -1) { DIE(); }	この下の判定に含まれるので不要。
					if((unsigned)iIdx >= (unsigned)nEnm) { DIE(); }	//データエラー
					/* FALLTHRU */
				case 2/*set*/:
					//列挙型の変数を書き込む。
					// - 配列データが有り,かつ,呼び出し側がインデクスを全て省略した場合、配列全体に書き込む。
					//  それ以外ならば、一つの変数,又は,配列の一要素に書き込む。
					if(iIdx == -1) {	//'init'からのFALLTHRUでなければ…
						for(;;) {
							if( ++iIdx >= nEnm) { DIE(); }
							if(*pEnm++ == iVal) { break; }	//このループ以降の処理でpEnmを参照しないのでpEnmを破壊して構わない。
						}
					}
					do {
						bitarray_lsb1st_set(pPrpTbl, iBitPos, iBitLen, iIdx);
						iBitPos += iBitLen;
						if(nIndex) { break; }	//配列変数で,かつ,呼び出し側がインデクスを指定した場合は、ここで抜ける。
					} while(--iArraySize);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
					break;
				case 3/*get/acc*/:
					{
						const int iAcc = iVal;
						//列挙型の変数を読み出す。
						iIdx = bitarray_lsb1st_get(pPrpTbl, iBitPos, iBitLen);
						if((unsigned)iIdx >= (unsigned)nEnm) { DIE(); }	//多分、当モジュールのバグ。
						//'acc'ならば…							//┐
						if(iAcc) {							//│
							//順序番号を増減する。(順序番号に対する飽和演算)	//│
							iIdx += iAcc;						//│
							if(iIdx <        0) { iIdx =        0; }		//├'get'の場合もこの処理を行っても構わないのだが、無駄であり性能低下するので避ける事にした。
							if(iIdx > nEnm - 1) { iIdx = nEnm - 1; }		//│
							//列挙型の変数を書き込む。				//│
							bitarray_lsb1st_set(pPrpTbl, iBitPos, iBitLen, iIdx);	//│
						}								//┘
						iVal = pEnm[iIdx];	//戻り値
					}
					break;
				}
			} else {
				DIE();
			}
			break;	//ここまで
		//タイプ名,又は,テーブル名が、0x7FFF以下ならばテーブル名である。
		} else {
			//テーブルキーを取得する。
			pTblKey = REG_open_key(pPrpKey, iType);
			if(!pTblKey) { DIE(); }
			//このテープルの(ビット数-1)を取得する。
			iBitLen = REG_get_value(pTblKey, Prp_len);
			if(iBitLen == -1) { DIE(); }
			//(ビット数-1)⇒(ビット数)に補正する。
			iBitLen++;
			//配列オフセットに、このテーブルのビット数を乗算する。
			iOffset *= iBitLen;
			//変数のビット位置に、配列オフセットを加算する。
			iBitPos += iOffset;
			//名前配列が終端ならば…
			if(*aName == -1) {
#ifdef  USE_PRP_DOUBLE//{{このブロックの処理はアプリケーションプログラムの利便性のためだけであり必須では有りません。組み込み'Double'型に関する他の処理はこのブロックの処理に依存していません。このブロックの利便性が不要ならばこのブロックを削除しても構いません。
				// * Mon Oct 12 13:35:44 JST 2015 Naoyuki Sawa
				// - アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_get_*()とPrpHdr_set_*()を呼び出した時の処理を変更しました。
				//   変更前は、エラー停止していました。
				//   変更後は、PrpHdr_get_*()は整数部を返し、PrpHdr_set_*()は指定された整数値を浮動小数値に変換して設定するようになりました。
				//   <例>
				//    │table App
				//    │      Double x
				//    │end
				//    ①PrpHdr_fset_l(pPrpHdr, 12.34, PrpVar_x, -1);	//12.34を設定する。
				//    　PrpHdr_get_l(pPrpHdr, PrpVar_x, -1);		//12を返す。		←サービス
				//    ②PrpHdr_set_l(pPrpHdr, 1234, PrpVar_x, -1);	//1234.0を設定する。	←サービス
				//    　PrpHdr_fget_l(pPrpHdr, PrpVar_x, -1);		//1234.0を返す。
				// - 上記はあくまでもサービスであり、組み込み'Double'型の変数に対して整数用の関数(PrpHdr_get_*()とPrpHdr_set_*())を呼び出す事は、望ましくはありません。
				//   このサービスの濫用は避けて、組み込み'Double'型の変数に対しては明示的に浮動小数用の関数(PrpHdr_fget_*()とPrpHdr_fset_*())を呼び出すの望ましいです。
				//   このサービスは却ってアプリケーションプログラムが変数型を間違えた場合のバグ発見を遅らせる恐れも有り、有害と判断したらこのブロックを削除して下さい。
				// - アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_incr_*(),PrpHdr_decr_*()を呼び出した場合は、変更後も変更前と同じでエラーになります。
				//   アプリケーションプログラムが組み込み'Double'型の変数に対してPrpHdr_init_*()を呼び出す事は、変更前も合法でした。変更後も変わらず合法で正しく動作します。
				if(iType == PrpTbl_Double) {
					if( iOp == 2/*set*/                     ) {             PrpTbl_fset_v(pPrpKey, iType, pPrpTbl, iBitPos, (int)iVal, aName); return 0/*dummy*/; }
					if((iOp == 3/*get/acc*/) && !iVal/*get*/) { return (int)PrpTbl_fget_v(pPrpKey, iType, pPrpTbl, iBitPos,            aName);                    }
					//0/*inf*/,1/*init*/ならばこの下で正しく処理される。((iOp==3/*get/acc*/)&&iVal/*acc*/)ならばこの下でエラー停止する。
				}
#endif//USE_PRP_DOUBLE//}}このブロックの処理はアプリケーションプログラムの利便性のためだけであり必須では有りません。組み込み'Double'型に関する他の処理はこのブロックの処理に依存していません。このブロックの利便性が不要ならばこのブロックを削除しても構いません。
				//'inf','init'以外ならば、呼び出し側のバグです。
				// - テーブル変数を対象として実行出来るのは、'inf','init'のみです。
				//   'set','get/acc'は、テーブル変数のフィールドを対象とする必要が有ります。
				switch(iOp) {
				default:DIE();
				case 0/*inf*/:
					{
						ST_PrpInf* pInf = (ST_PrpInf*)iVal;
						pInf->iType	= iType;						//変数の型。(-1=var型,0x0000～0x7FFF=table型,0x8000～0xFFFF=type型)
						pInf->iBitPos	= iBitPos;						//変数のビット位置。(0ベースのオフセット)
						pInf->pDim	= nIndex ? NULL : REG_get_blob(pVarKey, Prp_dim);	//配列の各次元のインデクスの最大値。		┬配列変数のパス名を指定し,かつ,インデクスを全て省略した場合のみ、nDim=1以上,pDim=配列データへのポインタを格納します。
						pInf->nDim	= REG_get_blob_size(pInf->pDim) >> 1;			//配列の次元数。				┘上記以外の場合は、nDim=0,pDim=NULLを格納します。配列変数の一要素のパス名を指定した場合(インデクスを指定した場合)は、nDim=0,pDim=NULLが格納される事に注意して下さい。		pDim[0～nDim-1]の値は、配列の各次元の要素数ではなく、インデクスの最大値(=要素数-1)である事に注意せよ。
						pInf->pName	= REG_get_string(pVarKey, Prp_name);			//名前文字列が無ければ、NULLが格納される。
						pInf->pDesc	= REG_get_string(pVarKey, Prp_desc);			//説明文が無ければ、NULLが格納される。
						pInf->pFmt	= REG_get_string(pVarKey, Prp_fmt);			//書式文字列が無ければ、NULLが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
						pInf->iFmt	= REG_get_value( pVarKey, Prp_fmt);			//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
						if(!pInf->pFmt && (pInf->iFmt == -1)) {					//値の書式が設定されていなければ、テーブルに設定された書式を検索する。
							pInf->pFmt	= REG_get_string(pTblKey, Prp_fmt);		//書式文字列が無ければ、NULLが格納される。	┬変数に対してPrpTbl_inf_l()等を呼び出した場合、書式文字列と書式番号の両方が無ければ、
							pInf->iFmt	= REG_get_value( pTblKey, Prp_fmt);		//書式番号が無ければ、-1が格納される。		┘その変数のタイプ,又は,その変数のテーブルから、書式文字列と書式番号の取得を試みる。
						}
					}
					break;
				case 1/*init*/:
					//テーブル変数を初期化する。
					// - 配列データが有り,かつ,呼び出し側がインデクスを全て省略した場合、配列全体にを初期化する。
					//  それ以外ならば、一つの変数,又は,配列の一要素を初期化する。
					do {
						PrpTbl_init(pPrpKey, iType, pPrpTbl, iBitPos);
						iBitPos += iBitLen;
						if(nIndex) { break; }	//配列変数で,かつ,呼び出し側がインデクスを指定した場合は、ここで抜ける。
					} while(--iArraySize);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
					break;
				}
				break;	//ここまで
			}
			//次のループでこのテーブルに対して処理を繰り返す。
		}
	}
	return iVal;
}
/*--------------------------------------------------------------------------*/
//{{2015/12/24追加:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
//リストaAttrの、一個目の終端までが必須属性リスト,二個目の終端までが拒否属性リストであると見なして、必須属性マスクと拒否属性マスクを作成する。
static void PrpTbl_make_attr_mask(int fIncl[/*(256/32)*/], int fExcl[/*(256/32)*/], const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/) {
	int iAttr;
	//必須属性マスクを作成する。
	memset(fIncl, 0, sizeof(int) * (256/32));
	while((iAttr = *aAttr++) != -1) {
		if((unsigned)iAttr > 255) { DIE(); }			//呼び出し側のバグ。属性値が範囲外,又は,終端(-1)を忘れている。
		if(bitarray_lsb1st_get(fIncl, iAttr, 1)) { DIE(); }	//呼び出し側のバグ。必須属性リスト内で属性値が重複指定された,又は,終端(-1)を忘れている。
		bitarray_lsb1st_set(fIncl, iAttr, 1, 1);
	}
	//拒否属性マスクを作成する。
	memset(fExcl, 0, sizeof(int) * (256/32));
	while((iAttr = *aAttr++) != -1) {
		if((unsigned)iAttr > 255) { DIE(); }			//呼び出し側のバグ。属性値が範囲外,又は,終端(-1)を忘れている。
		if(bitarray_lsb1st_get(fExcl, iAttr, 1)) { DIE(); }	//呼び出し側のバグ。拒否属性リスト内で属性値が重複指定された,又は,終端(-1)を忘れている。
		if(bitarray_lsb1st_get(fIncl, iAttr, 1)) { DIE(); }	//呼び出し側のバグ。必須属性リストと拒否属性リストの両方に同じ属性値を含めてはいけない。	この検査を行わずに処理を継続する事は可能だが、必ず失敗する条件であり呼び出し側のバグの可能性が高いので、発見を早めるためにエラー停止する事にした。
		bitarray_lsb1st_set(fExcl, iAttr, 1, 1);
	}
}
//}}2015/12/24追加:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
/*--------------------------------------------------------------------------*/
//{{2015/12/24追加:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
////変数キーpVarKeyの属性リスト(有れば)が、必須属性マスクを全て満たし,かつ,拒否属性マスクに含まれていなければ、成功とする。
//static int PrpTbl_test_attr_mask(const int _fIncl[/*(256/32)*/], const int fExcl[/*(256/32)*/], const void* pVarKey) {
//	int fIncl[(256/32)];
//	const uint8_t* pAttr;
//	//必須属性マスクをコピーする。
//	bitarray_lsb1st_copy(fIncl, 0, _fIncl, 0, 256);
//	//変数キーpVarKeyの属性リストを取得する。
//	pAttr = REG_get_blob(pVarKey, Prp_attr);
//	//変数キーpVarKeyの属性リストが有れば…
//	if(pAttr) {
//		//属性の数を取得する。
//		int nAttr = REG_get_blob_size(pAttr);
//		//各属性について…
//		while(--nAttr >= 0) {
//			int iAttr = *pAttr++;
//			//必須属性マスクの該当ビットを確実にクリアする。
//			bitarray_lsb1st_set(fIncl, iAttr, 1, 0);
//			//拒否属性マスクに含まれていたら0(=失敗)を返す。
//			if(bitarray_lsb1st_get(fExcl, iAttr, 1)) { return 0; }
//		}
//	}
//	//必須属性マスクのビットが残っていなければ1(=成功),残っていたら0(=失敗)を返す。
//	return !bitarray_lsb1st_test(fIncl, 0, 256);
//}
//↓2016/11/25変更:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和と、必須属性マスク,及び,拒否属性マスクとの比較を行う。
//・戻り値 = 0: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つ以上含んでいる。(必須属性マスクとの比較結果は不問)
//・戻り値 = 1: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでいないが、必須属性マスクの属性を全て満たしていない。
//・戻り値 = 2: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでおらず,かつ,必須属性マスクの属性を全て満たしている。
static int PrpTbl_test_attr_mask(const int fAttr[/*(256/32)*/], const int fIncl[/*(256/32)*/], const int fExcl[/*(256/32)*/]) {
	int iAttr, iTest = 2;	//仮の戻り値を2(=両方の条件を満たしている)としておく。
//低速版と高速版のどちらを使っても、結果は同じになります。
//低速版の方が処理内容が判り易いですが、実際に低速版を使う利点は無いので、常に高速版を選択して良いと思います。
#if 0	//低速版
	//全ての属性について…
	for(iAttr = 0; iAttr < 256; iAttr++) {
		//この属性が、属性マスクに含まれていたら…
		if(bitarray_lsb1st_get(fAttr, iAttr, 1)) {
			//この属性が、拒否属性マスクに含まれていたら、処理を打ち切って0(=拒否属性マスクの条件を満たしていない)を返す。
			if(bitarray_lsb1st_get(fExcl, iAttr, 1)) { return 0; }
		//この属性が、属性マスクに含まれていなければ…
		} else {
			//この属性が、必須属性マスクに含まれていたら、仮の戻り値を1(=必須属性マスクの条件を満たしていない)に変更する。
			if(bitarray_lsb1st_get(fIncl, iAttr, 1)) { iTest = 1; }
		}
	}
#else	//高速版
	//全ての属性について、32ビットづつ…
	for(iAttr = 0; iAttr < (256/32); iAttr++) {
		//セットされている属性の一部でも、拒否属性マスクに含まれていたら、処理を打ち切って0(=拒否属性マスクの条件を満たしていない)を返す。
		if( fAttr[iAttr] & fExcl[iAttr]) { return 0; }
		//クリアされている属性の一部でも、必須属性マスクに含まれていたら、仮の戻り値を1(=必須属性マスクの条件を満たしていない)に変更する。
		if(~fAttr[iAttr] & fIncl[iAttr]) { iTest = 1; }
	}
#endif
	//1(=必須属性マスクの条件を満たしていない),又は,2(=両方の条件を満たしている)を返す。
	return iTest;
}
//}}2016/11/25変更:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
/*--------------------------------------------------------------------------*/
//{{2016/11/25追加:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和の、属性マスクを作成する。
static void PrpTbl_merge_attr_mask(const void* pVarKey, const int fInhe[/*(256/32)*/], int fAttr[/*(256/32)*/]) {
	const uint8_t* pAttr;
	//継承属性マスクをコピーして、属性マスクの初期値とする。
	bitarray_lsb1st_copy(fAttr, 0, fInhe, 0, 256);
	//変数キーpVarKeyの属性リストを取得する。
	pAttr = REG_get_blob(pVarKey, Prp_attr);
	//変数キーpVarKeyの属性リストが有れば…
	if(pAttr) {
		//属性の数を取得する。
		int nAttr = REG_get_blob_size(pAttr);
		//各属性について…
		while(--nAttr >= 0) {
			int iAttr = *pAttr++;
			//属性マスクの該当ビットを確実にセットする。
			bitarray_lsb1st_set(fAttr, iAttr, 1, 1);
		}
	}
}
//}}2016/11/25追加:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
/*--------------------------------------------------------------------------*/
//{{2016/11/25追加:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
//PrpTbl_init_attr_v()の再帰処理とPrpTbl_copy_attr_v()の再帰処理は、共通部分が多いので一つの関数にまとめました。
static void PrpTbl_init_copy_attr_subr(const void* pPrpKey, int iTbl, void* pPrpTblDst, int iBitPosDst, void* pPrpTblSrc/*PrpTbl_init_attr_v()から呼び出された場合はNULL*/, int iBitPosSrc/*PrpTbl_init_attr_v()から呼び出された場合はダミー*/, const int fInhe[/*(256/32)*/], const int fIncl[/*(256/32)*/], const int fExcl[/*(256/32)*/]) {
	const void *pTblKey, *pVarKey;
	int i, aName[2];
	//テーブルキーを取得する。
	pTblKey = REG_open_key(pPrpKey, iTbl);
	if(!pTblKey) { DIE(); }
	//全ての変数キーについて…
	aName[1] = -1;
	for(i = 0;
	   (pVarKey = REG_open_nth_key(pTblKey, i, &aName[0])) != NULL;
	    i++) {
		int iType, iBitLen, iBitPos, iArraySize, iTest, fAttr[(256/32)];
		const uint16_t* pDim;
		//タイプ名,又は,テーブル名を取得する。
		iType = REG_get_value(pVarKey, Prp_type);
		//タイプ名,又は,テーブル名が有れば…
		if(iType != -1) {
			//タイプ,又は,テーブルのビット数を取得する。
			const void* pTblOrTypKey = REG_open_key(pPrpKey, iType);
			if(!pTblOrTypKey) { DIE(); }
			iBitLen = REG_get_value(pTblOrTypKey, Prp_len);
			if(iBitLen == -1) { DIE(); }
			iBitLen++;	//(ビット数-1)⇒(ビット数)に補正する。
		//タイプ名,又は,テーブル名が無ければ、'var'型と見なす。
		} else {
			iBitLen = 32;
		}
		//変数のビット位置を取得する。
		iBitPos = REG_get_value(pVarKey, Prp_pos);
		if(iBitPos == -1) { DIE(); }
		//配列全体の要素数を1としておく。スカラー変数だった場合は1のままになる。
		iArraySize = 1;
		//配列データを取得する。
		pDim = REG_get_blob(pVarKey, Prp_dim);
		//配列データが有れば…
		if(pDim) {
			//次元数を取得する。
			int nDim = REG_get_blob_size(pDim);
			if(nDim & 1) { DIE(); }	//(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
			nDim >>= 1;		//配列データのバイト数⇒次元数に変換する。
			do {
				//この次元の(要素数-1)を取得する。
				int iBound = *pDim++;	//このループ以降の処理でpDimを参照しないのでpDimを破壊して構わない。
				//(要素数-1)⇒(要素数)に補正する。
				iBound++;
				//配列全体の要素数に、この次元の要素数を乗算する。
				iArraySize *= iBound;
			} while(--nDim);
		}
		//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和の、属性マスクを作成する。
		PrpTbl_merge_attr_mask(pVarKey, fInhe, fAttr);
		//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和と、必須属性マスク,及び,拒否属性マスクとの比較を行う。
		//・iTest = 0: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つ以上含んでいる。(必須属性マスクとの比較結果は不問)
		//・iTest = 1: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでいないが、必須属性マスクの属性を全て満たしていない。
		//・iTest = 2: 変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでおらず,かつ,必須属性マスクの属性を全て満たしている。
		iTest = PrpTbl_test_attr_mask(fAttr, fIncl, fExcl);
		//テーブル変数(iType<=0x7FFF)ならば…
		if((unsigned)iType <= 0x7FFF) {
			//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、少なくとも、拒否属性マスクの属性を一つも含んでいなければ…
			// - この時点で必須属性マスクの属性を全て満たしていなくても、下位階層の変数の属性との論理和によって満たす可能性が有るので、この時点で条件を満たしていなくても再帰する。
			//   ただし、この時点で拒否属性マスクの属性を一つ以上含んでいたら、下位階層で条件を満たす可能性は無いので、再帰を打ち切る。(再帰しても結果は同じになるが、無駄である。)
			if(iTest >= 1) {
				//テーブル型のスカラ変数,又は,テーブル型の配列変数の各要素について、再帰する。
				do {
					PrpTbl_init_copy_attr_subr(pPrpKey, iType, pPrpTblDst, iBitPosDst + iBitPos,
					                                           pPrpTblSrc, iBitPosSrc + iBitPos, fAttr, fIncl, fExcl);
					iBitPos += iBitLen;
				} while(--iArraySize);		//スカラー変数だった場合は、(iArraySize=1)なので、一回のループで抜ける。
			}
		//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
		} else {
			//変数キーpVarKeyの属性リスト(有れば)と継承属性マスクの論理和が、拒否属性マスクの属性を一つも含んでおらず,かつ,必須属性マスクの属性を全て満たしていれば…
			if(iTest == 2) {
				//PrpTbl_copy_attr_v()から呼び出された場合…
				if(pPrpTblSrc) {
					//変数のビット位置から、(変数のビット数*配列全体の要素数)ぶんの範囲を、コピーする。
					bitarray_lsb1st_copy(pPrpTblDst, iBitPosDst + iBitPos,
					                     pPrpTblSrc, iBitPosSrc + iBitPos, iBitLen * iArraySize);
				//PrpTbl_init_attr_v()から呼び出された場合…
				} else {
					//このスカラ変数,又は,配列変数を初期化する。
					PrpTbl_op_v(pPrpKey, iTbl, pPrpTblDst, iBitPosDst, 0/*dummy*/, aName, 1/*init*/);
					//                                     ~~~~~~~~~~ 'iBitPosDst+iBitPos'としないように注意せよ。テーブルのビット位置に、変数のビット位置を加算する処理は、PrpTbl_op_v()がaNameを参照して行う。
				}
			}
		}
	}
}
//}}2016/11/25追加:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
/*--------------------------------------------------------------------------*/
#ifndef USE_PRPTBL_PATH_P_NEWVER
static int PrpTbl_path_callback(int iType, const int* aName, const char* sPath, void* arg) {
	if(strcmp(sPath, arg)) { return 0; }
	if(!iType) { DIE(); }	//dPrpTblC.exeは'タイプid'に0を割り当てないはず。
	return iType;
}
#endif//USE_PRPTBL_PATH_P_NEWVER
/*--------------------------------------------------------------------------*/
static int PrpTbl_list_subr(const void* pPrpKey, int iTbl, int (*callback)(int iType, const int* aName, const char* sPath, void* arg), int* aName/*[iNameCap]*/, int iNameCap, char* sPath/*[iPathCap]*/, int iPathCap, void* arg) {
	int i, iNameLen, iPathLen1;
	const void *pTblKey, *pVarKey;
	//変数名とインデクスの長さ(終端の-1を除く)を求める。
	for(iNameLen = 0; iNameLen < iNameCap; iNameLen++) {
		if(aName[iNameLen] == -1) { break; }
	}
	if((unsigned)iNameLen >= (unsigned)iNameCap) { DIE(); }		//多分当モジュールのバグ
	//変数名を追加する前の、パス名の長さを記憶しておく。
	iPathLen1 = strnlen(sPath, iPathCap);
	if((unsigned)iPathLen1 >= (unsigned)iPathCap) { DIE(); }	//多分当モジュールのバグ
	//テーブルキーを取得する。
	pTblKey = REG_open_key(pPrpKey, iTbl);
	if(!pTblKey) { DIE(); }
	//全ての変数キーについて…
	for(i = 0;
	   (pVarKey = REG_open_nth_key(pTblKey, i, &aName[iNameLen])) != NULL;	//aName[iNameLen]に変数名を格納する。	(iNameLen<iNameCap)である事は当関数の先頭で検査してあるので安全です。
	    i++) {
		char buf[16];	//"%d"を格納出来る充分な容量
		int retVal, iType;
		const char* pName;
		const uint16_t* pDim;
		//名前とインデクスの終端(-1)を格納する。
		if((unsigned)(iNameLen + 1) >= (unsigned)iNameCap) { DIE(); }	//aName[iNameCap]の容量が足りない。	aName[iNameLen]に変数名,aName[iNameLen+1]に終端(-1)を格納するので、(iNameLen+1)がaName[]の容量未満でなければいけない。
		aName[iNameLen + 1] = -1;
		//パス名に、変数名を追加する。
		pName = REG_get_string(pVarKey, Prp_name);
		if(!pName) {	//変数名が格納されていなければ、数値を変数名とする。
			sprintf(buf, "%d", aName[iNameLen]);
			pName = buf;
		}
		if((unsigned)strlcat(sPath, pName, iPathCap) >= (unsigned)iPathCap) { DIE(); }	//sPath[iPathCap]の容量が足りない。
		//タイプ名,又は,テーブル名を取得する。
		iType = REG_get_value(pVarKey, Prp_type);
		//配列データを取得する。
		pDim = REG_get_blob(pVarKey, Prp_dim);
		//配列データが有れば…
		if(pDim) {
			int nDim, iDim, iPathLen2;
#ifndef USE_PRPTBL_PATH_P_NEWVER
//{{2015/12/01追加:PrpTbl_path_p()等が、配列変数のインデクスを全て省略したパス名にも、マッチ出来るようにしました。
			// * Tue Dec 01 21:56:21 JST 2015 Naoyuki Sawa
			// - PrpTbl_path_p()等が、配列変数のインデクスを全て省略したパス名にも、マッチ出来るようにしました。
			// - 変更後の動作は、以下のようになりました。
			//   ①アプリケーション定義のコールバック関数がPrpTbl_path_callbackならば、(即ちPrpTbl_path_p()等からの呼び出しならば)、配列変数のインデクスを全て省略したパス名もコールバック関数へ通知するように変更しました。		←今回追加した動作
			//   ②アプリケーション定義のコールバック関数がPrpTbl_path_callbackでなければ、(即ちPrpTbl_path_p()等からの呼び出しでなければ)、これまでどおり、配列変数のインデクスを全て省略したパス名はコールバック関数へ通知しません。	←この動作は変更していない
			//   そのようにした理由は、下記のとおりです。
			// - [②の動作を変更していない理由について]
			//   本来、「配列変数のインデクスを全て省略したパス名はコールバック関数へ通知しない」のが、自然な動作です。
			//   もし無条件に「配列変数のインデクスを全て省略したパス名もコールバック関数へ通知」してしまうと、アプリケーション定義のコールバック関数内で、リテラル値の列挙等の処理が行えなくなってしまいます。
			//   コールバック関数に渡される情報から、配列変数のインデクスを全て省略したパス名であるかどうかが判断できなくなり、コールバックがそのパス名の変数からリテラル値を取得設定出来るかが判断出来なくなるからです。
			//   「配列変数のインデクスを全て省略したパス名はコールバック関数へ通知しない」であれば、そのパス名の変数からリテラル値を取得設定出来る事が判断出来ます。(例はPrpTbl_dump_callback()の実装を参照して下さい。)
			// - [①の動作を追加した理由について]
			//   しかし、PrpTbl_path_p()等からの呼び出しでは、「配列変数のインデクスを全て省略したパス名もコールバック関数へ通知する」必要が生じました。
			//   これまでの全て②としていた動作では、以下のような不都合が生じたからです。
			//   □プロパティテーブルスクリプト
			//   │table App
			//   │ var x[2]
			//   │end
			//   □例(今回の変更の【適用前】)
			//   │PrpHdr_set_l(phApp,12345,PrpVar_x,-1);	//これは成功します。配列変数のインデクスを全て省略してsetを行う事は、配列変数の全要素に値を格納する事を意味するからです。
			//   │PrpHdr_set_p(phApp,12345,"x");		//これが失敗するのが問題点です。上記と同じ処理をパス名を用いて行っているだけなのに、こちらは失敗してしまいます。この例ではset_pを使用しましたが、init_pでも同様です。
			//   │PrpHdr_path_p(phApp,aName,16,"x");	//なぜ上記の処理が失敗するかというと、PrpHdr_path_p()が失敗していたからです。PrpTbl_list()がPrpTbl_path_callback()に対して配列変数のインデクスを全て省略したパス名を通知しないので、アプリケーションがPrpHdr_path_p()等に対して配列変数のインデクスを全て省略したパス名を指定すると、マッチしないからです。
			//   上記の不都合を解決するため、PrpHdr_path_p()等から呼び出された場合だけは、配列変数のインデクスを全て省略したパス名も通知するのが良いです。
			//   PrpHdr_path_p()等を呼び出すアプリケーションは、そのパス名に対してリテラル変数の取得設定やその他の各種処理のどれを行うかを、アプリケーション自身が知っているからです。
			//   従って、PrpHdr_path_p()等から呼び出された場合だけは、配列変数のインデクスを全て省略したパス名も通知するように変更しました。
			//   変更後は、こうなります。
			//   □例(今回の変更の【適用後】)
			//   │PrpHdr_set_l(phApp,12345,PrpVar_x,-1);	//これは成功します。配列変数のインデクスを全て省略してsetを行う事は、配列変数の全要素に値を格納する事を意味するからです。
			//   │PrpHdr_set_p(phApp,12345,"x");		//これも成功します。
			//   │PrpHdr_path_p(phApp,aName,16,"x");	//これも成功します。
			if(callback == PrpTbl_path_callback) {
				//アプリケーション定義のコールバック関数(=PrpTbl_path_callback)を呼び出す。
				retVal = (*callback)(iType, aName, sPath, arg);
				if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数(=PrpTbl_path_callback)の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
			}
//}}2015/12/01追加:PrpTbl_path_p()等が、配列変数のインデクスを全て省略したパス名にも、マッチ出来るようにしました。
#endif//USE_PRPTBL_PATH_P_NEWVER
			//'[インデクス,インデクス,...,インデクス]'を追加する前の、パス名の長さを記憶しておく。
			iPathLen2 = strnlen(sPath, iPathCap);
			if((unsigned)iPathLen2 >= (unsigned)iPathCap) { DIE(); }	//多分当モジュールのバグ
			//次元数を取得する。
			nDim = REG_get_blob_size(pDim);
			if(nDim & 1) { DIE(); }	//(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
			nDim >>= 1;		//配列データのバイト数⇒次元数に変換する。
			//aNameはaName[iNameLen+1]～aName[iNameLen+nDim]にインデクスを格納するので、pDimもpDim[1]～pDim[nDim]で(要素数-1)を参照出来るようにポインタを1つ前へずらしておく。
			pDim--;
			//インデクスを初期化する。
			if((unsigned)(iNameLen + nDim + 1) >= (unsigned)iNameCap) { DIE(); }	//aName[iNameCap]の容量が足りない。	aName[iNameLen]に変数名,aName[iNameLen+1]～aName[iNameLen+nDim]にインデクス,aName[iNameLen+nDim+1]に終端(-1)を格納するので、(iNameLen+nDim+1)がaName[]の容量未満でなければいけない。
			for(iDim = 1; iDim <= nDim; iDim++) { aName[iNameLen + iDim] =  0; }	//この次元のインデクスを0としておく。
			                                      aName[iNameLen + iDim] = -1;	//名前とインデクスの終端(-1)を格納する。
			do {
				//パス名に、'[インデクス,インデクス,...,インデクス]'を追加する。
				if((unsigned)strlcat(sPath, "[", iPathCap) >= (unsigned)iPathCap) { DIE(); }	//sPath[iPathCap]の容量が足りない。
				for(iDim = 1; iDim <= nDim; iDim++) {
					if(iDim != 1) { if((unsigned)strlcat(sPath, ",", iPathCap) >= (unsigned)iPathCap) { DIE(); } }	//sPath[iPathCap]の容量が足りない。
					sprintf(buf, "%d", aName[iNameLen + iDim]);
					if((unsigned)strlcat(sPath, buf, iPathCap) >= (unsigned)iPathCap) { DIE(); }	//sPath[iPathCap]の容量が足りない。
				}
				if((unsigned)strlcat(sPath, "]", iPathCap) >= (unsigned)iPathCap) { DIE(); }	//sPath[iPathCap]の容量が足りない。
				//テーブル変数(iType<=0x7FFF)ならば…
				if((unsigned)iType <= 0x7FFF) {
#ifdef  USE_PRP_DOUBLE
					//組み込み'Double'型のテーブル変数ならば…
					if(iType == PrpTbl_Double) {
						//アプリケーション定義のコールバック関数を呼び出す。
						retVal = (*callback)(iType, aName, sPath, arg);
						if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
					//アプリケーション定義のテーブル変数ならば…
					} else {
#endif//USE_PRP_DOUBLE
						//アプリケーション定義のコールバック関数を呼び出す。
						retVal = (*callback)(iType, aName, sPath, arg);
						if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
						//このテーブル変数について再帰する。
						if((unsigned)strlcat(sPath, ".", iPathCap) >= (unsigned)iPathCap) { DIE(); }	//sPath[iPathCap]の容量が足りない。
						retVal = PrpTbl_list_subr(pPrpKey, iType, callback, aName, iNameCap, sPath, iPathCap, arg);
						if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
#ifdef  USE_PRP_DOUBLE
					}
#endif//USE_PRP_DOUBLE
				//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
				} else {
					//アプリケーション定義のコールバック関数を呼び出す。
					retVal = (*callback)(iType, aName, sPath, arg);
					if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
				}
				//パス名から、'[インデクス,インデクス,...,インデクス]'[.]を削除する。
				sPath[iPathLen2] = '\0';
				//インデクスを進める。後方の次元を早く変化させる。
				for(iDim = nDim; iDim >= 1; iDim--) {
					int iBound = pDim[iDim];	//この次元の(要素数-1)を取得する。	pDimもpDim[1]～pDim[nDim]で(要素数-1)を参照出来るようにポインタを1つ前へずらしてあります。
					    iBound++;			//(要素数-1)⇒(要素数)に補正する。
					if(++aName[iNameLen + iDim] < iBound) { break; }
					     aName[iNameLen + iDim] = 0;
				}//↓for()を抜けた時のiDimを参照している事に注意。
			} while(iDim);	//インデクスを進められなくなったら抜ける。
		//配列データが無ければ…
		} else {
			//テーブル変数(iType<=0x7FFF)ならば…
			if((unsigned)iType <= 0x7FFF) {
#ifdef  USE_PRP_DOUBLE
				//組み込み'Double'型のテーブル変数ならば…
				if(iType == PrpTbl_Double) {
					//アプリケーション定義のコールバック関数を呼び出す。
					retVal = (*callback)(iType, aName, sPath, arg);
					if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
				//アプリケーション定義のテーブル変数ならば…
				} else {
#endif//USE_PRP_DOUBLE
					//アプリケーション定義のコールバック関数を呼び出す。
					retVal = (*callback)(iType, aName, sPath, arg);
					if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
					//このテーブル変数について再帰する。
					if((unsigned)strlcat(sPath, ".", iPathCap) >= (unsigned)iPathCap) { DIE(); }	//sPath[iPathCap]の容量が足りない。
					retVal = PrpTbl_list_subr(pPrpKey, iType, callback, aName, iNameCap, sPath, iPathCap, arg);
					if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
#ifdef  USE_PRP_DOUBLE
				}
#endif//USE_PRP_DOUBLE
			//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
			} else {
				//アプリケーション定義のコールバック関数を呼び出す。
				retVal = (*callback)(iType, aName, sPath, arg);
				if(retVal) { return retVal; }	//アプリケーション定義のコールバック関数の戻り値,又は,再帰の結果が0以外ならば、sPath[]とaName[]の内容を維持したままで、処理を返す。
			}
		}
		//パス名から、変数名[.]を削除する。
		sPath[iPathLen1] = '\0';
	}
	//変数名とインデクスの長さを元に戻す。
	aName[iNameLen] = -1;
	return 0;
}
/*--------------------------------------------------------------------------*/
#ifdef  USE_PRP_DUMP
typedef struct _ST_PrpDmp {
	FILE*		fp;
	const void*	pPrpKey;
	int		iTbl;
	void*		pPrpTbl;
	int		iBitPos;
	void (*fnVarFmt)(char* buf/*[cap]*/, int cap, int iFmt, int iVal);
	int		fOpt;
	int		maxDepth;
} ST_PrpDmp;
static int PrpTbl_dump_maxDepth(int iType, const int* aName, const char* sPath, void* arg) {
	ST_PrpDmp* pDmp = arg;
	int c, depth = 0;
	while((c = *sPath++)) { if(c == '.') { depth++; } }
	if(depth > pDmp->maxDepth) { pDmp->maxDepth = depth; }
	return 0;
}
//階層形式のダンプは、リテラル値を持たない変数(=テーブル変数)も含めて、全ての変数について1行づつ出力する。
static int PrpTbl_dump_callback(int iType, const int* aName, const char* sPath, void* arg) {
	char buf[256/*調整可*/];
	ST_PrpDmp* pDmp = arg;
	const char* pName;
	ST_PrpInf stPrpInf;
	const char *p1 = sPath, *p2;
	int depth = 0;
	PrpTbl_inf_v(pDmp->pPrpKey, pDmp->iTbl, &stPrpInf, aName);
	if(stPrpInf.iType != iType) { DIE(); }	//バグ
	if(pDmp->fOpt & PrpDmp_Vbs) {	//verbose
		if(iType == -1) {
			pName = "var";
#ifdef  USE_PRP_DOUBLE
		} else if(iType == PrpTbl_Double) {
			pName = "Double";
#endif//USE_PRP_DOUBLE
		} else if(!(pName = REG_get_string_l(pDmp->pPrpKey, iType, Prp_name, -1))) {
			sprintf(buf, "%d", iType);
			pName = buf;
		}
		fprintf(pDmp->fp, "%d\t%s\t", stPrpInf.iBitPos, pName);
	}
	while((p2 = strchr(p1, '.'))) {
		fputc('\t', pDmp->fp);
		depth++;
		p1 = p2 + 1/*'.'*/;
	}
	fputs(p1, pDmp->fp);
	//テーブル変数(iType<=0x7FFF)ならば…
	if((unsigned)iType <= 0x7FFF) {
#ifdef  USE_PRP_DOUBLE
		if(iType == PrpTbl_Double) {
			while(depth < pDmp->maxDepth) {
				fputc('\t', pDmp->fp);
				depth++;
			}
			fputs("\t= ", pDmp->fp);
			PrpTbl_ffmt_v(pDmp->pPrpKey, pDmp->iTbl, pDmp->pPrpTbl, pDmp->iBitPos, buf, sizeof buf, aName);
			fputs(buf, pDmp->fp);
			depth++;
		}
#endif//USE_PRP_DOUBLE
	//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
	} else {
		while(depth < pDmp->maxDepth) {
			fputc('\t', pDmp->fp);
			depth++;
		}
		fputs("\t= ", pDmp->fp);
		PrpTbl_fmt_v(pDmp->pPrpKey, pDmp->iTbl, pDmp->pPrpTbl, pDmp->iBitPos, buf, sizeof buf, pDmp->fnVarFmt, aName);
		fputs(buf, pDmp->fp);
		depth++;
	}
	if(stPrpInf.pDesc) {
		while(depth < (pDmp->maxDepth + 1)) {
			fputc('\t', pDmp->fp);
			depth++;
		}
		fprintf(pDmp->fp, "\t#//%s", stPrpInf.pDesc);
	}
	fputc('\n', pDmp->fp);
	return 0;
}
//絶対パス形式のダンプは、リテラル値を持つ変数(=var変数,タイプ変数,Doubleテーブル変数)の行だけを出力する。
static int PrpTbl_dump_abs_callback(int iType, const int* aName, const char* sPath, void* arg) {
	char buf[256/*調整可*/];
	ST_PrpDmp* pDmp = arg;
	const char* pName;
	ST_PrpInf stPrpInf;
	PrpTbl_inf_v(pDmp->pPrpKey, pDmp->iTbl, &stPrpInf, aName);
	if(stPrpInf.iType != iType) { DIE(); }	//バグ
	//テーブル変数(iType<=0x7FFF)ならば…
	if((unsigned)iType <= 0x7FFF) {
#ifdef  USE_PRP_DOUBLE
		if(iType == PrpTbl_Double) {
			if(pDmp->fOpt & PrpDmp_Vbs) {	//verbose
				pName = "Double";
				fprintf(pDmp->fp, "%d\t%s\t", stPrpInf.iBitPos, pName);
			}
			fputs(sPath, pDmp->fp);
			fputs("\t= ", pDmp->fp);
			PrpTbl_ffmt_v(pDmp->pPrpKey, pDmp->iTbl, pDmp->pPrpTbl, pDmp->iBitPos, buf, sizeof buf, aName);
			fputs(buf, pDmp->fp);
			if(stPrpInf.pDesc) { fprintf(pDmp->fp, "\t#//%s", stPrpInf.pDesc); }
			fputc('\n', pDmp->fp);
		}
#endif//USE_PRP_DOUBLE
	//'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば…
	} else {
		if(pDmp->fOpt & PrpDmp_Vbs) {	//verbose
			if(iType == -1) {
				pName = "var";
			} else if(!(pName = REG_get_string_l(pDmp->pPrpKey, iType, Prp_name, -1))) {
				sprintf(buf, "%d", iType);
				pName = buf;
			}
			fprintf(pDmp->fp, "%d\t%s\t", stPrpInf.iBitPos, pName);
		}
		fputs(sPath, pDmp->fp);
		fputs("\t= ", pDmp->fp);
		PrpTbl_fmt_v(pDmp->pPrpKey, pDmp->iTbl, pDmp->pPrpTbl, pDmp->iBitPos, buf, sizeof buf, pDmp->fnVarFmt, aName);
		fputs(buf, pDmp->fp);
		if(stPrpInf.pDesc) { fprintf(pDmp->fp, "\t#//%s", stPrpInf.pDesc); }
		fputc('\n', pDmp->fp);
	}
	return 0;
}
#endif//USE_PRP_DUMP
/****************************************************************************
 *	基本的な関数
 ****************************************************************************/
void* PrpTbl_new(const void* pPrpKey, int iTbl) {
	void* pPrpTbl;
	const void* pTblKey;
	int iBitLen;
	//テーブルキーを取得する。
	pTblKey = REG_open_key(pPrpKey, iTbl);
	if(!pTblKey) { DIE(); }
	//このテープルの(ビット数-1)を取得する。
	iBitLen = REG_get_value(pTblKey, Prp_len);
	if(iBitLen == -1) { DIE(); }
	//(ビット数-1)⇒(ビット数)に補正する。
	iBitLen++;
	//テーブルのビット配列を確保する。
	pPrpTbl = bitarray_alloc(iBitLen);
	if(!pPrpTbl) { DIE(); }
	//テーブルを初期化する。
	PrpTbl_init(pPrpKey, iTbl, pPrpTbl, 0/*iBitPos*/);
	return pPrpTbl;
}
void PrpTbl_init(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos) {
	const void* pTblKey;
	int i, aName[2];
	//テーブルキーを取得する。
	pTblKey = REG_open_key(pPrpKey, iTbl);
	if(!pTblKey) { DIE(); }
	//全ての変数を初期化する。
	aName[1] = -1;
	for(i = 0;
	    REG_open_nth_key(pTblKey, i, &aName[0]);
	    i++) {
		PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*dummy*/, aName, 1/*init*/);
	}
}
//{{2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
//void PrpTbl_init_attr(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAttr) {
//	const void *pTblKey, *pVarKey;
//	int i, aName[2];
//	//テーブルキーを取得する。
//	pTblKey = REG_open_key(pPrpKey, iTbl);
//	if(!pTblKey) { DIE(); }
//	//全ての変数キーについて…
//	aName[1] = -1;
//	for(i = 0;
//	   (pVarKey = REG_open_nth_key(pTblKey, i, &aName[0])) != NULL;
//	    i++) {
//		//属性リストを取得する。
//		const uint8_t* pAttr = REG_get_blob(pVarKey, Prp_attr);
//		//属性リストが有れば…
//		if(pAttr) {
//			//属性の数を取得する。
//			int nAttr = REG_get_blob_size(pAttr);
//			//指定された属性idが、属性リストに含まれていたら…
//			// - 個々の変数に対して指定する属性の数は少ないだろうと想定して、リニアサーチにした。
//			//   バイナリサーチに変更する事も出来るが、たぶんリニアサーチの方が効率が良いだろう。
//			if(memchr(pAttr, iAttr, nAttr)) {
//				//この変数を初期化する。
//				// - この変数がテーブル変数の場合に、階層を辿って属性による限定は行わない事にした。例えば、
//				//   │table A
//				//   │  var x
//				//   │  var y
//				//   │end
//				//   │table B
//				//   │  A a1 attr1
//				//   │  A a2 attr2
//				//   │end
//				//   │---
//				//   │PrpTbl_def(B,b);
//				//   │PrpTbl_init(pPrpKey,PrpTbl_b,b,0);
//				//   │  ～
//				//   │PrpTbl_init_attr(pPrpKey,PrpTbl_b,b,0,PrpAtr_a1);
//				//   …とした場合、b->a1->x,b->a1->yが再初期化され、b->a2->x,b->a2->yは再初期化されません。
//				//   属性による限定はbの直下の変数に対してだけ適用するので、b->a1->x,b->a1->y自体がa1属性を持っていなくても動作に関係は無いからです。
//				//   こういう仕様にした理由は、もし階層を辿って属性による限定を適用する仕様にしてしまうと、
//				//   下位階層の細かなテーブルに対しても、上位階層での利用を意識して属性を付与する必要が生じてしまい、利用し辛くなってしまうからです。
//				// - 実際の利用においては、アプリケーションが直接利用する最上位テーブルの変数に対してだけ、(必要に応じて)属性を付与し、
//				//   変数の型として利用する下位テーブルの変数には、属性を指定しないのが判り易いと思います。
//				PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*dummy*/, aName, 1/*init*/);
//			}
//		}
//	}
//}
//↓2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
#ifndef PIECE
void PrpTbl_init_attr_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, ...) {
	va_list ap;
	va_start(ap, iBitPos);
	PrpTbl_init_attr_a(pPrpKey, iTbl, pPrpTbl, iBitPos, ap);
	va_end(ap);
}
void PrpTbl_init_attr_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, va_list ap) {
	int aAttr[(14+2)/*調整可*/], i = 0, j = 0;	//実用上、必須属性リストと拒否属性リストが14以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aAttr[i] = va_arg(ap, int)) == -1) { if(++j == 2/*必須属性リスト,拒否属性リスト*/) { break; } }
		if(++i >= ARRAY_SIZE(aAttr)) { DIE(); }	//ここで停止した場合は、aAttr[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpTbl_init_attr_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aAttr);
}
#else //PIECE
void PrpTbl_init_attr_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, ...);
void PrpTbl_init_attr_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, va_list ap);
asm("
		.code
		.align		1
		.global		PrpTbl_init_attr_l
		.global		PrpTbl_init_attr_a
PrpTbl_init_attr_l:
		xsub		%sp, %sp, 4
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//[%sp+ 4] := retp
		;//[%sp+ 8] := iBitPos
		;//[%sp+12] := ...
		xadd		%r9, %sp, 12				;//%r9     :=                                          ap = &...
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                          ap
		xld.w		%r15, [%sp+8]				;//%r15    :=                                 iBitPos
		call		PrpTbl_init_attr_a			;//PrpTbl_init_attr_a(pPrpKey, iTbl, pPrpTbl, iBitPos, ap)
		xadd		%sp, %sp, 4
		ret
PrpTbl_init_attr_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := ap
		xjp		PrpTbl_init_attr_v
");
#endif//PIECE
//{{2016/11/25変更:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
//void PrpTbl_init_attr_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/) {
//	int fIncl[(256/32)], fExcl[(256/32)];
//	const void *pTblKey, *pVarKey;
//	int i, aName[2];
//	//必須属性マスクと拒否属性マスクを作成する。
//	PrpTbl_make_attr_mask(fIncl, fExcl, aAttr);
//	//テーブルキーを取得する。
//	pTblKey = REG_open_key(pPrpKey, iTbl);
//	if(!pTblKey) { DIE(); }
//	//全ての変数キーについて…
//	aName[1] = -1;
//	for(i = 0;
//	   (pVarKey = REG_open_nth_key(pTblKey, i, &aName[0])) != NULL;
//	    i++) {
//		//変数キーpVarKeyの属性リスト(有れば)が、必須属性マスクを全て満たし,かつ,拒否属性マスクに含まれていなければ…
//		if(PrpTbl_test_attr_mask(fIncl, fExcl, pVarKey)) {
//			//この変数を初期化する。
//			// - この変数がテーブル変数の場合に、階層を辿って属性による限定は行わない事にした。例えば、
//			//   │table A
//			//   │  var x
//			//   │  var y
//			//   │end
//			//   │table B
//			//   │  A a1 attr1
//			//   │  A a2 attr2
//			//   │end
//			//   │---
//			//   │PrpTbl_def(B,b);
//			//   │PrpTbl_init(pPrpKey,PrpTbl_b,b,0);
//			//   │  ～
//			//   │PrpTbl_init_attr(pPrpKey,PrpTbl_b,b,0,PrpAtr_a1);
//			//   …とした場合、b->a1->x,b->a1->yが再初期化され、b->a2->x,b->a2->yは再初期化されません。
//			//   属性による限定はbの直下の変数に対してだけ適用するので、b->a1->x,b->a1->y自体がa1属性を持っていなくても動作に関係は無いからです。
//			//   こういう仕様にした理由は、もし階層を辿って属性による限定を適用する仕様にしてしまうと、
//			//   下位階層の細かなテーブルに対しても、上位階層での利用を意識して属性を付与する必要が生じてしまい、利用し辛くなってしまうからです。
//			// - 実際の利用においては、アプリケーションが直接利用する最上位テーブルの変数に対してだけ、(必要に応じて)属性を付与し、
//			//   変数の型として利用する下位テーブルの変数には、属性を指定しないのが判り易いと思います。
//			PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*dummy*/, aName, 1/*init*/);
//		}
//	}
//}
//↓2016/11/25変更:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
void PrpTbl_init_attr_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/) {
	int fInhe[(256/32)], fIncl[(256/32)], fExcl[(256/32)];
	//継承属性マスクをクリアする。
	memset(fInhe, 0, sizeof(int) * (256/32));
	//必須属性マスクと拒否属性マスクを作成する。
	PrpTbl_make_attr_mask(fIncl, fExcl, aAttr);
	//再帰処理を開始する。
	PrpTbl_init_copy_attr_subr(pPrpKey, iTbl, pPrpTbl, iBitPos, NULL/*pPrpTblSrc*/, 0/*iBitPosSrc*/, fInhe, fIncl, fExcl);	//PrpTbl_init_attr_v()とPrpTbl_copy_attr_v()の共通処理
}
//}}2016/11/25変更:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
//}}2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
//{{2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
//void PrpTbl_copy_attr(const void* pPrpKey, int iTbl, void* pPrpTblDst, int iBitPosDst, void* pPrpTblSrc, int iBitPosSrc, int iAttr) {
//	const void *pTblKey, *pVarKey;
//	int i;
//	//テーブルキーを取得する。
//	pTblKey = REG_open_key(pPrpKey, iTbl);
//	if(!pTblKey) { DIE(); }
//	//全ての変数キーについて…
//	for(i = 0;
//	   (pVarKey = REG_open_nth_key(pTblKey, i, NULL)) != NULL;
//	    i++) {
//		//属性リストを取得する。
//		const uint8_t* pAttr = REG_get_blob(pVarKey, Prp_attr);
//		//属性リストが有れば…
//		if(pAttr) {
//			//属性の数を取得する。
//			int nAttr = REG_get_blob_size(pAttr);
//			//指定された属性idが、属性リストに含まれていたら…
//			// - 個々の変数に対して指定する属性の数は少ないだろうと想定して、リニアサーチにした。
//			//   バイナリサーチに変更する事も出来るが、たぶんリニアサーチの方が効率が良いだろう。
//			if(memchr(pAttr, iAttr, nAttr)) {
//				int iType, iBitLen, iBitPos;
//				const uint16_t* pDim;
//				//タイプ名,又は,テーブル名を取得する。
//				iType = REG_get_value(pVarKey, Prp_type);
//				//タイプ名,又は,テーブル名が有れば…
//				if(iType != -1) {
//					//タイプ,又は,テーブルのビット数を取得する。
//					const void* pTblOrTypKey = REG_open_key(pPrpKey, iType);
//					if(!pTblOrTypKey) { DIE(); }
//					iBitLen = REG_get_value(pTblOrTypKey, Prp_len);
//					if(iBitLen == -1) { DIE(); }
//					iBitLen++;	//(ビット数-1)⇒(ビット数)に補正する。
//				//タイプ名,又は,テーブル名が無ければ、'var'型と見なす。
//				} else {
//					iBitLen = 32;
//				}
//				//配列データを取得する。
//				pDim = REG_get_blob(pVarKey, Prp_dim);
//				//配列データが有れば…
//				if(pDim) {
//					int nDim, iBound;
//					//次元数を取得する。
//					nDim = REG_get_blob_size(pDim);
//					if(nDim & 1) { DIE(); }	//(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
//					nDim >>= 1;		//配列データのバイト数⇒次元数に変換する。
//					do {
//						//この次元の(要素数-1)を取得する。
//						iBound = *pDim++;	//このループ以降の処理でpDimを参照しないのでpDimを破壊して構わない。
//						//(要素数-1)⇒(要素数)に補正する。
//						iBound++;
//						//変数のビット数に、この次元の要素数を乗算する。
//						iBitLen *= iBound;
//					} while(--nDim);
//				}
//				//変数のビット位置を取得する。
//				iBitPos = REG_get_value(pVarKey, Prp_pos);
//				if(iBitPos == -1) { DIE(); }
//				//変数のビット位置から、変数のビット数ぶんの範囲を、コピーする。
//				bitarray_lsb1st_copy(pPrpTblDst, iBitPosDst + iBitPos,
//				                     pPrpTblSrc, iBitPosSrc + iBitPos, iBitLen);
//			}
//		}
//	}
//}
//↓2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
#ifndef PIECE
void PrpTbl_copy_attr_l(const void* pPrpKey, int iTbl, void* pPrpTblDst, int iBitPosDst, void* pPrpTblSrc, int iBitPosSrc, ...) {
	va_list ap;
	va_start(ap, iBitPosSrc);
	PrpTbl_copy_attr_a(pPrpKey, iTbl, pPrpTblDst, iBitPosDst, pPrpTblSrc, iBitPosSrc, ap);
	va_end(ap);
}
void PrpTbl_copy_attr_a(const void* pPrpKey, int iTbl, void* pPrpTblDst, int iBitPosDst, void* pPrpTblSrc, int iBitPosSrc, va_list ap) {
	int aAttr[(14+2)/*調整可*/], i = 0, j = 0;	//実用上、必須属性リストと拒否属性リストが14以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aAttr[i] = va_arg(ap, int)) == -1) { if(++j == 2/*必須属性リスト,拒否属性リスト*/) { break; } }
		if(++i >= ARRAY_SIZE(aAttr)) { DIE(); }	//ここで停止した場合は、aAttr[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpTbl_copy_attr_v(pPrpKey, iTbl, pPrpTblDst, iBitPosDst, pPrpTblSrc, iBitPosSrc, aAttr);
}
#else //PIECE
void PrpTbl_copy_attr_l(const void* pPrpKey, int iTbl, void* pPrpTblDst, int iBitPosDst, void* pPrpTblSrc, int iBitPosSrc, ...);
void PrpTbl_copy_attr_a(const void* pPrpKey, int iTbl, void* pPrpTblDst, int iBitPosDst, void* pPrpTblSrc, int iBitPosSrc, va_list ap);
asm("
		.code
		.align		1
		.global		PrpTbl_copy_attr_l
		.global		PrpTbl_copy_attr_a
PrpTbl_copy_attr_l:
		xsub		%sp, %sp, 12
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTblDst
		;//%r15     := iBitPosDst
		;//[%sp+12] := retp
		;//[%sp+16] := pPrpTblSrc
		;//[%sp+20] := iBitPosSrc
		;//[%sp+24] := ...
		xadd		%r9, %sp, 24				;//%r9     :=                                                                        ap = &...
		xld.w		[%sp+8], %r9				;//[%sp+8] :=                                                                        ap
		xld.w		%r9, [%sp+20]				;//%r9     :=                                                            iBitPosSrc
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                                            iBitPosSrc
		xld.w		%r9, [%sp+16]				;//%r9     :=                                                pPrpTblSrc
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                                pPrpTblSrc
		call		PrpTbl_copy_attr_a			;//PrpTbl_copy_attr_v(pPrpKey, iTbl, pPrpTblDst, iBitPosDst, pPrpTblSrc, iBitPosSrc, ap)
		xadd		%sp, %sp, 12
		ret
PrpTbl_copy_attr_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTblDst
		;//%r15     := iBitPosDst
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := pPrpTblSrc
		;//[%sp+ 8] := iBitPosSrc
		;//[%sp+12] := ap
		xjp		PrpTbl_copy_attr_v
");
#endif//PIECE
//{{2016/11/25変更:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
//void PrpTbl_copy_attr_v(const void* pPrpKey, int iTbl, void* pPrpTblDst, int iBitPosDst, void* pPrpTblSrc, int iBitPosSrc, const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/) {
//	int fIncl[(256/32)], fExcl[(256/32)];
//	const void *pTblKey, *pVarKey;
//	int i;
//	//必須属性マスクと拒否属性マスクを作成する。
//	PrpTbl_make_attr_mask(fIncl, fExcl, aAttr);
//	//テーブルキーを取得する。
//	pTblKey = REG_open_key(pPrpKey, iTbl);
//	if(!pTblKey) { DIE(); }
//	//全ての変数キーについて…
//	for(i = 0;
//	   (pVarKey = REG_open_nth_key(pTblKey, i, NULL)) != NULL;
//	    i++) {
//		//変数キーpVarKeyの属性リスト(有れば)が、必須属性マスクを全て満たし,かつ,拒否属性マスクに含まれていなければ…
//		if(PrpTbl_test_attr_mask(fIncl, fExcl, pVarKey)) {
//			int iType, iBitLen, iBitPos;
//			const uint16_t* pDim;
//			//タイプ名,又は,テーブル名を取得する。
//			iType = REG_get_value(pVarKey, Prp_type);
//			//タイプ名,又は,テーブル名が有れば…
//			if(iType != -1) {
//				//タイプ,又は,テーブルのビット数を取得する。
//				const void* pTblOrTypKey = REG_open_key(pPrpKey, iType);
//				if(!pTblOrTypKey) { DIE(); }
//				iBitLen = REG_get_value(pTblOrTypKey, Prp_len);
//				if(iBitLen == -1) { DIE(); }
//				iBitLen++;	//(ビット数-1)⇒(ビット数)に補正する。
//			//タイプ名,又は,テーブル名が無ければ、'var'型と見なす。
//			} else {
//				iBitLen = 32;
//			}
//			//配列データを取得する。
//			pDim = REG_get_blob(pVarKey, Prp_dim);
//			//配列データが有れば…
//			if(pDim) {
//				int nDim, iBound;
//				//次元数を取得する。
//				nDim = REG_get_blob_size(pDim);
//				if(nDim & 1) { DIE(); }	//(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
//				nDim >>= 1;		//配列データのバイト数⇒次元数に変換する。
//				do {
//					//この次元の(要素数-1)を取得する。
//					iBound = *pDim++;	//このループ以降の処理でpDimを参照しないのでpDimを破壊して構わない。
//					//(要素数-1)⇒(要素数)に補正する。
//					iBound++;
//					//変数のビット数に、この次元の要素数を乗算する。
//					iBitLen *= iBound;
//				} while(--nDim);
//			}
//			//変数のビット位置を取得する。
//			iBitPos = REG_get_value(pVarKey, Prp_pos);
//			if(iBitPos == -1) { DIE(); }
//			//変数のビット位置から、変数のビット数ぶんの範囲を、コピーする。
//			bitarray_lsb1st_copy(pPrpTblDst, iBitPosDst + iBitPos,
//			                     pPrpTblSrc, iBitPosSrc + iBitPos, iBitLen);
//		}
//	}
//}
//↓2016/11/25変更:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
void PrpTbl_copy_attr_v(const void* pPrpKey, int iTbl, void* pPrpTblDst, int iBitPosDst, void* pPrpTblSrc, int iBitPosSrc, const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/) {
	int fInhe[(256/32)], fIncl[(256/32)], fExcl[(256/32)];
	//継承属性マスクをクリアする。
	memset(fInhe, 0, sizeof(int) * (256/32));
	//必須属性マスクと拒否属性マスクを作成する。
	PrpTbl_make_attr_mask(fIncl, fExcl, aAttr);
	//再帰処理を開始する。
	PrpTbl_init_copy_attr_subr(pPrpKey, iTbl, pPrpTblDst, iBitPosDst, pPrpTblSrc, iBitPosSrc, fInhe, fIncl, fExcl);	//PrpTbl_init_attr_v()とPrpTbl_copy_attr_v()の共通処理
}
//}}2016/11/25変更:PrpTbl_init_attr_*(),PrpTbl_copy_attr_*(),及び,PrpHdr_init_attr_*(),PrpHdr_copy_attr_*()の仕様を変更し、テーブル変数の属性は下位階層へ継承すると見なして、処理対象とする変数を判定するようにしました。
//}}2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
void PrpTbl_free(void* pPrpTbl) {
	free(pPrpTbl);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpTbl_init_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, ...) {
	va_list ap;
	va_start(ap, iBitPos);
	PrpTbl_init_a(pPrpKey, iTbl, pPrpTbl, iBitPos, ap);
	va_end(ap);
}
void PrpTbl_init_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpTbl_init_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
}
void PrpTbl_init_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
    //{{特例処理
	//「PrpTbl_init_l(pPrpKey,iTbl,pPrpTbl,0,-1)」の形で呼び出された場合は、PrpTbl_op_v()を経由せずに、ここでPrpTbl_init()を呼び出す事にした。
	// - PrpTbl_op_v()を呼び出すと、PrpTbl_op_v()が誤ってエラーと判断してしまう。
	//   PrpTbl_op_v()に特例処理を追加するよりも、ここで判断する方が自然だと思うので、ここに特例処理を追加する事にしました。
	if(*aName == -1) { PrpTbl_init(pPrpKey, iTbl, pPrpTbl, iBitPos); return; }
    //}}特例処理
	PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*dummy*/, aName, 1/*init*/);
}
#else //PIECE
void PrpTbl_init_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, ...);
void PrpTbl_init_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, va_list ap);
void PrpTbl_init_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpTbl_init_l
		.global		PrpTbl_init_a
		.global		PrpTbl_init_v
PrpTbl_init_l:
		xsub		%sp, %sp, 4
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//[%sp+ 4] := retp
		;//[%sp+ 8] := iBitPos
		;//[%sp+12] := ...
		xadd		%r9, %sp, 12				;//%r9     :=                                     ap = &...
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                     ap
		xld.w		%r15, [%sp+8]				;//%r15    :=                            iBitPos
		call		PrpTbl_init_a				;//PrpTbl_init_a(pPrpKey, iTbl, pPrpTbl, iBitPos, ap)
		xadd		%sp, %sp, 4
		ret
PrpTbl_init_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := ap
PrpTbl_init_v:
    ;//{{特例処理
		xld.w		%r9, [%sp+4]				;//%r9     :=  aName
		ld.w		%r9, [%r9]				;//%r9     := *aName
		cmp		%r9, -1					;//if(*aName == -1) {
		xjreq		PrpTbl_init				;//  PrpTbl_init(pPrpKey, iTbl, pPrpTbl, iBitPos); return; }
    ;//}}特例処理
		xsub		%sp, %sp, 12
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+12] := retp
		;//[%sp+16] := aName
		ld.w		%r9, 1					;//%r9     :=                                                      1/*init*/
		xld.w		[%sp+8], %r9				;//[%sp+8] :=                                                      1/*init*/
		xld.w		%r9, [%sp+16]				;//%r9     :=                                               aName
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                               aName
		xld.w		[%sp+0], %r8				;//[%sp+0] :=                                   0/*dummy*/
		xcall		PrpTbl_op_v				;//PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*dummy*/, aName, 1/*init*/)
		xadd		%sp, %sp, 12
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpTbl_init_f(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpTbl_init_g(pPrpKey, iTbl, pPrpTbl, iBitPos, sFmt, ap);
	va_end(ap);
}
void PrpTbl_init_g(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpTbl_init_p(pPrpKey, iTbl, pPrpTbl, iBitPos, sPath);
}
void PrpTbl_init_p(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	PrpTbl_init_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpTbl_set_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, ...) {
	va_list ap;
	va_start(ap, iNewVal);
	PrpTbl_set_a(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, ap);
	va_end(ap);
}
void PrpTbl_set_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpTbl_set_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, aName);
}
void PrpTbl_set_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, aName, 2/*set*/);
}
#else //PIECE
void PrpTbl_set_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, ...);
void PrpTbl_set_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, va_list ap);
void PrpTbl_set_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpTbl_set_l
		.global		PrpTbl_set_a
		.global		PrpTbl_set_v
PrpTbl_set_l:
		xsub		%sp, %sp, 8
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 8] := retp
		;//[%sp+12] := iNewVal
		;//[%sp+16] := ...
		xadd		%r9, %sp, 16				;//%r9     :=                                             ap = &...
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                             ap
		xld.w		%r9, [%sp+12]				;//%r9     :=                                    iNewVal
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                    iNewVal
		call		PrpTbl_set_a				;//PrpTbl_set_a(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, ap)
		xadd		%sp, %sp, 8
		ret
PrpTbl_set_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := iNewVal
		;//[%sp+ 8] := ap
PrpTbl_set_v:
		xsub		%sp, %sp, 12
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+12] := retp
		;//[%sp+16] := iNewVal
		;//[%sp+20] := aName
		ld.w		%r9, 2					;//%r9     :=                                                   2/*set*/
		xld.w		[%sp+8], %r9				;//[%sp+8] :=                                                   2/*set*/
		xld.w		%r9, [%sp+20]				;//%r9     :=                                            aName
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                            aName
		xld.w		%r9, [%sp+16]				;//%r9     :=                                   iNewVal
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                   iNewVal
		xcall		PrpTbl_op_v				;//PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, aName, 2/*set*/)
		xadd		%sp, %sp, 12
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpTbl_set_f(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpTbl_set_g(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, sFmt, ap);
	va_end(ap);
}
void PrpTbl_set_g(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpTbl_set_p(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, sPath);
}
void PrpTbl_set_p(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iNewVal, const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	PrpTbl_set_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iNewVal, aName);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
int PrpTbl_get_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, ...) {
	int iVal;
	va_list ap;
	va_start(ap, iBitPos);
	iVal = PrpTbl_get_a(pPrpKey, iTbl, pPrpTbl, iBitPos, ap);
	va_end(ap);
	return iVal;
}
int PrpTbl_get_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
}
int PrpTbl_get_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	return PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*増減値*/, aName, 3/*get/acc*/);
}
#else //PIECE
int PrpTbl_get_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, ...);
int PrpTbl_get_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, va_list ap);
int PrpTbl_get_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpTbl_get_l
		.global		PrpTbl_get_a
		.global		PrpTbl_get_v
PrpTbl_get_l:
		xsub		%sp, %sp, 4
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//[%sp+ 4] := retp
		;//[%sp+ 8] := iBitPos
		;//[%sp+12] := ...
		xadd		%r9, %sp, 12				;//%r9     :=                                           ap = &...
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                           ap
		xld.w		%r15, [%sp+8]				;//%r15    :=                                  iBitPos
		call		PrpTbl_get_a				;//return PrpTbl_get_a(pPrpKey, iTbl, pPrpTbl, iBitPos, ap)
		xadd		%sp, %sp, 4
		ret
PrpTbl_get_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := ap
PrpTbl_get_v:
		xsub		%sp, %sp, 12
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+12] := retp
		;//[%sp+16] := aName
		ld.w		%r9, 3					;//%r9     :=                                                              3/*get/acc*/
		xld.w		[%sp+8], %r9				;//[%sp+8] :=                                                              3/*get/acc*/
		xld.w		%r9, [%sp+16]				;//%r9     :=                                                       aName
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                                       aName
		xld.w		[%sp+0], %r8				;//[%sp+0] :=                                          0/*増減値*/
		xcall		PrpTbl_op_v				;//return PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, 0/*増減値*/, aName, 3/*get/acc*/)
		xadd		%sp, %sp, 12
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int PrpTbl_get_f(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sFmt, ...) {
	int iVal;
	va_list ap;
	va_start(ap, sFmt);
	iVal = PrpTbl_get_g(pPrpKey, iTbl, pPrpTbl, iBitPos, sFmt, ap);
	va_end(ap);
	return iVal;
}
int PrpTbl_get_g(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	return PrpTbl_get_p(pPrpKey, iTbl, pPrpTbl, iBitPos, sPath);
}
int PrpTbl_get_p(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	return PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
int PrpTbl_acc_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, ...) {
	int iVal;
	va_list ap;
	va_start(ap, iAcc);
	iVal = PrpTbl_acc_a(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, ap);
	va_end(ap);
	return iVal;
}
int PrpTbl_acc_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return PrpTbl_acc_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, aName);
}
int PrpTbl_acc_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	return PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, aName, 3/*get/acc*/);
}
#else //PIECE
int PrpTbl_acc_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, ...);
int PrpTbl_acc_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, va_list ap);
int PrpTbl_acc_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpTbl_acc_l
		.global		PrpTbl_acc_a
		.global		PrpTbl_acc_v
PrpTbl_acc_l:
		xsub		%sp, %sp, 8
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 8] := retp
		;//[%sp+12] := iAcc
		;//[%sp+16] := ...
		xadd		%r9, %sp, 16				;//%r9     :=                                          ap = &...
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                          ap
		xld.w		%r9, [%sp+12]				;//%r9     :=                                    iAcc
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                    iAcc
		call		PrpTbl_acc_a				;//PrpTbl_acc_a(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, ap)
		xadd		%sp, %sp, 8
		ret
PrpTbl_acc_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := iAcc
		;//[%sp+ 8] := ap
PrpTbl_acc_v:
		xsub		%sp, %sp, 12
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+12] := retp
		;//[%sp+16] := iAcc
		;//[%sp+20] := aName
		ld.w		%r9, 3					;//%r9     :=                                                       3/*get/acc*/
		xld.w		[%sp+8], %r9				;//[%sp+8] :=                                                       3/*get/acc*/
		xld.w		%r9, [%sp+20]				;//%r9     :=                                                aName
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                                aName
		xld.w		%r9, [%sp+16]				;//%r9     :=                                          iAcc
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                          iAcc
		xcall		PrpTbl_op_v				;//return PrpTbl_op_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, aName, 3/*get/acc*/)
		xadd		%sp, %sp, 12
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int PrpTbl_acc_f(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, const char* sFmt, ...) {
	int iVal;
	va_list ap;
	va_start(ap, sFmt);
	iVal = PrpTbl_acc_g(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, sFmt, ap);
	va_end(ap);
	return iVal;
}
int PrpTbl_acc_g(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	return PrpTbl_acc_p(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, sPath);
}
int PrpTbl_acc_p(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, int iAcc, const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	return PrpTbl_acc_v(pPrpKey, iTbl, pPrpTbl, iBitPos, iAcc, aName);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpTbl_inf_l(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, ...) {
	va_list ap;
	va_start(ap, pInf);
	PrpTbl_inf_a(pPrpKey, iTbl, pInf, ap);
	va_end(ap);
}
void PrpTbl_inf_a(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpTbl_inf_v(pPrpKey, iTbl, pInf, aName);
}
void PrpTbl_inf_v(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//	PrpTbl_op_v(pPrpKey, iTbl, NULL/*dummy*/, 0/*iBitPos*/, (int)pInf, aName, 0/*inf*/);
//	//                                        ~~~~~~~~~~~~PrpTbl_op_v()が(pInf->iBitPos)を計算するためにiBitPosの初期値として0を指定する。
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	PrpTbl_op_v(pPrpKey, iTbl, NULL/*dummy*/, 0/*iBitPos*/, (intptr_t)pInf, aName, 0/*inf*/);
	//                                        ~~~~~~~~~~~~PrpTbl_op_v()が(pInf->iBitPos)を計算するためにiBitPosの初期値として0を指定する。
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
#else //PIECE
void PrpTbl_inf_l(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, ...);
void PrpTbl_inf_a(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, va_list ap);
void PrpTbl_inf_v(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpTbl_inf_l
		.global		PrpTbl_inf_a
		.global		PrpTbl_inf_v
PrpTbl_inf_l:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := pInf
		;//[%sp+ 8] := ...
		xld.w		%r14, [%sp+4]				;//%r14    := pInf
		xadd		%r15, %sp, 8				;//%r15    := ap = &...
PrpTbl_inf_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pInf
		;//%r15     := ap
PrpTbl_inf_v:
		xsub		%sp, %sp, 12
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pInf
		;//%r15     := aName
		ld.w		%r9, 0					;//%r9     :=                                                           0/*inf*/
		xld.w		[%sp+8], %r9				;//[%sp+8] :=                                                           0/*inf*/
		xld.w		[%sp+4], %r15				;//[%sp+4] :=                                                    aName
		xld.w		[%sp+0], %r14				;//[%sp+0] :=                                              pInf
		ld.w		%r15, 0					;//%r15    :=                                0/*iBitPos*/
		ld.w		%r14, 0					;//%r14    :=                 NULL/*dummy*/
		xcall		PrpTbl_op_v				;//PrpTbl_op_v(pPrpKey, iTbl, NULL/*dummy*/, 0/*iBitPos*/, pInf, aName, 0/*inf*/)
		xadd		%sp, %sp, 12
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpTbl_inf_f(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpTbl_inf_g(pPrpKey, iTbl, pInf, sFmt, ap);
	va_end(ap);
}
void PrpTbl_inf_g(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpTbl_inf_p(pPrpKey, iTbl, pInf, sPath);
}
void PrpTbl_inf_p(const void* pPrpKey, int iTbl, ST_PrpInf* pInf, const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	PrpTbl_inf_v(pPrpKey, iTbl, pInf, aName);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpTbl_fmt_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), ...) {
	va_list ap;
	va_start(ap, fnVarFmt);
	PrpTbl_fmt_a(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, fnVarFmt, ap);
	va_end(ap);
}
void PrpTbl_fmt_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpTbl_fmt_v(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, fnVarFmt, aName);
}
#else //PIECE
void PrpTbl_fmt_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), ...);
void PrpTbl_fmt_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), va_list ap);
asm("
		.code
		.align		1
		.global		PrpTbl_fmt_l
		.global		PrpTbl_fmt_a
PrpTbl_fmt_l:
		xsub		%sp, %sp, 16
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+16] := retp
		;//[%sp+20] := buf
		;//[%sp+24] := cap
		;//[%sp+28] := fnVarFmt
		;//[%sp+32] := ...
		xadd		%r9, %sp, 32				;//%r9      :=                                                       ap = &...
		xld.w		[%sp+12], %r9				;//[%sp+12] :=                                                       ap
		xld.w		%r9, [%sp+28]				;//%r9      :=                                             fnVarFmt
		xld.w		[%sp+8], %r9				;//[%sp+8]  :=                                             fnVarFmt
		xld.w		%r9, [%sp+24]				;//%r9      :=                                        cap
		xld.w		[%sp+4], %r9				;//[%sp+4]  :=                                        cap
		xld.w		%r9, [%sp+20]				;//%r9      :=                                   buf
		xld.w		[%sp+0], %r9				;//[%sp+0]  :=                                   buf
		call		PrpTbl_fmt_a				;//PrpTbl_fmt_a(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, fnVarFmt, ap)
		xadd		%sp, %sp, 16
		ret
PrpTbl_fmt_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := buf
		;//[%sp+ 8] := cap
		;//[%sp+12] := fnVarFmt
		;//[%sp+16] := ap
		xjp		PrpTbl_fmt_v
");
#endif//PIECE
void PrpTbl_fmt_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	int iVal = PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
	ST_PrpInf stPrpInf;
	PrpTbl_inf_v(pPrpKey, iTbl, &stPrpInf, aName);
	//<"書式文字列">と<書式番号>の同時指定は不可としました。
	//│2016/1/1以前は同時指定も可能だったのですが、変数フォーマッタに書式文字列と書式番号を渡しても、実質、書式文字列の使い道が無く無駄でした。
	//│変数フォーマッタの仕様を単純にするために、<"書式文字列">と<書式番号>の同時指定は不可とする事にしました。
	if(stPrpInf.pFmt && (stPrpInf.iFmt != -1)) { DIE(); }	//<"書式文字列">と<書式番号>の同時指定は不可。もしここで止まったらdPrpTblC.exeのバグです。
	//書式指定=<"書式文字列">ならば…
	if(stPrpInf.pFmt) {
		snprintf(buf, cap, stPrpInf.pFmt, iVal);
	//書式指定=<書式番号>,かつ,変数フォーマッタ指定有りならば…
	} else if((stPrpInf.iFmt != -1) && fnVarFmt) {
		(*fnVarFmt)(buf, cap, stPrpInf.iFmt, iVal);
	//書式指定=<書式番号>,かつ,変数フォーマッタ指定無し、又は、書式指定無しならば…
	} else {
		snprintf(buf, cap, "%d", iVal);
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpTbl_fmt_f(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpTbl_fmt_g(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, fnVarFmt, sFmt, ap);
	va_end(ap);
}
void PrpTbl_fmt_g(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpTbl_fmt_p(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, fnVarFmt, sPath);
}
void PrpTbl_fmt_p(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	PrpTbl_fmt_v(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, fnVarFmt, aName);
}
/*--------------------------------------------------------------------------*/
#ifdef  USE_PRP_DOUBLE
#ifndef PIECE
void PrpTbl_fset_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, double dNewVal, ...) {
	va_list ap;
	va_start(ap, dNewVal);
	PrpTbl_fset_a(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, ap);
	va_end(ap);
}
void PrpTbl_fset_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, double dNewVal, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpTbl_fset_v(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, aName);
}
#else //PIECE
void PrpTbl_fset_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, double dNewVal, ...);
void PrpTbl_fset_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, double dNewVal, va_list ap);
asm("
		.code
		.align		1
		.global		PrpTbl_fset_l
		.global		PrpTbl_fset_a
PrpTbl_fset_l:
		xsub		%sp, %sp, 12
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+12] := retp
		;//[%sp+16] := dNewValL
		;//[%sp+20] := dNewValH
		;//[%sp+24] := ...
		xadd		%r9, %sp, 24				;//%r9     :=                                              ap = &...
		xld.w		[%sp+8], %r9				;//[%sp+8] :=                                              ap
		xld.w		%r9, [%sp+20]				;//%r9     :=                                     dNewValH
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                     dNewValH
		xld.w		%r9, [%sp+16]				;//%r9     :=                                     dNewValL
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                     dNewValL
		call		PrpTbl_fset_a				;//PrpTbl_fset_a(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, ap)
		xadd		%sp, %sp, 12
		ret
PrpTbl_fset_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := dNewValL
		;//[%sp+ 8] := dNewValH
		;//[%sp+12] := ap
		xjp		PrpTbl_fset_v
");
#endif//PIECE
void PrpTbl_fset_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, double dNewVal, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	int aName2[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName2[i] = aName[i]) == -1) { break; }
		if(++i >= (ARRAY_SIZE(aName2) - 1)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	aName2[i + 0] =  1;	//下位ワード
	aName2[i + 1] = -1;
	PrpTbl_set_v(pPrpKey, iTbl, pPrpTbl, iBitPos, ((int*)&dNewVal)[0], aName2);
	aName2[i + 0] =  2;	//上位ワード
//不要	aName2[i + 1] = -1;
	PrpTbl_set_v(pPrpKey, iTbl, pPrpTbl, iBitPos, ((int*)&dNewVal)[1], aName2);
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpTbl_fset_f(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, double dNewVal, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpTbl_fset_g(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, sFmt, ap);
	va_end(ap);
}
void PrpTbl_fset_g(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, double dNewVal, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpTbl_fset_p(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, sPath);
}
void PrpTbl_fset_p(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, double dNewVal, const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	PrpTbl_fset_v(pPrpKey, iTbl, pPrpTbl, iBitPos, dNewVal, aName);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
double PrpTbl_fget_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, ...) {
	double dVal;
	va_list ap;
	va_start(ap, iBitPos);
	dVal = PrpTbl_fget_a(pPrpKey, iTbl, pPrpTbl, iBitPos, ap);
	va_end(ap);
	return dVal;
}
double PrpTbl_fget_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return PrpTbl_fget_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
}
#else //PIECE
double PrpTbl_fget_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, ...);
double PrpTbl_fget_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, va_list ap);
asm("
		.code
		.align		1
		.global		PrpTbl_fget_l
		.global		PrpTbl_fget_a
PrpTbl_fget_l:
		xsub		%sp, %sp, 4
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//[%sp+ 4] := retp
		;//[%sp+ 8] := iBitPos
		;//[%sp+12] := ...
		xadd		%r9, %sp, 12				;//%r9     :=                                            ap = &...
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                            ap
		xld.w		%r15, [%sp+8]				;//%r15    :=                                   iBitPos
		call		PrpTbl_fget_a				;//return PrpTbl_fget_a(pPrpKey, iTbl, pPrpTbl, iBitPos, ap)
		xadd		%sp, %sp, 4
		ret
PrpTbl_fget_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := ap
		xjp		PrpTbl_fget_v
");
#endif//PIECE
double PrpTbl_fget_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	int aName2[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	double dVal;
	for(;;) {
		if((aName2[i] = aName[i]) == -1) { break; }
		if(++i >= (ARRAY_SIZE(aName2) - 1)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	aName2[i + 0] =  1;	//下位ワード
	aName2[i + 1] = -1;
	((int*)&dVal)[0] = PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName2);
	aName2[i + 0] =  2;	//上位ワード
//不要	aName2[i + 1] = -1;
	((int*)&dVal)[1] = PrpTbl_get_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName2);
	return dVal;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
double PrpTbl_fget_f(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sFmt, ...) {
	double dVal;
	va_list ap;
	va_start(ap, sFmt);
	dVal = PrpTbl_fget_g(pPrpKey, iTbl, pPrpTbl, iBitPos, sFmt, ap);
	va_end(ap);
	return dVal;
}
double PrpTbl_fget_g(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	return PrpTbl_fget_p(pPrpKey, iTbl, pPrpTbl, iBitPos, sPath);
}
double PrpTbl_fget_p(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	return PrpTbl_fget_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpTbl_ffmt_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, ...) {
	va_list ap;
	va_start(ap, cap);
	PrpTbl_ffmt_a(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, ap);
	va_end(ap);
}
void PrpTbl_ffmt_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpTbl_ffmt_v(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, aName);
}
#else //PIECE
void PrpTbl_ffmt_l(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, ...);
void PrpTbl_ffmt_a(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, va_list ap);
asm("
		.code
		.align		1
		.global		PrpTbl_ffmt_l
		.global		PrpTbl_ffmt_a
PrpTbl_ffmt_l:
		xsub		%sp, %sp, 12
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+12] := retp
		;//[%sp+16] := buf
		;//[%sp+20] := cap
		;//[%sp+24] := ...
		xadd		%r9, %sp, 24				;//%r9     :=                                              ap = &...
		xld.w		[%sp+8], %r9				;//[%sp+8] :=                                              ap
		xld.w		%r9, [%sp+20]				;//%r9     :=                                          cap
		xld.w		[%sp+4], %r9				;//[%sp+4] :=                                          cap
		xld.w		%r9, [%sp+16]				;//%r9     :=                                     buf
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                     buf
		call		PrpTbl_ffmt_a				;//PrpTbl_fset_a(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, ap)
		xadd		%sp, %sp, 12
		ret
PrpTbl_ffmt_a:
		;//%r12     := pPrpKey
		;//%r13     := iTbl
		;//%r14     := pPrpTbl
		;//%r15     := iBitPos
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := buf
		;//[%sp+ 8] := cap
		;//[%sp+12] := ap
		xjp		PrpTbl_ffmt_v
");
#endif//PIECE
void PrpTbl_ffmt_v(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	double dVal = PrpTbl_fget_v(pPrpKey, iTbl, pPrpTbl, iBitPos, aName);
	ST_PrpInf stPrpInf;
	PrpTbl_inf_v(pPrpKey, iTbl, &stPrpInf, aName);
	//組み込み'Double'型の変数に対して設定出来る書式指定は<"書式文字列">のみとした。
	//│そうしないと変数フォーマッタの第5引数をintに出来ず複雑になるからです。
	//│組み込み'Double'型の変数に対して<書式番号>を指定しないで下さい。
	if(stPrpInf.iFmt != -1) { DIE(); }	//組み込み'Double'型の変数に対して<書式番号>の指定は不可。
	//書式指定=<"書式文字列">ならば…
	if(stPrpInf.pFmt) {
		snprintf(buf, cap, stPrpInf.pFmt, dVal);
	//書式指定無しならば…
	} else {
		snprintf(buf, cap, "%g", dVal);
	}
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpTbl_ffmt_f(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpTbl_ffmt_g(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, sFmt, ap);
	va_end(ap);
}
void PrpTbl_ffmt_g(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpTbl_ffmt_p(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, sPath);
}
void PrpTbl_ffmt_p(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, char* buf/*[cap]*/, int cap, const char* sPath) {
	int aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	PrpTbl_path_p(pPrpKey, iTbl, aName, ARRAY_SIZE(aName), sPath);
	PrpTbl_ffmt_v(pPrpKey, iTbl, pPrpTbl, iBitPos, buf, cap, aName);
}
#endif//USE_PRP_DOUBLE
/*--------------------------------------------------------------------------*/
int PrpTbl_path_f(const void* pPrpKey, int iTbl, int* aName/*[iNameCap]*/, int iNameCap, const char* sFmt, ...) {
	int iType;
	va_list ap;
	va_start(ap, sFmt);
	iType = PrpTbl_path_g(pPrpKey, iTbl, aName, iNameCap, sFmt, ap);
	va_end(ap);
	return iType;
}
int PrpTbl_path_g(const void* pPrpKey, int iTbl, int* aName/*[iNameCap]*/, int iNameCap, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	return PrpTbl_path_p(pPrpKey, iTbl, aName, iNameCap, sPath);
}
#ifndef USE_PRPTBL_PATH_P_NEWVER
static int PrpTbl_path_p_subr(const void* pPrpKey, int iTbl, int* aName/*[iNameCap]*/, int iNameCap, const char* sPath) {
//{{2017/03/12追加:PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
	if(*sPath) {
//}}2017/03/12追加:PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
		int iType = PrpTbl_list(pPrpKey, iTbl, PrpTbl_path_callback, aName, iNameCap, NULL, 0, (void*)sPath);
		if(!iType) { DIE(); }	//指定されたパス名(sPath)に一致する変数が見つからなかった。
		return iType;	//テーブル型(0x7FFF以下),又は,タイプ型(0x8000以上),又は,'var'型(-1)
//{{2017/03/12追加:PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
	} else {
		if(--iNameCap < 0) { DIE(); }	//配列の容量が不足ならばエラー停止する。
		*aName++ = -1;			//配列の終端を格納して空の名前配列とする。
		return iTbl;			//テーブル名として引数iTblをそのまま返す。
	}
//}}2017/03/12追加:PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
}
int PrpTbl_path_p(const void* pPrpKey, int iTbl, int* aName/*[iNameCap]*/, int iNameCap, const char* sPath) {
	int iType;
#if     defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
// * Thu Dec 10 21:13:28 JST 2015 Naoyuki Sawa
// - Windows環境で、PrpTbl_path_p()を高速化しました。
// - Windows環境ではメモリが潤沢に使えるので、一度解決したパスはキャッシュする事にしました。
//   Windows環境で、ght_hash_table.h をインクルードしている場合のみ、このブロックが有効になります。
//   プロパティテーブルの大きさにもよりますが、キャッシュヒットすると数百倍の高速化が期待出来ます。
// - 本当は、元々高速なWindows環境よりも、P/ECE環境こそ高速化すべきなのですが、
//   P/ECE環境では実行速度よりもメモリの方が重要なので、P/ECE環境ではこのブロックを有効にしない事にしました。
//   元々、PrpTbl_path_p(),及び,PrpTbl_path_p()を呼び出す関数は、速度が重要なケースでは使用しないと思います。
	struct { const void* pPrpKey; int iTbl; } key = { pPrpKey, iTbl };
	static ght_hash_table_t* p_ht1;
	       ght_hash_table_t* p_ht2;
	if(!p_ht1) { ght_set_rehash((p_ht1 = ght_create(0)), 1); }
	if(!(p_ht2 = ght_get(p_ht1, sizeof key, &key))) {
		ght_set_rehash((p_ht2 = ght_create(0)), 1);
		if(ght_insert(p_ht1, p_ht2, sizeof key, &key)) { DIE(); }	//バグ
	}{
		int iName, *entry;
		if((entry = ght_get(p_ht2, strlen(sPath) + 1/*nul*/, sPath))) {
			do {
				if(--iNameCap < 0) { DIE(); }
				iName = *aName++ = *entry++;
			} while(iName != -1);
			return *entry;	//iType
		}
	}{
#endif//defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
	iType = PrpTbl_path_p_subr(pPrpKey, iTbl, aName, iNameCap, sPath);
#if     defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
// * Thu Dec 10 21:13:28 JST 2015 Naoyuki Sawa
// - Windows環境で、PrpTbl_path_p()を高速化しました。
//   詳細は、上のブロックのコメントを参照して下さい。
	}{
		int iNameLen = 0, *entry;
		while(aName[iNameLen++] != -1) { /** no job **/ }
		if(!(entry = malloc(sizeof(int) * (iNameLen/*aName*/ + 1/*iType*/)))) { DIE(); }	//メモリ不足
		memcpy(entry, aName, sizeof(int) * iNameLen/*aName*/);
		entry[iNameLen] = iType;
		if(ght_insert(p_ht2, entry, strlen(sPath) + 1/*nul*/, sPath)) { DIE(); }	//バグ
	}
#endif//defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
	return iType;	//テーブル型(0x7FFF以下),又は,タイプ型(0x8000以上),又は,'var'型(-1)
}
#else //USE_PRPTBL_PATH_P_NEWVER
static int PrpTbl_path_p_subr(const void* pPrpKey, int iTbl, int* aName/*[iNameCap]*/, int iNameCap, const char* sPath) {
	int iType = iTbl;
//{{2017/03/12追加:PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
	if(*sPath) {
//}}2017/03/12追加:PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
		for(;;) {
			char buf[16];	//"%d"を格納出来る充分な容量
			const void *pTblKey, *pVarKey;
			int len, i, c, iName;
#ifdef  _DEBUG
			const uint16_t* pDim;	//┬当関数においてレジストリから配列データを取得するのはエラー検査のためだけである。
			int nDim;		//┘結果には影響無いので、リリースビルドでは配列データを取得しない事にした。
#endif//_DEBUG
			pTblKey = REG_open_key(pPrpKey, iType);	//テーブルキーを取得する。
			if(!pTblKey) { DIE(); }			//テーブルキーが無ければエラー停止する。
			len = strcspn(sPath, ".[");		//パス名の文字列から、次の変数名の文字列の長さを取得する。
			if(!len) { DIE(); }			//変数名の文字列が無ければエラー停止する。
			for(i = 0;				//現在のテーブルの全ての変数キーについて…
			   (pVarKey = REG_open_nth_key(pTblKey, i, &iName)) != NULL;
			    i++) {
				const char* pName = REG_get_string(pVarKey, Prp_name);	//変数名の文字列を取得する。
				if(!pName) {		//変数名の文字列が格納されていなければ、数値を変数名とする。
					sprintf(buf, "%d", iName);
					pName = buf;
				}
				if(!strncmp(pName, sPath, len) && !pName[len]) { break; }	//変数名の文字列が一致したら抜ける。
			}
			if(!pVarKey) { DIE(); }				//変数名の文字列が一致する変数キーが無ければエラー停止する。
			iType = REG_get_value(pVarKey, Prp_type);	//タイプ名,又は,テーブル名を取得する。
			if(--iNameCap < 0) { DIE(); }			//配列の容量が不足ならばエラー停止する。
			*aName++ = iName;				//変数名の数値を格納する。
#ifdef  _DEBUG
			pDim = REG_get_blob(pVarKey, Prp_dim);		//配列データを取得する。	配列変数でなければ(pDim=NULL)になる。
			nDim = REG_get_blob_size(pDim/*NULL可*/);	//┬次元数を取得する。		配列変数でなければ(nDim=0)になる。
			if(nDim & 1) { DIE(); }				//│(要素数-1)は1個2バイトなので配列データのバイト数が奇数にはなり得ない。もしそうなったらデータエラーです。
			nDim >>= 1;					//┘配列データのバイト数⇒次元数に変換する。
#endif//_DEBUG
			sPath += len;					//パス名の文字列を、この変数名の文字列の分進める。
			c = *sPath++;					//変数名の文字列の次の文字を取得して、次へ進める。
			if(c == '[') {					//配列指定ならば…
				for(;;) {
					char *endptr;
					if(!isdigit(*sPath)) { DIE(); }	//'[',又は,','の直後の文字が数字でなければエラー。
					i = strtoul(sPath, &endptr, 0);	//インデクスを取得する。
#ifdef  _DEBUG
					if(--nDim < 0) { DIE(); }	//次元数がオーバーしたらエラー停止する。	スカラー変数に対して配列指定が行われた場合もここで停止する。
					if(i > *pDim++) { DIE(); }	//インデクスが範囲外ならばエラー停止する。	配列データの値は(要素数-1),即ちインデクスの最大値であるから、インデクスがエラーとなる条件は'>='ではなく'>'である事に注意せよ。
#endif//_DEBUG
					if(--iNameCap < 0) { DIE(); }	//配列の容量が不足ならばエラー停止する。
					*aName++ = i;			//インデクスを格納する。
					sPath = endptr;			//インデクスを読み飛ばす。
					c = *sPath++;			//インデクスの終端文字を取得して、次へ進める。
					if(c == ']') { break; }		//インデクスの終端文字が']'だったならば、ループを抜ける。
					if(c != ',') { DIE(); }		//インデクスの終端文字が','だったならば、次のシーケンスに対してインデクスアクセスを継続する。']'でも','でもなかったらエラー。
				}
#ifdef  _DEBUG
				if(nDim) { DIE(); }		//配列変数に対しては、次元を全て指定するか,又は,全て省略するかの、どちらかのみ可。このブロックは次元を指定した場合なので、全て指定されなかったら(=次元が残っていたら)エラー停止する。
#endif//_DEBUG
				c = *sPath++;			//']'の次の文字を取得して、次へ進める。
			}
			if(!c) { break; }			//変数名の文字列の次の文字,又は,']'の次の文字がヌル文字ならば、ループを抜ける。
			if(c != '.') { DIE(); }			//変数名の文字列の次の文字,又は,']'の次の文字が'.'ならば、継続する。ヌル文字でも'.'でもなければ、エラー停止する。
			if((unsigned)iType > 0x7FFF) { DIE(); }	//この変数がテーブル変数(iType<=0x7FFF)でなければ，即ち'var'変数(iType=-1),又は,タイプ変数(iType>=0x8000)ならば、次の階層は無いはずである。従って、継続しようとしたらエラー停止する。
#ifdef  _DEBUG
			if(nDim) { DIE(); }			//配列変数に対して次元を全て省略する事は、パスの末尾でのみ可。配列変数に対して次元を全て省略した後に、継続しようとしたらエラー停止する。
#endif//_DEBUG
		}
//{{2017/03/12追加:PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
	}
//}}2017/03/12追加:PrpTbl_path_p_subr()のsPathに空文字列が指定された場合、空の名前配列と引数iTblをそのまま返すようにしました。
	if(--iNameCap < 0) { DIE(); }	//配列の容量が不足ならばエラー停止する。
	*aName++ = -1;			//配列の終端を格納する。
	return iType;			//タイプ名,又は,テーブル名を返す。
}
#if     defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
typedef struct _ST_PrpTbl_path_p_Key {
	const void*	pPrpKey;	//PrpTbl_path_p()の引数pPrpKey。
	int		iTbl;		//PrpTbl_path_p()の引数iTbl。
	char		sPath[0];	//PrpTbl_path_p()の引数sPathのコピー。(終端のnulも格納する)	終端のnulも格納する理由は、PrpTbl_path_p_FreeEntry()でのデバッグ表示のためです。
} ST_PrpTbl_path_p_Key;
typedef struct _ST_PrpTbl_path_p_Entry {
	int		iType;		//テーブル型(0x7FFF以下),又は,タイプ型(0x8000以上),又は,'var'型(-1)
	int		iNameSize;	//名前の要素数。(終端の(-1)も含む)
	int		aName[0];	//名前の配列。(終端の(-1)も格納する)
} ST_PrpTbl_path_p_Entry;
static void PrpTbl_path_p_FreeEntry(void* data, const void* _key) {
    #ifdef  _DEBUG
//{{デバッグ出力が多過ぎるのでコメントアウトしました。必要に応じて有効に戻して下さい。
//	ST_PrpTbl_path_p_Key* key = (ST_PrpTbl_path_p_Key*)_key;	//キャストはconst警告抑制のため。
//	syslog(LOG_DEBUG, "PrpTbl_path_p_FreeEntry: freeing '%s'", key->sPath);
//}}デバッグ出力が多過ぎるのでコメントアウトしました。必要に応じて有効に戻して下さい。
    #endif//_DEBUG
	free(data);
}
#ifdef  USE_PRPTBL_PATH_STATISTICS
ST_PrpTbl_path_Statistics st_PrpTbl_path_Statistics;	//描画統計情報。アプリケーションから直接参照して下さい。
#endif//USE_PRPTBL_PATH_STATISTICS
#endif//defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
int PrpTbl_path_p(const void* pPrpKey, int iTbl, int* aName/*[iNameCap]*/, int iNameCap, const char* sPath) {
	int iType;
#if     defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
	static ght_hash_table_t* p_ht; /* バケットリミットを設定した小さなキャッシュ、ＳＴＡＴＩＣです！ */
	ST_PrpTbl_path_p_Key* key;
	ST_PrpTbl_path_p_Entry* entry;
	int iPathSize, iNameSize;
	if(!p_ht) { ght_set_bounded_buckets((p_ht = ght_create(17/*調整可*/)), 8/*調整可*/, PrpTbl_path_p_FreeEntry); }	//ハッシュテーブルがまだ作成されていなければ、ハッシュテーブルを作成する。
	iPathSize = strlen(sPath) + 1/*nul*/;						//sPathのサイズを求める。(終端のnulも含む)
	key = alloca(sizeof(ST_PrpTbl_path_p_Key) + iPathSize);				//一時的なキーのメモリを確保する。alloca()を使用しているので、一時的なキーのメモリ開放は不要です。
	key->pPrpKey = pPrpKey;								//┐
	key->iTbl = iTbl;								//├一時的なキーを組み立てる。
	strcpy(key->sPath, sPath);							//┘
	if((entry = ght_get(p_ht, sizeof(ST_PrpTbl_path_p_Key) + iPathSize, key))) {	//キャッシュヒットしたら…
    #ifdef  USE_PRPTBL_PATH_STATISTICS
		st_PrpTbl_path_Statistics.nCacheHit++;					//キャッシュヒット回数を増やす。
    #endif//USE_PRPTBL_PATH_STATISTICS
		if(iNameCap < entry->iNameSize) { DIE(); }				//ここで停止したらaName[]の容量不足です。呼び出し側でaName[]の容量を増やして下さい。
		memcpy(aName, entry->aName, sizeof(int) * entry->iNameSize);		//名前の配列をコピーする。(終端の(-1)も含む)
		return entry->iType;							//iTypeを返す。
	}
    #ifdef  USE_PRPTBL_PATH_STATISTICS
	st_PrpTbl_path_Statistics.nCacheMiss++;						//キャッシュミス回数を増やす。
    #endif//USE_PRPTBL_PATH_STATISTICS
#endif//defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
	iType = PrpTbl_path_p_subr(pPrpKey, iTbl, aName, iNameCap, sPath);
#if     defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
	iNameSize = 0;									//┬aName[]の要素数を数える。(終端の(-1)も含む)
	while(aName[iNameSize++] != -1) { /** no job **/ }				//┘
	entry = malloc(sizeof(ST_PrpTbl_path_p_Entry) + sizeof(int) * iNameSize);	//ハッシュテーブルに登録するエントリのメモリを確保する。
	if(!entry) { DIE(); }								//ここで停止したらメモリ不足です。
	entry->iType = iType;								//┐
	entry->iNameSize = iNameSize;							//├ハッシュテーブルに登録するエントリを組み立てる。
	memcpy(entry->aName, aName, sizeof(int) * iNameSize);				//┘
	if(ght_insert(p_ht, entry, sizeof(ST_PrpTbl_path_p_Key) + iPathSize, key)) { DIE(); }	//ここで停止したら当モジュールのバグです。
#endif//defined(WIN32) && defined(__GHT_HASH_TABLE_H__)
	return iType;	//テーブル型(0x7FFF以下),又は,タイプ型(0x8000以上),又は,'var'型(-1)
}
#endif//USE_PRPTBL_PATH_P_NEWVER
/*--------------------------------------------------------------------------*/
int PrpTbl_list(const void* pPrpKey, int iTbl, int (*callback)(int iType, const int* aName, const char* sPath, void* arg), int* aName/*[iNameCap],NULL可*/, int iNameCap, char* sPath/*[iPathCap],NULL可*/, int iPathCap, void* arg) {
//{{2015/12/11追加:PrpTbl_list()に、(aName=NULL),及び,(sPath=NULL)を指定出来るようにしました。
// * Fri Dec 11 21:38:17 JST 2015 Naoyuki Sawa
// - PrpTbl_list()に、(aName=NULL),及び,(sPath=NULL)を指定出来るようにしました。
//   NULLが指定されたら、関数内の固定サイズのバッファを使います。
// - 上記の変更を行った理由は、利便性のためです。
//   元々、PrpTbl_list()が使うバッファを、アプリケーション側で指定するようにしていた理由は、以下の二つの理由でした。
//   │① コールバックが中断した時に、その時点でのバッファの内容を参照する。PrpTbl_path_p()がこのケースに相当します。
//   │② プロパティツリーの階層の深さが想定できないので、階層の深さに応じた容量のバッファを指定出来るようにするため。
//   ①は必須ですので、PrpTbl_list()のaName,sPath引数指定自体を削除する事は出来ません。
//   しかし、②については、よほど階層が深くない限り、ライブラリ側で用意したバッファを使っても良いと思いました。
//   なぜなら、他の多くの関数で、aName[(15+1)],sPath[256]のような固定サイズのバッファを使用しており、PrpTbl_list()だけ柔軟性を持たせてもあまり効果が無いからです。
//   それよりも、PrpTbl_list()を呼び出す度に、アプリケーション側で(①の用途でなくても)バッファを用意しなければいけない煩わしさを回避したいと思いました。
//   そこで、PrpTbl_list()に、(aName=NULL),及び,(sPath=NULL)を指定出来るようにし、NULLが指定されたら、関数内の固定サイズのバッファを使う事にしました。
// - 今回の変更によって、PrpTbl_list()に(aName=NULL),及び,(sPath=NULL)を指定してもしなくても、常に、PrpTbl_list()のスタック消費量が多くなります。
//   NULLが指定された場合だけmalloc()で確保する方法も検討しましたが、動的メモリ割り当てが使えない環境に対応出来なくなるので、そうしませんでした。
//   万一、今後、PrpTbl_list()のスタック消費量増加が問題になった場合は、再検討して下さい。
	int _aName[(15+1)/*調整可*/];	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	char _sPath[256/*調整可*/];
	if(!aName) { aName = _aName; iNameCap = ARRAY_SIZE(_aName); }	//(aName=NULL)が指定されたら、固定サイズのバッファを使う。これはサービスですが、実質、PrpTbl_list()中断時のバッファ内容を参照する用途以外では、よほど階層が深くない限り常に(aName=NULL)で充分だと思います。
	if(!sPath) { sPath = _sPath; iPathCap = ARRAY_SIZE(_sPath); }	//(sPath=NULL)が指定されたら、固定サイズのバッファを使う。これはサービスですが、実質、PrpTbl_list()中断時のバッファ内容を参照する用途以外では、よほど階層が深くない限り常に(sPath=NULL)で充分だと思います。
//}}2015/12/11追加:PrpTbl_list()に、(aName=NULL),及び,(sPath=NULL)を指定出来るようにしました。
	if((iPathCap <= 0) || (iNameCap <= 0)) { DIE(); }	//多分アプリケーションのバグ
	aName[0] = -1;		//aName[iNameCap]を初期化する。
	sPath[0] = '\0';	//sPath[iPathCap]を初期化する。
	return PrpTbl_list_subr(pPrpKey, iTbl, callback, aName, iNameCap, sPath, iPathCap, arg);
}
/*--------------------------------------------------------------------------*/
#ifdef  USE_PRP_DUMP
void PrpTbl_dump(FILE* fp, const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, void (*fnVarFmt)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), int fOpt/*(PrpDmp_*の0個以上の組み合わせ)*/) {
	ST_PrpDmp stPrpDmp;
	memset(&stPrpDmp, 0, sizeof stPrpDmp);
	stPrpDmp.fp		= fp;
	stPrpDmp.pPrpKey	= pPrpKey;
	stPrpDmp.iTbl		= iTbl;
	stPrpDmp.pPrpTbl	= pPrpTbl;
	stPrpDmp.iBitPos	= iBitPos;
	stPrpDmp.fnVarFmt	= fnVarFmt;
	stPrpDmp.fOpt		= fOpt;
	if(fOpt & PrpDmp_Abs) {	//absolute
		PrpTbl_list(pPrpKey, iTbl, PrpTbl_dump_abs_callback, NULL, 0, NULL, 0, &stPrpDmp);
	} else {
		PrpTbl_list(pPrpKey, iTbl, PrpTbl_dump_maxDepth, NULL, 0, NULL, 0, &stPrpDmp);	//1パス目で最大深度を判断する。
		PrpTbl_list(pPrpKey, iTbl, PrpTbl_dump_callback, NULL, 0, NULL, 0, &stPrpDmp);	//2パス目で表示する。値とコメントの列を最大深度に揃える。
	}
}
#endif//USE_PRP_DUMP
/****************************************************************************
 *	ユーティリティ関数
 ****************************************************************************/
ST_PrpHdr* PrpHdr_new(const void* pPrpKey, int iTbl) {
	ST_PrpHdr* pPrpHdr;
	const void* pTblKey;
	int iBitLen;
	//テーブルキーを取得する。
	pTblKey = REG_open_key(pPrpKey, iTbl);
	if(!pTblKey) { DIE(); }
	//このテープルの(ビット数-1)を取得する。
	iBitLen = REG_get_value(pTblKey, Prp_len);
	if(iBitLen == -1) { DIE(); }
	//(ビット数-1)⇒(ビット数)に補正する。
	iBitLen++;
	//ST_PrpHdrとテーブルのビット配列を確保する。
	pPrpHdr = bitarray_alloc((sizeof(ST_PrpHdr) * 8) + iBitLen);
	if(!pPrpHdr) { DIE(); }
	//ST_PrpHdrとテーブルを初期化する。
	PrpHdr_init(pPrpHdr, pPrpKey, iTbl);
	return pPrpHdr;
}
void PrpHdr_init(ST_PrpHdr* pPrpHdr, const void* pPrpKey, int iTbl) {
	//プロパティテーブルキーとテーブル名を格納する。
	pPrpHdr->pPrpKey	= pPrpKey;
	pPrpHdr->iTbl		= iTbl;
	//テーブルを初期化する。
	PrpTbl_init(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8);
}
//{{2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
//void PrpHdr_init_attr(ST_PrpHdr* pPrpHdr, int iAttr) {
//	PrpTbl_init_attr(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, iAttr);
//}
//↓2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
#ifndef PIECE
void PrpHdr_init_attr_l(ST_PrpHdr* pPrpHdr, ...) {
	va_list ap;
	va_start(ap, pPrpHdr);
	PrpHdr_init_attr_a(pPrpHdr, ap);
	va_end(ap);
}
void PrpHdr_init_attr_a(ST_PrpHdr* pPrpHdr, va_list ap) {
	int aAttr[(14+2)/*調整可*/], i = 0, j = 0;	//実用上、必須属性リストと拒否属性リストが14以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aAttr[i] = va_arg(ap, int)) == -1) { if(++j == 2/*必須属性リスト,拒否属性リスト*/) { break; } }
		if(++i >= ARRAY_SIZE(aAttr)) { DIE(); }	//ここで停止した場合は、aAttr[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpHdr_init_attr_v(pPrpHdr, aAttr);
}
void PrpHdr_init_attr_v(ST_PrpHdr* pPrpHdr, const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/) {
	PrpTbl_init_attr_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, aAttr);
}
#else //PIECE
void PrpHdr_init_attr_l(ST_PrpHdr* pPrpHdr, ...);
void PrpHdr_init_attr_a(ST_PrpHdr* pPrpHdr, va_list ap);
void PrpHdr_init_attr_v(ST_PrpHdr* pPrpHdr, const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_init_attr_l
		.global		PrpHdr_init_attr_a
		.global		PrpHdr_init_attr_v
PrpHdr_init_attr_l:
		;//[%sp+0] := retp
		;//[%sp+4] := pPrpHdr
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12    := pPrpHdr
		xadd		%r13, %sp, 8				;//%r13    := ap = &...
PrpHdr_init_attr_a:
		;//%r12    := pPrpHdr
		;//%r13    := ap
PrpHdr_init_attr_v:
		xsub		%sp, %sp, 4
		;//%r12    := pPrpHdr
		;//%r13    := aAttr
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                          aAttr
		xld.w		%r15, 64				;//%r15    :=                                                   sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                          pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                           pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=         pPrpHdr->pPrpKey
		xcall		PrpTbl_init_attr_v			;//PrpTbl_init_attr_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, aAttr)
		xadd		%sp, %sp, 4
		ret
");
#endif//PIECE
//}}2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
//{{2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
//void PrpHdr_copy_attr(ST_PrpHdr* pPrpHdrDst, ST_PrpHdr* pPrpHdrSrc, int iAttr) {
//	if((pPrpHdrDst->pPrpKey != pPrpHdrSrc->pPrpKey) ||
//	   (pPrpHdrDst->iTbl    != pPrpHdrSrc->iTbl   )) { DIE(); }	//コピー先とコピー元は同じ型のプロパティテーブルでなければならない。
//	PrpTbl_copy_attr(pPrpHdrDst->pPrpKey, pPrpHdrDst->iTbl, pPrpHdrDst, sizeof(ST_PrpHdr) * 8,
//	                                                        pPrpHdrSrc, sizeof(ST_PrpHdr) * 8, iAttr);
//}
//↓2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
#ifndef PIECE
void PrpHdr_copy_attr_l(ST_PrpHdr* pPrpHdrDst, ST_PrpHdr* pPrpHdrSrc, ...) {
	va_list ap;
	va_start(ap, pPrpHdrSrc);
	PrpHdr_copy_attr_a(pPrpHdrDst, pPrpHdrSrc, ap);
	va_end(ap);
}
void PrpHdr_copy_attr_a(ST_PrpHdr* pPrpHdrDst, ST_PrpHdr* pPrpHdrSrc, va_list ap) {
	int aAttr[(14+2)/*調整可*/], i = 0, j = 0;	//実用上、必須属性リストと拒否属性リストが14以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aAttr[i] = va_arg(ap, int)) == -1) { if(++j == 2/*必須属性リスト,拒否属性リスト*/) { break; } }
		if(++i >= ARRAY_SIZE(aAttr)) { DIE(); }	//ここで停止した場合は、aAttr[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpHdr_copy_attr_v(pPrpHdrDst, pPrpHdrSrc, aAttr);
}
void PrpHdr_copy_attr_v(ST_PrpHdr* pPrpHdrDst, ST_PrpHdr* pPrpHdrSrc, const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/) {
	if((pPrpHdrDst->pPrpKey != pPrpHdrSrc->pPrpKey) ||
	   (pPrpHdrDst->iTbl    != pPrpHdrSrc->iTbl   )) { DIE(); }	//コピー先とコピー元は同じ型のプロパティテーブルでなければならない。
	PrpTbl_copy_attr_v(pPrpHdrDst->pPrpKey, pPrpHdrDst->iTbl, pPrpHdrDst, sizeof(ST_PrpHdr) * 8,
	                                                          pPrpHdrSrc, sizeof(ST_PrpHdr) * 8, aAttr);
}
#else //PIECE
void PrpHdr_copy_attr_l(ST_PrpHdr* pPrpHdrDst, ST_PrpHdr* pPrpHdrSrc, ...);
void PrpHdr_copy_attr_a(ST_PrpHdr* pPrpHdrDst, ST_PrpHdr* pPrpHdrSrc, va_list ap);
void PrpHdr_copy_attr_v(ST_PrpHdr* pPrpHdrDst, ST_PrpHdr* pPrpHdrSrc, const int* aAttr/*[inclAttr,...,]-1,[exclAttr,...,]-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_copy_attr_l
		.global		PrpHdr_copy_attr_a
		.global		PrpHdr_copy_attr_v
PrpHdr_copy_attr_l:
		;//%r12    := pPrpHdrDst
		;//[%sp+0] := retp
		;//[%sp+4] := pPrpHdrSrc
		;//[%sp+8] := ...
		xld.w		%r13, [%sp+4]				;//%r13    := pPrpHdrSrc
		xadd		%r14, %sp, 8				;//%r14    := ap = &...
PrpHdr_copy_attr_a:
		;//%r12    := pPrpHdrDst
		;//%r13    := pPrpHdrSrc
		;//%r14    := ap
PrpHdr_copy_attr_v:
		xsub		%sp, %sp, 12
		;//%r12    := pPrpHdrDst
		;//%r13    := pPrpHdrSrc
		;//%r14    := aAttr
		xld.w		[%sp+8], %r14				;//[%sp+8] :=                                                                                                                      aAttr
		xld.w		%r15, 64				;//%r15    :=                                                            sizeof(ST_PrpHdr) * 8
		xld.w		[%sp+4], %r15				;//[%sp+4] :=                                                                                               sizeof(ST_PrpHdr) * 8
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                                   pPrpHdrSrc
		ld.w		%r14, %r12				;//%r14    :=                                                pPrpHdrDst
		xld.w		%r13, [%r12+4]				;//%r13    :=                              pPrpHdrDst->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=         pPrpHdrDst->pPrpKey
		xcall		PrpTbl_copy_attr_v			;//PrpTbl_copy_attr_v(pPrpHdrDst->pPrpKey, pPrpHdrDst->iTbl, pPrpHdrDst, sizeof(ST_PrpHdr) * 8, pPrpHdrSrc, sizeof(ST_PrpHdr) * 8, aAttr)
		xadd		%sp, %sp, 12
		ret
");
#endif//PIECE
//}}2015/12/24変更:PrpTbl_init_attr(),PrpTbl_copy_attr(),PrpHdr_init_attr(),PrpHdr_copy_attr()を変更し、必須属性リストと拒否属性リストを指定出来るようにしました。
void PrpHdr_free(ST_PrpHdr* pPrpHdr) {
	free(pPrpHdr);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpHdr_init_l(ST_PrpHdr* pPrpHdr, ...) {
	va_list ap;
	va_start(ap, pPrpHdr);
	PrpHdr_init_a(pPrpHdr, ap);
	va_end(ap);
}
void PrpHdr_init_a(ST_PrpHdr* pPrpHdr, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpHdr_init_v(pPrpHdr, aName);
}
void PrpHdr_init_v(ST_PrpHdr* pPrpHdr, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	PrpTbl_init_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, aName);
}
#else //PIECE
void PrpHdr_init_l(ST_PrpHdr* pPrpHdr, ...);
void PrpHdr_init_a(ST_PrpHdr* pPrpHdr, va_list ap);
void PrpHdr_init_v(ST_PrpHdr* pPrpHdr, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_init_l
		.global		PrpHdr_init_a
		.global		PrpHdr_init_v
PrpHdr_init_l:
		;//[%sp+0] := retp
		;//[%sp+4] := pPrpHdr
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12    := pPrpHdr
		xadd		%r13, %sp, 8				;//%r13    := ap = &...
PrpHdr_init_a:
		;//%r12    := pPrpHdr
		;//%r13    := ap
PrpHdr_init_v:
		xsub		%sp, %sp, 4
		;//%r12    := pPrpHdr
		;//%r13    := aName
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                     aName
		xld.w		%r15, 64				;//%r15    :=                                              sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                     pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                      pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=    pPrpHdr->pPrpKey
		xcall		PrpTbl_init_v				;//PrpTbl_init_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, aName)
		xadd		%sp, %sp, 4
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpHdr_init_f(ST_PrpHdr* pPrpHdr, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpHdr_init_g(pPrpHdr, sFmt, ap);
	va_end(ap);
}
void PrpHdr_init_g(ST_PrpHdr* pPrpHdr, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpHdr_init_p(pPrpHdr, sPath);
}
void PrpHdr_init_p(ST_PrpHdr* pPrpHdr, const char* sPath) {
	PrpTbl_init_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, sPath);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpHdr_set_l(ST_PrpHdr* pPrpHdr, int iNewVal, ...) {
	va_list ap;
	va_start(ap, iNewVal);
	PrpHdr_set_a(pPrpHdr, iNewVal, ap);
	va_end(ap);
}
void PrpHdr_set_a(ST_PrpHdr* pPrpHdr, int iNewVal, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpHdr_set_v(pPrpHdr, iNewVal, aName);
}
void PrpHdr_set_v(ST_PrpHdr* pPrpHdr, int iNewVal, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	PrpTbl_set_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, iNewVal, aName);
}
#else //PIECE
void PrpHdr_set_l(ST_PrpHdr* pPrpHdr, int iNewVal, ...);
void PrpHdr_set_a(ST_PrpHdr* pPrpHdr, int iNewVal, va_list ap);
void PrpHdr_set_v(ST_PrpHdr* pPrpHdr, int iNewVal, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_set_l
		.global		PrpHdr_set_a
		.global		PrpHdr_set_v
PrpHdr_set_l:
		;//%r12    := pPrpHdr
		;//[%sp+0] := retp
		;//[%sp+4] := iNewVal
		;//[%sp+8] := ...
		xld.w		%r13, [%sp+4]				;//%r13    := iNewVal
		xadd		%r14, %sp, 8				;//%r14    := ap = &...
PrpHdr_set_a:
		;//%r12    := pPrpHdr
		;//%r13    := iNewVal
		;//%r14    := ap
PrpHdr_set_v:
		xsub		%sp, %sp, 8
		;//%r12    := pPrpHdr
		;//%r13    := iNewVal
		;//%r14    := aName
		xld.w		[%sp+4], %r14				;//[%sp+4] :=                                                                             aName
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                    iNewVal
		xld.w		%r15, 64				;//%r15    :=                                             sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                    pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                     pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=   pPrpHdr->pPrpKey
		xcall		PrpTbl_set_v				;//PrpTbl_set_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, iNewVal, aName)
		xadd		%sp, %sp, 8
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpHdr_set_f(ST_PrpHdr* pPrpHdr, int iNewVal, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpHdr_set_g(pPrpHdr, iNewVal, sFmt, ap);
	va_end(ap);
}
void PrpHdr_set_g(ST_PrpHdr* pPrpHdr, int iNewVal, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpHdr_set_p(pPrpHdr, iNewVal, sPath);
}
void PrpHdr_set_p(ST_PrpHdr* pPrpHdr, int iNewVal, const char* sPath) {
	PrpTbl_set_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, iNewVal, sPath);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
int PrpHdr_get_l(ST_PrpHdr* pPrpHdr, ...) {
	int iVal;
	va_list ap;
	va_start(ap, pPrpHdr);
	iVal = PrpHdr_get_a(pPrpHdr, ap);
	va_end(ap);
	return iVal;
}
int PrpHdr_get_a(ST_PrpHdr* pPrpHdr, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return PrpHdr_get_v(pPrpHdr, aName);
}
int PrpHdr_get_v(ST_PrpHdr* pPrpHdr, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	return PrpTbl_get_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, aName);
}
#else //PIECE
int PrpHdr_get_l(ST_PrpHdr* pPrpHdr, ...);
int PrpHdr_get_a(ST_PrpHdr* pPrpHdr, va_list ap);
int PrpHdr_get_v(ST_PrpHdr* pPrpHdr, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_get_l
		.global		PrpHdr_get_a
		.global		PrpHdr_get_v
PrpHdr_get_l:
		;//[%sp+0] := retp
		;//[%sp+4] := pPrpHdr
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12    := pPrpHdr
		xadd		%r13, %sp, 8				;//%r13    := ap = &...
PrpHdr_get_a:
		;//%r12    := pPrpHdr
		;//%r13    := ap
PrpHdr_get_v:
		xsub		%sp, %sp, 4
		;//%r12    := pPrpHdr
		;//%r13    := aName
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                           aName
		xld.w		%r15, 64				;//%r15    :=                                                    sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                           pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                            pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=          pPrpHdr->pPrpKey
		xcall		PrpTbl_get_v				;//return PrpTbl_get_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, aName)
		xadd		%sp, %sp, 4
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int PrpHdr_get_f(ST_PrpHdr* pPrpHdr, const char* sFmt, ...) {
	int iVal;
	va_list ap;
	va_start(ap, sFmt);
	iVal = PrpHdr_get_g(pPrpHdr, sFmt, ap);
	va_end(ap);
	return iVal;
}
int PrpHdr_get_g(ST_PrpHdr* pPrpHdr, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	return PrpHdr_get_p(pPrpHdr, sPath);
}
int PrpHdr_get_p(ST_PrpHdr* pPrpHdr, const char* sPath) {
	return PrpTbl_get_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, sPath);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
int PrpHdr_acc_l(ST_PrpHdr* pPrpHdr, int iAcc, ...) {
	int iVal;
	va_list ap;
	va_start(ap, iAcc);
	iVal = PrpHdr_acc_a(pPrpHdr, iAcc, ap);
	va_end(ap);
	return iVal;
}
int PrpHdr_acc_a(ST_PrpHdr* pPrpHdr, int iAcc, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return PrpHdr_acc_v(pPrpHdr, iAcc, aName);
}
int PrpHdr_acc_v(ST_PrpHdr* pPrpHdr, int iAcc, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	return PrpTbl_acc_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, iAcc, aName);
}
#else //PIECE
int PrpHdr_acc_l(ST_PrpHdr* pPrpHdr, int iAcc, ...);
int PrpHdr_acc_a(ST_PrpHdr* pPrpHdr, int iAcc, va_list ap);
int PrpHdr_acc_v(ST_PrpHdr* pPrpHdr, int iAcc, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_acc_l
		.global		PrpHdr_acc_a
		.global		PrpHdr_acc_v
PrpHdr_acc_l:
		;//%r12    := pPrpHdr
		;//[%sp+0] := retp
		;//[%sp+4] := iAcc
		;//[%sp+8] := ...
		xld.w		%r13, [%sp+4]				;//%r13    := iAcc
		xadd		%r14, %sp, 8				;//%r14    := ap = &...
PrpHdr_acc_a:
		;//%r12    := pPrpHdr
		;//%r13    := iAcc
		;//%r14    := ap
PrpHdr_acc_v:
		xsub		%sp, %sp, 8
		;//%r12    := pPrpHdr
		;//%r13    := iAcc
		;//%r14    := aName
		xld.w		[%sp+4], %r14				;//[%sp+4] :=                                                                                 aName
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                           iAcc
		xld.w		%r15, 64				;//%r15    :=                                                    sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                           pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                            pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=          pPrpHdr->pPrpKey
		xcall		PrpTbl_acc_v				;//return PrpTbl_acc_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, iAcc, aName)
		xadd		%sp, %sp, 8
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
int PrpHdr_acc_f(ST_PrpHdr* pPrpHdr, int iAcc, const char* sFmt, ...) {
	int iVal;
	va_list ap;
	va_start(ap, sFmt);
	iVal = PrpHdr_acc_g(pPrpHdr, iAcc, sFmt, ap);
	va_end(ap);
	return iVal;
}
int PrpHdr_acc_g(ST_PrpHdr* pPrpHdr, int iAcc, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	return PrpHdr_acc_p(pPrpHdr, iAcc, sPath);
}
int PrpHdr_acc_p(ST_PrpHdr* pPrpHdr, int iAcc, const char* sPath) {
	return PrpTbl_acc_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, iAcc, sPath);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpHdr_inf_l(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, ...) {
	va_list ap;
	va_start(ap, pInf);
	PrpHdr_inf_a(pPrpHdr, pInf, ap);
	va_end(ap);
}
void PrpHdr_inf_a(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpHdr_inf_v(pPrpHdr, pInf, aName);
}
void PrpHdr_inf_v(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	PrpTbl_inf_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pInf, aName);
}
#else //PIECE
void PrpHdr_inf_l(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, ...);
void PrpHdr_inf_a(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, va_list ap);
void PrpHdr_inf_v(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_inf_l
		.global		PrpHdr_inf_a
		.global		PrpHdr_inf_v
PrpHdr_inf_l:
		;//%r12    := pPrpHdr
		;//[%sp+0] := retp
		;//[%sp+4] := pInf
		;//[%sp+8] := ...
		xld.w		%r13, [%sp+4]				;//%r13    := pInf
		xadd		%r14, %sp, 8				;//%r14    := ap = &...
PrpHdr_inf_a:
		;//%r12    := pPrpHdr
		;//%r13    := pInf
		;//%r14    := ap
PrpHdr_inf_v:
		;//%r12    := pPrpHdr
		;//%r13    := pInf
		;//%r14    := aName
		ld.w		%r15, %r14				;//%r15 :=                                             aName
		ld.w		%r14, %r13				;//%r14 :=                                       pInf
		xld.w		%r13, [%r12+4]				;//%r13 :=                        pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12 :=      pPrpHdr->pPrpKey
		xjp		PrpTbl_inf_v				;//PrpTbl_inf_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pInf, aName)
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpHdr_inf_f(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpHdr_inf_g(pPrpHdr, pInf, sFmt, ap);
	va_end(ap);
}
void PrpHdr_inf_g(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpHdr_inf_p(pPrpHdr, pInf, sPath);
}
void PrpHdr_inf_p(ST_PrpHdr* pPrpHdr, ST_PrpInf* pInf, const char* sPath) {
	PrpTbl_inf_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pInf, sPath);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpHdr_fmt_l(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), ...) {
	va_list ap;
	va_start(ap, fnVarFmt);
	PrpHdr_fmt_a(pPrpHdr, buf, cap, fnVarFmt, ap);
	va_end(ap);
}
void PrpHdr_fmt_a(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpHdr_fmt_v(pPrpHdr, buf, cap, fnVarFmt, aName);
}
void PrpHdr_fmt_v(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	PrpTbl_fmt_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, buf, cap, fnVarFmt, aName);
}
#else //PIECE
void PrpHdr_fmt_l(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), ...);
void PrpHdr_fmt_a(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), va_list ap);
void PrpHdr_fmt_v(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_fmt_l
		.global		PrpHdr_fmt_a
		.global		PrpHdr_fmt_v
PrpHdr_fmt_l:
		xsub		%sp, %sp, 4
		;//%r12     := pPrpHdr
		;//%r13     := buf
		;//%r14     := cap
		;//[%sp+ 4] := retp
		;//[%sp+ 8] := fnVarFmt
		;//[%sp+12] := ...
		xadd		%r9, %sp, 12				;//%r9     :=                                ap = &...
		xld.w		[%sp+0], %r9				;//[%sp+0] :=                                ap
		xld.w		%r15, [%sp+8]				;//%r15    :=                      fnVarFmt
		call		PrpHdr_fmt_a				;//PrpHdr_fmt_a(pPrpHdr, buf, cap, fnVarFmt, ap)
		xadd		%sp, %sp, 4
		ret
PrpHdr_fmt_a:
		;//%r12     := pPrpHdr
		;//%r13     := buf
		;//%r14     := cap
		;//%r15     := fnVarFmt
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := ap
PrpHdr_fmt_v:
		xsub		%sp, %sp, 16
		;//%r12     := pPrpHdr
		;//%r13     := buf
		;//%r14     := cap
		;//%r15     := fnVarFmt
		;//[%sp+16] := retp
		;//[%sp+20] := aName
		xld.w		%r9, [%sp+20]				;//%r9     :=                                                                                        aName
		xld.w		[%sp+12], %r9				;//%r9     :=                                                                                        aName
		xld.w		[%sp+8], %r15				;//%r9     :=                                                                              fnVarFmt
		xld.w		[%sp+4], %r14				;//%r9     :=                                                                         cap
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                    buf
		xld.w		%r15, 64				;//%r15    :=                                             sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                    pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                     pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=   pPrpHdr->pPrpKey
		xcall		PrpTbl_fmt_v				;//PrpTbl_fmt_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, buf, cap, fnVarFmt, aName)
		xadd		%sp, %sp, 16
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpHdr_fmt_f(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpHdr_fmt_g(pPrpHdr, buf, cap, fnVarFmt, sFmt, ap);
	va_end(ap);
}
void PrpHdr_fmt_g(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpHdr_fmt_p(pPrpHdr, buf, cap, fnVarFmt, sPath);
}
void PrpHdr_fmt_p(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), const char* sPath) {
	PrpTbl_fmt_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, buf, cap, fnVarFmt, sPath);
}
/*--------------------------------------------------------------------------*/
#ifdef  USE_PRP_DOUBLE
#ifndef PIECE
void PrpHdr_fset_l(ST_PrpHdr* pPrpHdr, double dNewVal, ...) {
	va_list ap;
	va_start(ap, dNewVal);
	PrpHdr_fset_a(pPrpHdr, dNewVal, ap);
	va_end(ap);
}
void PrpHdr_fset_a(ST_PrpHdr* pPrpHdr, double dNewVal, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpHdr_fset_v(pPrpHdr, dNewVal, aName);
}
void PrpHdr_fset_v(ST_PrpHdr* pPrpHdr, double dNewVal, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	PrpTbl_fset_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, dNewVal, aName);
}
#else //PIECE
void PrpHdr_fset_l(ST_PrpHdr* pPrpHdr, double dNewVal, ...);
void PrpHdr_fset_a(ST_PrpHdr* pPrpHdr, double dNewVal, va_list ap);
void PrpHdr_fset_v(ST_PrpHdr* pPrpHdr, double dNewVal, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_fset_l
		.global		PrpHdr_fset_a
		.global		PrpHdr_fset_v
PrpHdr_fset_l:
		;//%r12     := pPrpHdr
		;//[%sp+ 0] := retp
		;//[%sp+ 4] := dNewValL
		;//[%sp+ 8] := dNewValH
		;//[%sp+12] := ...
		xld.w		%r13, [%sp+4]				;//%r13    := dNewValL
		xld.w		%r14, [%sp+8]				;//%r14    := dNewValH
		xadd		%r15, %sp, 12				;//%r15    := ap = &...
PrpHdr_fset_a:
		;//%r12    := pPrpHdr
		;//%r13    := dNewValL
		;//%r14    := dNewValH
		;//%r15    := ap
PrpHdr_fset_v:
		xsub		%sp, %sp, 12
		;//%r12    := pPrpHdr
		;//%r13    := dNewValL
		;//%r14    := dNewValH
		;//%r15    := aName
		xld.w		[%sp+8], %r15				;//[%sp+8] :=                                                                              aName
		xld.w		[%sp+4], %r14				;//[%sp+4] :=                                                                     dNewValH
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                     dNewValL
		xld.w		%r15, 64				;//%r15    :=                                              sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                     pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                      pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=    pPrpHdr->pPrpKey
		xcall		PrpTbl_fset_v				;//PrpTbl_fset_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, dNewVal, aName)
		xadd		%sp, %sp, 12
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpHdr_fset_f(ST_PrpHdr* pPrpHdr, double dNewVal, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpHdr_fset_g(pPrpHdr, dNewVal, sFmt, ap);
	va_end(ap);
}
void PrpHdr_fset_g(ST_PrpHdr* pPrpHdr, double dNewVal, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpHdr_fset_p(pPrpHdr, dNewVal, sPath);
}
void PrpHdr_fset_p(ST_PrpHdr* pPrpHdr, double dNewVal, const char* sPath) {
	PrpTbl_fset_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, dNewVal, sPath);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
double PrpHdr_fget_l(ST_PrpHdr* pPrpHdr, ...) {
	double dVal;
	va_list ap;
	va_start(ap, pPrpHdr);
	dVal = PrpHdr_fget_a(pPrpHdr, ap);
	va_end(ap);
	return dVal;
}
double PrpHdr_fget_a(ST_PrpHdr* pPrpHdr, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return PrpHdr_fget_v(pPrpHdr, aName);
}
double PrpHdr_fget_v(ST_PrpHdr* pPrpHdr, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	return PrpTbl_fget_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, aName);
}
#else //PIECE
double PrpHdr_fget_l(ST_PrpHdr* pPrpHdr, ...);
double PrpHdr_fget_a(ST_PrpHdr* pPrpHdr, va_list ap);
double PrpHdr_fget_v(ST_PrpHdr* pPrpHdr, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_fget_l
		.global		PrpHdr_fget_a
		.global		PrpHdr_fget_v
PrpHdr_fget_l:
		;//[%sp+0] := retp
		;//[%sp+4] := pPrpHdr
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12    := pPrpHdr
		xadd		%r13, %sp, 8				;//%r13    := ap = &...
PrpHdr_fget_a:
		;//%r12    := pPrpHdr
		;//%r13    := ap
PrpHdr_fget_v:
		xsub		%sp, %sp, 4
		;//%r12    := pPrpHdr
		;//%r13    := aName
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                            aName
		xld.w		%r15, 64				;//%r15    :=                                                     sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                            pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                             pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=           pPrpHdr->pPrpKey
		xcall		PrpTbl_fget_v				;//return PrpTbl_fget_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, aName)
		xadd		%sp, %sp, 4
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
double PrpHdr_fget_f(ST_PrpHdr* pPrpHdr, const char* sFmt, ...) {
	double dVal;
	va_list ap;
	va_start(ap, sFmt);
	dVal = PrpHdr_fget_g(pPrpHdr, sFmt, ap);
	va_end(ap);
	return dVal;
}
double PrpHdr_fget_g(ST_PrpHdr* pPrpHdr, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	return PrpHdr_fget_p(pPrpHdr, sPath);
}
double PrpHdr_fget_p(ST_PrpHdr* pPrpHdr, const char* sPath) {
	return PrpTbl_fget_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, sPath);
}
/*--------------------------------------------------------------------------*/
#ifndef PIECE
void PrpHdr_ffmt_l(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, ...) {
	va_list ap;
	va_start(ap, cap);
	PrpHdr_ffmt_a(pPrpHdr, buf, cap, ap);
	va_end(ap);
}
void PrpHdr_ffmt_a(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, va_list ap) {
	int aName[(15+1)/*調整可*/], i = 0;	//実用上、変数名と配列インデクスの階層が15以下(終端(-1)を含めて16以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((aName[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(aName)) { DIE(); }	//ここで停止した場合は、aName[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	PrpHdr_ffmt_v(pPrpHdr, buf, cap, aName);
}
void PrpHdr_ffmt_v(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/) {
	PrpTbl_ffmt_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, buf, cap, aName);
}
#else //PIECE
void PrpHdr_ffmt_l(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, ...);
void PrpHdr_ffmt_a(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, va_list ap);
void PrpHdr_ffmt_v(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, const int* aName/*[varName[,...[,varName]]][,index[,...[,index]]],-1*/);
asm("
		.code
		.align		1
		.global		PrpHdr_ffmt_l
		.global		PrpHdr_ffmt_a
		.global		PrpHdr_ffmt_v
PrpHdr_ffmt_l:
		;//%r12    := pPrpHdr
		;//%r13    := buf
		;//[%sp+0] := retp
		;//[%sp+4] := cap
		;//[%sp+8] := ...
		xld.w		%r14, [%sp+4]				;//%r14    := cap
		xadd		%r15, %sp, 8				;//%r15    := ap = &...
PrpHdr_ffmt_a:
		;//%r12   := pPrpHdr
		;//%r13   := buf
		;//%r14   := cap
		;//%r15   := ap
PrpHdr_ffmt_v:
		xsub		%sp, %sp, 12
		;//%r12   := pPrpHdr
		;//%r13   := buf
		;//%r14   := cap
		;//%r15   := aName
		xld.w		[%sp+8], %r15				;//[%sp+8] :=                                                                               aName
		xld.w		[%sp+4], %r14				;//[%sp+4] :=                                                                          cap
		xld.w		[%sp+0], %r13				;//[%sp+0] :=                                                                     buf
		xld.w		%r15, 64				;//%r15    :=                                              sizeof(ST_PrpHdr) * 8
		ld.w		%r14, %r12				;//%r14    :=                                     pPrpHdr
		xld.w		%r13, [%r12+4]				;//%r13    :=                      pPrpHdr->iTbl
		ld.w		%r12, [%r12]				;//%r12    :=    pPrpHdr->pPrpKey
		xcall		PrpTbl_ffmt_v				;//PrpTbl_ffmt_v(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, buf, cap, aName)
		xadd		%sp, %sp, 12
		ret
");
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void PrpHdr_ffmt_f(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, const char* sFmt, ...) {
	va_list ap;
	va_start(ap, sFmt);
	PrpHdr_ffmt_g(pPrpHdr, buf, cap, sFmt, ap);
	va_end(ap);
}
void PrpHdr_ffmt_g(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	PrpHdr_ffmt_p(pPrpHdr, buf, cap, sPath);
}
void PrpHdr_ffmt_p(ST_PrpHdr* pPrpHdr, char* buf/*[cap]*/, int cap, const char* sPath) {
	PrpTbl_ffmt_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, buf, cap, sPath);
}
#endif//USE_PRP_DOUBLE
/*--------------------------------------------------------------------------*/
int PrpHdr_path_f(ST_PrpHdr* pPrpHdr, int* aName/*[iNameCap]*/, int iNameCap, const char* sFmt, ...) {
	int iType;
	va_list ap;
	va_start(ap, sFmt);
	iType = PrpHdr_path_g(pPrpHdr, aName, iNameCap, sFmt, ap);
	va_end(ap);
	return iType;
}
int PrpHdr_path_g(ST_PrpHdr* pPrpHdr, int* aName/*[iNameCap]*/, int iNameCap, const char* sFmt, va_list ap) {
	char sPath[256/*調整可*/];
	vsnprintf(sPath, ARRAY_SIZE(sPath), sFmt, ap);
	return PrpHdr_path_p(pPrpHdr, aName, iNameCap, sPath);
}
int PrpHdr_path_p(ST_PrpHdr* pPrpHdr, int* aName/*[iNameCap]*/, int iNameCap, const char* sPath) {
	return PrpTbl_path_p(pPrpHdr->pPrpKey, pPrpHdr->iTbl, aName, iNameCap, sPath);
}
/*--------------------------------------------------------------------------*/
int PrpHdr_list(ST_PrpHdr* pPrpHdr, int (*callback)(int iType, const int* aName, const char* sPath, void* arg), int* aName/*[iNameCap],NULL可*/, int iNameCap, char* sPath/*[iPathCap],NULL可*/, int iPathCap, void* arg) {
	return PrpTbl_list(pPrpHdr->pPrpKey, pPrpHdr->iTbl, callback, aName, iNameCap, sPath, iPathCap, arg);
}
/*--------------------------------------------------------------------------*/
#ifdef  USE_PRP_DUMP
void PrpHdr_dump(FILE* fp, ST_PrpHdr* pPrpHdr, void (*fnVarFmt)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), int fOpt/*(PrpDmp_*の0個以上の組み合わせ)*/) {
	PrpTbl_dump(fp, pPrpHdr->pPrpKey, pPrpHdr->iTbl, pPrpHdr, sizeof(ST_PrpHdr) * 8, fnVarFmt, fOpt);
}
#endif//USE_PRP_DUMP
/****************************************************************************
 *	プロパティエディタ
 ****************************************************************************/
#if     defined(WIN32) && defined(__PDCURSES__)
//□使用例
//void sample(){
//  WINDOW* win;
//  ST_PrpEdt* pPrpEdt;
//  initscr();
//  refresh();//initscr()の直後にrefresh()を呼び出しておくのはPDCursesの定石です。
//  border('|','|','-','-','+','+','+','+');
//  wnoutrefresh(stdscr);
//  win=newwin(LINES-2,COLS-2,1,1);//この例ではウインドウを作成しましたが、stdscrを使っても構いません。
//  //nodelay(win,1);//┬おこなってもおこなわなくても構いません。単体ツールでPrpEdt_exec()がブロックしても構わない場合はおこなわない方が良いでしょう。
//  //curs_set(0);   //┘アプリケーションに組み込んで、刻々と変化してゆくプロパティをモニタリングしながら編集する場合は、この2行を有効にしてください。
//  pPrpEdt=PrpEdt_new(phApp->pPrpKey,phApp->iTbl,phApp+1,0,NULL,win,30,10);
//  for(;;){
//    wnoutrefresh(win);
//    doupdate();
//    if(PrpEdt_exec(pPrpEdt)==KEY_F(12)){break;}
//    PrpEdt_draw(pPrpEdt);
//  }
//  PrpEdt_free(pPrpEdt);
//  endwin();
//}
/*--------------------------------------------------------------------------*/
/*typedef*/ struct _ST_PrpEdt {
	const void*	pPrpKey;
	int		iTbl;
	void*		pPrpTbl;
	int		iBitPos;
	int		cPath;				//┐
	char**		vPath/*[cPath+1(NULL)]*/;	//┴strv形式
	void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal);
	//-- curses ---
	WINDOW*		win;		//描画先ウインドウ	stdscrでも、newwin()等で作成したウインドウでも、どちらでも良い。
	int		win_h;		//ウインドウの行数
	int		win_w;		//ウインドウの列数
	int		path_w;		//パス名の表示列数
	int		val_w;		//値の表示列数
	int		sel;		//選択行
	int		top;		//先頭行
} /*ST_PrpEdt*/;
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#define PrpEdt_no_w	4	//調整可
/*--------------------------------------------------------------------------*/
static int PrpEdt_new_cb(int iType, const int* aName, const char* sPath, void* arg) {
	struct obstack* o = arg;
	if((short)iType < 0) {	//'var'型(-1),又は,タイプ型(0x8000～0xFFFF)
		obstack_ptr_grow(o, strdup(sPath));
#ifdef  USE_PRP_DOUBLE
	} else if(iType == PrpTbl_Double) {	//組み込み'Double'型(0x7FFF)
		obstack_ptr_grow(o, strdup(sPath));
#endif//USE_PRP_DOUBLE
	}
	return 0;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ST_PrpEdt* PrpEdt_new(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), void/*WINDOW*/* win, int path_w, int val_w) {
	ST_PrpEdt* pPrpEdt = calloc(1, sizeof(ST_PrpEdt));
	if(!pPrpEdt) { DIE(); }
	pPrpEdt->pPrpKey	= pPrpKey;
	pPrpEdt->iTbl		= iTbl;
	pPrpEdt->pPrpTbl	= pPrpTbl;
	pPrpEdt->iBitPos	= iBitPos;
	pPrpEdt->fnVarFmt	= fnVarFmt;
	pPrpEdt->win		= win;
	pPrpEdt->path_w		= path_w;
	pPrpEdt->val_w		= val_w;
	{
		struct obstack o;
		obstack_init(&o);
		PrpTbl_list(pPrpKey, iTbl, PrpEdt_new_cb, NULL, 0, NULL, 0, &o);
		obstack_ptr_grow(&o, NULL);	//strv形式の終端
		pPrpEdt->vPath	= memdup(obstack_base(&o), obstack_object_size(&o));
		pPrpEdt->cPath	= strv_length(pPrpEdt->vPath);
		if(!pPrpEdt->cPath) { DIE(); }	//プロパティテーブルが空
		obstack_free(&o, NULL);
	}
	{
		getmaxyx(win, pPrpEdt->win_h, pPrpEdt->win_w);
		keypad(win, 1);	//PrpEdt_exec()の中で呼び出すwgetch()でカーソルキー等を取得するために必要。	{{2016/06/09コメント追記:wgetch(win)でKEY_MOUSEを取得するためにも、keypad(win,1)は必要です。mouse_on(ALL_MOUSE_EVENTS),又は,mousemask(ALL_MOUSE_EVENTS,NULL)を行っても、keypad(win,1)が行われていないと、wgetch(win)はKEY_MOUSEを返さないからです。参照資料「SourceForge - Public Domain Curses - Discussion - Mouse no working?」(https://sourceforge.net/p/pdcurses/discussion/95731/thread/bc12f48c/)}}
	    //{{2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
		//全てのマウスイベントを有効にする。
		// - マウスホイールのスクロールイベントだけを有効にしても良いのですが、以下の不明点が有ったので、確実のために全てのマウスイベントを有効にする事にしました。
		//   PDCursesはマウスホイールのスクロールイベントをBUTTON4_PRESSEDとBUTTON5_PRESSEDで表しており、それにもかかわらず別にMOUSE_WHEEL_SCROLLというマスクも定義されています。
		//   マウスホイールのスクロールイベントだけを有効にするには、BUTTON4_PRESSED,BUTTON5_PRESSED,MOUSE_WHEEL_SCROLLの内、どのマスクをセットすれば良いのかが不明でした。
		// - PDCursesのマウスAPIは、古いSYSVR4互換形式と、新しいncurses互換形式の、二種類のマウスAPIが有ります。
		//   どちらも常に使用可能で、両者を混在して使用する事も出来ます。
		//   今回は、古いSYSVR4互換形式のマウスAPIを使う事にしました。
		//   新しいncurses互換形式のマウスAPIは、アプリケーションが明示的にMEVENT変数を用意してマウスイベントを取得しなければいけないのに対して、
		//   古いSYSVR4互換形式は、グローバル変数Mouse_status,及び,それにアクセスするマクロ(MOUSE_WHEEL_UP等)を使用してイベントを参照出来、(僅かではありますが)コーディングの手間が省けるからです。
		// - mouse_on()(又はmousemask())は、特定のウインドウだけでなく、PDCurses全体に影響する設定であり、ここで設定して良いものかどうか少し迷いました。						┐
		//   今の所は、アプリケーション側の手間を省く事を優先して、ここで設定する事にしました。														├■■■要検討■■■
		//   もし問題となった場合は、nodelay()やcurs_set()の設定をアプリケーション側に任せているのと同様に、mouse_on()(又はmousemask())の設定もここで行わずに、アプリケーション側へ移動して下さい。	┘
		mouse_on(ALL_MOUSE_EVENTS);	//これはSYSVR4互換形式のマウスAPIです。ncurses互換形式ならば'mousemask(ALL_MOUSE_EVENTS,NULL)'です。
	    //}}2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
	}
    //{{2016/01/05追加:PrpEdt_new()の中でwclear()を呼び出すようにしました。標準出力とCursesが混在している場合に確実にゴミを消しておくためです。
	//標準出力とCursesが混在している場合に確実にゴミを消しておく。この処理は必須ではない。標準出力とCursesを混在せずに正しく使っている場合は不要である。
	// - wclear()はwerase()よりも遅いようなので、最初にPrpEdt_new()でwclear()を実行し、毎回のPrpEdt_draw()の処理ではこれまで通りwerase()を使う事にした。
	wclear(win);
    //}}2016/01/05追加:PrpEdt_new()の中でwclear()を呼び出すようにしました。標準出力とCursesが混在している場合に確実にゴミを消しておくためです。
	//初回のPrpEdt_exec()でブロックする前に、確実に初回の描画を行っておく事にしました。
	// - ただし、初回のPrpEdt_exec()の前にwnoutrefresh(),doupdate()を呼び出す事は、アプリケーションの役割です。
	//   (実際にはwgetch()がwrefresh()を呼び出すので、wnoutrefresh(),doupdate()を呼び出さなくても大丈夫ですが)
	// - パネルライブラリを使う可能性もあるので、当関数内でwnoutrefresh()やdoupdate()を呼び出す事は出来ません。
	PrpEdt_draw(pPrpEdt);
	return pPrpEdt;
}
/*--------------------------------------------------------------------------*/
void PrpEdt_free(ST_PrpEdt* pPrpEdt) {
	strfreev(pPrpEdt->vPath);
	free(pPrpEdt);
}
/*--------------------------------------------------------------------------*/
int PrpEdt_exec(ST_PrpEdt* pPrpEdt) {
	char* buf = alloca(pPrpEdt->val_w + 1/*nul*/);
	char *endptr, *pPath;
	int c, x, y, ok, old_vis;
    //{{2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
	int save_c;		//wgetch()が返した元の'c'を、書き換える前に保存しておく変数。
	int scroll_speed = 1;	//KEY_UP,及び,KEY_DOWNのスクロール行数。本当にキーボードが押された時のKEY_UP/KEY_DOWNならば1行(必須)、マウスホイールのスクロールによる擬似的なKEY_UP/KEY_DOWNならば4行(調整可)づつスクロールする事にした。
    //}}2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
	if((unsigned)pPrpEdt->sel >= (unsigned)pPrpEdt->cPath) { DIE(); }	//バグ
	pPath = pPrpEdt->vPath[pPrpEdt->sel];
	old_vis = curs_set(0);	//カーソル消去
	if(SP->echo) {
		noecho();
		c = wgetch(pPrpEdt->win);
		echo();
	} else {
		c = wgetch(pPrpEdt->win);
	}
	curs_set(old_vis);	//カーソル復元
    //{{2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
	//この下で'c'を書き換える可能性が有るので、wgetch()が返した元の'c'を'save_c'に保存しておく。
	save_c = c;
	//マウスイベントならば…
	if(c == KEY_MOUSE) {
		//マウス状態を更新出来たら…(必ず成功するはずだが一応検査する事にした)
		if(!request_mouse_pos()) {	//これはSYSVR4互換形式のマウスAPIです。ncurses互換形式ならば'nc_getmouse(&event)'です。
			//マウスの左ボタンが押下されたら…
			if((BUTTON_STATUS(1) == BUTTON_PRESSED) ||		//┬クリックした時は、BUTTON_CLICKEDだけが来て、BUTTON_PRESSEDは来ないようだ。長押しした時は、BUTTON_PRESSEDが来て、その後、離した時にBUTTON_RELEASEDが来て、BUTTON_CLICKEDは来ないようだ。
			   (BUTTON_STATUS(1) == BUTTON_CLICKED) ||		//┘従って、押下イベントを処理するには、BUTTON_PRESSEDとBUTTON_CLICKEDを処理するのが良いだろう。ちなみに、BUTTON_PRESSED,BUTTON_CLICKED等は列挙値であり、ビットマスクではない事に注意せよ。
			   (BUTTON_STATUS(1) == BUTTON_MOVED  ) ||		//─すぐ上で'BUTTON_PRESSEDとBUTTON_CLICKEDを処理するのが良い'と書いたが、試して見た所、ボタンを押下したままドラッグした時も選択行が変わる方が便利だったので、BUTTON_PRESSEDとBUTTON_CLICKEDに加えてBUTTON_MOVEDも処理する事にした。
			   (BUTTON_STATUS(1) == BUTTON_DOUBLE_CLICKED) ||	//┬さらに加えて、ダブルクリック,又は,トリプルクリックされたら、選択行を変更して、即、編集開始する事にした。
			   (BUTTON_STATUS(1) == BUTTON_TRIPLE_CLICKED)) {	//┘この操作はさほど便利な訳ではないが、ダブルクリックに対して何も反応が無いと使用者が不安に感じる気がしたので、編集開始の反応をする事にした。
				wmouse_position(pPrpEdt->win, &y, &x);				//マウスカーソルの位置を取得する(ウインドウ相対)。ウインドウ外ならば(y=-1,x=-1)になる。
				if((unsigned)y < (unsigned)(pPrpEdt->cPath - pPrpEdt->top)) {	//押下された位置が、有効な行ならば…
					pPrpEdt->sel = pPrpEdt->top + y;			//選択行を変更する。
					if((BUTTON_STATUS(1) == BUTTON_DOUBLE_CLICKED) ||	//┐
					   (BUTTON_STATUS(1) == BUTTON_TRIPLE_CLICKED)) {	//├ダブルクリック,又は,トリプルクリックだったならば、編集開始する。'c=KEY_DC'で編集開始になる理由は、以降の処理を参照せよ。
						c = KEY_DC;					//┘
					}
				}
			//マウスホイールのスクロールアップならば、[↑]キーが押されたと見なす。
			} else if(MOUSE_WHEEL_UP) {	//これはSYSVR4互換形式のマウスAPIです。ncurses互換形式ならば'event.bstate&BUTTON4_PRESSED'です。
				pPrpEdt->sel = pPrpEdt->top;							//─すぐにスクロールする方が操作性が良いと思うので、カーソルを最上行へ移動しておく事にした。必須ではない。
				scroll_speed = 4/*調整可*/;	//マウスホイールのスクロールによる擬似的なKEY_UP/KEY_DOWNならば4行(調整可)づつスクロールする事にした。
				c = KEY_UP;
			//マウスホイールのスクロールダウンならば、[↓]キーが押されたと見なす。
			} else if(MOUSE_WHEEL_DOWN) {	//これはSYSVR4互換形式のマウスAPIです。ncurses互換形式ならば'event.bstate&BUTTON5_PRESSED'です。
				pPrpEdt->sel = pPrpEdt->top + (pPrpEdt->win_h - 1);				//┬すぐにスクロールする方が操作性が良いと思うので、カーソルを最下行へ移動しておく事にした。必須ではない。
				if(pPrpEdt->sel > pPrpEdt->cPath - 1) { pPrpEdt->sel = pPrpEdt->cPath - 1; }	//┘
				scroll_speed = 4/*調整可*/;	//マウスホイールのスクロールによる擬似的なKEY_UP/KEY_DOWNならば4行(調整可)づつスクロールする事にした。
				c = KEY_DOWN;
			}
		}
	}
    //}}2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
	switch(c) {
	//以下のキーが押されたら、その文字も含めて入力を開始する。
	case '-':
#ifdef  USE_PRP_DOUBLE
	case '.':
#endif//USE_PRP_DOUBLE
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		ungetch(c);
		/* FALLTHRU */
	//以下のキーが押されたら、その文字を除いて入力を開始する。
	case KEY_DC:		//[Delete]
//誤	case KEY_BACKSPACE:	//[Backspace]
/*正*/	case '\b':		//[Backspace]
		y = pPrpEdt->sel - pPrpEdt->top;
		x = PrpEdt_no_w + 1/*'|'*/ + pPrpEdt->path_w + 1/*'|'*/;
		wmove(pPrpEdt->win, y, x);
		wprintw(pPrpEdt->win, "%*s", pPrpEdt->val_w, "");
		wmove(pPrpEdt->win, y, x);
		old_vis = curs_set(1);	//カーソル表示
		if(SP->echo) {
			wgetnstr(pPrpEdt->win, buf, pPrpEdt->val_w);
		} else {
			echo();
			wgetnstr(pPrpEdt->win, buf, pPrpEdt->val_w);
			noecho();
		}
		curs_set(old_vis);	//カーソル復元
		if(!*buf) { break; }	//入力文字が無ければ変更をキャンセルしたと見なす。
		ok = 0;	//失敗としておく。
		SEH_try {
#ifdef  USE_PRP_DOUBLE
			ST_PrpInf stPrpInf;
			PrpTbl_inf_p(pPrpEdt->pPrpKey, pPrpEdt->iTbl, &stPrpInf, pPath);
			if(stPrpInf.iType == PrpTbl_Double) {
				double dNewVal = strtod(buf, &endptr);
				if(!*endptr) {	//正しい数値が入力されたら…
					PrpTbl_fset_p(pPrpEdt->pPrpKey, pPrpEdt->iTbl, pPrpEdt->pPrpTbl, pPrpEdt->iBitPos, dNewVal, pPath);
					ok = 1;	//成功とする。
				}
			} else {
#endif//USE_PRP_DOUBLE
				int iNewVal = strtol(buf, &endptr, 0);
				if(!*endptr) {	//正しい数値が入力されたら…
					PrpTbl_set_p(pPrpEdt->pPrpKey, pPrpEdt->iTbl, pPrpEdt->pPrpTbl, pPrpEdt->iBitPos, iNewVal, pPath);
					ok = 1;	//成功とする。
				}
#ifdef  USE_PRP_DOUBLE
			}
#endif//USE_PRP_DOUBLE
		} SEH_catch(PrpException) {
			/** no job **/
		} SEH_end
		if(!ok) {	//値の変更が成功しなければ…
			beep();
			flash();
			break;	//ここまで
		}
		/* FALLTHRU */
	//以下のキーが押されたら、選択行を変更する。
//誤	case KEY_ENTER:		//[Enter]
/*正*/	case '\n':		//[Enter]
		//値の変更が成功した場合,及び,[Enter]キーが押された場合、次の行へ進める。
		c = KEY_DOWN;
		/* FALLTHRU */
	case KEY_UP:		//[↑]
	case KEY_DOWN:		//[↓]
	case KEY_PPAGE:		//[Page Up]
	case KEY_NPAGE:		//[Page Down]
	case KEY_HOME:		//[Home]
	case KEY_END:		//[End]
		switch(c) {
		default:DIE();
	    //{{2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
	    //	case KEY_UP:    pPrpEdt->sel--;                    break;
	    //	case KEY_DOWN:  pPrpEdt->sel++;                    break;
	    //↓2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
		case KEY_UP:    pPrpEdt->sel -= scroll_speed;      break;
		case KEY_DOWN:  pPrpEdt->sel += scroll_speed;      break;
	    //}}2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
		case KEY_PPAGE: pPrpEdt->sel -= pPrpEdt->win_h;    break;
		case KEY_NPAGE: pPrpEdt->sel += pPrpEdt->win_h;    break;
		case KEY_HOME:  pPrpEdt->sel = 0;                  break;
		case KEY_END:   pPrpEdt->sel = pPrpEdt->cPath - 1; break;
		}
		if(pPrpEdt->sel <                  0) { pPrpEdt->sel =                  0; }
		if(pPrpEdt->sel > pPrpEdt->cPath - 1) { pPrpEdt->sel = pPrpEdt->cPath - 1; }
		//スクロール
		if(pPrpEdt->sel < pPrpEdt->top                       ) { pPrpEdt->top = pPrpEdt->sel;                        }
		if(pPrpEdt->sel > pPrpEdt->top + (pPrpEdt->win_h - 1)) { pPrpEdt->top = pPrpEdt->sel - (pPrpEdt->win_h - 1); }
		//スクロールの行き過ぎ補正
		if(pPrpEdt->top > pPrpEdt->cPath - pPrpEdt->win_h) { pPrpEdt->top = pPrpEdt->cPath - pPrpEdt->win_h; }	//負になる可能性が有るが、
		if(pPrpEdt->top <                               0) { pPrpEdt->top =                               0; }	//すぐにゼロに補正される。
		break;	//ここまで
	case KEY_LEFT:		//[←]
	case KEY_RIGHT:		//[→]
#ifdef  USE_PRP_DOUBLE
		SEH_try {
#endif//USE_PRP_DOUBLE
			switch(c) {
			default:DIE();
			case KEY_LEFT:  PrpTbl_acc_p(pPrpEdt->pPrpKey, pPrpEdt->iTbl, pPrpEdt->pPrpTbl, pPrpEdt->iBitPos, -1, pPath); break;
			case KEY_RIGHT: PrpTbl_acc_p(pPrpEdt->pPrpKey, pPrpEdt->iTbl, pPrpEdt->pPrpTbl, pPrpEdt->iBitPos,  1, pPath); break;
			}
#ifdef  USE_PRP_DOUBLE
		} SEH_catch(PrpException) {	//組み込み'Double'型の変数を選択して[←][→]を押した場合に、上記の処理が例外を投入します。
			beep();
			flash();
		} SEH_end
#endif//USE_PRP_DOUBLE
		break;	//ここまで
	}
    //{{2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
    //	return c;
    //↓2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
	//'c'は書き換えられた可能性が有るが、当関数の戻り値としては、書き換えられる前の、wgetch()が返した元の'c'を'save_c'に保存しておいた値を返す。
	return save_c;
    //}}2016/06/09追加:プロパティエディタを、マウスボタンで行選択,及び,マウスホイールでスクロール出来るようにしました。
}
/*--------------------------------------------------------------------------*/
// * Tue Jan 19 21:44:45 JST 2016 Naoyuki Sawa
// - PRPEDT_NARROW_KATAKANAシンボルを定義すると、値と説明文の中の全角かな文字(,及び,全角句読点等)を、半角文字に変換して表示するようにしました。
//   こうした理由は、全角かな文字が多いデータを表示する時に、ある位置の文字が1バイト目が一致して2バイト目が違う全角かな文字に変わる時に、文字化けし易いからです。
//   PDCursesは2バイト文字を意識しないので、2バイト目だけを出力して、ターミナル上では文字化けが生じるのだと思います。
//   全角かな文字を半角文字に変換して表示すれば、1バイトの書き換えでは文字化けが生じないので、上記の問題が発生する事が少なくなります。
//   尚、さほど読み辛くなる事は無いと思いますが、もし読み辛い場合は、PRPEDT_NARROW_KATAKANAシンボルをコメントアウトすると、元の動作に戻ります。
// - 厳密には、上記の問題は全角かな文字だけではなく、漢字や全角記号等でも発生し得るので、今回の対策だけで文字化けを全て回避する事は出来ません。
//   しかし実際には、全角かな文字で発生するケースがほとんどである事と、多少文字化けしても実用上大きな支障は無いので、全角かな文字だけの対策に留める事にしました。
//   根本的に解決するには、毎回clear()を行う事ですが、速度が大幅に低下するので望ましく有りません。
//   また、PDCursesライブラリにWIDEを指定してビルドしても、上記の問題は解決できません。
//   WIDE指定は、既存の関数をマルチバイト対応にするオプションではなく、UTF-8対応の関数群を追加するオプションだからです。
#define PRPEDT_NARROW_KATAKANA	//←←←←←この行をコメントアウトすると、元の動作に戻ります。
void PrpEdt_draw(ST_PrpEdt* pPrpEdt) {
#ifdef  PRPEDT_NARROW_KATAKANA
	char* tmp;
#endif//PRPEDT_NARROW_KATAKANA
	char buf[256/*調整可*/];
	int x, y, iPath;
	const char *pPath, *pDesc;
	ST_PrpInf stPrpInf;
	werase(pPrpEdt->win);
	for(y = 0; y < pPrpEdt->win_h; y++) {
		iPath = pPrpEdt->top + y;
		if(iPath >= pPrpEdt->cPath) { break; }
		pPath = pPrpEdt->vPath[iPath];
		PrpTbl_inf_p(pPrpEdt->pPrpKey, pPrpEdt->iTbl, &stPrpInf, pPath);
		x = 0;
		//連番
		wmove(pPrpEdt->win, y, x);
		wprintw(pPrpEdt->win, "%*d", PrpEdt_no_w, iPath + 1/*連番は1から数える事にした*/);
		x += PrpEdt_no_w;
		//パス名
		if(x < pPrpEdt->win_w) {
			wmove(pPrpEdt->win, y, x);
			wprintw(pPrpEdt->win, "|%.*s", pPrpEdt->path_w, pPath);
		}
		x += 1/*'|'*/ + pPrpEdt->path_w;
		//値
		if(x < pPrpEdt->win_w) {
#ifdef  USE_PRP_DOUBLE
			if(stPrpInf.iType == PrpTbl_Double) {
				PrpTbl_ffmt_p(pPrpEdt->pPrpKey, pPrpEdt->iTbl, pPrpEdt->pPrpTbl, pPrpEdt->iBitPos, buf, sizeof buf, pPath);
			} else {
#endif//USE_PRP_DOUBLE
				PrpTbl_fmt_p(pPrpEdt->pPrpKey, pPrpEdt->iTbl, pPrpEdt->pPrpTbl, pPrpEdt->iBitPos, buf, sizeof buf, pPrpEdt->fnVarFmt, pPath);
#ifdef  USE_PRP_DOUBLE
			}
#endif//USE_PRP_DOUBLE
			wmove(pPrpEdt->win, y, x);
#ifndef PRPEDT_NARROW_KATAKANA
			wprintw(pPrpEdt->win, "|%.*s", pPrpEdt->val_w, buf);
#else //PRPEDT_NARROW_KATAKANA
			tmp = StrConv(buf, vbNarrow|vbKatakana);
			wprintw(pPrpEdt->win, "|%.*s", pPrpEdt->val_w, tmp);
			free(tmp);
#endif//PRPEDT_NARROW_KATAKANA
		}
		x += 1/*'|'*/ + pPrpEdt->val_w;
		//説明文
		if(x < pPrpEdt->win_w) {
			pDesc = stPrpInf.pDesc ? stPrpInf.pDesc : "";
			wmove(pPrpEdt->win, y, x);
#ifndef PRPEDT_NARROW_KATAKANA
			wprintw(pPrpEdt->win, "|%.*s", pPrpEdt->win_w - x, pDesc);
#else //PRPEDT_NARROW_KATAKANA
			tmp = StrConv(pDesc, vbNarrow|vbKatakana);
			wprintw(pPrpEdt->win, "|%.*s", pPrpEdt->win_w - x, tmp);
			free(tmp);
#endif//PRPEDT_NARROW_KATAKANA
		}
		//選択行
		if(iPath == pPrpEdt->sel) {
			wmove(pPrpEdt->win, y, 0);
			wchgat(pPrpEdt->win, pPrpEdt->win_w, A_REVERSE, 0, NULL);
		}
	}
}
#undef  PRPEDT_NARROW_KATAKANA
/*--------------------------------------------------------------------------*/
// * Tue Jan 05 21:29:01 JST 2016 Naoyuki Sawa
// - PrpEdt_run()を追加しました。
// - これは、'使用例'と同等の処理を簡単に実行する、ユーティリティ関数です。
//   この関数を用意した目的は、アプリケーションが'使用例'のループを毎回実装する手間を省くためです。
//   アプリケーションの処理の中で、プロパティエディタを使いたい箇所で、この関数を呼び出して下さい。
//   当関数は、ユーザーが指定されたキーを押してプロパティエディタを終了するまで、処理を返しません。
// - この関数を使用する事は、必須では有りません。
//   もっと複雑な処理を行いたかったり、アプリケーションのメインループと並行してプロパティエディタを実行したい場合は、アプリケーションが独自に処理して下さい。
// - 当関数は、Cursesの初期化とクリーンアップを行いません。
//   当関数を呼び出す前にCursesを初期化する事と、Cursesが不要になったらクリーンアップする事は、アプリケーションが行ってください。
//□使用例
//│void app_main(){
//│  initscr();
//│  refresh();//initscr()の直後にrefresh()を呼び出しておくのはPDCursesの定石です。
//│  for(;;){
//│    schedule();
//│    if(CheckHitKey(KEY_INPUT_TAB)){//DxLib
//│      PrpEdt_run(phApp->pPrpKey,phApp->iTbl,phApp+1,0,NULL,stdscr,30,10,'\x1B');
//│    }
//│    //～ここでアプリケーションの処理を行う～
//│  }
//│  endwin();
//│}
void PrpEdt_run(const void* pPrpKey, int iTbl, void* pPrpTbl, int iBitPos, void (*fnVarFmt/*NULL可*/)(char* buf/*[cap]*/, int cap, int iFmt, int iVal), void/*WINDOW*/* win, int path_w, int val_w, int iExitKey) {
	//プロパティエディタを作成する。
	ST_PrpEdt* pPrpEdt = PrpEdt_new(pPrpKey, iTbl, pPrpTbl, iBitPos, fnVarFmt, win, path_w, val_w);
	for(;;){
		//初回はPrpEdt_new()関数の最後で実行されたPrpEdt_draw()を反映する。
		//二回目以降はこのループの最後で実行されたPrpEdt_draw()を反映する。
		wrefresh(win);
		//プロパティエディタを実行し、指定されたキーが押されたらループを抜ける。
		if(PrpEdt_exec(pPrpEdt) == iExitKey) { break; }
		//プロパティエディタを描画する。
		PrpEdt_draw(pPrpEdt);
	}
	//プロパティエディタを開放する。
	PrpEdt_free(pPrpEdt);
}
#endif//defined(WIN32) && defined(__PDCURSES__)
/****************************************************************************
 *	応用例
 ****************************************************************************/
#if 0
PrpHdr_inf_l()等を利用すると、'プロパティテーブルの階層の途中のテーブルへのポインタ'を取得して、アクセス出来ます。
この方法を使うと、階層の深い位置に有るテーブル変数の複数のフィールドに連続してアクセスする場合に、高速化出来ます。
以下に、例を示します。
□スクリプト
│table  App                                    "ｱﾌﾟﾘｹｰｼｮﾝﾃｰﾌﾞﾙ"
│       Game                 game              "ｹﾞｰﾑ"
│end
│table  Game                                   "ｹﾞｰﾑﾃｰﾌﾞﾙ"
│       Player               player            "ﾌﾟﾚｲﾔｰ"
│       Enemy                enemy[5]          "ｴﾈﾐｰ配列"
│end
│table  Player
│       limit 9 init 9       Life              "ﾗｲﾌ"
│       Pos                  pos               "位置"
│end
│table  Enemy
│       enum 0,1             Stat      <Stat>  "状態"
│       Pos                  pos               "位置"
│end
│table  Pos
│       range 4,124 init 63  x         <"%u">  "X座標"
│       range 4, 84 init 43  y         <"%u">  "Y座標"
│end
□プログラム
│//--- 初期化 ---
│PrpHdr_def(App,phApp);
│PrpHdr_init(phApp,pPrpKey,PrpTbl_App);
│{//--- ﾌﾟﾛﾊﾟﾃｨﾃｰﾌﾞﾙの階層の途中のﾃｰﾌﾞﾙへのﾎﾟｲﾝﾀを取得してｱｸｾｽする例 ---
│ ST_PrpInf stPrpInf;
│ PrpHdr_inf_f(phApp,&stPrpInf,"game.enemy[%d]",2);
│ PrpTbl_set_f(pPrpKey,stPrpInf.iType,phApp+1,stPrpInf.iBitPos,1,"Stat");
│ PrpTbl_set_f(pPrpKey,stPrpInf.iType,phApp+1,stPrpInf.iBitPos,12,"pos.x");
│ PrpTbl_set_f(pPrpKey,stPrpInf.iType,phApp+1,stPrpInf.iBitPos,34,"pos.y");}
│//--- 確認 ---
│PrpHdr_dump(stdout,phApp,NULL,0);
#endif
