/*	
 *	clipreg.c
 *
 *	レジストリテーブル
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015 Naoyuki Sawa
 *
 *	* Tue Mar 24 02:10:47 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Tue Mar 24 21:45:37 JST 2015 Naoyuki Sawa
 *	- REG_open_key(),及び,REG_get_value()に、(keyBody=NULL)を指定しても安全にしました。
 *	  REG_open_key_v()とREG_get_value_v()の処理の大部分を共通化してコード削減しました。
 *	* Thu Mar 26 21:28:16 JST 2015 Naoyuki Sawa
 *	- dRegTblC.exeの出力データ構造を変更した事に伴い、当モジュールも大幅に変更しました。
 *	  前回まではキー配列をリニアサーチしていましたが、今後はバイナリサーチになりました。
 *	  詳細は、「clip/tool/dRegTblC/winapp.h」の同日のコメントを参照してください。
 *	* Sat Apr 11 13:20:40 JST 2015 Naoyuki Sawa
 *	 - 文字列のデータタイプを追加し、大幅な変更を行いました。
 *	   変更前のコードを参照するには、前回のアーカイブを参照してください。
 *	* Mon Jul 27 21:32:15 JST 2015 Naoyuki Sawa
 *	- REG_open_key_v()の処理を修正しました。修正内容は、以下の通りです:
 *	  'REG_open_key_l(keyBody,-1)'に対して、これまではNULLを返していました。(keyBody)自身を返すのが自然であると思うので、そのように修正しました。
 *	- 既に、clipfsm.c の FsmObj_GetTransKey() にて、'REG_open_key_l(keyBody,-1)'が(keyBody)自身を返す事を期待したコードを書いてしまっていました。
 *	  これまでは、'REG_open_key_l(keyBody,-1)'がNULLを返していたので、FsmObj_GetTransKey() が正しく動作していませんでした。
 *	  今回、'REG_open_key_l(keyBody,-1)'が(keyBody)自身を返すように修正したので、FsmObj_GetTransKey() が正しく動作するようになりました。
 *	- 上記の修正を、REG_open_get_v()やREG_open_key()ではなく、REG_open_key_v()で行った理由は、影響範囲を小さく留めるためです。
 *	  REG_open_get_v()やREG_open_key()は、他の関数との共通性のために、(keyName=-1)を終端と見なす特例処理を行いたくありません。
 *	  特例処理は、呼び出し階層の浅い部分で行う方が安全だと考えて、REG_open_key_v()で行う事にしました。
 *	* Tue Sep 22 12:15:09 JST 2015 Naoyuki Sawa
 *	- 「インデクスアクセス型,及び,イテレーション用の関数」を追加しました。
 *	- インデクスアクセス型の関数を使用して、イテレーションを行う例を示します。
 *	  □TBL_RegTbl->RegKey_X->RegKey_Yに属する値をｲﾃﾚｰﾄする｡TBL_RegTbl->RegKey_X->RegKey_Yが存在しなくても安全です｡
 *	  │for(index=0;
 *	  │    (valueData=REG_get_nth_value_l(TBL_RegTbl,index,&valueName,RegKey_X,RegKey_Y,-1))!=-1;
 *	  │    index++){
 *	  │      printf("%d:%d=>%d\n",index,valueName,valueData);
 *	  │}
 */
#include "clip.h"
/****************************************************************************
 *	辞書アクセス型の関数
 ****************************************************************************/
/*==========================================================================*
 *	基本的な関数
 *==========================================================================*/
