/*
 *	clipyaml.c
 *
 *	LibYAMLヘルパー関数
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2016 Naoyuki Sawa
 *
 *	* Sun Apr 24 21:05:43 JST 2016 Naoyuki Sawa
 *	- 1st リリース。
 *	  LibYAMLには、SAX形式のAPI(yaml_parser_scan(),yaml_parser_parse())と、DOM形式ののAPI(yaml_parser_load())が有ります。
 *	  アプリケーションの都合上は、DOM形式で処理する方が楽なのですが、実際の所、LibYAMLのDOM対応はあまり使い易くないです。
 *	  yaml_document_t構造体にドキュメント全体を読み込むだけで、データをトラバースする関数は一切用意されていないからです。
 *	  そこで、LibYAMLに不足している、データをトラバースするための関数を、当モジュールで実装する事にしました。
 *	  関数仕様は、使い易いJSONパーサー'parson'の関数仕様を参考にしました。
 *	* Mon Apr 25 22:45:55 JST 2016 Naoyuki Sawa
 *	- clipyaml.cに「使用例」を追記しました。
 *	* Fri Apr 29 21:34:57 JST 2016 Naoyuki Sawa
 *	- yaml_document_parse()を追加しました。
 *	- 「パス文字列による読み出し」の関数を追加しました。
 *	  パス文字列の書式は、既存のclipprp.cモジュールのPrpTbl_get_p()等とほぼ同じです。
 *	- 「使用例」を、「パス文字列による読み出し」の関数を使うように変更しました。
 *	* Sun May 01 23:11:51 JST 2016 Naoyuki Sawa
 *	- シフトJISに対応しました。
 *	  'USE_SJIS'シンボルを定義して当モジュールをビルドすると、入力ファイル,入力文字列,関数引数,関数戻り値が全てシフトJISで扱えます。
 *	  アプリケーションがUTF-8を意識する必要が一切無くなりました。
 *	  詳細は、clipyaml.c内の'#define USE_SJIS'を定義している箇所のコメントを参照して下さい。
 *	* Mon May 02 21:51:14 JST 2016 Naoyuki Sawa
 *	- clipunic.cに「文字列変換(シフトJIS⇔UTF-8)」を追加した事に伴い、これまではyaml_sjis_read_handler()の中で、
 *	  ShiftJisToUnicodeStr()とUcs2ToUtf8Str()を組み合わせて行っていた変換を、ShiftJisToUtf8Str()で一度に変換するように変更しました。
 *	* Sat May 07 21:48:49 JST 2016 Naoyuki Sawa
 *	- yaml_document_new(),yaml_document_dump()を追加しました。
 *	  「パス文字列による書き込み」の関数を追加しました。
 *	- yaml_sjis_read_handler()に、'\'の特例処理を追加しました。
 *	  詳細は、yaml_sjis_read_handler()内のコメントを参照して下さい。
 *	- 「書き込み関数の使用例」を追記しました。
 *	* Sun May 08 23:30:59 JST 2016 Naoyuki Sawa
 *	- バックスラッシュの変換問題を、clipunic.cモジュール内で吸収した事により、個別の処理が不要になりました。
 *	  この変更に伴い、yaml_sjis_read_handler()内の特例処理を削除しました。
 *	- 「パス文字列による読み出し」の関数の、node引数にNULLを指定出来るようにしました。
 *	  nodeにNULLが指定されたら、ルートノードからの相対パス(=ドキュメントの絶対パス)と見なします。
 *	  つまりnodeにNULLを指定すれば、「パス文字列による書き込み」と同様の使い方が出来ます。
 *	- yaml_document_dump()のシフトJIS対応を改良しました。
 *	  これまでは、日本語文字が'\uXXXX'形式で出力されてしまっており、シフトJISではあるもののYAMLファイルが読み辛い問題が有りました。
 *	  今回の改良により、日本語文字がそのままシフトJISコードで出力されるようになりました。
 *	* Tue May 10 22:06:16 JST 2016 Naoyuki Sawa
 *	- USE_YAML_SEHシンボルを定義すると、clipyaml.c内のDIE()を全て、SEH_throw(YamlException)に置き換えるようにしました。
 *	  当モジュールの関数は、呼び出し側のバグ(引数不正など)で失敗する事が多いので、即エラー停止でなく、呼び出し側で捕捉出来る方が便利だと思ったからです。
 *	  例えば、以下のように処理して下さい。
 *	  │double number;
 *	  │SEH_try {
 *	  │  number = yaml_path_get_number_f(document, node, "foo.bar[%d]", index);
 *	  │} SEH_catch(YamlException) {
 *	  │  number = 0.0; //デフォルト値を0.0とする。
 *	  │} SEH_end
 *	- USE_YAML_SEHシンボルを定義しなければ、これまで通りclipyaml.c内のDIE()はそのままで、即エラー停止します。
 *	  特に、コードサイズを低減する事が要求される実行環境の場合は、USE_YAML_SEHシンボルを定義しないで下さい。
 *	* Fri May 13 21:43:38 JST 2016 Naoyuki Sawa
 *	- これまでstrndupa()を使っていた箇所を、strndupa()を使わないように変更しました。
 *	  結果は変わりません。
 *	- strndupa()を使わないように変更した理由は、P/ECEではallocaを使用した関数から例外投入で関数を抜けると、allocaのチェインが破損する危険が有るからです。
 *	  (詳細はclipalca.cの実装を参照して下さい。)
 *	  上記は当モジュールに限った事ではないのですが、当モジュールは特に通常の使用で例外を投入する事が多いので、strndupa()を使わないようにする事にしました。
 *	  '通常の使用で例外を投入する事が多い'とは、存在しないキーを読みだそうとしたり、既に存在するキーを書き換えようとしたエラーを、例外で通知するからです。
 *	  具体例は、'Tue May 10 22:06:16 JST 2016'のコメントを参照して下さい。
 *	  これまでは、このような例外を補足して続行すると、P/ECE環境ではallocaのチェインが破損してしまっていました。
 *	  今後は、同様の処理を行っても、allocaのチェインが破損する事は有りません。
 *	* Sat May 14 21:51:15 JST 2016 Naoyuki Sawa
 *	- 既存のyaml_document_dump()をyaml_document_save()に変更し、新規にyaml_document_dump()を作成しました。
 *	  yaml_document_save()がファイル出力用、yaml_document_dump()が文字列出力用となります。
 *	- 上記の変更に伴い、「書き込み関数の使用例」を変更しました。
 *	* Wed May 25 10:22:02 JST 2016 Naoyuki Sawa
 *	- yaml_path_get_node(),yaml_path_set_string()の、キー文字列に'.','[',']'を含められるようになりました。
 *	  キー文字列に'.','[',']'を含めるには、直前に'\'を置いてエスケープして下さい。
 *	  │<例1> "foo.bar"   「foo」キーの「bar」キーと解釈します。
 *	  │      "foo\\.bar" 「foo.bar」キーと解釈します。
 *	  │<例2> "foo[0]"    「foo」キーの0番目の要素と解釈します。
 *	  │      "foo\\[0\\] 「foo[0]」キーと解釈します。
 *	  │      "foo\\[0]   これも「foo[0]」キーと解釈します。厳密には、']'はエスケープしてもしなくても同じです。しかし、']'も明示的にエスケープする方が判り易いと思います。
 *	  │<例3> "表現.十回.予備"     「表現」キーの「十回」キーの「予備」キーと解釈します。 ┬2バイト目に'\'を含む全角文字も正しく扱える事を確認するための例です。
 *	  │      "表現\\.十回\\.予備" 「表現.十回.予備」キーと解釈します。                   ┘
 *	- 今回は変更量がかなり多かったので、変更前のコードはコメントアウトして残していません。
 *	  変更前のコードを参照する場合は、前回のアーカイブを参照して下さい。
 *	* Thu May 26 23:31:18 JST 2016 Naoyuki Sawa
 *	- clipyaml.cに「パス文字列のキーに特殊文字が含まれている場合にエスケープする例」を追記しました。
 *	* Tue Jun 21 21:15:30 JST 2016 Naoyuki Sawa
 *	- yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
 *	  これまでは、当モジュール内でエラー停止,又は,例外を投入した行しか判らず、読み込もうとしたYAMLテキストのどこにエラーが有るのかを、見付けづらかったからです。
 *	  今後は、表示されたエラー内容を元に、読み込もうとしたYAMLのどこにエラーが有るのかを、見付け易くなりました。
 *	- yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
 *	  保存する時にエラーが出る事はまず無いので、こちらはこれまでのままでも特に不便は無かったのですが、上記の変更に合わせて一応こちらも変更しておく事にしました。
 *	* Wed Jun 22 22:49:18 JST 2016 Naoyuki Sawa
 *	- タブ文字展開の独自拡張を追加しました。
 *	  詳細は、USE_TABを定義している箇所のコメントを参照して下さい。
 *	* Sun Aug 14 21:50:35 JST 2016 Naoyuki Sawa
 *	- yaml_path_get_node()が例外を投入した時に、一時的な文字列が解放されずに、メモリリークが発生していた問題を修正しました。
 *	- yaml_path_set_string()が例外を投入した時に、一時的な文字列が解放されずに、メモリリークが発生していた問題を修正しました。
 *	- yaml_path_set_number()が例外を投入した時に、一時的な文字列が解放されずに、メモリリークが発生していた問題を修正しました。
 *	* Sun Sep 04 21:41:17 JST 2016 Naoyuki Sawa
 *	- 64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
 *	  setjmp()/longjmp()のパラメータは(int)であり、(void*)や(intptr_t)を使えないからです。
 *	  尚、32ビット版も64ビット版と共通に変更しても良いのですが、万一既存のコードに影響が生じる事を防ぐために、32ビット版はこれまで通りとしました。
 *	- 64ビット版では、size_tの書式文字列に'%zd'を使用するように修正しました。
 *	  尚、32ビット版は、これまでと同じままにしました。
 *	  自作のfprintf()は長さ修飾子'z'に対応しているので(clipprnt.cのdoprnt()を参照)、32ビット版も64ビット版と同じでも構わないのですが、
 *	  gcc33.exeが警告を長さ修飾子'z'を知らないため警告を表示する事を回避するために、32ビット版はこれまでと同じままにする事にしました。
 */
#include "clip.h"
/****************************************************************************
 *	
 ****************************************************************************/
#ifdef  USE_YAML_SEH
//USE_YAML_SEHシンボルが定義されたら、clipyaml.c内のDIE()を全て、SEH_throw(YamlException)に置き換えます。
#undef  DIE
#ifndef PIECE
  #define DIE() SEH_throw(YamlException)
#else //PIECE
  //P/ECEでも上のように定義しても良いのですが、メモリ節約のため下のように定義する事にしました。結果は同じになります。
  //以下の定義はclipseh.hのSEH_throw()の定義に依存しています。もし今後SEH_throw()を変更する時は以下も変更して下さい。
  #define DIE() do { yaml_throw(__FILE__, __LINE__); } while(0)
  static void __attribute__((noreturn)) yaml_throw(const char* file, int line) {
    SEH_info.file = file;
    SEH_info.line = line;
    SEH_info.msg  = NULL;
    SEH_longjmp((int)YamlException); }
#endif//PIECE
//{{2016/09/04変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
//const char YamlException[1/*dummy*/];
//↓2016/09/04変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
#ifndef _WIN64
const char YamlException[1/*dummy*/];	//32ビット版
#endif//_WIN64
//}}2016/09/04変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
#endif//USE_YAML_SEH
/****************************************************************************
 *	
 ****************************************************************************/
//┌───────────────────┬─────┬─────────────┐
//│'USE_SJIS'シンボルを定義するか?       │する      │しない                    │
//├───────────────────┼─────┼─────────────┤
//│yaml_document_load()が読み込むファイル│シフトJIS │UTF-8/UTF-16-LE/UTF-16-BE │
//│yaml_document_parse()が読み込む文字列 │シフトJIS │UTF-8/UTF-16-LE/UTF-16-BE │
//│yaml_node_get_string()が返す文字列    │シフトJIS │UTF-8                     │…内部でyaml_node_get_string()を呼び出している関数についても同様です。
//│yaml_mapping_get_*()に指定するキー    │シフトJIS │UTF-8                     │…内部でyaml_mapping_get_*()を呼び出している関数についても同様です。
//└───────────────────┴─────┴─────────────┘
//'USE_SJIS'シンボルを定義すれば、アプリケーションの観点からはUTF-8を一切意識せず当モジュールを利用出来ます。
//'USE_SJIS'シンボルを定義しなければ、オリジナルのLibYAMLのエンコーディングの動作に対して何も手を加えません。
#undef  USE_SJIS
#define USE_SJIS	//'USE_SJIS'シンボルを定義しない場合は、この行をコメントアウトして下さい。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//'USE_TAB'シンボルを定義すれば、タブ文字を展開します。
// - 本来、YAMLではタブ文字は使用禁止であり、どうしてもタブ文字を使いたければ、前段にexpand.exeを入れる等の対応が必要です。
//   しかし、実際に、テキストエディタでYAMLを書いていると、タブ文字を使ってインデントを揃えたい事が多かったので、独自拡張する事にしました。
//   読み込むYAMLドキュメントがタブ文字を使用していなければ、この独自拡張機能が動作に影響を与える事は有りません。
// - 前述のシフトJIS対応の独自拡張が有効な場合のみ、それに加えて、このタブ文字展開の独自拡張を有効にする事が出来ます。
//   厳密には、シフトJIS対応とタブ文字展開は独立した機能なので、タブ文字展開だけを個別に有効にする事も出来るべきなのですが、今回はそうしませんでした。
//   理由1. もし個別に有効にできるようにすると、リードハンドラを、シフトJIS対応版,タブ文字展開対応版,両方対応版の3種類用意する必要が生じてしまうから。
//   理由2. 入力テキストをシフトJISと想定できないと、文字のバイト数(半角/全角)を区別するのに少々手間がかかり、タブ文字展開の処理が少々難しくなるから。
//   どちらの理由も極端に困難という訳ではなく、個別に有効する事も可能ではあるのですが、実際の所両方有効にして使う予定なので、個別に有効に出来なくても支障は無いはずです。
#undef  USE_TAB
#define USE_TAB		//'USE_TAB'シンボルを定義しない場合は、この行をコメントアウトして下さい。
#if     (!defined(USE_SJIS) && defined(USE_TAB))
#error  USE_SJISを定義せずに、USE_TABだけを定義する事は出来ません。
#endif//(!defined(USE_SJIS) && defined(USE_TAB))
/*--------------------------------------------------------------------------*/
#ifdef  USE_SJIS
typedef struct _ST_yaml_sjis_read_handler_param {
	FILE*		file;			//yaml_document_load()の場合に使用する。yaml_document_parse()の場合はNULL。
	const char*	string;			//yaml_document_parse()の場合に使用する。yaml_document_load()の場合はNULL。
	int		left;			//シフトJIS⇒UTF-8変換バッファの変換済み残りバイト数。buf[0〜(left-1)]が残りバイトです。
	unsigned char	buf[4 + 1/*'\0'*/];	//シフトJIS⇒UTF-8変換バッファ
#ifdef  USE_TAB
	unsigned char	col;			//8桁単位のカラム位置。bit2〜0だけを参照します。
#endif//USE_TAB
} ST_yaml_sjis_read_handler_param;
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//The read handler is called when the parser needs to read more bytes from the source.
//The handler should write not more than size bytes to the buffer.
//The number of written bytes should be set to the length variable.
//param[in,out]	data        A pointer to an application data specified by yaml_parser_set_input().
//param[out]	buffer      The buffer to write the data from the source.
//param[in]	size        The size of the buffer.
//param[out]	size_read   The actual number of bytes read from the source.
//returns	On success, the handler should return 1.
//		If the handler failed, returned value should be 0.
//		On EOF, the handler should set the size_read to 0 and return 1.
static int yaml_sjis_read_handler(void* data, unsigned char* buffer, size_t size, size_t* size_read) {
	ST_yaml_sjis_read_handler_param* param = data;
	if(!size) { DIE(); }	//(size=0)で呼び出される事は無いはず。
	//読み込んだバイト数を0としておく。
	// - 実際には、/yaml/reader.cのyaml_parser_update_raw_buffer()が、size_read=0にしてからread_handlerを呼び出すので、この処理を省略しても構わない。
	*size_read = 0;
	//シフトJIS⇒UTF-8変換バッファの変換済み残りバイト数が無ければ…
	if(!param->left) {
		//次のシフトJIS文字が有れば…
		int c = param->file ? getc(param->file)				//┐yaml_document_load()の場合
		                    : *param->string++;				//┘yaml_document_parse()の場合
		if(param->file ? (c != EOF )					//┐yaml_document_load()の場合
		               : (c != '\0')) {					//┘yaml_document_parse()の場合
			char    s[2 + 1/*'\0'*/] = { c };
#ifdef  USE_TAB
			if((c == '\r') || (c == '\n')) {			//今回の入力文字が、改行文字ならば…		┬改行文字がCRでもLFでもCR+LFでも対応出来るように、CRでもLFでもカラム位置を先頭に戻す事にした。
				param->col = 0;					//8桁単位のカラム位置を先頭に戻す。		┘改行文字がCR+LFだった場合は、CRと直後のLFで二回連続先頭に戻してしまう事になるが、支障は無い。
			} else {						//今回の入力文字が、改行文字以外ならば…
				param->col++;					//8桁単位のカラム位置を進める。
				if(c == '\t') {
					s[0] = ' ';				//今回の出力文字を、空白文字に置き換える。
					if(param->col & 7) {			//上で8桁単位のカラム位置を進めた結果が8の倍数でなければ、次回もタブ文字展開を行うためにタブ文字を戻す。
						if(param->file) {
							ungetc(c, param->file);	//┐yaml_document_load()の場合
						} else {			//│
							param->string--;	//┘yaml_document_parse()の場合
						}
					}
				}
			}
#endif//USE_TAB
			if(ismbblead(c)) {
				c = param->file ? getc(param->file)		//┐yaml_document_load()の場合
				                : *param->string++;		//┘yaml_document_parse()の場合
				if(ismbbtrail(c)) {
					s[1] = c;
#ifdef  USE_TAB
					param->col++;				//8桁単位のカラム位置を進める。
#endif//USE_TAB
				} else {
					if(param->file) {
						ungetc(c, param->file);		//┐yaml_document_load()の場合
					} else {				//│
						param->string--;		//┘yaml_document_parse()の場合
					}
				}
			}
			//シフトJIS文字列(1文字)⇒UTF-8文字列(1文字)変換を行う。
			param->left = ShiftJisToUtf8Str(s, -1, param->buf, 4 + 1/*'\0'*/);
			if((param->left < 1) || (param->left > 4)) { DIE(); }
	    //{{2016/05/08削除:バックスラッシュの変換問題を、clipunic.cモジュール内で吸収した事により、個別の処理が不要になりました。この変更に伴い、yaml_sjis_read_handler()内の特例処理を削除しました。
	    //	//{{特例処理
	    //		// * Sat May 07 21:48:49 JST 2016 Naoyuki Sawa
	    //		// - yaml_sjis_read_handler()に、'\'の特例処理を追加しました。
	    //		// - シフトJIS⇒UTF-8変換表(厳密にはシフトJIS⇒Unicode変換表)の問題のため、'\'だけ特例処理する必要が有ります。
	    //		//   こうしないと、以下の流れで問題が生じます。
	    //		//   1. 「"\u65E5"」という内容のYAMLファイルを読み込もうとした時に…	(ちなみにこれは「日」という漢字一文字です)
	    //		//   2. 二文字目の'\'が、本当は'\'のままであるべきところ、ShiftJisToUtf8Str()にて"\x5C"⇒"\xC2\xA5"に変換されてしまいます。	←これが変換表の問題です。
	    //		//   3. '\'ではなくなってしまうので、LibYAMLが'\u'シーケンスと解釈出来ずに、"\xC2\xA5u65E5"という文字列として読み込んでしまいます。
	    //		//   4. その後、当モジュールのyaml_node_get_string()を使って値を取り出すと、strdup_Utf8ToShiftJis()で"\xC2\xA5"⇒"\x5C"に戻ります。
	    //		//   5. 従ってプログラムの観点からは、"\u65E5"という文字列として読み込まれてしまったように見えます。
	    //		// - 上記の問題を回避するために、'\'だけ特例処理しました。
	    //		//   具体的には、'\'一文字が"\xC2\xA5"二文字に変換されたら、'\'一文字に戻すという処理を行います。
	    //		//   尚、以下の処理は意図を明示するために少々回りくどく書いてありますが、「param->left=1, param->buf[0]='\\';」と書いても同じです。
	    //		// - この問題は、/clip/tool/dpsprsht/app.cppの'Mon Mar 14 21:59:15 JST 2016'のコメントで発生した問題と同じです。
	    //		//   詳細は、上記のコメントを参照して下さい。
	    //		if(!strcmp(s, "\x5C") && !strcmp(param->buf, "\xC2\xA5")) { param->left = strlen(strcpy(param->buf, s)); }
	    //	//}}特例処理
	    //}}2016/05/08削除:バックスラッシュの変換問題を、clipunic.cモジュール内で吸収した事により、個別の処理が不要になりました。この変更に伴い、yaml_sjis_read_handler()内の特例処理を削除しました。
		}
	}
	//シフトJIS⇒UTF-8変換バッファの変換済み残りバイト数が有れば…
	if(param->left) {
		//1バイト格納する。
		buffer[0] = param->buf[0];
		*size_read = 1;
		//1バイト格納した分、シフトJIS⇒UTF-8変換バッファをずらす。
		memmove(&param->buf[0], &param->buf[1], --param->left);
	}
	return 1;	//On success, the handler should return 1. On EOF, the handler should set the size_read to 0 and return 1.
}
/*--------------------------------------------------------------------------*/
typedef struct _ST_yaml_sjis_write_handler_param {
	FILE*		file;			//yaml_document_save()の場合に使用する。yaml_document_dump()の場合はNULL。
	GByteArray*	barray;			//yaml_document_dump()の場合に使用する。yaml_document_save()の場合はNULL。
	int		left;			//UTF-8⇒シフトJIS変換バッファの変換済み残りバイト数。buf[0〜(left-1)]が残りバイトです。
	unsigned char	buf[4 + 1/*'\0'*/];	//UTF-8⇒シフトJIS変換バッファ
} ST_yaml_sjis_write_handler_param;
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//The prototype of a write handler.
//The write handler is called when the emitter needs to flush the accumulated characters to the output.
//The handler should write size bytes of the buffer to the output.
//param[in,out]	data        A pointer to an application data specified by yaml_emitter_set_output().
//param[in]	buffer      The buffer with bytes to be written.
//param[in]	size        The size of the buffer.
//returns	On success, the handler should return 1.
//		If the handler failed, the returned value should be 0.
static int yaml_sjis_write_handler(void* data, unsigned char* buffer, size_t size) {
	ST_yaml_sjis_write_handler_param* param = data;
	if(!size) { DIE(); }	//(size=0)で呼び出される事は無いはず。
	//出力データが残っている間…
	do {
		//出力データを1バイト、UTF-8⇒シフトJIS変換バッファに追加する。
		if(param->left >= 4) { DIE(); }
		param->buf[param->left++] = *buffer++;
		{
			//UTF-8文字のバイト数を判定する。
			int len = 1;
			if(param->buf[0] >= 0xC0) { len++; }
			if(param->buf[0] >= 0xE0) { len++; }
			if(param->buf[0] >= 0xF0) { len++; }
			//UTF-8⇒シフトJIS変換バッファの文字数と、UTF-8文字のバイト数が一致したら…
			if(param->left == len) {
				char s[2 + 1/*'\0'*/];
				//UTF-8⇒シフトJIS変換バッファを終端する。
				param->buf[len] = '\0';
				//UTF-8文字列(1文字)⇒シフトJIS文字列(1文字)変換を行う。
				len = Utf8ToShiftJisStr(param->buf, -1, s, 2 + 1/*'\0'*/);
				if((len < 1) || (len > 2)) { DIE(); }
				//シフトJIS文字列(1文字)を出力する。
				if(param->file) {
					if((int)fwrite(s, 1, len, param->file) != len) { DIE(); }
				} else {
					g_byte_array_append(param->barray, s, len);
				}
				//UTF-8⇒シフトJIS変換バッファを空に戻す。
				param->left = 0;
			}
		}
	} while(--size);
	return 1;	//On success, the handler should return 1. If the handler failed, the returned value should be 0.
}
/*--------------------------------------------------------------------------*/
static int yaml_document_add_scalar_SJIS(yaml_document_t* document, yaml_char_t* tag, yaml_char_t* value, int length/*-1可*/, yaml_scalar_style_t style) {
	int result;
	if(tag) { DIE(); }					//当モジュール内では全て(tag=NULL)で呼び出しているはず。もしtagを指定して呼び出すようになった場合は、tagもシフトJIS⇒UTF-8変換するように変更せよ。
	value = strndup_ShiftJisToUtf8(value, length/*-1可*/);	//値(value)のシフトJIS文字列を、一時的なUTF-8文字列に変換する。
	length = strlen(value);					//シフトJIS文字列⇒UTF-8文字列に変換した事によって、文字列のバイト数が変わった可能性が有るので、UTF-8文字列のバイト数を数え直す。	←←←←←忘れないで!!
	result = yaml_document_add_scalar(document, tag, value, length, style);
	free(value);						//一時的なUTF-8文字列を開放する。
	return result;
}
#define yaml_document_add_scalar yaml_document_add_scalar_SJIS //ここより下のyaml_document_add_scalarを全てyaml_document_add_scalar_SJISに置き換える。
#endif//USE_SJIS
/****************************************************************************
 *	document
 ****************************************************************************/