#ifndef PIECE
static int REG_name_compar(const void* _x, const void* _y) {
	const unsigned char* x = _x;
	const unsigned char* y = _y;
	int retVal = *x++ - *y++;					//name(符号無し16ビット)の上位8ビットを比較する。┬オーバーフローの心配は無いので減算結果を比較結果と見なして良い。
	if(!retVal) { retVal = *x - *y; }				//上位16ビットが同じならば下位8ビットを比較する。┘
	return retVal;
}
//(keyBody=NULL)を指定しても安全です。結果は常にNULLになります。
//keyNameに範囲外の値(0~0xFFFF以外)を指定しても安全です。結果は常にNULLになります。
const unsigned char* REG_open_key(const unsigned char* keyBody, int keyName) {
	unsigned char keyName2[2];
	int nKey, keyBodyDist;
	if(!keyBody  ) { return NULL; }					//(keyBody=NULL)が指定されたらNULLを返す。
	keyName2[1]    = keyName;					//┐
	keyName      >>= 8;						//├符号無し16ビット,ビッグエンディアン
	keyName2[0]    = keyName;					//┘
	keyName      >>= 8;						//┐
	if(keyName   ) { return NULL; }					//┴以下の処理はkeyNameの上位16bitを無視するので、下位16bitが偶然一致しないよう範囲外の値を除外しておく。
	//キーの配列内を検索する。
	nKey           = *keyBody++;					//┐
	nKey         <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nKey          |= *keyBody++;					//┘
	keyBody = bsearch(
		keyName2,						//keyNameの下位16bitのみを参照する。
		keyBody,
		nKey,
		(2/*keyName*/+3/*keyBodyDist*/),
		REG_name_compar);
	if(!keyBody  ) { return NULL; }					//キーが見つからなければNULLを返す。
	keyBody += 2/*keyName*/;
	keyBodyDist    = (char)*keyBody++;				//┐
	keyBodyDist  <<= 8;						//│
	keyBodyDist   |=       *keyBody++;				//├符号有り24ビット,ビッグエンディアン
	keyBodyDist  <<= 8;						//│
	keyBodyDist   |=       *keyBody++;				//┘
	keyBody       += keyBodyDist;					//キーボディのアドレスを求める。
	return keyBody;							//キーボディのアドレスを返す。
}
//(keyBody=NULL)を指定しても安全です。結果は常に(-1)になります。
//valueNameに範囲外の値(0~0xFFFF以外)を指定しても安全です。結果は常に(-1)になります。
int REG_get_value(const unsigned char* keyBody, int valueName) {
	unsigned char valueName2[2];
	int nKey, nValue, valueData;
	if(!keyBody  ) { return -1; }					//(keyBody=NULL)が指定されたら(-1)を返す。
	valueName2[1]  = valueName;					//┐
	valueName    >>= 8;						//├符号無し16ビット,ビッグエンディアン
	valueName2[0]  = valueName;					//┘
	valueName    >>= 8;						//┐
	if(valueName ) { return -1; }					//┴以下の処理はvalueNameの上位16bitを無視するので、下位16bitが偶然一致しないよう範囲外の値を除外しておく。
	//キーの配列をスキップする。
	nKey           = *keyBody++;					//┐
	nKey         <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nKey          |= *keyBody++;					//┘
	keyBody       += nKey * (2/*keyName*/+3/*keyBodyDist*/);
	//値の配列内を検索する。
	nValue         = *keyBody++;					//┐
	nValue       <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nValue        |= *keyBody++;					//┘
	keyBody = bsearch(
		valueName2,						//valueNameの下位16bitのみを参照する。
		keyBody,
		nValue,
		(2/*valueName*/+2/*valueData*/),
		REG_name_compar);
	if(!keyBody  ) { return -1; }					//値が見つからなければ(-1)を返す。
	keyBody += 2/*valueName*/;
	valueData      = *keyBody++;					//┐
	valueData    <<= 8;						//├符号無し16ビット,ビッグエンディアン
	valueData     |= *keyBody;					//┘
	return valueData;						//値のデータを返す。
}
//(keyBody=NULL)を指定しても安全です。結果は常にNULLになります。
//stringNameに範囲外の値(0~0xFFFF以外)を指定しても安全です。結果は常にNULLになります。
const char* REG_get_string(const unsigned char* keyBody, int stringName) {
	unsigned char stringName2[2];
	int nKey, nValue, nString, stringDist;
	if(!keyBody  ) { return NULL; }					//(keyBody=NULL)が指定されたらNULLを返す。
	stringName2[1] = stringName;					//┐
	stringName   >>= 8;						//├符号無し16ビット,ビッグエンディアン
	stringName2[0] = stringName;					//┘
	stringName   >>= 8;						//┐
	if(stringName) { return NULL; }					//┴以下の処理はstringNameの上位16bitを無視するので、下位16bitが偶然一致しないよう範囲外の値を除外しておく。
	//キーの配列をスキップする。
	nKey           = *keyBody++;					//┐
	nKey         <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nKey          |= *keyBody++;					//┘
	keyBody       += nKey * (2/*keyName*/+3/*keyBodyDist*/);
	//値の配列をスキップする。
	nValue         = *keyBody++;					//┐
	nValue       <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nValue        |= *keyBody++;					//┘
	keyBody       += nValue * (2/*valueName*/+2/*valueData*/);
	//文字列の配列内を検索する。
	nString        = *keyBody++;					//┐
	nString      <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nString       |= *keyBody++;					//┘
	keyBody = bsearch(
		stringName2,						//stringNameの下位16bitのみを参照する。
		keyBody,
		nString,
		(2/*stringName*/+3/*stringDist*/),
		REG_name_compar);
	if(!keyBody  ) { return NULL; }					//文字列が見つからなければNULLを返す。
	keyBody += 2/*stringName*/;
	stringDist     = (char)*keyBody++;				//┐
	stringDist   <<= 8;						//│
	stringDist    |=       *keyBody++;				//├符号有り24ビット,ビッグエンディアン
	stringDist   <<= 8;						//│
	stringDist    |=       *keyBody++;				//┘
	keyBody       += stringDist;					//文字列データのアドレスを求める。
	return (const char*)keyBody;					//文字列データのアドレスを返す。
}
#else //PIECE
const unsigned char* REG_open_key(const unsigned char* keyBody, int keyName);
int REG_get_value(const unsigned char* keyBody, int valueName);
const char* REG_get_string(const unsigned char* keyBody, int stringName);
asm("
		.code
		.align		1
		.global		REG_open_key
		.global		REG_get_value
		.global		REG_get_string
REG_open_key:
		;//%r12 := keyBody
		;//%r13 := keyName
		jp.d		REG_open_get				;//
		ld.w		%r14, 0					;//%r14    := flag = 0												*delay*
REG_get_string:
		;//%r12 := keyBody
		;//%r13 := stringName
		ld.w		%r14, 1					;//%r14    := flag = 1
REG_open_get:
		xsub		%sp, %sp, 8				;//
		cmp		%r12, 0					;//if(!keyBody) { return NULL }
		jreq.d		REG_open_get_RET			;//
		ld.w		%r10, 0					;//%r10    :=            NULL											*delay*
		xld.b		[%sp+5], %r13				;//[%sp+5] := Name2[1] = Name
		sra		%r13, 8					;//%r13    :=            Name >>= 8
		xld.b		[%sp+4], %r13				;//[%sp+4] := Name2[0] = Name
		sra		%r13, 8					;//%r13    :=            Name >>= 8
		jrne		REG_open_get_RET			;//if(Name    ) { return NULL }
		cmp		%r14, 0					;//if(flag) {
		jreq.d		REG_open_get_L10			;//  
		ld.w		%r13, %r12				;//%r13    := keyBody												*delay*
		ld.ub		%r10, [%r12]+				;//  %r10    :=                      nKeyHi                = *keyBody++
		ld.ub		%r13, [%r12]+				;//  %r13    :=                                   nKeyLo   = *keyBody++
		sla		%r10, 8					;//  %r10    :=                      nKeyHi  <<8
		or		%r13, %r10				;//  %r13    :=            nKey   = (nKeyHi  <<8)|nKeyLo
		add		%r12, %r13				;//  %r12    := keyBody +  nKey   * 1
		sla		%r13, 2					;//  %r13    :=            nKey   * 4
		add		%r12, %r13				;//  %r12    := keyBody += nKey   * (2/*keyName*/+3/*keyBodyDist*/)
		ld.ub		%r10, [%r12]+				;//  %r10    :=                      nValueHi              = *keyBody++
		ld.ub		%r13, [%r12]+				;//  %r13    :=                                   nValueLo = *keyBody++
		sla		%r10, 8					;//  %r10    :=                      nValueHi<<8
		or		%r13, %r10				;//  %r13    :=            nValue = (nValueHi<<8)|nValueLo
		sla		%r13, 2					;//  %r13    :=            nValue * (2/*valueName*/+2/*valueData*/)
		add		%r13, %r12				;//  %r13    := keyBody += nValue * (2/*valueName*/+2/*valueData*/)
REG_open_get_L10:							;//}
		ld.w		%r12, %sp				;//%r12    := &[%sp+0]
		xld.w		%r10, REG_name_compar			;//%r10    := REG_name_compar
		ld.w		[%r12]+, %r10				;//[%sp+0] := REG_name_compar, %r12 := Name2
		ld.ub		%r10, [%r13]+				;//%r10    :=       nHi         = *keyBody++
		ld.ub		%r14, [%r13]+				;//%r14    :=               nLo = *keyBody++
		sla		%r10, 8					;//%r10    :=       nHi<<8
		or		%r14, %r10				;//%r14    := n  = (nHi<<8)|nLo
		xcall.d		bsearch					;//%r10    := keyBody = bsearch(Name2, keyBody, n, (2/*Name*/+3/*Dist*/), REG_name_compar)
		ld.w		%r15, 5					;//%r15    :=                                      (2/*Name*/+3/*Dist*/)					*delay*
		cmp		%r10, 0					;//if(!keyBody) { return NULL }
		jreq		REG_open_get_RET			;//
		add		%r10, 2					;//%r10    :=                                                             keyBody += 2/*Name*/
		ld.b		%r11, [%r10]+				;//%r11    :=                      DistHi                        = (char)*keyBody++
		ld.ub		%r12, [%r10]+				;//%r12    :=                                 DistMi             =       *keyBody++
		ld.ub		%r13, [%r10]+				;//%r13    :=                                             DistLo =       *keyBody++
		sla		%r11, 8					;//%r11    :=                      DistHi<<8
		or		%r11, %r12				;//%r11    :=                     (DistHi<<8)|DistMi
		sla		%r11, 8					;//%r11    :=                    ((DistHi<<8)|DistMi)<<8
		or		%r11, %r13				;//%r11    :=            Dist = (((DistHi<<8)|DistMi)<<8)|DistLo
		add		%r10, %r11				;//%r10    := keyBody += Dist
REG_open_get_RET:							;//
		xadd		%sp, %sp, 8				;//
		ret							;//return     keyBody
		;//-----------------------------------------------------;//
REG_get_value:
		;//%r12 := keyBody
		;//%r13 := valueName
		xsub		%sp, %sp, 8				;//
		cmp		%r12, 0					;//if(!keyBody ) { return -1 }
		jreq		REG_get_value_RET_M1			;//
		xld.b		[%sp+5], %r13				;//[%sp+5] := valueName2[1] = valueName
		sra		%r13, 8					;//%r13    :=                 valueName >>= 8
		xld.b		[%sp+4], %r13				;//[%sp+4] := valueName2[0] = valueName
		sra		%r13, 8					;//%r13    :=                 valueName >>= 8
		jrne		REG_get_value_RET_M1			;//if(valueName) { return -1 }
		ld.ub		%r10, [%r12]+				;//%r10    :=                    nKeyHi            = *keyBody++
		ld.ub		%r13, [%r12]+				;//%r13    :=                               nKeyLo = *keyBody++
		sla		%r10, 8					;//%r10    :=                    nKeyHi<<8
		or		%r13, %r10				;//%r13    :=            nKey = (nKeyHi<<8)|nKeyLo
		add		%r12, %r13				;//%r12    := keyBody +  nKey * 1
		sla		%r13, 2					;//%r13    :=            nKey * 4
		add		%r13, %r12				;//%r13    := keyBody += nKey * (2/*keyName*/+3/*keyBodyDist*/)
		ld.w		%r12, %sp				;//%r12    := &[%sp+0]
		xld.w		%r10, REG_name_compar			;//%r10    := REG_name_compar
		ld.w		[%r12]+, %r10				;//[%sp+0] := REG_name_compar, %r12 := valueName2
		ld.ub		%r10, [%r13]+				;//%r10    :=            nValueHi              = *keyBody++
		ld.ub		%r14, [%r13]+				;//%r14    :=                         nValueLo = *keyBody++
		sla		%r10, 8					;//%r10    :=            nValueHi<<8
		or		%r14, %r10				;//%r14    := nValue  = (nValueHi<<8)|nValueLo
		xcall.d		bsearch					;//%r10    := keyBody = bsearch(valueName2, keyBody, nValue, (2/*valueName*/+2/*valueData*/), REG_name_compar)
		ld.w		%r15, 4					;//%r15    :=                                                (2/*valueName*/+2/*valueData*/)			*delay*
		cmp		%r10, 0					;//if(!keyBody ) { return -1 }
		jreq		REG_get_value_RET_M1			;//
		add		%r10, 2					;//%r10    :=                                             keyBody += 2/*valueName*/
		ld.ub		%r11, [%r10]+				;//%r11    :=              valueDataHi                 = *keyBody++
		ld.ub		%r10, [%r10]				;//%r10    :=                              valueDataLo = *keyBody
		sla		%r11, 8					;//%r11    :=              valueDataHi<<8									*anti-interlock*
		or		%r10, %r11				;//%r10    := valueData = (valueDataHi<<8)|valueDataLo
REG_get_value_RET:							;//
		xadd		%sp, %sp, 8				;//
		ret							;//return     valueData
REG_get_value_RET_M1:							;//
		jp.d		REG_get_value_RET			;//
		ld.w		%r10, -1				;//%r10    := valueData = -1											*delay*
		;//-----------------------------------------------------;//
REG_name_compar:
		;//%r12 := x
		;//%r13 := y
		ld.ub		%r10, [%r12]+				;//%r10 := xVal = *x++
		ld.ub		%r11, [%r13]+				;//%r11 := yVal = *y++
		cmp		%r10, %r11				;//if(xVal == yVal) {
		jrne		3					;//  
		 ld.ub		%r10, [%r12]				;//  %r10 := xVal = *x
		 ld.ub		%r11, [%r13]				;//  %r11 := yVal = *y }
		ret.d							;//return  xVal - yVal												*anti-interlock*
		sub		%r10, %r11				;//%r10 := xVal - yVal												*delay*
");
#endif//PIECE
/*==========================================================================*
 *	ユーティリティ関数
 *==========================================================================*/
#ifndef PIECE
static int REG_open_get_v(const unsigned char* keyBody, const int* names, int (*fn)(const unsigned char*, int)) {
	int name = *names++;
	if(name != -1) {
		goto L_START;
		do {
			keyBody = REG_open_key(keyBody, name);	//(keyBody=NULL)が指定されたり、REG_open_key()がNULLを返して(keyBody=NULL)になっても、継続して安全です。
			name = *names++;
L_START:		;
		} while(*names != -1);
	}
	return (*fn)(keyBody, name);	//(keyBody=NULL)や(name=-1)の場合でも、この処理を実行して安全です。
}
/*--------------------------------------------------------------------------*/
const unsigned char* REG_open_key_l(const unsigned char* keyBody, ...) {
	va_list ap;
	va_start(ap, keyBody);
	keyBody = REG_open_key_a(keyBody, ap);
	va_end(ap);
	return keyBody;
}
const unsigned char* REG_open_key_a(const unsigned char* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_open_key_v(keyBody, names);
}
const unsigned char* REG_open_key_v(const unsigned char* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
    //{{2015/07/27追加:'REG_open_key_l(keyBody,-1)'に対して、これまではNULLを返していました。(keyBody)自身を返すのが自然であると思うので、そのように修正しました。
	if(names[0] == -1) { return keyBody; }
    //}}2015/07/27追加:'REG_open_key_l(keyBody,-1)'に対して、これまではNULLを返していました。(keyBody)自身を返すのが自然であると思うので、そのように修正しました。
	return (const unsigned char*)REG_open_get_v(keyBody, names, (int (*)(const unsigned char*, int))REG_open_key);
}
/*--------------------------------------------------------------------------*/
int REG_get_value_l(const unsigned char* keyBody, ...) {
	int valueData;
	va_list ap;
	va_start(ap, keyBody);
	valueData = REG_get_value_a(keyBody, ap);
	va_end(ap);
	return valueData;
}
int REG_get_value_a(const unsigned char* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_value_v(keyBody, names);
}
int REG_get_value_v(const unsigned char* keyBody, const int* names/*[[[[keyName,]keyName],…,]valueName,]-1*/) {
	return REG_open_get_v(keyBody, names, REG_get_value);
}
/*--------------------------------------------------------------------------*/
const char* REG_get_string_l(const unsigned char* keyBody, ...) {
	const char* stringData;
	va_list ap;
	va_start(ap, keyBody);
	stringData = REG_get_string_a(keyBody, ap);
	va_end(ap);
	return stringData;
}
const char* REG_get_string_a(const unsigned char* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_string_v(keyBody, names);
}
const char* REG_get_string_v(const unsigned char* keyBody, const int* names/*[[[[keyName,]keyName],…,]stringName,]-1*/) {
	return (const char*)REG_open_get_v(keyBody, names, (int (*)(const unsigned char*, int))REG_get_string);
}
#else //PIECE
const unsigned char* REG_open_key_l(const unsigned char* keyBody, ...);
const unsigned char* REG_open_key_a(const unsigned char* keyBody, va_list ap);
const unsigned char* REG_open_key_v(const unsigned char* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
/*--------------------------------------------------------------------------*/
int REG_get_value_l(const unsigned char* keyBody, ...);
int REG_get_value_a(const unsigned char* keyBody, va_list ap);
int REG_get_value_v(const unsigned char* keyBody, const int* names/*[[[[keyName,]keyName],…,]valueName,]-1*/);
/*--------------------------------------------------------------------------*/
const char* REG_get_string_l(const unsigned char* keyBody, ...);
const char* REG_get_string_a(const unsigned char* keyBody, va_list ap);
const char* REG_get_string_v(const unsigned char* keyBody, const int* names/*[[[[keyName,]keyName],…,]stringName,]-1*/);
asm("
		.code
		.align		1
		.global		REG_open_key_l
		.global		REG_open_key_a
		.global		REG_open_key_v
		.global		REG_get_value_l
		.global		REG_get_value_a
		.global		REG_get_value_v
		.global		REG_get_string_l
		.global		REG_get_string_a
		.global		REG_get_string_v
REG_open_key_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_open_key_a:
		;//%r12 := keyBody
		;//%r13 := ap
REG_open_key_v:
		;//%r12 := keyBody
		;//%r13 := names
	   ;//{{2015/07/27変更:'REG_open_key_l(keyBody,-1)'に対して、これまではNULLを返していました。(keyBody)自身を返すのが自然であると思うので、そのように修正しました。
	   ;//	xld.w		%r14, REG_open_key			;//%r14 := fn = REG_open_key
	   ;//	jp		REG_open_get_v				;//
	   ;//↓2015/07/27変更:'REG_open_key_l(keyBody,-1)'に対して、これまではNULLを返していました。(keyBody)自身を返すのが自然であると思うので、そのように修正しました。
		ld.w		%r9, [%r13]				;//%r9  := names[0]
		xld.w		%r14, REG_open_key			;//%r14 := fn = REG_open_key											*anti-interlock*
		cmp		%r9, -1					;//if(names[0] != -1) {
		jrne		REG_open_get_v				;//  goto REG_open_get_v }
		ret.d							;//return  keyBody
		ld.w		%r10, %r12				;//%r10 := keyBody												*delay*
	   ;//}}2015/07/27変更:'REG_open_key_l(keyBody,-1)'に対して、これまではNULLを返していました。(keyBody)自身を返すのが自然であると思うので、そのように修正しました。
		;//-----------------------------------------------------;//
REG_get_value_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_get_value_a:
		;//%r12 := keyBody
		;//%r13 := ap
REG_get_value_v:
		;//%r12 := keyBody
		;//%r13 := names
		xld.w		%r14, REG_get_value			;//%r14 := fn = REG_get_value
		jp		REG_open_get_v				;//
		;//-----------------------------------------------------;//
REG_get_string_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_get_string_a:
		;//%r12 := keyBody
		;//%r13 := ap
REG_get_string_v:
		;//%r12 := keyBody
		;//%r13 := names
		xld.w		%r14, REG_get_string			;//%r14 := fn = REG_get_string
		;//-----------------------------------------------------;//
REG_open_get_v:
		;//%r12 := keyBody
		;//%r13 := names
		;//%r14 := fn
		pushn		%r1					;//
		ld.w		%r0, %r13				;//%r0  :=         names
		ld.w		%r1, %r14				;//%r1  :=         fn
		ld.w		%r13, [%r0]+				;//%r13 := name = *names++
		cmp		%r13, -1				;//if(name != -1)
		jreq		REG_open_get_v_NAMES_EMPTY		;//  
		jp		REG_open_get_v_START			;//  goto L_START
REG_open_get_v_LOOP:							;//  do {
		xcall		REG_open_key				;//    %r10 := keyBody = REG_open_key(keyBody, name)
		ld.w		%r12, %r10				;//    %r12 := keyBody
		ld.w		%r13, [%r0]+				;//    %r13 := name = *names++
REG_open_get_v_START:							;//    
		ld.w		%r14, [%r0]				;//    %r14 := *names
		cmp		%r14, -1				;//    														!INTERLOCK!
		jrne		REG_open_get_v_LOOP			;//  } while(*names != -1)
REG_open_get_v_NAMES_EMPTY:						;//}
		ld.w		%r14, %r1				;//%r14 :=  fn
		popn		%r1					;//
		jp		%r14					;//return (*fn)(keyBody, name)
");
#endif//PIECE
/****************************************************************************
 *	インデクスアクセス型,及び,イテレーション用の関数
 ****************************************************************************/
/*==========================================================================*
 *	基本的な関数
 *==========================================================================*/
#ifndef PIECE
const unsigned char* REG_open_nth_key(const unsigned char* keyBody, int index, int* p_keyName/*NULL可*/) {
	int nKey, keyName, keyBodyDist;
	if(!keyBody) { return NULL; }					//(keyBody=NULL)が指定されたらNULLを返す。
	//キーの配列内の指定されたインデクスの要素を返す。
	nKey           = *keyBody++;					//┐
	nKey         <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nKey          |= *keyBody++;					//┘
	if((unsigned)index >= (unsigned)nKey) { return NULL; }		//指定されたインデクスが配列の要素数以上ならばNULLを返す。
	keyBody       += index * (2/*keyName*/+3/*keyBodyDist*/);
	keyName        = *keyBody++;					//┐
	keyName      <<= 8;						//├符号無し16ビット,ビッグエンディアン
	keyName       |= *keyBody++;					//┘
	if(p_keyName) { *p_keyName = keyName; }				//キーの名前を格納する。
	keyBodyDist    = (char)*keyBody++;				//┐
	keyBodyDist  <<= 8;						//│
	keyBodyDist   |=       *keyBody++;				//├符号有り24ビット,ビッグエンディアン
	keyBodyDist  <<= 8;						//│
	keyBodyDist   |=       *keyBody++;				//┘
	keyBody       += keyBodyDist;					//キーボディのアドレスを求める。
	return keyBody;							//キーボディのアドレスを返す。
}
int REG_get_nth_value(const unsigned char* keyBody, int index, int* p_valueName/*NULL可*/) {
	int nKey, nValue, valueName, valueData;
	if(!keyBody) { return -1; }					//(keyBody=NULL)が指定されたら(-1)を返す。
	//キーの配列をスキップする。
	nKey           = *keyBody++;					//┐
	nKey         <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nKey          |= *keyBody++;					//┘
	keyBody       += nKey * (2/*keyName*/+3/*keyBodyDist*/);
	//値の配列をスキップする。
	nValue         = *keyBody++;					//┐
	nValue       <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nValue        |= *keyBody++;					//┘
	if((unsigned)index >= (unsigned)nValue) { return -1; }		//指定されたインデクスが配列の要素数以上ならば(-1)を返す。
	keyBody       += index * (2/*valueName*/+2/*valueData*/);
	valueName      = *keyBody++;					//┐
	valueName    <<= 8;						//├符号無し16ビット,ビッグエンディアン
	valueName     |= *keyBody++;					//┘
	if(p_valueName) { *p_valueName = valueName; }			//キーの名前を格納する。
	valueData      = *keyBody++;					//┐
	valueData    <<= 8;						//├符号無し16ビット,ビッグエンディアン
	valueData     |= *keyBody;					//┘
	return valueData;						//値のデータを返す。
}
const char* REG_get_nth_string(const unsigned char* keyBody, int index, int* p_stringName/*NULL可*/) {
	int nKey, nValue, nString, stringName, stringDist;
	if(!keyBody) { return NULL; }					//(keyBody=NULL)が指定されたらNULLを返す。
	//キーの配列をスキップする。
	nKey           = *keyBody++;					//┐
	nKey         <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nKey          |= *keyBody++;					//┘
	keyBody       += nKey * (2/*keyName*/+3/*keyBodyDist*/);
	//値の配列をスキップする。
	nValue         = *keyBody++;					//┐
	nValue       <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nValue        |= *keyBody++;					//┘
	keyBody       += nValue * (2/*valueName*/+2/*valueData*/);
	//文字列の配列内の指定されたインデクスの要素を返す。
	nString        = *keyBody++;					//┐
	nString      <<= 8;						//├符号無し16ビット,ビッグエンディアン
	nString       |= *keyBody++;					//┘
	if((unsigned)index >= (unsigned)nString) { return NULL; }	//指定されたインデクスが配列の要素数以上ならばNULLを返す。
	keyBody       += index * (2/*stringName*/+3/*stringDist*/);
	stringName     = *keyBody++;					//┐
	stringName   <<= 8;						//├符号無し16ビット,ビッグエンディアン
	stringName    |= *keyBody++;					//┘
	if(p_stringName) { *p_stringName = stringName; }		//文字列の名前を格納する。
	stringDist     = (char)*keyBody++;				//┐
	stringDist   <<= 8;						//│
	stringDist    |=       *keyBody++;				//├符号有り24ビット,ビッグエンディアン
	stringDist   <<= 8;						//│
	stringDist    |=       *keyBody++;				//┘
	keyBody       += stringDist;					//文字列データのアドレスを求める。
	return (const char*)keyBody;					//文字列データのアドレスを返す。
}
#else //PIECE
const unsigned char* REG_open_nth_key(const unsigned char* keyBody, int index, int* p_keyName/*NULL可*/);
int REG_get_nth_value(const unsigned char* keyBody, int index, int* p_valueName/*NULL可*/);
const char* REG_get_nth_string(const unsigned char* keyBody, int index, int* p_stringName/*NULL可*/);
asm("
		.code
		.align		1
		.global		REG_open_nth_key
		.global		REG_get_nth_value
		.global		REG_get_nth_string
REG_open_nth_key:
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_keyName
		ld.w		%r10, 0					;//%r10 := onError = NULL
		jp.d		REG_get_open_nth
		ld.w		%r11, 0					;//%r11 := skipCnt = 0							*delay*
REG_get_nth_value:
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_valueName
		ld.w		%r10, -1				;//%r10 := onError = -1
		jp.d		REG_get_open_nth
		ld.w		%r11, 1					;//%r11 := skipCnt = 1							*delay*
REG_get_nth_string:
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_stringName
		ld.w		%r10, 0					;//%r10 := onError = NULL
		ld.w		%r11, 2					;//%r11 := skipCnt = 2
REG_get_open_nth:
		;//%r10 := onError
		;//%r11 := skipCnt
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_name
		cmp		%r12, 0					;//if(!keyBody) { return onError }
		jreq		REG_get_open_nth_ERR			;//
		ld.w		%r15, 4					;//%r15 := size		(5⇒4⇒5と変化する)
REG_get_open_nth_LOOP:
		ld.ub		%r4, [%r12]+				;//%r4  :=         nHi            = *keyBody++
		ld.ub		%r5, [%r12]+				;//%r5  :=                    nLo = *keyBody++
		sla		%r4, 8					;//%r4  :=         nHi<<8
		or		%r4, %r5				;//%r4  := n = (nHi<<8)|nLo
		sub		%r11, 1					;//%r11 := skipCnt--
		jrlt.d		REG_get_open_nth_L10			;//if(skipCnt < 0) { goto L10 }
		xor		%r15, 1					;//%r15 := size ^= 1	(5⇒4⇒5と変化する)				*delay*
		mltu.h		%r4, %r15				;//%alr :=            n * size
		ld.w		%r4, %alr				;//%r4  :=            n * size
		jp.d		REG_get_open_nth_LOOP
		add		%r12, %r4				;//%r12 := keyBody += n * size						*delay*
REG_get_open_nth_L10:
		;//%r4  := n
		;//%r10 := onError
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_name
		;//%r15 := size
		cmp		%r13, %r4				;//if((unsigned)index >= (unsigned)n) { return onError }
		jruge		REG_get_open_nth_ERR			;//
		mltu.h		%r13, %r15				;//%alr :=            index * size
		ld.w		%r13, %alr				;//%r13 :=            index * size
		add		%r12, %r13				;//%r12 := keyBody += index * size
		ld.ub		%r4, [%r12]+				;//%r4  :=           nameHi            = *keyBody++
		ld.ub		%r5, [%r12]+				;//%r5  :=                      nameLo = *keyBody++
		cmp		%r14, 0					;//if(p_name) {
		jreq		4					;//  
		 sla		%r4, 8					;//  %r4  :=         nameHi<<8
		 or		%r4, %r5				;//  %r4  := name = (nameHi<<8)|nameLo
		 ld.w		[%r14], %r4				;//  *p_name = name }
		cmp		%r10, 0					;//if(!onError) {
		jreq		REG_get_open_nth_L20			;//  
		;//REG_get_nth_value()の場合				;//  
		ld.ub		%r10, [%r12]+				;//  %r10 :=         dataHi            = *keyBody++
		ld.ub		%r11, [%r12]				;//  %r11 :=                    dataLo = *keyBody
		sla		%r10, 8					;//  %r10 :=         dataHi<<8
		ret.d							;//  
		or		%r10, %r11				;//  %r10 := data = (dataHi<<8)|dataLo					*delay*
REG_get_open_nth_L20:							;//} else /*if(size == 5)*/ {
		;//REG_open_nth_key(),又は,REG_get_nth_string()の場合	;//  
		ld.b		%r10, [%r12]+				;//  %r10 :=           distHi                        = (char)*keyBody++
		ld.ub		%r11, [%r12]+				;//  %r11 :=                      distMi             =       *keyBody++
		ld.ub		%r13, [%r12]+				;//  %r13 :=                                  distLo =       *keyBody++
		sla		%r10, 8					;//  %r10 :=           distHi<<8
		or		%r10, %r11				;//  %r10 :=          (distHi<<8)|distMi
		sla		%r10, 8					;//  %r10 :=         ((distHi<<8)|distMi)<<8
		or		%r10, %r13				;//  %r10 := dist = (((distHi<<8)|distMi)<<8)|distLo
		ret.d							;//  
		add		%r10, %r12				;//  %r10 := dist + keyBody						*delay*
REG_get_open_nth_ERR:							;//}
		;//%r10 := onError
		ret							;//return onError
");
#endif//PIECE
/*==========================================================================*
 *	ユーティリティ関数
 *==========================================================================*/
#ifndef PIECE
const unsigned char* REG_open_nth_key_l(const unsigned char* keyBody, int index, int* p_keyName/*NULL可*/, ...) {
	va_list ap;
	va_start(ap, p_keyName);
	keyBody = REG_open_nth_key_a(keyBody, index, p_keyName, ap);
	va_end(ap);
	return keyBody;
}
const unsigned char* REG_open_nth_key_a(const unsigned char* keyBody, int index, int* p_keyName/*NULL可*/, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_open_nth_key_v(keyBody, index, p_keyName, names);
}
const unsigned char* REG_open_nth_key_v(const unsigned char* keyBody, int index, int* p_keyName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_open_nth_key(REG_open_key_v(keyBody, names), index, p_keyName);
}
/*--------------------------------------------------------------------------*/
int REG_get_nth_value_l(const unsigned char* keyBody, int index, int* p_valueName/*NULL可*/, ...) {
	int valueData;
	va_list ap;
	va_start(ap, p_valueName);
	valueData = REG_get_nth_value_a(keyBody, index, p_valueName, ap);
	va_end(ap);
	return valueData;
}
int REG_get_nth_value_a(const unsigned char* keyBody, int index, int* p_valueName/*NULL可*/, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_nth_value_v(keyBody, index, p_valueName, names);
}
int REG_get_nth_value_v(const unsigned char* keyBody, int index, int* p_valueName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_get_nth_value(REG_open_key_v(keyBody, names), index, p_valueName);
}
/*--------------------------------------------------------------------------*/
const char* REG_get_nth_string_l(const unsigned char* keyBody, int index, int* p_stringName/*NULL可*/, ...) {
	const char* stringData;
	va_list ap;
	va_start(ap, p_stringName);
	stringData = REG_get_nth_string_a(keyBody, index, p_stringName, ap);
	va_end(ap);
	return stringData;
}
const char* REG_get_nth_string_a(const unsigned char* keyBody, int index, int* p_stringName/*NULL可*/, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_nth_string_v(keyBody, index, p_stringName, names);
}
const char* REG_get_nth_string_v(const unsigned char* keyBody, int index, int* p_stringName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_get_nth_string(REG_open_key_v(keyBody, names), index, p_stringName);
}
#else //PIECE
const unsigned char* REG_open_nth_key_l(const unsigned char* keyBody, int index, int* p_keyName/*NULL可*/, ...);
const unsigned char* REG_open_nth_key_a(const unsigned char* keyBody, int index, int* p_keyName/*NULL可*/, va_list ap);
const unsigned char* REG_open_nth_key_v(const unsigned char* keyBody, int index, int* p_keyName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
int REG_get_nth_value_l(const unsigned char* keyBody, int index, int* p_valueName/*NULL可*/, ...);
int REG_get_nth_value_a(const unsigned char* keyBody, int index, int* p_valueName/*NULL可*/, va_list ap);
int REG_get_nth_value_v(const unsigned char* keyBody, int index, int* p_valueName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
const char* REG_get_nth_string_l(const unsigned char* keyBody, int index, int* p_stringName/*NULL可*/, ...);
const char* REG_get_nth_string_a(const unsigned char* keyBody, int index, int* p_stringName/*NULL可*/, va_list ap);
const char* REG_get_nth_string_v(const unsigned char* keyBody, int index, int* p_stringName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
asm("
		.code
		.align		1
		.global		REG_open_nth_key_l
		.global		REG_open_nth_key_a
		.global		REG_open_nth_key_v
		.global		REG_get_nth_value_l
		.global		REG_get_nth_value_a
		.global		REG_get_nth_value_v
		.global		REG_get_nth_string_l
		.global		REG_get_nth_string_a
		.global		REG_get_nth_string_v
REG_open_nth_key_l:
		;//%r12    := keyBody
		;//%r13    := index
		;//[%sp+0] := retp
		;//[%sp+4] := p_keyName
		;//[%sp+8] := ...
		xld.w		%r14, [%sp+4]				;//%r14 := p_keyName
		xadd		%r15, %sp, 8				;//%r15 := ap = &...
REG_open_nth_key_a:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_keyName
		;//%r15    := ap
REG_open_nth_key_v:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_keyName
		;//%r15    := names
		xld.w		%r10, REG_open_nth_key			;//%r10 := fn = REG_open_nth_key
		jp		REG_open_get_nth_v
		;//-----------------------------------------------------;//
REG_get_nth_value_l:
		;//%r12    := keyBody
		;//%r13    := index
		;//[%sp+0] := retp
		;//[%sp+4] := p_valueName
		;//[%sp+8] := ...
		xld.w		%r14, [%sp+4]				;//%r14 := p_valueName
		xadd		%r15, %sp, 8				;//%r15 := ap = &...
REG_get_nth_value_a:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_valueName
		;//%r15    := ap
REG_get_nth_value_v:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_valueName
		;//%r15    := names
		xld.w		%r10, REG_get_nth_value			;//%r10 := fn = REG_get_nth_value
		jp		REG_open_get_nth_v
		;//-----------------------------------------------------;//
REG_get_nth_string_l:
		;//%r12    := keyBody
		;//%r13    := index
		;//[%sp+0] := retp
		;//[%sp+4] := p_stringName
		;//[%sp+8] := ...
		xld.w		%r14, [%sp+4]				;//%r14 := p_stringName
		xadd		%r15, %sp, 8				;//%r15 := ap = &...
REG_get_nth_string_a:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_stringName
		;//%r15    := ap
REG_get_nth_string_v:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_stringName
		;//%r15    := names
		xld.w		%r10, REG_get_nth_string		;//%r10 := fn = REG_get_nth_string
		;//-----------------------------------------------------;//
REG_open_get_nth_v:
		;//%r10    := fn
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_name
		;//%r15    := names
		xsub		%sp, %sp, 12
		xld.w		[%sp+0], %r13				;//[%sp+0] := index
		xld.w		[%sp+4], %r14				;//[%sp+4] := p_name
		xld.w		[%sp+8], %r10				;//[%sp+8] := fn
		xcall.d		REG_open_key_v				;//%r10 := keyBody = REG_open_key_v(keyBody, names)
		ld.w		%r13, %r15				;//%r13 :=                                   names	*delay*
		xld.w		%r13, [%sp+0]				;//%r13 :=                 index
		xld.w		%r14, [%sp+4]				;//%r14 :=                        p_name
		xadd		%sp, %sp, 8				;//[%sp+0] := fn
		ret.d							;//return   (*fn)(keyBody, index, p_name)
		ld.w		%r12, %r10				;//%r12 :=        keyBody				*delay*
");
#endif//PIECE