yaml_document_t* yaml_document_new() {
	yaml_document_t* document = malloc(sizeof(yaml_document_t));
	if(!document) { DIE(); }
	if(!yaml_document_initialize(document, NULL, NULL, NULL, 1/*start_implicit*/, 1/*end_implicit*/)) { DIE(); }
	return document;				//       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~これを指定しないとドキュメントの先頭と末尾に'---'が出力されてしまいます。普通は必要無いので読み易さのために出力しない事にしました。
}
/*--------------------------------------------------------------------------*/
//{{2016/06/21追加:yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
static int yaml_parser_load_subr(yaml_parser_t* parser, yaml_document_t* document) {
	int success = yaml_parser_load(parser, document);
	if(!success) {
//{{2016/09/04変更:64ビット版では、size_tの書式文字列に'%zd'を使用するように修正しました。
//		fprintf(stderr, "###yaml_parser_load()がエラーを返しました。\n");
//		fprintf(stderr, "parser->error               = %d\n", parser->error);
//		fprintf(stderr, "parser->problem             = %s\n", parser->problem ? parser->problem : "");
//		fprintf(stderr, "parser->problem_offset      = %d\n", parser->problem_offset);
//		fprintf(stderr, "parser->problem_value       = %d\n", parser->problem_value);
//		fprintf(stderr, "parser->problem_mark.index  = %d\n", parser->problem_mark.index);
//		fprintf(stderr, "parser->problem_mark.line   = %d\n", parser->problem_mark.line);
//		fprintf(stderr, "parser->problem_mark.column = %d\n", parser->problem_mark.column);
//		fprintf(stderr, "parser->context             = %s\n", parser->context ? parser->context : "");
//		fprintf(stderr, "parser->context_mark.index  = %d\n", parser->context_mark.index);
//		fprintf(stderr, "parser->context_mark.line   = %d\n", parser->context_mark.line);
//		fprintf(stderr, "parser->context_mark.column = %d\n", parser->context_mark.column);
//↓2016/09/04変更:64ビット版では、size_tの書式文字列に'%zd'を使用するように修正しました。
// * Sun Sep 04 21:41:17 JST 2016 Naoyuki Sawa
// - 64ビット版では、size_tの書式文字列に'%zd'を使用するように修正しました。
//   尚、32ビット版は、これまでと同じままにしました。
//   自作のfprintf()は長さ修飾子'z'に対応しているので(clipprnt.cのdoprnt()を参照)、32ビット版も64ビット版と同じでも構わないのですが、
//   gcc33.exeが警告を長さ修飾子'z'を知らないため警告を表示する事を回避するために、32ビット版はこれまでと同じままにする事にしました。
#ifndef _WIN64
		fprintf(stderr, "###yaml_parser_load()がエラーを返しました。\n");
		fprintf(stderr, "parser->error               = %d\n", parser->error);
		fprintf(stderr, "parser->problem             = %s\n", parser->problem ? parser->problem : "");
		fprintf(stderr, "parser->problem_offset      = %d\n", parser->problem_offset);
		fprintf(stderr, "parser->problem_value       = %d\n", parser->problem_value);
		fprintf(stderr, "parser->problem_mark.index  = %d\n", parser->problem_mark.index);
		fprintf(stderr, "parser->problem_mark.line   = %d\n", parser->problem_mark.line);
		fprintf(stderr, "parser->problem_mark.column = %d\n", parser->problem_mark.column);
		fprintf(stderr, "parser->context             = %s\n", parser->context ? parser->context : "");
		fprintf(stderr, "parser->context_mark.index  = %d\n", parser->context_mark.index);
		fprintf(stderr, "parser->context_mark.line   = %d\n", parser->context_mark.line);
		fprintf(stderr, "parser->context_mark.column = %d\n", parser->context_mark.column);
#else //_WIN64
		fprintf(stderr, "###yaml_parser_load()がエラーを返しました。\n");
		fprintf(stderr, "parser->error               = %d\n",  parser->error);
		fprintf(stderr, "parser->problem             = %s\n",  parser->problem ? parser->problem : "");
		fprintf(stderr, "parser->problem_offset      = %zd\n", parser->problem_offset);
		fprintf(stderr, "parser->problem_value       = %d\n",  parser->problem_value);
		fprintf(stderr, "parser->problem_mark.index  = %zd\n", parser->problem_mark.index);
		fprintf(stderr, "parser->problem_mark.line   = %zd\n", parser->problem_mark.line);
		fprintf(stderr, "parser->problem_mark.column = %zd\n", parser->problem_mark.column);
		fprintf(stderr, "parser->context             = %s\n",  parser->context ? parser->context : "");
		fprintf(stderr, "parser->context_mark.index  = %zd\n", parser->context_mark.index);
		fprintf(stderr, "parser->context_mark.line   = %zd\n", parser->context_mark.line);
		fprintf(stderr, "parser->context_mark.column = %zd\n", parser->context_mark.column);
#endif//_WIN64
//}}2016/09/04変更:64ビット版では、size_tの書式文字列に'%zd'を使用するように修正しました。
	}
	return success;
}
//}}2016/06/21追加:yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
yaml_document_t* yaml_document_load(const char* filename) {
	yaml_document_t* document = malloc(sizeof(yaml_document_t));
	if(!document) { DIE(); }
	{
		FILE* file = fopen(filename, "r");
		if(!file) { DIE(); }
		{
			yaml_parser_t parser;
			if(!yaml_parser_initialize(&parser)) { DIE(); }
#ifndef USE_SJIS
			yaml_parser_set_input_file(&parser, file);
#else //USE_SJIS
			{
				ST_yaml_sjis_read_handler_param param;
				memset(&param, 0, sizeof param);
				param.file = file;
				yaml_parser_set_input(&parser, yaml_sjis_read_handler, &param);
			}
#endif//USE_SJIS
//{{2016/06/21変更:yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
//			if(!yaml_parser_load(&parser, document)) { DIE(); }
//↓2016/06/21変更:yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
			if(!yaml_parser_load_subr(&parser, document)) { DIE(); }
//}}2016/06/21変更:yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
			yaml_parser_delete(&parser);
		}
		fclose(file);
	}
	return document;
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
yaml_document_t* yaml_document_parse(const char* string) {
	yaml_document_t* document = malloc(sizeof(yaml_document_t));
	if(!document) { DIE(); }
	{
		yaml_parser_t parser;
		if(!yaml_parser_initialize(&parser)) { DIE(); }
#ifndef USE_SJIS
		yaml_parser_set_input_string(&parser, string, strlen(string));
#else //USE_SJIS
		{
			ST_yaml_sjis_read_handler_param param;
			memset(&param, 0, sizeof param);
			param.string = string;
			yaml_parser_set_input(&parser, yaml_sjis_read_handler, &param);
		}
#endif//USE_SJIS
//{{2016/06/21変更:yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
//		if(!yaml_parser_load(&parser, document)) { DIE(); }
//↓2016/06/21変更:yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
		if(!yaml_parser_load_subr(&parser, document)) { DIE(); }
//}}2016/06/21変更:yaml_parser_load()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
		yaml_parser_delete(&parser);
	}
	return document;
}
/*--------------------------------------------------------------------------*/
void yaml_document_free(yaml_document_t* document) {
	yaml_document_delete(document);
	free(document);
}
/*--------------------------------------------------------------------------*/
//{{2016/06/21追加:yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
static int yaml_emitter_dump_subr(yaml_emitter_t* emitter, yaml_document_t* document) {
	int success = yaml_emitter_dump(emitter, document);
	if(!success) {
		fprintf(stderr, "###yaml_emitter_dump()がエラーを返しました。\n");
		fprintf(stderr, "emitter->error   = %d\n", emitter->error);
		fprintf(stderr, "emitter->problem = %s\n", emitter->problem ? emitter->problem : "");
	}
	return success;
}
//}}2016/06/21追加:yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
void yaml_document_save(yaml_document_t* document, const char* filename) {
	yaml_emitter_t emitter;
	if(!yaml_emitter_initialize(&emitter)) { DIE(); }
	{
		FILE* file = fopen(filename, "w");
		if(!file) { DIE(); }
		{
#ifndef USE_SJIS
			yaml_emitter_set_output_file(&emitter, file);
#else //USE_SJIS
		//{{2016/05/08変更:yaml_document_dump()のシフトJIS対応を改良しました。これまでは、日本語文字が'\uXXXX'形式で出力されてしまっており、シフトJISではあるもののYAMLファイルが読み辛い問題が有りました。今回の改良により、日本語文字がそのままシフトJISコードで出力されるようになりました。
		//	{
		//		//【NOTE】シフトJIS対応版も、通常版と全く同じ実装で大丈夫です。
		//		// - ここでは、yaml_document_load()やyaml_document_parse()のような、変換フィルタを行う必要は有りません。
		//		//   LibYAMLは非ASCII文字を'\uXXXX'形式で出力するようなので、実質、ASCIIファイルとして出力されるからです。
		//		//   その後、読み込んだ時に、'\uXXXX'がLibYAML内部でUTF-8に復元され、その後、当モジュールのyaml_node_get_string()を使って値を取り出すと、シフトJISに戻ります。
		//		//   従って、アプリケーションの観点からは透過的にシフトJISで扱えます。
		//		// - 問題点としては、
		//		//   │yaml_path_set_string(d, "日本語", "key1");
		//		//   │yaml_document_save(d, "test.yml");	⇒{{2016/05/14コメント変更:既存のyaml_document_dump()をyaml_document_save()に変更し、新規にyaml_document_dump()を作成しました。yaml_document_save()がファイル出力用、yaml_document_dump()が文字列出力用となります。}}
		//		//   のようにしてYAMLファイルを作成した場合、YAMLファイルの内容は
		//		//   │key: "\u65E5\u672C\u8A9E"
		//		//   になってしまって、見た目に判りづらい事です。
		//		//   UTF-8文字が直接入っているわけではないので、ファイル見た目に判り辛い事以外は、シフトJISのファイルと見なして問題は有りません。
		//		//   つまり、プログラム処理上は、シフトJISファイルと見なして問題ありません。
		//		yaml_emitter_set_output_file(&emitter, file);
		//	}
		//↓2016/05/08変更:yaml_document_dump()のシフトJIS対応を改良しました。これまでは、日本語文字が'\uXXXX'形式で出力されてしまっており、シフトJISではあるもののYAMLファイルが読み辛い問題が有りました。今回の改良により、日本語文字がそのままシフトJISコードで出力されるようになりました。
			{
				ST_yaml_sjis_write_handler_param param;
				memset(&param, 0, sizeof param);
				param.file = file;
				yaml_emitter_set_unicode(&emitter, 1);	//Set if unescaped non-ASCII characters are allowed.	この設定をしておくとLibYAMLが日本語を'\uXXXX'に変換せずにそのままyaml_sjis_write_handlerへ引き渡す。
				yaml_emitter_set_output(&emitter, yaml_sjis_write_handler, &param);
			}
		//}}2016/05/08変更:yaml_document_dump()のシフトJIS対応を改良しました。これまでは、日本語文字が'\uXXXX'形式で出力されてしまっており、シフトJISではあるもののYAMLファイルが読み辛い問題が有りました。今回の改良により、日本語文字がそのままシフトJISコードで出力されるようになりました。
#endif//USE_SJIS
			if(!yaml_emitter_open(&emitter)) { DIE(); }
//{{2016/06/21変更:yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
//			if(!yaml_emitter_dump(&emitter, document)) { DIE(); }	//yaml_emitter_dump()はyaml_document_delete()の効果も持っている。yaml_emitter_dump()が処理を返した時点でdocumentはもう無効になっている事に注意せよ。
//↓2016/06/21変更:yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
			if(!yaml_emitter_dump_subr(&emitter, document)) { DIE(); }	//yaml_emitter_dump()はyaml_document_delete()の効果も持っている。yaml_emitter_dump()が処理を返した時点でdocumentはもう無効になっている事に注意せよ。
//}}2016/06/21変更:yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
			if(!yaml_emitter_close(&emitter)) { DIE(); }
		}
		fclose(file);
	}
	yaml_emitter_delete(&emitter);
	free(document);								//yaml_document_save(),yaml_document_dump()はyaml_document_free()の効果も兼ねる事にした。documentはもう無効でありここでメモリを開放しないと開放するタイミングが無いから。
}
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
char* yaml_document_dump(yaml_document_t* document) {
	char* string;
	yaml_emitter_t emitter;
	if(!yaml_emitter_initialize(&emitter)) { DIE(); }
	{
		GByteArray* barray = g_byte_array_new();
		{
#ifndef USE_SJIS
			DIE();	//yaml_emitter_set_output_string(&emitter, output, size, &size_written);	⇒非シフトJISバージョンは未実装です。yaml_emitter_set_output_string()後にyaml_emitter_dump()を呼び出し、出力バッファが不足していた場合、yaml_emitter_dump()は失敗するにもかかわらず、成功した時と同様にドキュメントは破棄されるようです。つまり、'成功するまでバッファを増やしながらリトライする'ような使い方が出来ません。最初に十分大きなバッファを設定して一度で成功させるしかなく、万一それでも不足した場合はドキュメントの内容を取り戻す手段は有りません。(欠陥仕様だと思います…)
#else //USE_SJIS
			{
				ST_yaml_sjis_write_handler_param param;
				memset(&param, 0, sizeof param);
				param.barray = barray;
				yaml_emitter_set_unicode(&emitter, 1);	//Set if unescaped non-ASCII characters are allowed.	この設定をしておくとLibYAMLが日本語を'\uXXXX'に変換せずにそのままyaml_sjis_write_handlerへ引き渡す。
				yaml_emitter_set_output(&emitter, yaml_sjis_write_handler, &param);
			}
#endif//USE_SJIS
			if(!yaml_emitter_open(&emitter)) { DIE(); }
//{{2016/06/21変更:yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
//			if(!yaml_emitter_dump(&emitter, document)) { DIE(); }	//yaml_emitter_dump()はyaml_document_delete()の効果も持っている。yaml_emitter_dump()が処理を返した時点でdocumentはもう無効になっている事に注意せよ。
//↓2016/06/21変更:yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
			if(!yaml_emitter_dump_subr(&emitter, document)) { DIE(); }	//yaml_emitter_dump()はyaml_document_delete()の効果も持っている。yaml_emitter_dump()が処理を返した時点でdocumentはもう無効になっている事に注意せよ。
//}}2016/06/21変更:yaml_emitter_dump()がエラーを返した場合、エラー停止,又は,例外を投入する前に、エラー内容を表示するようにしました。
			if(!yaml_emitter_close(&emitter)) { DIE(); }
		}
	//不要	{ char c = '\0'; g_byte_array_append(barray, &c, 1); }		//当ライブラリのgarray.cの実装では、GByteArrayも常にゼロ終端されているので、明示的に終端のヌル文字を追加する必要は無い。オリジナル版のGByteArrayを使う場合は、明示的に終端のヌル文字を追加する必要が有るので注意せよ。
		string = g_byte_array_free(barray, 0/*free_segment*/);		//GByteArrayの構造体を開放し、バッファは開放せずに取得する。
	}
	yaml_emitter_delete(&emitter);
	free(document);								//yaml_document_save(),yaml_document_dump()はyaml_document_free()の効果も兼ねる事にした。documentはもう無効でありここでメモリを開放しないと開放するタイミングが無いから。
	return string;	//戻り値の文字列は呼び出し側でfree()で開放して下さい。
}
/*--------------------------------------------------------------------------*/
//yaml_node_t* yaml_document_get_root_node(yaml_document_t* document);	⇒yaml.hで定義されています。
/*--------------------------------------------------------------------------*/
yaml_node_type_t yaml_document_get_root_type(yaml_document_t* document) {
	return yaml_node_get_type(yaml_document_get_root_node(document));
}
/*--------------------------------------------------------------------------*/
yaml_mapping_t* yaml_document_get_root_mapping(yaml_document_t* document) {
	return yaml_node_get_mapping(yaml_document_get_root_node(document));
}
/*--------------------------------------------------------------------------*/
yaml_sequence_t* yaml_document_get_root_sequence(yaml_document_t* document) {
	return yaml_node_get_sequence(yaml_document_get_root_node(document));
}
/*--------------------------------------------------------------------------*/
const char* yaml_document_get_root_string(yaml_document_t* document) {
	return yaml_node_get_string(yaml_document_get_root_node(document));
}
/*--------------------------------------------------------------------------*/
double yaml_document_get_root_number(yaml_document_t* document) {
	return yaml_node_get_number(yaml_document_get_root_node(document));
}
/*--------------------------------------------------------------------------*/
int yaml_document_get_root_boolean(yaml_document_t* document) {
	return yaml_node_get_boolean(yaml_document_get_root_node(document));
}
/****************************************************************************
 *	node
 ****************************************************************************/
yaml_node_type_t yaml_node_get_type(yaml_node_t* node) {
	if(!node) { DIE(); }
	return node->type;
}
/*--------------------------------------------------------------------------*/
yaml_mapping_t* yaml_node_get_mapping(yaml_node_t* node) {
	if(yaml_node_get_type(node) != YAML_MAPPING_NODE) { DIE(); }
	return (yaml_mapping_t*)node;
}
/*--------------------------------------------------------------------------*/
yaml_sequence_t* yaml_node_get_sequence(yaml_node_t* node) {
	if(yaml_node_get_type(node) != YAML_SEQUENCE_NODE) { DIE(); }
	return (yaml_sequence_t*)node;
}
/*--------------------------------------------------------------------------*/
const char* yaml_node_get_string(yaml_node_t* node) {
	if(yaml_node_get_type(node) != YAML_SCALAR_NODE) { DIE(); }
#ifndef USE_SJIS
	return node->data.scalar.value;
#else //USE_SJIS
	{
		//UTF-8文字列を取得する。
		const char* s = node->data.scalar.value;
		//UTF-8文字列を、一時的なシフトJIS文字列に変換する。
		char* t = strdup_Utf8ToShiftJis(s);
		//UTF-8文字列のバイト並びと、シフトJIS文字列のバイト並びが、違うならば…
		if(strcmp(s, t)) {
			//インターン化したシフトJIS文字列を取得する。
			s = intern_string(t);
		//UTF-8文字列のバイト並びと、シフトJIS文字列のバイト並びが、同じならば…
		} else {
			//インターン化せずに、元のUTF-8文字列をそのまま返す。(メモリ節約のためです)
			/** no job **/
		}
		//一時的なシフトJIS文字列を開放する。
		free(t);
		//インターン化したシフトJIS文字列,又は,元のUTF-8文字列を返す。
		return s;
	}
#endif//USE_SJIS
}
/*--------------------------------------------------------------------------*/
double yaml_node_get_number(yaml_node_t* node) {
	const char* string;
	double number;
	char*  endptr;
	string = yaml_node_get_string(node);
	if(string[0] == '\0') { DIE(); }
	number = strtod(string, &endptr);
	if(endptr[0] != '\0') { DIE(); }
	return number;
}
/*--------------------------------------------------------------------------*/
int yaml_node_get_boolean(yaml_node_t* node) {
	const char* string = yaml_node_get_string(node);
	if(!strcasecmp(string, "true" )) { return 1; }
	if(!strcasecmp(string, "false")) { return 0; }
	DIE();
}
/****************************************************************************
 *	mapping
 ****************************************************************************/
int yaml_mapping_get_count(yaml_document_t* document, yaml_mapping_t* mapping) {	//当関数は引数'document'を参照しませんが、他の関数と引数を揃える方が判り易いので指定する事にしました。
	yaml_node_pair_t* start = ((yaml_node_t*)mapping)->data.mapping.pairs.start;
	yaml_node_pair_t* top   = ((yaml_node_t*)mapping)->data.mapping.pairs.top;	//有効な要素の終端は'end'ではなく'top'である事に注意せよ。'end'は(未使用の要素も含めて)バッファの終端でありアプリケーションが意識する必要は無い。
	int count = top - start;
	if(count < 0) { DIE(); }
	return count;
}
/*--------------------------------------------------------------------------*/
const char* yaml_mapping_get_key(yaml_document_t* document, yaml_mapping_t* mapping, int index) {
	int count = yaml_mapping_get_count(document, mapping);
	if((unsigned)index >= (unsigned)count) { DIE(); }
	return yaml_node_get_string(yaml_document_get_node(document, (((yaml_node_t*)mapping)->data.mapping.pairs.start)[index].key));
}
/*--------------------------------------------------------------------------*/
yaml_node_t* yaml_mapping_get_node(yaml_document_t* document, yaml_mapping_t* mapping, const char* key) {
	yaml_node_pair_t* start = ((yaml_node_t*)mapping)->data.mapping.pairs.start;
	yaml_node_pair_t* top   = ((yaml_node_t*)mapping)->data.mapping.pairs.top;	//有効な要素の終端は'end'ではなく'top'である事に注意せよ。'end'は(未使用の要素も含めて)バッファの終端でありアプリケーションが意識する必要は無い。
	yaml_node_pair_t* pair;
	for(pair = start; pair < top; pair++) {
		yaml_node_t* key_node = yaml_document_get_node(document, pair->key);
		const char* key_str = yaml_node_get_string(key_node);
		if(!strcmp(key_str, key)) {
			yaml_node_t* value_node = yaml_document_get_node(document, pair->value);
			return value_node;
		}
	}
	DIE();
}
/*--------------------------------------------------------------------------*/
yaml_node_type_t yaml_mapping_get_type(yaml_document_t* document, yaml_mapping_t* mapping, const char* key) {
	return yaml_node_get_type(yaml_mapping_get_node(document, mapping, key));
}
/*--------------------------------------------------------------------------*/
yaml_mapping_t* yaml_mapping_get_mapping(yaml_document_t* document, yaml_mapping_t* mapping, const char* key) {
	return yaml_node_get_mapping(yaml_mapping_get_node(document, mapping, key));
}
/*--------------------------------------------------------------------------*/
yaml_sequence_t* yaml_mapping_get_sequence(yaml_document_t* document, yaml_mapping_t* mapping, const char* key) {
	return yaml_node_get_sequence(yaml_mapping_get_node(document, mapping, key));
}
/*--------------------------------------------------------------------------*/
const char* yaml_mapping_get_string(yaml_document_t* document, yaml_mapping_t* mapping, const char* key) {
	return yaml_node_get_string(yaml_mapping_get_node(document, mapping, key));
}
/*--------------------------------------------------------------------------*/
double yaml_mapping_get_number(yaml_document_t* document, yaml_mapping_t* mapping, const char* key) {
	return yaml_node_get_number(yaml_mapping_get_node(document, mapping, key));
}
/*--------------------------------------------------------------------------*/
int yaml_mapping_get_boolean(yaml_document_t* document, yaml_mapping_t* mapping, const char* key) {
	return yaml_node_get_boolean(yaml_mapping_get_node(document, mapping, key));
}
/****************************************************************************
 *	sequence
 ****************************************************************************/
int yaml_sequence_get_count(yaml_document_t* document, yaml_sequence_t* sequence) {	//当関数は引数'document'を参照しませんが、他の関数と引数を揃える方が判り易いので指定する事にしました。
	yaml_node_item_t* start = ((yaml_node_t*)sequence)->data.sequence.items.start;
	yaml_node_item_t* top   = ((yaml_node_t*)sequence)->data.sequence.items.top;	//有効な要素の終端は'end'ではなく'top'である事に注意せよ。'end'は(未使用の要素も含めて)バッファの終端でありアプリケーションが意識する必要は無い。
	int count = top - start;
	if(count < 0) { DIE(); }
	return count;
}
/*--------------------------------------------------------------------------*/
yaml_node_t* yaml_sequence_get_node(yaml_document_t* document, yaml_sequence_t* sequence, int index) {
	int count = yaml_sequence_get_count(document, sequence);
	if((unsigned)index >= (unsigned)count) { DIE(); }
	return yaml_document_get_node(document, (((yaml_node_t*)sequence)->data.sequence.items.start)[index]);
}
/*--------------------------------------------------------------------------*/
yaml_node_type_t yaml_sequence_get_type(yaml_document_t* document, yaml_sequence_t* sequence, int index) {
	return yaml_node_get_type(yaml_sequence_get_node(document, sequence, index));
}
/*--------------------------------------------------------------------------*/
yaml_mapping_t* yaml_sequence_get_mapping(yaml_document_t* document, yaml_sequence_t* sequence, int index) {
	return yaml_node_get_mapping(yaml_sequence_get_node(document, sequence, index));
}
/*--------------------------------------------------------------------------*/
yaml_sequence_t* yaml_sequence_get_sequence(yaml_document_t* document, yaml_sequence_t* sequence, int index) {
	return yaml_node_get_sequence(yaml_sequence_get_node(document, sequence, index));
}
/*--------------------------------------------------------------------------*/
const char* yaml_sequence_get_string(yaml_document_t* document, yaml_sequence_t* sequence, int index) {
	return yaml_node_get_string(yaml_sequence_get_node(document, sequence, index));
}
/*--------------------------------------------------------------------------*/
double yaml_sequence_get_number(yaml_document_t* document, yaml_sequence_t* sequence, int index) {
	return yaml_node_get_number(yaml_sequence_get_node(document, sequence, index));
}
/*--------------------------------------------------------------------------*/
int yaml_sequence_get_boolean(yaml_document_t* document, yaml_sequence_t* sequence, int index) {
	return yaml_node_get_boolean(yaml_sequence_get_node(document, sequence, index));
}
/****************************************************************************
 *	パス文字列による読み出し	pathはnodeからの相対パスです。		nodeにNULLが指定されたら、ルートノードからの相対パス(=ドキュメントの絶対パス)と見なします。つまりnodeにNULLを指定すれば、「パス文字列による書き込み」と同様の使い方が出来ます。
 ****************************************************************************/
yaml_node_t* yaml_path_get_node_f(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, ...) {
	yaml_node_t* retval;
	va_list ap;
	va_start(ap, fmt);
	retval = yaml_path_get_node_g(document, node, fmt, ap);
	va_end(ap);
	return retval;
}
yaml_node_t* yaml_path_get_node_g(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	return yaml_path_get_node(document, node, path);
}
yaml_node_t* yaml_path_get_node(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* path) {
	//nodeにNULLが指定されたら、ルートノードからの相対パス(=ドキュメントの絶対パス)と見なします。
	if(!node) { node = yaml_document_get_root_node(document); }
	//パス文字列の最初の文字が'.'ならば、'.'を読み飛ばす。
	if(*path == '.') { path++; }						//'.'を読み飛ばす。
	//パス文字列が空でなければ…
	if(*path) {
		//パス文字列の最初の文字が'['ならば、このノードはシーケンスであると見なして、インデクスアクセスを行う。
		if(*path == '[') {
			path++;							//'['を読み飛ばす。
			for(;;) {
				int index, c;
				char* endptr;
				if(!isdigit(*path)) { DIE(); }			//'[',又は,','の直後の文字が数字でなければエラー。
				index = strtoul(path, &endptr, 0);		//インデクスを取得する。
				node = yaml_sequence_get_node(document, yaml_node_get_sequence(node), index);	//node = ((sequence)node)[index]
				path = endptr;					//インデクスを読み飛ばす。
				c = *path++;					//インデクスの終端文字を取得し、読み飛ばす。
				if(c == ']') { break; }				//インデクスの終端文字が']'だったならば、ループを抜ける。
				if(c != ',') { DIE(); }				//インデクスの終端文字が','だったならば、次のシーケンスに対してインデクスアクセスを継続する。']'でも','でもなかったらエラー。
			}
		//パス文字列の最初の文字が'['以外ならば、このノードはマッピングであると見なして、キーアクセスを行う。
		} else {
			char* key = strcompress(path, (char**)&path, ".[");	//'.'が出現するまで,又は,'['が出現するまで,又は,文字列の終端までをキーとして切り出す。	strcompress()はマルチバイト対応版しか有りません。(2016/05/25〜)
			SEH_try {
				node = yaml_mapping_get_node(document, yaml_node_get_mapping(node), key);	//node = ((mapping)node).key
			} SEH_catch(YamlException) {
				free(key);	//┬上のyaml_mapping_get_node()が例外を投入した場合(=ノードが存在しなかった場合)は、strcompress()で作成した一時的な文字列を開放してから、例外を再投入する。
				SEH_throw_last;	//┘
			} SEH_end
			free(key);
		}
		//インデクスアクセス,又は,キーアクセスで取得したノードに対して、残りのパス文字列による読み出しを行う。
		node = yaml_path_get_node(document, node, path);
	}
	return node;	//パス文字列が空だった場合は、引数nodeをそのまま返す。
}
/*--------------------------------------------------------------------------*/
yaml_node_type_t yaml_path_get_type_f(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, ...) {
	yaml_node_type_t retval;
	va_list ap;
	va_start(ap, fmt);
	retval = yaml_path_get_type_g(document, node, fmt, ap);
	va_end(ap);
	return retval;
}
yaml_node_type_t yaml_path_get_type_g(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	return yaml_path_get_type(document, node, path);
}
yaml_node_type_t yaml_path_get_type(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* path) {
	return yaml_node_get_type(yaml_path_get_node(document, node, path));
}
/*--------------------------------------------------------------------------*/
yaml_mapping_t* yaml_path_get_mapping_f(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, ...) {
	yaml_mapping_t* retval;
	va_list ap;
	va_start(ap, fmt);
	retval = yaml_path_get_mapping_g(document, node, fmt, ap);
	va_end(ap);
	return retval;
}
yaml_mapping_t* yaml_path_get_mapping_g(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	return yaml_path_get_mapping(document, node, path);
}
yaml_mapping_t* yaml_path_get_mapping(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* path) {
	return yaml_node_get_mapping(yaml_path_get_node(document, node, path));
}
/*--------------------------------------------------------------------------*/
yaml_sequence_t* yaml_path_get_sequence_f(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, ...) {
	yaml_sequence_t* retval;
	va_list ap;
	va_start(ap, fmt);
	retval = yaml_path_get_sequence_g(document, node, fmt, ap);
	va_end(ap);
	return retval;
}
yaml_sequence_t* yaml_path_get_sequence_g(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	return yaml_path_get_sequence(document, node, path);
}
yaml_sequence_t* yaml_path_get_sequence(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* path) {
	return yaml_node_get_sequence(yaml_path_get_node(document, node, path));
}
/*--------------------------------------------------------------------------*/
const char* yaml_path_get_string_f(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, ...) {
	const char* retval;
	va_list ap;
	va_start(ap, fmt);
	retval = yaml_path_get_string_g(document, node, fmt, ap);
	va_end(ap);
	return retval;
}
const char* yaml_path_get_string_g(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	return yaml_path_get_string(document, node, path);
}
const char* yaml_path_get_string(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* path) {
	return yaml_node_get_string(yaml_path_get_node(document, node, path));
}
/*--------------------------------------------------------------------------*/
double yaml_path_get_number_f(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, ...) {
	double retval;
	va_list ap;
	va_start(ap, fmt);
	retval = yaml_path_get_number_g(document, node, fmt, ap);
	va_end(ap);
	return retval;
}
double yaml_path_get_number_g(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	return yaml_path_get_number(document, node, path);
}
double yaml_path_get_number(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* path) {
	return yaml_node_get_number(yaml_path_get_node(document, node, path));
}
/*--------------------------------------------------------------------------*/
int yaml_path_get_boolean_f(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, ...) {
	int retval;
	va_list ap;
	va_start(ap, fmt);
	retval = yaml_path_get_boolean_g(document, node, fmt, ap);
	va_end(ap);
	return retval;
}
int yaml_path_get_boolean_g(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	return yaml_path_get_boolean(document, node, path);
}
int yaml_path_get_boolean(yaml_document_t* document, yaml_node_t* node/*NULL可*/, const char* path) {
	return yaml_node_get_boolean(yaml_path_get_node(document, node, path));
}
/****************************************************************************
 *	パス文字列による書き込み	pathはdocumentからの絶対パスです。	「パス文字列による書き込み」の関数を呼び出すとLibYAML内部でメモリの再割り当てが行われる可能性が有るので、それまでに取得したノードのポインタは無効になる事に注意せよ。「パス文字列による書き込み」の関数の呼び出しを跨いでは、document以外のポインタを保持しない事が望ましい。従って「パス文字列による書き込み」は常にドキュメントからの絶対パスで指定する仕様とした。「パス文字列による読み出し」のようにノード相対パス指定は出来ない仕様とした。
 ****************************************************************************/
//□LibYAMLの書き込み関数の使い方について下記のソースを参考にさせて頂きました:
//│「GitHub - jeffreyolchovy/todo」
//│(https://github.com/jeffreyolchovy/todo/blob/master/src/serialize.c)
/*--------------------------------------------------------------------------*/
void yaml_path_set_string_f(yaml_document_t* document, const char* value, const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	yaml_path_set_string_g(document, value, fmt, ap);
	va_end(ap);
}
void yaml_path_set_string_g(yaml_document_t* document, const char* value, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	yaml_path_set_string(document, value, path);
}
void yaml_path_set_string(yaml_document_t* document, const char* value, const char* path) {
	int   last_node_id =    0;	//最後のノードのid	0ならば無効					┬last_node_id==0ならば、last_index==-1,かつ,last_key==NULLである。
	int   last_index   =   -1;	//最後のインデクス	-1ならば無効	┬少なくとも一方は無効である。	┘last_node_id!=0ならば、last_index!=-1,又は,last_key!=NULLである。
	char* last_key     = NULL;	//最後のキー		NULLならば無効	┘
	SEH_try {
		for(;;) {
			yaml_node_t* node;
			//パス文字列の最初の文字が'.'ならば、'.'を読み飛ばす。
			if(*path == '.') { path++; }					//'.'を読み飛ばす。
			//パス文字列が空でなければ…
			if(*path) {
				//パス文字列の最初の文字が'['ならば、このノードはシーケンスであると見なして、インデクスアクセスを行う。
				if(*path == '[') {
					path++;						//'['を読み飛ばす。
					for(;;) {
						int index, c;
						char* endptr;
						if(!isdigit(*path)) { DIE(); }		//'[',又は,','の直後の文字が数字でなければエラー。
						index = strtoul(path, &endptr, 0);	//インデクスを取得する。
						{
							int sequence_id;
							//最後のノードが有れば…
							if(last_node_id) {
								//最後のノードを取得する。
								node = yaml_document_get_node(document, last_node_id);
								//最後のノードがシーケンスならば…
								if((last_index != -1) && !last_key) {
									//最後のノードが、本当にシーケンスである事を確認する。
									yaml_node_get_sequence(node);	//戻り値は不要	もしここで停止したら、当モジュールのバグです。
									{
										//要素数を取得する。
										int count = node->data.sequence.items.top - node->data.sequence.items.start;
										//インデクスが要素数未満ならば…
										if(last_index < count) {
											//既存のシーケンスを取得する。
											sequence_id = node->data.sequence.items.start[last_index];
											//既存のシーケンスが、本当にシーケンスである事を確認する。
											yaml_node_get_sequence(yaml_document_get_node(document, sequence_id));	//戻り値は不要	もしここで停止したら、呼び出し側のバグの可能性が高い。
										//インデクスが要素数と同じならば…
										} else if(last_index == count) {
											//新規のシーケンスを作成する。
											sequence_id = yaml_document_add_sequence(document, NULL, YAML_ANY_SEQUENCE_STYLE);		node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
											if(!sequence_id) { DIE(); }
											//既存の要素の末尾に、新規のシーケンスを追加する。
											if(!yaml_document_append_sequence_item(document, last_node_id, sequence_id)) { DIE(); }
										//インデクスが要素数よりも大きければ…
										} else {
											DIE();	//インデクスが不正。要素を追加出来る位置は、既存の要素の末尾だけです。
										}
									}
								//最後のノードがマッピングならば…
								} else if(last_key && (last_index == -1)) {
									//最後のノードが、本当にマッピングである事を確認する。
									yaml_node_get_mapping(node);	//戻り値は不要	もしここで停止したら、当モジュールのバグです。
									{
										//キーが既存のキーに一致するかを調べる。
										int i, count = node->data.mapping.pairs.top - node->data.mapping.pairs.start;
										for(i = 0; i < count; i++) {
											yaml_node_pair_t* pair = &node->data.mapping.pairs.start[i];
											yaml_node_t* key_node = yaml_document_get_node(document, pair->key);
											const char* key_str = yaml_node_get_string(key_node);
											if(!strcmp(key_str, last_key)) { break; }
										}
										//キーが既存のキーに一致したら…
										if(i < count) {
											//既存のシーケンスを取得する。
											sequence_id = node->data.mapping.pairs.start[i].value;
											//既存のシーケンスが、本当にシーケンスである事を確認する。
											yaml_node_get_sequence(yaml_document_get_node(document, sequence_id));	//戻り値は不要	もしここで停止したら、呼び出し側のバグの可能性が高い。
										//キーが既存のキーに一致しなければ…
										} else {
											//新規のキーを作成する。
											// - yaml_document_add_scalar()のlength引数に(-1)を指定すると、yaml_document_add_scalar()が自動的に文字列の長さを求めてくれる。/yaml/api.cのyaml_document_add_scalar()の実装を参照せよ。
											int key_id = yaml_document_add_scalar(document, NULL, last_key, -1, YAML_ANY_SCALAR_STYLE);	node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
											if(!key_id) { DIE(); }
											//新規のシーケンスを作成する。
											sequence_id = yaml_document_add_sequence(document, NULL, YAML_ANY_SEQUENCE_STYLE);		node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
											if(!sequence_id) { DIE(); }
											//既存の要素の末尾に、新規のシーケンスを追加する。
											if(!yaml_document_append_mapping_pair(document, last_node_id, key_id, sequence_id)) { DIE(); }
										}
									}
								} else {
									DIE();	//ここで停止したら当モジュールのバグです。
								}
							//最後のノードが無ければ…
							} else {
								//ルートノードを取得する。
								node = yaml_document_get_root_node(document);
								//ルートノードが有れば…
								if(node) {
									//ルートノードはid=1に相当するノードであるはず。
									sequence_id = (node - document->nodes.start) + 1/*1ベース*/;
									if(sequence_id != 1) { DIE(); }	//ここで停止したら当モジュールのバグです。
									//ルートノードが、シーケンスである事を確認する。
									yaml_node_get_sequence(yaml_document_get_node(document, sequence_id));	//戻り値は不要	もしここで停止したら、呼び出し側のバグの可能性が高い。
								//ルートノードが無ければ…
								} else {
									//新規のシーケンスを作成する。
									sequence_id = yaml_document_add_sequence(document, NULL, YAML_ANY_SEQUENCE_STYLE);				node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
									if(!sequence_id) { DIE(); }
								}
							}
							//最後のノードのid,最後のインデクス,最後のキーを更新する。
							last_node_id	= sequence_id;	//新規のシーケンスを、最後のノードのidとして記憶する。
							last_index	= index;	//今回のインデクスを、最後のインデクスとして記憶する。
							free(last_key/*NULL可*/);	//┬最後のキーを無効とする。
							last_key	= NULL;		//┘
						}
						path = endptr;				//インデクスを読み飛ばす。
						c = *path++;				//インデクスの終端文字を取得し、読み飛ばす。
						if(c == ']') { break; }			//インデクスの終端文字が']'だったならば、ループを抜ける。
						if(c != ',') { DIE(); }			//インデクスの終端文字が','だったならば、次のシーケンスに対してインデクスアクセスを継続する。']'でも','でもなかったらエラー。
					}
				//パス文字列の最初の文字が'['以外ならば、このノードはマッピングであると見なして、キーアクセスを行う。
				} else {
					int mapping_id;
					//最後のノードが有れば…
					if(last_node_id) {
						//最後のノードを取得する。
						node = yaml_document_get_node(document, last_node_id);
						//最後のノードがシーケンスならば…
						if((last_index != -1) && !last_key) {
							//最後のノードが、本当にシーケンスである事を確認する。
							yaml_node_get_sequence(node);	//戻り値は不要	もしここで停止したら、当モジュールのバグです。
							{
								//要素数を取得する。
								int count = node->data.sequence.items.top - node->data.sequence.items.start;
								//インデクスが要素数未満ならば…
								if(last_index < count) {
									//既存のマッピングを取得する。
									mapping_id = node->data.sequence.items.start[last_index];
									//既存のマッピングが、本当にマッピングである事を確認する。
									yaml_node_get_mapping(yaml_document_get_node(document, mapping_id));	//戻り値は不要	もしここで停止したら、呼び出し側のバグの可能性が高い。
								//インデクスが要素数と同じならば…
								} else if(last_index == count) {
									//新規のマッピングを作成する。
									mapping_id = yaml_document_add_mapping(document, NULL, YAML_ANY_MAPPING_STYLE);					node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
									if(!mapping_id) { DIE(); }
									//既存の要素の末尾に、新規のマッピングを追加する。
									if(!yaml_document_append_sequence_item(document, last_node_id, mapping_id)) { DIE(); }
								//インデクスが要素数よりも大きければ…
								} else {
									DIE();	//インデクスが不正。要素を追加出来る位置は、既存の要素の末尾だけです。
								}
							}
						//最後のノードがマッピングならば…
						} else if(last_key && (last_index == -1)) {
							//最後のノードが、本当にマッピングである事を確認する。
							yaml_node_get_mapping(node);	//戻り値は不要	もしここで停止したら、当モジュールのバグです。
							{
								//キーが既存のキーに一致するかを調べる。
								int i, count = node->data.mapping.pairs.top - node->data.mapping.pairs.start;
								for(i = 0; i < count; i++) {
									yaml_node_pair_t* pair = &node->data.mapping.pairs.start[i];
									yaml_node_t* key_node = yaml_document_get_node(document, pair->key);
									const char* key_str = yaml_node_get_string(key_node);
									if(!strcmp(key_str, last_key)) { break; }
								}
								//キーが既存のキーに一致したら…
								if(i < count) {
									//既存のマッピングを取得する。
									mapping_id = node->data.mapping.pairs.start[i].value;
									//既存のマッピングが、本当にマッピングである事を確認する。
									yaml_node_get_mapping(yaml_document_get_node(document, mapping_id));	//戻り値は不要	もしここで停止したら、呼び出し側のバグの可能性が高い。
								//キーが既存のキーに一致しなければ…
								} else {
									//新規のキーを作成する。
									// - yaml_document_add_scalar()のlength引数に(-1)を指定すると、yaml_document_add_scalar()が自動的に文字列の長さを求めてくれる。/yaml/api.cのyaml_document_add_scalar()の実装を参照せよ。
									int key_id = yaml_document_add_scalar(document, NULL, last_key, -1, YAML_ANY_SCALAR_STYLE);			node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
									if(!key_id) { DIE(); }
									//新規のマッピングを作成する。
									mapping_id = yaml_document_add_mapping(document, NULL, YAML_ANY_MAPPING_STYLE);					node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
									if(!mapping_id) { DIE(); }
									//既存の要素の末尾に、新規のマッピングを追加する。
									if(!yaml_document_append_mapping_pair(document, last_node_id, key_id, mapping_id)) { DIE(); }
								}
							}
						} else {
							DIE();	//ここで停止したら当モジュールのバグです。
						}
					//最後のノードが無ければ…
					} else {
						//ルートノードを取得する。
						node = yaml_document_get_root_node(document);
						//ルートノードが有れば…
						if(node) {
							//ルートノードはid=1に相当するノードであるはず。
							mapping_id = (node - document->nodes.start) + 1/*1ベース*/;
							if(mapping_id != 1) { DIE(); }	//ここで停止したら当モジュールのバグです。
							//ルートノードが、マッピングである事を確認する。
							yaml_node_get_mapping(yaml_document_get_node(document, mapping_id));	//戻り値は不要	もしここで停止したら、呼び出し側のバグの可能性が高い。
						//ルートノードが無ければ…
						} else {
							//新規のマッピングを作成する。
							mapping_id = yaml_document_add_mapping(document, NULL, YAML_ANY_MAPPING_STYLE);							node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
							if(!mapping_id) { DIE(); }
						}
					}
					//最後のノードのid,最後のインデクス,最後のキーを更新する。
					last_node_id	= mapping_id;					//新規のマッピングを、最後のノードのidとして記憶する。
					last_index	= -1;						//最後のインデクスを無効とする。
					free(last_key/*NULL可*/);					//┬今回のキーを、最後のキーとして記憶する。
					last_key	= strcompress(path, (char**)&path, ".[");	//┘	//'.'が出現するまで,又は,'['が出現するまで,又は,文字列の終端までをキーとして切り出す。	strcompress()はマルチバイト対応版しか有りません。(2016/05/25〜)
				}
			//パス文字列が空ならば…
			} else {
				int scalar_id;
				//最後のノードが有れば…
				if(last_node_id) {
					//最後のノードを取得する。
					node = yaml_document_get_node(document, last_node_id);
					//最後のノードがシーケンスならば…
					if((last_index != -1) && !last_key) {
						//最後のノードが、本当にシーケンスである事を確認する。
						yaml_node_get_sequence(node);	//戻り値は不要	もしここで停止したら、当モジュールのバグです。
						{
							//要素数を取得する。
							int count = node->data.sequence.items.top - node->data.sequence.items.start;
							//インデクスが要素数未満ならば…
							if(last_index < count) {
								DIE();	//既存の要素を書き換える事は出来ない事にしました。もし書き換える事が出来るように場合は処理を追加して下さい。
							//インデクスが要素数と同じならば…
							} else if(last_index == count) {
								//新規のスカラーを作成する。
								// - yaml_document_add_scalar()のlength引数に(-1)を指定すると、yaml_document_add_scalar()が自動的に文字列の長さを求めてくれる。/yaml/api.cのyaml_document_add_scalar()の実装を参照せよ。
								scalar_id = yaml_document_add_scalar(document, NULL, (char*)value, -1, YAML_ANY_SCALAR_STYLE);				node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
								if(!scalar_id) { DIE(); }
								//既存の要素の末尾に、新規のスカラーを追加する。
								if(!yaml_document_append_sequence_item(document, last_node_id, scalar_id)) { DIE(); }
							//インデクスが要素数よりも大きければ…
							} else {
								DIE();	//インデクスが不正。要素を追加出来る位置は、既存の要素の末尾だけです。
							}
						}
					//最後のノードがマッピングならば…
					} else if(last_key && (last_index == -1)) {
						//最後のノードが、本当にマッピングである事を確認する。
						yaml_node_get_mapping(node);	//戻り値は不要	もしここで停止したら、当モジュールのバグです。
						{
							//キーが既存のキーに一致するかを調べる。
							int i, count = node->data.mapping.pairs.top - node->data.mapping.pairs.start;
							for(i = 0; i < count; i++) {
								yaml_node_pair_t* pair = &node->data.mapping.pairs.start[i];
								yaml_node_t* key_node = yaml_document_get_node(document, pair->key);
								const char* key_str = yaml_node_get_string(key_node);
								if(!strcmp(key_str, last_key)) { break; }
							}
							//キーが既存のキーに一致したら…
							if(i < count) {
								DIE();	//既存の要素を書き換える事は出来ない事にしました。もし書き換える事が出来るように場合は処理を追加して下さい。
							//キーが既存のキーに一致しなければ…
							} else {
								//新規のキーを作成する。
								// - yaml_document_add_scalar()のlength引数に(-1)を指定すると、yaml_document_add_scalar()が自動的に文字列の長さを求めてくれる。/yaml/api.cのyaml_document_add_scalar()の実装を参照せよ。
								int key_id = yaml_document_add_scalar(document, NULL, last_key, -1, YAML_ANY_SCALAR_STYLE);				node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
								if(!key_id) { DIE(); }
								//新規のスカラーを作成する。
								// - yaml_document_add_scalar()のlength引数に(-1)を指定すると、yaml_document_add_scalar()が自動的に文字列の長さを求めてくれる。/yaml/api.cのyaml_document_add_scalar()の実装を参照せよ。
								scalar_id = yaml_document_add_scalar(document, NULL, (char*)value, -1, YAML_ANY_SCALAR_STYLE);				node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
								if(!scalar_id) { DIE(); }
								//既存の要素の末尾に、新規のシーケンスを追加する。
								if(!yaml_document_append_mapping_pair(document, last_node_id, key_id, scalar_id)) { DIE(); }
							}
						}
					}
				//最後のノードが無ければ…
				} else {
					//ドキュメントが空である事を確認する。
					if(yaml_document_get_root_node(document)) { DIE(); }
					//新規のスカラーを作成する。
					// - yaml_document_add_scalar()のlength引数に(-1)を指定すると、yaml_document_add_scalar()が自動的に文字列の長さを求めてくれる。/yaml/api.cのyaml_document_add_scalar()の実装を参照せよ。
					scalar_id = yaml_document_add_scalar(document, NULL, (char*)value, -1, YAML_ANY_SCALAR_STYLE);							node = NULL;	//メモリの再割り当てが行われた可能性が有るので、ここまでに取得したノードのポインタは無効になる事に注意せよ。
					if(!scalar_id) { DIE(); }
				}
				break;	//ここまで
			}
		}
	} SEH_catch(YamlException) {
		free(last_key);	//┬上のforループ内のいずれかの処理が例外を投入した場合は、strcompress()で作成した一時的な文字列を開放してから、例外を再投入する。
		SEH_throw_last;	//┘
	} SEH_end
	free(last_key/*NULL可*/);
}
/*--------------------------------------------------------------------------*/
void yaml_path_set_number_f(yaml_document_t* document, double value, const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	yaml_path_set_number_g(document, value, fmt, ap);
	va_end(ap);
}
void yaml_path_set_number_g(yaml_document_t* document, double value, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	yaml_path_set_number(document, value, path);
}
void yaml_path_set_number(yaml_document_t* document, double value, const char* path) {
	char* s = strdup_printf("%g", value);
	SEH_try {
		yaml_path_set_string(document, s, path);
	} SEH_catch(YamlException) {
		free(s);	//┬上のyaml_path_set_string()が例外を投入した場合は、strdup_printf()で作成した一時的な文字列を開放してから、例外を再投入する。
		SEH_throw_last;	//┘
	} SEH_end
	free(s);
}
/*--------------------------------------------------------------------------*/
void yaml_path_set_boolean_f(yaml_document_t* document, int value, const char* fmt, ...) {
	va_list ap;
	va_start(ap, fmt);
	yaml_path_set_boolean_g(document, value, fmt, ap);
	va_end(ap);
}
void yaml_path_set_boolean_g(yaml_document_t* document, int value, const char* fmt, va_list ap) {
	char path[256/*調整可*/];
	vsnprintf(path, ARRAY_SIZE(path), fmt, ap);
	yaml_path_set_boolean(document, value, path);
}
void yaml_path_set_boolean(yaml_document_t* document, int value, const char* path) {
	yaml_path_set_string(document, value ? "true" : "false", path);
}
/****************************************************************************
 *	使用例
 ****************************************************************************/
#if 0
─── サンプルデータ: invoice.yml ここから ───
#//【重要】日本語を使う場合はUTF-8形式で保存して下さい。シフトJIS形式で保存するとyaml_parser_load()がエラーになります。		⇒2016/05/01追記:'USE_SJIS'シンボルを定義すれば、シフトJIS形式で保存したファイルを読み込めるようになりました。
#//http://yaml.org/spec/1.2/spec.html「Example 2.27. Invoice」より:
invoice: 34843
date   : 2001-01-23
bill-to: &id001
    given  : Chris
    family : Dumars
    address:
        lines: |
            458 Walkman Dr.
            Suite #292
        city    : Royal Oak
        state   : MI
        postal  : 48046
ship-to: *id001
product:
    - sku         : BL394D
      quantity    : 4
      description : Basketball
      price       : 450.00
    - sku         : BL4438H
      quantity    : 1
      description : Super Hoop
      price       : 2392.00
tax  : 251.42
total: 4443.52
comments:
    Late afternoon is best.
    Backup contact is Nancy
    Billsmer @ 338-4338.
─── サンプルデータ: invoice.yml ここまで ───
//□ドキュメントの構造が未知である場合の使用例:
void dump(yaml_document_t* d, yaml_node_t* n, int indent);	//前方参照
void test1() {
	yaml_document_t* d = yaml_document_load("invoice.yml");
	yaml_node_t* n = yaml_document_get_root_node(d);
	dump(d, n, 0);
	yaml_document_free(d);
}
void dump(yaml_document_t* d, yaml_node_t* n, int indent) {
	yaml_sequence_t* s;
	yaml_mapping_t* m;
	yaml_node_t* n2;
	const char *v, *k;
	char* t;
    #ifdef  USE_SJIS	//実際にはアプリケーションのソースコードからは当モジュール内のUSE_SJISシンボル定義の有無は見えない事に注意して下さい。これはあくまでもサンプルです。以下同様です。
	char* u;
    #endif//USE_SJIS
	int i, c;
	switch(yaml_node_get_type(n)) {
	default:DIE();
	case YAML_SCALAR_NODE:
		v = yaml_node_get_string(n);
    #ifdef  USE_SJIS
		u = strdup_Utf8ToShiftJis(v);			//UTF-8⇒シフトJIS変換する。					⇒2016/05/01追記:'USE_SJIS'シンボルを定義すれば、この変換処理は不要になりました。
		t = strreplace(u, "\n", "\\n");			//読み易さのために改行コードをエスケープする。strescape()を使うと日本語までエスケープされて読みづらくなってしまうので改行コードだけエスケープする事にした。
    #else //USE_SJIS
		t = strreplace(v, "\n", "\\n");			//読み易さのために改行コードをエスケープする。strescape()を使うと日本語までエスケープされて読みづらくなってしまうので改行コードだけエスケープする事にした。
    #endif//USE_SJIS
		printf("%*s\"%s\"\n", indent, "", t);
		free(t);
    #ifdef  USE_SJIS
		free(u);					//								⇒2016/05/01追記:'USE_SJIS'シンボルを定義すれば、この変換処理は不要になりました。
    #endif//USE_SJIS
		break;
	case YAML_SEQUENCE_NODE:
		s = yaml_node_get_sequence(n);
		c = yaml_sequence_get_count(d, s);
		for(i = 0; i < c; i++) {
			printf("%*s-\n", indent, "");
			n2 = yaml_sequence_get_node(d, s, i);
			dump(d, n2, indent + 4/*調整可*/);
		}
		break;
	case YAML_MAPPING_NODE:
		m = yaml_node_get_mapping(n);
		c = yaml_mapping_get_count(d, m);
		for(i = 0; i < c; i++) {
			k = yaml_mapping_get_key(d, m, i);
    #ifdef  USE_SJIS
			u = strdup_Utf8ToShiftJis(k);		//UTF-8⇒シフトJIS変換する。					⇒2016/05/01追記:'USE_SJIS'シンボルを定義すれば、この変換処理は不要になりました。
			t = strreplace(u, "\n", "\\n");		//読み易さのために改行コードをエスケープする。strescape()を使うと日本語までエスケープされて読みづらくなってしまうので改行コードだけエスケープする事にした。
    #else //USE_SJIS
			t = strreplace(k, "\n", "\\n");		//読み易さのために改行コードをエスケープする。strescape()を使うと日本語までエスケープされて読みづらくなってしまうので改行コードだけエスケープする事にした。
    #endif//USE_SJIS
			printf("%*s%s:\n", indent, "", t);
			free(t);
    #ifdef  USE_SJIS
			free(u);				//								⇒2016/05/01追記:'USE_SJIS'シンボルを定義すれば、この変換処理は不要になりました。
    #endif//USE_SJIS
			n2 = yaml_mapping_get_node(d, m, k);
			dump(d, n2, indent + 4/*調整可*/);
		}
		break;
	}
}
//□ドキュメントの構造が既知である場合の使用例:
void test2() {
	yaml_document_t* d = yaml_document_load("invoice.yml");
	yaml_node_t* n = yaml_document_get_root_node(d);																				//{{2016/05/08追記:左記のコードはnode引数を明示していますが、ルートノードからの相対パスならばnode引数は省略可能になりました。}}
	//root -> bill-to -> address -> city                            ".bill-to.address.city"でも構いません。
	printf("bill-to address city = %s\n", yaml_path_get_string(d, n, "bill-to.address.city"));	//Royal Oak	日本語を使っていない事が判っていればUTF-8⇒シフトJIS変換を省略して構いません。			//{{2016/05/08追記:左記のコードはnode引数を明示していますが、ルートノードからの相対パスならばnode引数は省略可能になりました。}}
	//root -> product -> [1] -> price                              ".product[1].price"でも構いません。
	printf("2nd product's price = %f\n", yaml_path_get_number(d, n, "product[1].price"));		//2392.000000													//{{2016/05/08追記:左記のコードはnode引数を明示していますが、ルートノードからの相対パスならばnode引数は省略可能になりました。}}
	yaml_document_free(d);
}
//□多次元配列を「パス文字列による読み出し」の関数でアクセスする例:
void test3() {
	static const char sYml[]=
		"matrix:\n"
		"  - [11,12,13,14,15]\n"
		"  - [21,22,23,24,25]\n"
		"  - [31,32,33,34,35]\n"
		"  - [41,42,43,44,45]\n";
	yaml_document_t* d = yaml_document_parse(sYml);
	yaml_node_t* n = yaml_document_get_root_node(d);	//   ".matrix[2,3]"でも構いません。															//{{2016/05/08追記:左記のコードはnode引数を明示していますが、ルートノードからの相対パスならばnode引数は省略可能になりました。}}
	printf("matrix[2,3]  = %d\n", (int)yaml_path_get_number(d, n, "matrix[2,3]"));		//34	既存のclipprp.cモジュールのPrpTbl_get_p()等と同じ書式。		┬どちらの書式を使っても構いません。		//{{2016/05/08追記:左記のコードはnode引数を明示していますが、ルートノードからの相対パスならばnode引数は省略可能になりました。}}
	printf("matrix[2][3] = %d\n", (int)yaml_path_get_number(d, n, "matrix[2][3]"));		//34	C言語配列に似た書式。これはPrpTbl_get_p()等では使えません。	┘						//{{2016/05/08追記:左記のコードはnode引数を明示していますが、ルートノードからの相対パスならばnode引数は省略可能になりました。}}
	yaml_document_free(d);					//   ".matrix[2][3]"でも構いません。
}
#endif
/****************************************************************************
 *	書き込み関数の使用例
 ****************************************************************************/
#if 0
//□ファイル出力の例:
void test4() {	//P/ECEでも動作する事を確認しました。(2016/05/10)	かなり遅いです。30秒〜1分ぐらい待ってください。主な原因はシフトJIS⇔UTF-8変換が遅い事です。frambpe.oを高速RAMに配置すると少しましになります。
	{
		//空のドキュメントを作成する。
		yaml_document_t* d = yaml_document_new();
		//ドキュメントに値を書き込む。
		yaml_path_set_string_f(d, "P/ECE", "Aquaplus.Machine[%d].名前", 0);	//この使用例では[%d]形式しか使っていませんが、[%d,%d]形式や[%d][%d]形式も使えます。三次元以上も使えます。
		yaml_path_set_string_f(d, "PME-001", "Aquaplus.Machine[%d].Model", 0);
		yaml_path_set_number_f(d, 123, "Aquaplus.Machine[%d].Power", 0);
		yaml_path_set_string_f(d, "マルチ", "Aquaplus.Machine[%d].名前", 1);
		yaml_path_set_string_f(d, "HMX-12B", "Aquaplus.Machine[%d].Model", 1);
		yaml_path_set_number_f(d, 456, "Aquaplus.Machine[%d].Power", 1);
		//ドキュメントを保存して開放する。(開放せずに保存する方法は無い。)
		yaml_document_save(d, "output1.yml");
	}
	{
		//保存したドキュメントをもう一度読み込む。
		yaml_document_t* d = yaml_document_load("output1.yml");
		//ドキュメントに値を追加する。(現在の実装では'値の変更'は出来ません。)
		yaml_path_set_string_f(d, "セリオ", "Aquaplus.Machine[%d].名前", 2);
		yaml_path_set_string_f(d, "HMX-13", "Aquaplus.Machine[%d].Model", 2);
		yaml_path_set_number_f(d, yaml_path_get_number_f(d, yaml_document_get_root_node(d), "Aquaplus.Machine[%d].Power", 1) * 1.3, "Aquaplus.Machine[%d].Power", 2);	//書き込みと読み出しの併用も出来ます。	//{{2016/05/08追記:左記のコードはnode引数を明示していますが、ルートノードからの相対パスならばnode引数は省略可能になりました。}}
		//ドキュメントを別名で保存して開放する。(開放せずに保存する方法は無い。)
		yaml_document_save(d, "output2.yml");
	}
}
─── 出力結果: output1.yml ───
Aquaplus:
  Machine:
  - 名前: P/ECE
    Model: PME-001
    Power: 123
  - 名前: マルチ
    Model: HMX-12B
    Power: 456
─── 出力結果: output2.yml ───
Aquaplus:
  Machine:
  - 名前: P/ECE
    Model: PME-001
    Power: 123
  - 名前: マルチ
    Model: HMX-12B
    Power: 456
  - 名前: セリオ
    Model: HMX-13
    Power: 592.8
//□文字列出力の例:
void test5() {	//P/ECEでも動作する事を確認しました。(2016/05/14)	かなり遅いです。30秒〜1分ぐらい待ってください。主な原因はシフトJIS⇔UTF-8変換が遅い事です。frambpe.oを高速RAMに配置すると少しましになります。
	char *string1, *string2;
	{
		//空のドキュメントを作成する。
		yaml_document_t* d = yaml_document_new();
		//ドキュメントに値を書き込む。
		yaml_path_set_string_f(d, "P/ECE", "Aquaplus.Machine[%d].名前", 0);	//この使用例では[%d]形式しか使っていませんが、[%d,%d]形式や[%d][%d]形式も使えます。三次元以上も使えます。
		yaml_path_set_string_f(d, "PME-001", "Aquaplus.Machine[%d].Model", 0);
		yaml_path_set_number_f(d, 123, "Aquaplus.Machine[%d].Power", 0);
		yaml_path_set_string_f(d, "マルチ", "Aquaplus.Machine[%d].名前", 1);
		yaml_path_set_string_f(d, "HMX-12B", "Aquaplus.Machine[%d].Model", 1);
		yaml_path_set_number_f(d, 456, "Aquaplus.Machine[%d].Power", 1);
		//ドキュメントを保存して開放する。(開放せずに保存する方法は無い。)
		string1 = yaml_document_dump(d);
	}
	{
		//保存したドキュメントをもう一度読み込む。
		yaml_document_t* d = yaml_document_parse(string1);
		//ドキュメントに値を追加する。(現在の実装では'値の変更'は出来ません。)
		yaml_path_set_string_f(d, "セリオ", "Aquaplus.Machine[%d].名前", 2);
		yaml_path_set_string_f(d, "HMX-13", "Aquaplus.Machine[%d].Model", 2);
		yaml_path_set_number_f(d, yaml_path_get_number_f(d, yaml_document_get_root_node(d), "Aquaplus.Machine[%d].Power", 1) * 1.3, "Aquaplus.Machine[%d].Power", 2);	//書き込みと読み出しの併用も出来ます。	//{{2016/05/08追記:左記のコードはnode引数を明示していますが、ルートノードからの相対パスならばnode引数は省略可能になりました。}}
		//ドキュメントを別名で保存して開放する。(開放せずに保存する方法は無い。)
		string2 = yaml_document_dump(d);
	}
	puts(string1);
	puts(string2);
	free(string1);
	free(string2);
}
─── 出力結果: string1 ───
Aquaplus:
  Machine:
  - 名前: P/ECE
    Model: PME-001
    Power: 123
  - 名前: マルチ
    Model: HMX-12B
    Power: 456
─── 出力結果: string2 ───
Aquaplus:
  Machine:
  - 名前: P/ECE
    Model: PME-001
    Power: 123
  - 名前: マルチ
    Model: HMX-12B
    Power: 456
  - 名前: セリオ
    Model: HMX-13
    Power: 592.8
#endif
/****************************************************************************
 *	パス文字列のキーに特殊文字が含まれている場合にエスケープする例
 ****************************************************************************/
#if 0
//test1()〜test5()が、P/ECEでも正しく動作する事を確認しました。(2016/05/26)	かなり遅いです。30秒〜1分ぐらい待ってください。主な原因はシフトJIS⇔UTF-8変換が遅い事です。frambpe.oを高速RAMに配置すると少しましになります。
//□パス内の'.','[',']'を普通に特殊文字として解釈した例:
void test1() {
	yaml_document_t* d = yaml_document_new();
	yaml_path_set_string(d, "値の文字列はｴｽｹｰﾌﾟ関係無し\\.[]", "表現.十回[0]");
	{ char* s = yaml_document_dump(d); puts(s); free(s); }
	//│表現:
	//│  十回:
	//│  - 値の文字列はｴｽｹｰﾌﾟ関係無し\.[]
}
//□パス内の'.','[',']'をエスケープして一つのキーと見なした例:
void test2() {
	yaml_document_t* d = yaml_document_new();
	yaml_path_set_string(d, "値の文字列はｴｽｹｰﾌﾟ関係無し\\.[]", "表現\\.十回\\[0\\]");
	{ char* s = yaml_document_dump(d); puts(s); free(s); }
	//│表現.十回[0]: 値の文字列はｴｽｹｰﾌﾟ関係無し\.[]
}
//□キーの文字列が特殊文字を含むかどうか予測出来ない場合は、実行時にエスケープすれば良い:
void test3() {
	const char* key = "表現.十回[0]";//この文字列の内容が予測出来ないものと仮定する。
	yaml_document_t* d = yaml_document_new();
	char* tmp = strescape(key, ".[]");
	yaml_path_set_string(d, "値の文字列はｴｽｹｰﾌﾟ関係無し\\.[]", tmp);
	free(tmp);
	{ char* s = yaml_document_dump(d); puts(s); free(s); }
	//│表現.十回[0]: 値の文字列はｴｽｹｰﾌﾟ関係無し\.[]
}
//□上記の例を各キーに用い、かつ、複数のキーやインデクスも組み合わせる応用例:
void test4() {
	const char* key1 = "表現.十回";//この文字列の内容が予測出来ないものと仮定する。
	const char* key2 = "予備[123]";//この文字列の内容が予測出来ないものと仮定する。
	const char* index = 0;
	yaml_document_t* d = yaml_document_new();
	char* tmp1 = strescape(key1, ".[]");	//┬個々のキー単位にエスケープする。
	char* tmp2 = strescape(key2, ".[]");	//┘
	yaml_path_set_string_f(d, "値の文字列はｴｽｹｰﾌﾟ関係無し\\.[]", "%s.%s[%d]", tmp1, tmp2, index);
	free(tmp1);
	free(tmp2);
	{ char* s = yaml_document_dump(d); puts(s); free(s); }
	//│表現.十回:
	//│  予備[123]:
	//│  - 値の文字列はｴｽｹｰﾌﾟ関係無し\.[]
}
//□読み込み時に指定するパス文字列のエスケープについても同様です:
void test5() {
	const char yaml[] = "表現.十回:\n"
	                    "  予備[123]:\n"
	                    "  - 値の文字列はｴｽｹｰﾌﾟ関係無し\\.[]\n";
	yaml_document_t* d = yaml_document_parse(yaml);
	const char* value = yaml_path_get_string(d, NULL, "表現\\.十回.予備\\[123\\][0]");
	puts(value);
	//│値の文字列はｴｽｹｰﾌﾟ関係無し\.[]
	yaml_document_free(d);
}
#endif
