/* vi: set tabstop=4 nocindent noautoindent: */

/**
Tiny List 構造ライブラリ		tlist.c
											by Fumi.Iseki 2008 2/1

  ヘッダ
	  #include "tlist.h"
*/




#include  "tlist.h"




/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// List Data
//
//     静的に生成される． 
//

/**
tList_data  init_tListdata(void)
  
	機能: 空のノードデータを静的に作成
		  データを初期化するのに使用する．

	戻り値: 作られたノードデータ．
*/
tList_data  init_tListdata(void)
{
	tList_data pp;

	memset(&pp, 0, sizeof(tList_data));
	return pp;
}





/**
tList_data  make_tListdata(int id, int lv, Buffer key, Buffer val, void* ptr, int sz)
  
	機能: データを指定してノードデータを作成
		  sz>0 で ptr==NULL の場合は ptrの領域を確保し，0クリアする．

	引数: id  -- ノードのID
		  lv  -- ノードのデータ
		  key -- ノードのキー	(Buffer)	複製
		  val -- ノードのデータ (Buffer)	複製
		　ptr -- 汎用データへのポインタ		複製
		  sz  -- *ptr のサイズ

	戻り値: 作られたノードデータ．
*/
tList_data  make_tListdata(int id, int lv, Buffer key, Buffer val, void* ptr, int sz)
{
	tList_data pp;

	memset(&pp, 0, sizeof(tList_data));

	pp.id  = id;
	pp.lv  = lv;
	pp.sz  = sz;
	pp.key = dup_Buffer(key);	
	pp.val = dup_Buffer(val);

	if (sz>0) {
		pp.ptr = (void*)malloc(sz);
		if (pp.ptr!=NULL) {
			if (ptr!=NULL) memcpy(pp.ptr, ptr, sz);
			else           memset(pp.ptr, 0,   sz);
		}
	}
	
	return pp;
}





/**
tList_data  make_tListdata_bystr(int id, int lv, char* key, char* val, void* ptr, int sz)
  
	機能: データを指定してノードデータを作成
		  sz>0 で ptr==NULL の場合は ptrの領域を確保し，0クリアする．

	引数: id  -- ノードのID
		  lv  -- ノードのデータ
		  key -- ノードのキー	 			複製
		  val -- ノードのデータ 			複製
		　ptr -- 汎用データへのポインタ		複製
		  sz  -- *ptr のサイズ

	戻り値: 作られたノードデータ．
*/
tList_data  make_tListdata_bystr(int id, int lv, char* key, char* val, void* ptr, int sz)
{
	tList_data pp;
	
	memset(&pp, 0, sizeof(tList_data));

	pp.id  = id;
	pp.lv  = lv;
	pp.sz  = sz;
	pp.key = make_Buffer_bystr(key);	// key==NULLなら init_Buffer()
	pp.val = make_Buffer_bystr(val);

	if (sz>0) {
		pp.ptr = (void*)malloc(sz);
		if (pp.ptr!=NULL) {
			if (ptr!=NULL) memcpy(pp.ptr, ptr, sz);
			else           memset(pp.ptr, 0,   sz);
		}
	}

	return pp;
}





/**
void  free_tListdata(tList_data* ldat)
  
	機能: ノードデータのバッファ部をクリアする．
		  データ自身は削除しない．

	引数: ldat -- クリアするノードデータ

	戻り値: なし
*/
void  free_tListdata(tList_data* ldat)
{
	if (ldat==NULL) return;

	ldat->id = 0;
	ldat->lv = 0;
	ldat->sz = 0;

	free_Buffer(&(ldat->key));	
	free_Buffer(&(ldat->val));
	if (ldat->ptr!=NULL) free(ldat->ptr);
	del_all_tList(&(ldat->lst));

	ldat->key = init_Buffer();
	ldat->val = init_Buffer();
	ldat->ptr = NULL;
	ldat->lst = NULL;

	return;
}





/**
tListdata  dup_tListdata(tList_data ldat)
  
	機能: ノードデータの複製を作成する．
		  ldat.sz には正確に ldat.ptrのサイズが設定されている必要がある．

	引数: ldat -- 複製するノードデータ

	戻り値: 複製したノードデータへのポインタ．

*/
tList_data  dup_tListdata(tList_data ldat)
{
	tList_data dup;	

	memcpy(&dup, &ldat, sizeof(tList_data));
	dup.key = dup_Buffer(ldat.key);
	dup.val = dup_Buffer(ldat.val);
	if (ldat.ptr!=NULL && ldat.sz>0) {
		dup.ptr = (void*)malloc(ldat.sz);
		if (dup.ptr!=NULL) memcpy(dup.ptr, ldat.ptr, ldat.sz);
	}
	dup.lst = dup_tList(ldat.lst);
	
	return dup;
}








/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tiny List
//

/**
tList*  new_tList_node(void)

	機能: リスト用の空ノードを動的に生成．

	戻り値: 生成されたノードへのポインタ．
*/
tList*  new_tList_node(void)
{
	tList* pp;

	pp = (tList*)malloc(sizeof(tList));
	if (pp==NULL) return NULL;
	memset(pp, 0, sizeof(tList));
	pp->ldat = init_tListdata();

	return pp;
}





/**
tList   make_tList_node(tList_data ldat)

	機能: リスト用ノードを静的に生成する．
		  ldat はそのまま新しい変数内で使用される．（単純に代入される）

		  この関数で生成したノードを del_*_tList()関数で削除してはいけない．

	引数: ldat  -- ノードデータ

	戻り値: 作られたノード．
*/
tList   make_tList_node(tList_data ldat)
{
	tList pp;

	memset(&pp, 0, sizeof(tList));
	pp.ldat = ldat;	

	return pp;
}




/**
tList*  add_tList_node_bydata(tList* pp, tList_data ldat) 

	機能: データ(ldat)からリスト用ノードをつくり出し(new),それを指定したリストの後ろに追加．
		  リストポインタ ppが指すノードの後につくり出した ノードを挿入する．
		  ldat は指定されたものがそのまま使用される．

	引数: pp   -- 追加する場所の手前のノードへのポインタ．
		  ldat -- 追加するノードデータ．このデータがそのまま使用される．
		   
	戻り値: 追加したノードへのポインタ．
*/
tList*  add_tList_node_bydata(tList* pp, tList_data ldat) 
{
	tList* pt;

	pt = new_tList_node();
	pt->ldat = ldat;

	if (pp==NULL) return pt;

	pt->next = pp->next;
	pt->prev = pp;
	pp->next = pt;
	if (pt->next!=NULL) (pt->next)->prev = pt;	

	return pt;
}





/**
tList*  add_tList_node_bystr(tList* pp, int id, int lv, char* key, char* val, void* ptr, int sz) 

	機能: データからリスト用ノードをつくり出し(new),それをリストに追加．
		  リストポインタ ppが指すノードの後につくり出した ノードを挿入する．
		  sz>0 で ptr==NULL の場合は ptrの領域を確保し，0クリアする．

	引数: pp  -- 追加する場所の手前のノードへのポインタ．
		  id  -- 追加するデータ．
		  lv  -- 追加するデータ．
		  key -- 追加するデータ．		複製
		  val -- 追加するデータ．		複製
		　ptr -- 汎用データへのポインタ	複製
		  sz  -- *ptr のサイズ
		   
	戻り値: 追加したノードへのポインタ．
*/
tList*  add_tList_node_bystr(tList* pp, int id, int lv, char* key, char* val, void* ptr, int sz) 
{
	tList* pt;
	tList_data ldat;

	ldat = make_tListdata_bystr(id, lv, key, val, ptr, sz);
	pt   = add_tList_node_bydata(pp, ldat);

	return pt;
}




/**
tList*  add_tList_node_byBuffer(tList* pp, int id, int lv, Buffer key, Buffer val, void* ptr, int sz) 

	機能: データからリスト用ノードをつくり出し(new),それをリストに追加．
		  リストポインタ ppが指すノードの後につくり出した ノードを挿入する．
		  sz>0 で ptr==NULL の場合は ptrの領域を確保し，0クリアする．

	引数: pp  -- 追加する場所の手前のノードへのポインタ．
		  id  -- 追加するデータ．
		  lv  -- 追加するデータ．
		  key -- 追加するデータ．			複製
		  val -- 追加するデータ．			複製
		　*ptr -- 汎用データへのポインタ	複製
		  sz   -- *ptr のサイズ
		   
	戻り値: 追加したノードへのポインタ．
*/
tList*  add_tList_node_byBuffer(tList* pp, int id, int lv, Buffer key, Buffer val, void* ptr, int sz) 
{
	tList* pt;
	tList_data ldat;

	ldat = make_tListdata(id, lv, key, val, ptr, sz);
	pt   = add_tList_node_bydata(pp, ldat);

	return pt;
}





/**	
tList*  free_tList_node(tList** node) 

	機能: 
		リスト用ノードのバッファ部(データ)の開放．
		*node には NULLが代入される．

	引数: *node  -- 開放するノードへのポインタ．
*/
void   free_tList_node(tList** node)
{
	if (node==NULL || *node==NULL) return;

	free_tListdata(&((*node)->ldat));
	*node = NULL;

	return;
}	





/**	
tList*  del_tList_node(tList* node) 

	機能: リスト用のノードを削除．
		  リストポインタ nodeが指すノードを削除し,リスト構造を詰める．

	引数: node  -- 削除するノードへのポインタ．

	戻り値: 削除したノードの直後のノードへのポインタ．
*/
tList*  del_tList_node(tList* node) 
{	
	tList* pp = NULL;

	if (node==NULL) return NULL;

	free_tListdata(&(node->ldat));

	if (node->prev!=NULL) node->prev->next = node->next;
	if (node->next!=NULL) {
		node->next->prev = node->prev;
		pp = node->next;
	}
	free(node);

	return pp;
}





/**
tList*  dup_tList_node(tList* node)

	機能：ノードを複製する (new)．ノードのポインタは複製しない．

*/			 
tList*  dup_tList_node(tList* node)
{
	tList* pp;
	int	sz;

	if (node==NULL) return NULL;

	sz = sizeof(tList);
	pp = (tList*)malloc(sz);
	if (pp==NULL) return NULL;

	memcpy(pp, node, sz);
	pp->ldat = dup_tListdata(node->ldat);
	pp->next = NULL;
	pp->prev = NULL;
	pp->altp = NULL;
	pp->back = NULL;
	pp->esis = NULL;
	pp->ysis = NULL;

	return pp;
}




/**
tList*  move_tList_node(tList* pp, tList* node)

	機能: nodeを現在のリストから切り離し，ppへ移動する．
		  nodeを削除しないで del_tList_node(), add_tList_node() を実行するようなもの．

	引数: pp    -- 移動先で親となるノードへのポインタ．
		  node  -- 移動するノードへのポインタ．

	戻り値: 移動したノードノードへのポインタ．
*/
tList*  move_tList_node(tList* pp, tList* node)
{
	if (pp==NULL || node==NULL) return NULL;
    
	if (node->prev!=NULL) node->prev->next = node->next;
	if (node->next!=NULL) node->next->prev = node->prev;

	node->prev = pp;
	node->next = pp->next;
	if (pp->next!=NULL) pp->next->prev = node;
	pp->next   = node;
	
	return node;
}





/**
void	set_tList_node_bydata(tList* pp, tList_data ldat)

	機能：リストのノードに値を設定する．
		  ldat は指定されたものがそのまま使用される．

	引数: pp   -- 設定するノードへのポインタ．
		  ldat -- 設定するノードデータ．このデータがそのまま使用される．

*/
void	set_tList_node_bydata(tList* node, tList_data dat)
{
	if (node==NULL) return;

	free_tListdata(&(node->ldat));
	node->ldat = dat;
}





/**
void	set_tList_node_bystr(tList* pp, int id, int lv, char* key, char* val, void* ptr, int sz)

	機能：リストのノードに値を設定する．それぞれのデータは複製されて設定される．
		  key, valが NULLの場合は，その値はノードは設定されない．

	引数: id  -- ノードのID
		  lv  -- ノードのデータ
		  key -- ノードのキー				複製
		  val -- ノードのデータ 			複製
		　ptr -- 汎用データへのポインタ		複製
		  sz  -- *ptr のサイズ

*/
void	set_tList_node_bystr(tList* pp, int id, int lv, char* key, char* val, void* ptr, int sz)
{
	if (pp==NULL) return;

	pp->ldat.id = id;
	pp->ldat.lv = lv;
	pp->ldat.sz = sz;

	if (key!=NULL) {
		free_Buffer(&(pp->ldat.key));
		pp->ldat.key = make_Buffer_bystr(key);
	}
	if (val!=NULL) {
		free_Buffer(&(pp->ldat.val));
		pp->ldat.val = make_Buffer_bystr(val);
	}

	if (sz>0 && ptr!=NULL) {
		if (pp->ldat.ptr!=NULL) free(pp->ldat.ptr);
		pp->ldat.ptr = (void*)malloc(sz);
		if (pp->ldat.ptr!=NULL) memcpy(pp->ldat.ptr, ptr, sz);
	}
}





/**
void	set_tList_node_byBuffer(tList* pp, int id, int lv, Buffer key, Buffer val, void* ptr, int sz)

	機能：リストのノードに値を設定する．それぞれのデータは複製されて設定される．
		  key.buf, val.bufが NULLの場合は，その値はノードには設定されない．

	引数: id  -- ノードのID
		  lv  -- ノードのデータ
		  key -- ノードのキー	(Buffer)	複製
		  val -- ノードのデータ (Buffer)	複製
		　ptr -- 汎用データへのポインタ		複製
		  sz  -- *ptr のサイズ

*/
void	set_tList_node_byBuffer(tList* pp, int id, int lv, Buffer key, Buffer val, void* ptr, int sz)
{
	if (pp==NULL) return;

	pp->ldat.id = id;
	pp->ldat.lv = lv;

	if (pp->ldat.key.buf!=NULL) {
		free_Buffer(&(pp->ldat.key));
		pp->ldat.key = dup_Buffer(key);
	}

	if (pp->ldat.val.buf!=NULL) {
		free_Buffer(&(pp->ldat.val));
		pp->ldat.val = dup_Buffer(val);
	}

	if (sz>0 && ptr!=NULL) {
		if (pp->ldat.ptr!=NULL) free(pp->ldat.ptr);
		pp->ldat.ptr = (void*)malloc(sz);
		if (pp->ldat.ptr!=NULL) memcpy(pp->ldat.ptr, ptr, sz);
	}
}





/**
tList*	update_tList_node(tList* pp, tList* pt)

	機能：ppを pt->keyで検索し，該当ノードがあればノードをコピーする．無ければ最後にノードを追加する(new)．

	引数: pp -- 検索を開始するノードへのポインタ．
		  pt -- 設定するノードへのポインタ．検索キーは pt->key

	戻り値：設定または追加したノードへのポインタ
*/
tList*	update_tList_node(tList* pp, tList* pt)
{
	tList* pm;
	tList_data ldat;

	if (pt==NULL) return pp;
	
	ldat = pp->ldat;
	pm = update_tList_node_byBuffer(pp, ldat.id, ldat.lv, ldat.key, ldat.val, ldat.ptr, ldat.sz);
	
	return pm;
}





/**
tList*	update_tList_node_bydata(tList* pp, char* srch, tList_data ldat)

	機能：ppを srchで検索し，該当ノードがあればノードを設定する．無ければ最後にノードを追加する(new)．
		  ldat は指定されたものがそのまま使用される．

	引数: pp   -- 検索を開始するノードへのポインタ．
		  srch -- 検索キー
		  ldat -- 追加するノードデータ．このデータがそのまま使用される．

	戻り値：設定または追加したノードへのポインタ
*/
tList*	update_tList_node_bydata(tList* pp, char* srch, tList_data ldat)
{
	tList* pm = NULL;

	if (pp==NULL || srch==NULL) return NULL;

	pm = strncmp_tList(pp, srch, 0, 1);
	if (pm!=NULL) set_tList_node_bydata(pm, ldat);
	else {
		pm = find_tList_end(pp);
		pm = add_tList_node_bydata(pm, ldat);
	}
	
	return pm;
}





/**
tList*	update_tList_node_bystr(tList* pp, int id, int lv, char* key, char* val, void* ptr, int sz)

	機能：ppを keyで検索し，該当ノードがあればノードを設定する．無ければ最後にノードを追加する(new)．
		  それぞれのデータは複製される．

	引数: pp  -- 検索を開始するノードへのポインタ．
		  id  -- ノードのID
		  lv  -- ノードのデータ
		  key -- ノードのキー．検索キー		複製
		  val -- ノードのデータ (Buffer)	複製
		　ptr -- 汎用データへのポインタ		複製
		  sz  -- *ptr のサイズ

	戻り値：設定または追加したノードへのポインタ
*/
tList*	update_tList_node_bystr(tList* pp, int id, int lv, char* key, char* val, void* ptr, int sz)
{
	tList* pm = NULL;

	if (pp==NULL || key==NULL) return NULL;

	pm = strncmp_tList(pp, key, 0, 1);
	if (pm!=NULL) {
		set_tList_node_bystr(pm, id, lv, NULL, val, ptr, sz);
	}
	else {
		pm = find_tList_end(pp);
		pm = add_tList_node_bystr(pm, id, lv, key, val, ptr, sz);
	}
	
	return pm;
}





/**
tList*	update_tList_node_byBuffer(tList* pp, int id, int lv, Buffer key, Buffer val, void* ptr, int sz)

	機能：ppを key.bufで検索し，該当ノードがあればノードを設定する．無ければ最後にノードを追加する(new)．
		  それぞれのデータは複製される．

	引数: pp  -- 検索を開始するノードへのポインタ．
		  id  -- ノードのID
		  lv  -- ノードのデータ
		  key -- ノードのキー   (Buffer)	複製
		  val -- ノードのデータ (Buffer)	複製
		　ptr -- 汎用データへのポインタ		複製
		  sz  -- *ptr のサイズ

	戻り値：設定または追加したノードへのポインタ
*/
tList*	update_tList_node_byBuffer(tList* pp, int id, int lv, Buffer key, Buffer val, void* ptr, int sz)
{
	tList* pm = NULL;

	if (pp==NULL || key.buf==NULL) return NULL;

	pm = strncmp_tList(pp, (char*)key.buf, 0, 1);
	if (pm!=NULL) set_tList_node_byBuffer(pm, id, lv, key, val, ptr, sz);
	else {
		pm = find_tList_end(pp);
		pm = add_tList_node_byBuffer(pm, id, lv, key, val, ptr, sz);
	}
	
	return pm;
}







/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// tiny List
//

/**	
tList*  del_tList(tList** pp) 

	機能: リスト用の指定したノード以降のノードを削除．

	引数: *pp  -- 削除するノードへのポインタ．

	戻り値: 削除したノード(s)の直前のノードへのポインタ．
*/
tList*  del_tList(tList** pp) 
{	
	tList* pt;
	tList* pm;
	tList* pw;

	if (pp==NULL || *pp==NULL) return NULL;

	pt = (*pp)->prev;
	if (pt!=NULL) pt->next = NULL;

	pm = *pp;
	while (pm!=NULL) {
		pw = pm;
		pm = pm->next;
   		free_tListdata(&(pw->ldat));
		free(pw);
	}
	*pp = NULL;

	return pt;
}





/**
void  del_all_tList(tList** pp)

	機能: リストの全ノードの削除．
		  ポインタ ppのノードを含むリスト全体を削除する．
		  pp はりスト中であれば，どこを指していても良い．

	引数: *pp  -- 削除を開始するノードへのポインタ．

	戻り値: なし．
*/
void  del_all_tList(tList** pp)
{
	tList* pm;
	tList* pv;

	if (pp==NULL || *pp==NULL) return;

	pm = *pp;
	pv = (*pp)->prev;

	do {
		pm = del_tList_node(pm);
	} while (pm!=NULL);

	pm = pv;
	while (pm!=NULL) {
		pv = pm->prev;
		del_tList_node(pm);
		pm = pv;
	}

	*pp = NULL;
}




/**	 
int  del_tList_key(tList* pl, char* key, int no)
		
	機能: plからサーチして，no番目の keyのノードを削除する．
		
	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）．大文字，小文字を区別しない．	
		  no  -- 一致した物の中で何番目の物を削除するか指定する．1から数える．0の場合は全て削除する．
		
	戻り値: 削除したノードの数．
*/	  
int  del_tList_key(tList** pl, char* key, int no)
{	   
	int dl = 0;
	int nn = 0;
	if (no<0) no = 0;

	tList* pp = *pl;

	while (pp!=NULL) {
		if (ex_strncasecmp((char*)(pp->ldat).key.buf, (char*)key, 0)) {
			nn++;
			if (no==0 || no==nn) {
				if (pp->prev==NULL) *pl = pp->next;
				pp = del_tList_node(pp);	
				dl++;
				if (no!=0) break;
			}
			else {
				pp = pp->next;
			}
		}
		else {
			pp = pp->next;
		}
	}

	return dl;
}






/**
tList*  dup_tList(tList* pp)

	機能：リストを複製する．

*/			 
tList*  dup_tList(tList* pp)
{
	tList* pt;
	tList* pl;
	tList* tt;

	if (pp==NULL) return NULL;

	pt = pl = dup_tList_node(pp);
	pp = pp->next;

	while(pp!=NULL) {
		tt = dup_tList_node(pp);
		pl = insert_tList(pl, tt);
		pp = pp->next;
	}

	return pt;
}



/**
tList*  add_tList(tList* pp, tList* pt)

	機能：リストppの最後に リストptを追加する．

	pp->1->2->3, pt->4->5 => pp->1->2->pt->4->5 
*/

tList*  add_tList_end(tList* pp, tList* pt)
{
	if (pt==NULL) return pp;
	if (pp==NULL) return pt;

	tList* pe = find_tList_end(pp);
	pe->next = pt;
	pt->prev = pe;

	return pp;
}





/**
tList*  insert_tList(tList* pp, tList* pt)

	機能：ノードppの直ぐ後ろに ptを挿入する．
	
	戻り値：挿入した先頭のリストへのアドレス．

	pp->1->2->3, pt->4->5 => pp->pt->4->5->1->2 
*/
tList*  insert_tList(tList* pp, tList* pt)
{
	tList* pe;
	
	if (pt==NULL) return pp;
	if (pp==NULL) return pt;

	pe = find_tList_end(pt);
	if (pp->next!=NULL) pp->next->prev = pe;
	pe->next = pp->next;
	pp->next = pt;
	pt->prev = pp;
	
	return pt;
}





/**
void  print_tList(File* fp, tList* pp)

	機能: リストの表示．
		  ポインタ pp以降の全てのノードのキー部のバッファを標準エラー出力に表示する．

	引数: fp -- 出力するファイルへのポインタ．NULLの場合は stderr
		  pp -- 表示を開始するノードへのポインタ．

	戻り値: なし．

*/
void  print_tList(FILE* fp, tList* pp)
{
	if (fp==NULL) fp = stderr;

	if (pp!=NULL) {
		while(pp!=NULL) {
			tList_data ld = pp->ldat;
			fprintf(fp, "[%d] [%d] [%s] [%s]\n", ld.id, ld.lv, ld.key.buf, ld.val.buf);
			//if (pp->next!=NULL) print_tList(pp->next);
			pp = pp->next;
		}
	}
	else {
		fprintf(fp, "(List is NULL)\n");
	}
	return;
}




void  dump_tList(FILE* fp, tList* pp)
{
	if (fp==NULL) fp = stderr;

	if (pp!=NULL) {
		while(pp!=NULL) {
			tList_data ld = pp->ldat;
			fprintf(fp, "[%d] [%d] [%s] [%d]\n", ld.id, ld.lv, ld.key.buf, ld.val.vldsz);
			fdump(fp, (unsigned char*)ld.val.buf, ld.val.vldsz);
			pp = pp->next;
		}
	}
	else {
		fprintf(fp, "(List is NULL)\n");
	}
	return;
}





/**
int  count_tList(tList* pp)

	機能：リストの ppノード以降のノードの数を数える．

	引数: pp -- 数え始めるノードへのポインタ．

	戻り値: ノードの数．
*/
int  count_tList(tList* pp)
{
	int cnt = 0;

	while (pp!=NULL) {
		cnt++;
		pp = pp->next;
	}	
	return cnt;
}






///////////////////////////////////////////////////////////////////////////////////////////
//
// String Compare
//

/**
tList*  strncmp_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．
		  ポインタ pl以降のノードで,キー部の文字列が keyと前方一致（部分的も可）するノードの内，
		  no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					 TLIST_MATCH_COMPLETE   (0): 完全一致．
					 TLIST_MATCH_TLISTKEY  (-1): pl->key.buf の長さに合わせる．
					 TLIST_MATCH_STRINGKEY (-2): key の長さに合わせる．
		  no  -- 一致した物の中で何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strncmp_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (len<=-3) return NULL;
	if (no<=0) no = 1;

	while (pl!=NULL) {
		if (ex_strncmp((char*)pl->ldat.key.buf, (char*)key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->next;
	}
	return NULL;
}





/**
tList*  strncasecmp_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．大文字小文字を無視する．
		  ポインタ pl以降のノードで,キー部の文字列が keyと前方一致（部分的も可）するノードの内，
		  no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					  0: 完全一致．
					 -1: pl->key の長さに合わせる．
					 -2: key の長さに合わせる．
		  no  -- 一致した物の中で何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strncasecmp_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (len<=-3) return NULL;
	if (no<=0) no = 1;

	while (pl!=NULL) {
		if (ex_strncasecmp((char*)(pl->ldat).key.buf, (char*)key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->next;
	}
	return NULL;
}





/**
tList*  strnrvscmp_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．
		  ポインタ pl以降のノードで,キー部の文字列が keyと後方一致（部分的も可）するノードの内，
		  no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					  0: 完全一致．
					 -1: pl->key の長さに合わせる．
					 -2: key の長さに合わせる．
		  no  -- 一致した物の中で何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strnrvscmp_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (len<=-3) return NULL;
	if (no<=0) no = 1;

	while (pl!=NULL) {
		if (ex_strnrvscmp((char*)(pl->ldat).key.buf, (char*)key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->next;
	}
	return NULL;
}





/**
tList*  strncaservscmp_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．大文字小文字を無視．
		  ポインタ pl以降のノードで,キー部の文字列が keyと後方一致（部分的も可）するノードの内，
		  no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					  0: 完全一致．
					 -1: pl->key の長さに合わせる．
					 -2: key の長さに合わせる．
		  no  -- 一致した物の中で何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strncaservscmp_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (len<=-3) return NULL;
	if (no<=0) no = 1;

	while (pl!=NULL) {
		if (ex_strncaservscmp((char*)(pl->ldat).key.buf, (char*)key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->next;
	}
	return NULL;
}





/**
tList*  strstr_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．
		  ポインタ pl以降のノードで,キー部の文字列または keyの文字列が相手の文字列に含まれる
		  ノードの内，no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー．
		  len  -- >=0: key が plのキーに含まれるかどうか検査する．
				   <0: plのキーが Keyに含まれるかどうか検査する．
		  no  -- 一致した物の中で何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strstr_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (no<=0) no = 1;

	while (pl!=NULL) {
		if (len>=0) {
			if (strstr((char*)(pl->ldat).key.buf, (char*)key)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}
		else if (len<0) {
			if (strstr((char*)key, (char*)(pl->ldat).key.buf)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}

		pl = pl->next;
	}
	return NULL;
}





/**
tList*  strstrcase_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．大文字小文字を無視．
		  ポインタ pl以降のノードで,キー部の文字列または keyの文字列が相手の文字列に含まれる
		  ノードの内，no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー．
		  len  -- >=0: key が plのキーに含まれるかどうか検査する．
				   <0: plのキーが Keyに含まれるかどうか検査する．
		  no  -- 一致した物の中で何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strstrcase_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (no<=0) no = 1;

	while (pl!=NULL) {
		if (len>=0) {
			if (strstrcase((char*)(pl->ldat).key.buf, (char*)key)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}
		else if (len<0) {
			if (strstrcase((char*)key, (char*)(pl->ldat).key.buf)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}

		pl = pl->next;
	}
	return NULL;
}




///////////////////////////////////////////////////////////////////////////////////////////
//
// String Compare Back List
//

/**
tList*  strncmp_back_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．
		  ポインタ pl以降のノードで,キー部の文字列が keyと前方一致（部分的も可）するノードの内，
		  後ろから数えて no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					  0: 完全一致．
					 -1: pl->key の長さに合わせる．
					 -2: key の長さに合わせる．
		  no  -- 一致した物の中で後ろから数えて，何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strncmp_back_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (len<=-3) return NULL;
	if (no<=0) no = 1;

	pl = find_tList_end(pl);
	
	while (pl!=NULL) {
		if (ex_strncmp((char*)(pl->ldat).key.buf, (char*)key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->prev;
	}
	return NULL;
}





/**
tList*  strncasecmp_back_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．大文字小文字を無視する．
		  ポインタ pl以降のノードで,キー部の文字列が keyと前方一致（部分的も可）するノードの内，
		  後ろから数えて no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					  0: 完全一致．
					 -1: pl->key の長さに合わせる．
					 -2: key の長さに合わせる．
		  no  -- 一致した物の中で後ろから数えて，何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strncasecmp_back_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (len<=-3) return NULL;
	if (no<=0) no = 1;

	pl = find_tList_end(pl);

	while (pl!=NULL) {
		if (ex_strncasecmp((char*)(pl->ldat).key.buf, (char*)key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->prev;
	}
	return NULL;
}





/**
tList*  strnrvscmp_back_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．
		  ポインタ pl以降のノードで,キー部の文字列が keyと後方一致（部分的も可）するノードの内，
		  後ろから数えて no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					  0: 完全一致．
					 -1: pl->key の長さに合わせる．
					 -2: key の長さに合わせる．
		  no  -- 一致した物の中で後ろから数えて，何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strnrvscmp_back_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (len<=-3) return NULL;
	if (no<=0) no = 1;

	pl = find_tList_end(pl);

	while (pl!=NULL) {
		if (ex_strnrvscmp((char*)(pl->ldat).key.buf, (char*)key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->prev;
	}
	return NULL;
}





/**
tList*  strncaservscmp_back_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．大文字小文字を無視．
		  ポインタ pl以降のノードで,キー部の文字列が keyと後方一致（部分的も可）するノードの内，
		  後ろから数えて no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					  0: 完全一致．
					 -1: pl->key の長さに合わせる．
					 -2: key の長さに合わせる．
		  no  -- 一致した物の中で後ろから数えて，何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strncaservscmp_back_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (len<=-3) return NULL;
	if (no<=0) no = 1;

	pl = find_tList_end(pl);

	while (pl!=NULL) {
		if (ex_strncaservscmp((char*)(pl->ldat).key.buf, (char*)key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->prev;
	}
	return NULL;
}





/**
tList*  strstr_back_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．
		  ポインタ pl以降のノードで,キー部の文字列または keyの文字列が相手の文字列に含まれる
		  ノードの内，後ろから数えて no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー．
		  len  -- >=0: key が plのキーに含まれるかどうか検査する．
				   <0: plのキーが Keyに含まれるかどうか検査する．
		  no  -- 一致した物の中で後ろから数えて，何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strstr_back_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (no<=0) no = 1;

	pl = find_tList_end(pl);

	while (pl!=NULL) {
		if (len>=0) {
			if (strstr((char*)(pl->ldat).key.buf, (char*)key)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}
		else if (len<0) {
			if (strstr((char*)key, (char*)(pl->ldat).key.buf)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}

		pl = pl->prev;
	}
	return NULL;
}





/**
tList*  strstrcase_back_tList(tList* pl, char* key, int len, int no)

	機能: char*型変数によるノードのサーチ．大文字小文字を無視．
		  ポインタ pl以降のノードで,キー部の文字列または keyの文字列が相手の文字列に含まれる
		  ノードの内，後ろから数えて no番目にあるのを捜し出す．

	引数: pl   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー．
		  len  -- >=0: key が plのキーに含まれるかどうか検査する．
				   <0: plのキーが Keyに含まれるかどうか検査する．
		  no  -- 一致した物の中で後ろから数えて，何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tList*  strstrcase_back_tList(tList* pl, char* key, int len, int no)
{
	int nn = 0;

	if (no<=0) no = 1;

	pl = find_tList_end(pl);

	while (pl!=NULL) {
		if (len>=0) {
			if (strstrcase((char*)(pl->ldat).key.buf, (char*)key)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}
		else if (len<0) {
			if (strstrcase((char*)key, (char*)(pl->ldat).key.buf)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}

		pl = pl->prev;
	}
	return NULL;
}







///////////////////////////////////////////////////////////////////////////////////////////

/**
tList*  find_tList_top(tList* pl)

	機能: リストの最初のノードへを探す．

	引数: pl -- サーチを開始するノードへのポインタ．

	戻り値: リストの最初のノードへのポインタ．
*/
tList*  find_tList_top(tList* pl)
{
	if (pl==NULL) return NULL;

	while (pl->prev!=NULL) pl = pl->prev;
	return pl;
}





/**
tList*  find_tList_end(tList* pl)

	機能: リストの最後のノードへを探す．
		  リスト構造の最後のノードを探す関数なので，tTree 構造に適用しても正しい
		　ノードを見つけることは出来ない．tTreeに対しては find_tTree_end()を使うこと．

	引数: pl -- サーチを開始するノードへのポインタ．

	戻り値: リストの最後のノードへのポインタ．
*/
tList*  find_tList_end(tList* pl)
{
	if (pl==NULL) return NULL;

	while (pl->next!=NULL) pl = pl->next;
	return pl;
}




/**
Buffer  search_key_tList(tList* list, char* key, int no) 

	機能：リストの中から no番目の keyノード(ldat.key)を探し出し，ldat.valのコピーを返す．
		  key はケースインセンシティブ．

	引数：key  -- ヘッダ種別．大文字，小文字を区別しない．

	戻り値：
		  要free
*/
Buffer  search_key_tList(tList* list, char* key, int no) 
{
	tList* pp;
	Buffer buf;

	buf = init_Buffer();
	if (list==NULL || key==NULL) return buf;
	
	pp = strncasecmp_tList(list, key, 0, no);		// 完全一致
	if (pp!=NULL) {
		buf = dup_Buffer(pp->ldat.val);
	}
	
	return buf;
}





/**
Buffer  search_key_value_tList(tList* list, char* key, char* data, int no) 

	機能：リストの中から no番目の keyノードを探し出し，data で始まるノード値を返す．
		  key, dataはケースインセンシティブ．

	引数：key  -- ヘッダ種別． 大文字，小文字を区別しない．
	　　　data -- 検索するヘッダ値の最初の文字．
*/
Buffer  search_key_value_tList(tList* list, char* key, char* data, int no) 
{
	tList* pp;
	Buffer buf;
	char*  str;
	int	   len;

	buf = init_Buffer();
	if (list==NULL || key==NULL) return buf;

	if (data==NULL) {
		buf = search_key_tList(list, key, no);
		return buf;
	}

	buf = init_Buffer();
	len = (int)strlen(data); 
	
	pp = strncasecmp_tList(list, key, 0, no);
	if (pp!=NULL) {
		str = (char*)pp->ldat.val.buf;
		if (str!=NULL && !strncasecmp(str, data, len)) {
			buf = make_Buffer_bystr(str);
			return buf;
		}
	}

	return buf;
}






/*
int   set_value_tList(tList* list, char* key, int no, char* value, int add_mode)

	機能：リスト(lt)中の no番目の keyノードの値に valueを設定する．
		no が 0以下の場合は，全ての keyノードの値に対して設定が行われる．
		keyノードが存在せず，かつ mode==ON の場合は，リストの最後に追加される．

	引数：
		list   -- 処理対象のリスト
		key    -- 設定を行うノードのキー部．大文字，小文字を区別しない．
	 	value  -- 設定される文字列．
		no     -- keyが一致する何個目のノードに対して設定を行うか．1から数える．
				  0以下の場合はkeyが一致するすべてのノードに対して設定を行う．
		add_mod - この値がON かつ指定したノードが無い場合，ノードをリストの最後に追加する．

	戻り値：
		設定されたノードの数．指定されたノードが存在しない場合は（追加された場合も）0
		負数の場合はエラー．

*/
int   set_value_tList(tList* list, char* key, int no, char* value, int add_mode)
{
	int    cn = 0;
	tList* pm;

	if (list==NULL || key==NULL || value==NULL) return -1;

	if (no>0) {
		pm = strncasecmp_tList(list, key, 0, no);
		if (pm!=NULL) {
			int rep = set_value_tList_node(pm, value);
			if (rep) cn = 1;
		}
	}
	else {		// no<=0
		int nn = 1;
		cn = 0;
		pm = strncasecmp_tList(list, key, 0, nn);
		while (pm!=NULL) {
			int rep = set_value_tList_node(pm, value);
			if (rep) cn++;
			pm = strncasecmp_tList(list, key, 0, ++nn);
		}
	}

	// Not Found
	if (add_mode==ON && cn==0) {
		add_tList_node_str(list, key, value);
	}

	return cn;
}





int   set_value_tList_node(tList* lp, char* value)
{
	if (lp==NULL || value==NULL) return FALSE;
	
	Buffer buf = make_Buffer_bystr(value);
	free_Buffer(&lp->ldat.val);
	lp->ldat.val = buf;

	return TRUE;
}





/**
int	 replace_value_tList(tList* list, char* key, int no, char* srcval, char* value)

	機能：リスト(lt)中の no番目の keyノードの値の srcvalの部分を value に置き換える．
		no が 0以下の場合は，全ての keyノードの値に対して置き換えが行われる．

	引数：
		list   -- 処理対象のリスト
		key    -- 置き換えを行うノードのキー部．大文字，小文字を区別しない．
		srcval -- 置き換え対象の文字列．NULLなら指定した項目の文字列全体．
	 	value  -- 置き換えを行う文字列．
		no     -- 何個目のノードを置き換えるか．1から数える．0以下の場合はkeyが一致する全てのノードを置き換える

	戻り値：
		変更されたノードの数．指定されたノードが存在しないは（追加された場合も）0
		負数の場合はエラー．

*/
int	 replace_value_tList(tList* list, char* key, int no, char* srcval, char* value)
{
	int	cn = 0;
	tList* pm;

	if (list==NULL || key==NULL || value==NULL) return -1;
	if (srcval==NULL) {
		return set_value_tList(list, key, no, value, OFF);
	}

	if (no>0) {
		pm = strncasecmp_tList(list, key, 0, no);
		if (pm!=NULL) {
			int rep = replace_value_tList_node(pm, srcval, value);
			if (rep) cn = 1;
		}
	}
	else {	  // no<=0
		int nn = 1;
		cn = 0;
		pm = strncasecmp_tList(list, key, 0, nn);
		while (pm!=NULL) {
			int rep = replace_value_tList_node(pm, srcval, value);
			if (rep) cn++;
			pm = strncasecmp_tList(list, key, 0, ++nn);
		}
	}
	
	return cn;
}





int	 replace_value_tList_node(tList* lp, char* srcval, char* value)
{
	if (lp==NULL || value==NULL) return FALSE;
	if (srcval==NULL) {
		return set_value_tList_node(lp, value);
	}

	Buffer buf = replace_sBuffer(lp->ldat.val, srcval, value);
	free_Buffer(&lp->ldat.val);
	lp->ldat.val = buf;
	
	return TRUE;
}
	







tList*	awk_tList(char* str, char cc)
{
	int    nn = 1;
	char*  item;
	tList* lp = NULL;

	if (str==NULL) return NULL;

	item = awk(str, cc, nn);
	while (item!=NULL) {
		lp = add_tList_node_bystr(lp, nn, 0, item, NULL, NULL, 0);
		free(item);
		item = awk(str, cc, ++nn);
	}

	if (lp!=NULL) lp = find_tList_top(lp);
	return lp;
}





tList*	cawk_tList(char* str, char cc)
{
	int    nn = 1;
	char*  item;
	tList* lp = NULL;

	if (str==NULL) return NULL;

	item = cawk(str, cc, nn);
	while (item!=NULL) {
		lp = add_tList_node_bystr(lp, nn, 0, item, NULL, NULL, 0);
		free(item);
		item = cawk(str, cc, ++nn);
	}

	if (lp!=NULL) lp = find_tList_top(lp);
	return lp;

}




tList*	awk_Buffer_tList(Buffer buf, char cc)
{
	int    nn = 1;
	Buffer item;
	tList* lp = NULL;

	if (buf.buf==NULL) return NULL;

	item = awk_Buffer(buf, cc, nn);
	while (item.buf!=NULL) {
		lp = add_tList_node_bystr(lp, nn, 0, (char*)item.buf, NULL, NULL, 0);
		free_Buffer(&item);
		item = awk_Buffer(buf, cc, ++nn);
	}

	if (lp!=NULL) lp = find_tList_top(lp);
	return lp;
}





tList*	cawk_Buffer_tList(Buffer buf, char cc)
{
	int    nn = 1;
	Buffer item;
	tList* lp = NULL;

	if (buf.buf==NULL) return NULL;

	item = cawk_Buffer(buf, cc, nn);
	while (item.buf!=NULL) {
		lp = add_tList_node_bystr(lp, nn, 0, (char*)item.buf, NULL, NULL, 0);
		free_Buffer(&item);
		item = cawk_Buffer(buf, cc, ++nn);
	}

	if (lp!=NULL) lp = find_tList_top(lp);
	return lp;

}





char*  get_str_join_tList(tList* lp, char* deli)
{
	Buffer buf = get_Buffer_join_tList(lp, deli);
	return (char*)buf.buf;
}






Buffer  get_Buffer_join_tList(tList* lp, char* deli)
{
	Buffer buf;
	
	buf = init_Buffer();
	if (lp==NULL) return buf;

	buf = make_Buffer(LBUF);

	if (lp!=NULL && lp->ldat.key.buf!=NULL) {
		cat_s2Buffer((char*)lp->ldat.key.buf, &buf);
		lp = lp->next;

		while (lp!=NULL && lp->ldat.key.buf!=NULL) {
			if (deli!=NULL) cat_s2Buffer(deli, &buf);
			cat_s2Buffer((char*)lp->ldat.key.buf, &buf);
			lp = lp->next;
		}
	}

	return buf;
}






//////////////////////////////////////////////////////////////////////////
// for Configuration File
//

char*  get_str_param_tList(tList* lt, char* key, char* dflt)
{
	Buffer buf;

	buf = search_key_tList(lt, key, 1);
	if (buf.buf==NULL) buf = make_Buffer_bystr(dflt);
		
	return (char*)buf.buf;
}



int  get_int_param_tList(tList* lt, char* key, int dflt)
{
	Buffer buf;

	buf = search_key_tList(lt, key, 1);
	if (buf.buf!=NULL) {
		int ret = atoi((char*)buf.buf);
		free_Buffer(&buf);
		return ret;
	}
	return dflt;
}



double  get_double_param_tList(tList* lt, char* key, double dflt)
{
	Buffer buf;

	buf = search_key_tList(lt, key, 1);
	if (buf.buf!=NULL) {
		double ret = atof((char*)buf.buf);
		free_Buffer(&buf);
		return ret;
	}
	return dflt;
}



float  get_float_param_tList(tList* lt, char* key, float dflt)
{
	Buffer buf;

	buf = search_key_tList(lt, key, 1);
	if (buf.buf!=NULL) {
		float ret = (float)atof((char*)buf.buf);
		free_Buffer(&buf);
		return ret;
	}
	return dflt;
}



int  get_bool_param_tList(tList* lt, char* key, int dflt)
{
	int   ret = dflt;
	char* val = NULL;

	if (dflt) val = get_str_param_tList(lt, key, "true");
	else      val = get_str_param_tList(lt, key, "false");

	if (val!=NULL) {
		if (!strcasecmp("true", val)) ret = 1;		// TRUE
		else ret = 0;								// FALSE
		free(val);
	}

	return ret;
}









/////////////////////////////////////////////////////////////////////////////
//
// Tiny List File I/O
//

/**
tList*  read_tList_file(char* fname, int mode) 

	機能：ファイルから一行づつ読み込んでリストのキー部に格納．
		  空行はリストに加えない．

	引数：fname -- ファイル名． 
		  mode  -- 0 の場合，ファイルをそのまま読み込む．
			 	   1 の場合，先頭が # の行はリストに加えない．また前後の空白を削除し，その他の連続する空白も1つの空白に変換する．
				   さらにタブは一個の空白として処理される．
				   2 の場合，1に加えて，途中の # 以降も無視する

	戻り値：格納したリストへのポインタ．
*/
tList*  read_tList_file(char* fname, int mode) 
{
	tList* lp = NULL;
	FILE* fp;

	fp = fopen(fname, "rb");
	if (fp!=NULL) {
		lp = read_tList_fp(fp, mode);
		fclose(fp);
	}
	else {
		DEBUG_MESG("READ_TLIST_FILE: cannot file open [%s]\n", fname);
	}

	return lp;
}






/**
tList*  read_tList_fp(FILE* fp, int mode) 

	機能：ファイルポインタが示すファイルから一行づつ読み込んでリストのキー部に格納．
		  空行はリストに加えない．

	引数：fp   -- ファイルポインタ． 
		  mode -- 0 の場合，ファイルをそのまま読み込む．
				  1 の場合，先頭が # の行はリストに加えない．また前後の空白を削除し，
				　その他の連続する空白も1つの空白に変換する．
				  また，タブは一個の空白として処理される．
				  2 の場合，1に加えて，途中の # 以降も無視する

	戻り値：格納したリストへのポインタ．

	バグ：ディレクトリを読ませると，戻ってこない．

*/
tList*  read_tList_fp(FILE* fp, int mode) 
{
	char	val[LBUF+1];
	char*   str;
	tList*   lp = NULL;
	tList*   lt = NULL;

	if (fp==NULL) return NULL;

	fgets(val, LBUF, fp);
	while (!feof(fp)) {
		if (mode>0) {
			if (mode>1) {
				int i;
				for (i=0; i<(int)strlen(val); i++) {
					if (val[i]=='#') {
						val[i] = '\0';
						break;
					}
					if (i>=LBUF) break;
				}
			}
			str = pack_char(val, ' ');
		}
		else {
			str = (char*)malloc(LBUF+1);
			if (str!=NULL) strncpy(val, str, LBUF);
		}

		if (str!=NULL) {
			if (strlen(str)>0) {	// 空行のチェック
				if (mode==0 || str[0]!='#') {
					lt = add_tList_node_str(lt, str, NULL);
					if (lp==NULL) lp = lt;
				}
			}
			free(str);
		}
		fgets(val, LBUF, fp);
	}
	
	return lp;
}





/**
tList*  read_index_tList_file(char* fname, char deli) 

	機能：ファイルから一行づつ読み込んで，deliを区切り文字にしてリストのキー部とデータ部に格納．
		  空行はリストに加えない．#で始まる行はリストに加えない

	引数：fname -- ファイル名． 
		  deli  -- 区切り文字

	戻り値：格納したリストへのポインタ．
*/
tList*  read_index_tList_file(char* fname, char deli) 
{
	tList* lp = NULL;
	FILE* fp;

	fp = fopen(fname, "rb");
	if (fp!=NULL) {
		lp = read_index_tList_fp(fp, deli);
		fclose(fp);
	}
	return lp;
}





/**
tList*  read_index_tList_file(char* fname, char deli) 

	機能：ファイルから一行づつ読み込んで，deliを区切り文字にしてリストのキー部とデータ部に格納．
		  空行はリストに加えない．#で始まる行はリストに加えない

	引数：fp	-- ファイルポインタ． 
		  deli  -- 区切り文字

	戻り値：格納したリストへのポインタ．
*/
tList*  read_index_tList_fp(FILE* fp, char deli)
{
	Buffer key, val;
	tList* pl;
	tList* pp;
	tList* lt = NULL;

 	pp = pl = read_tList_fp(fp, 1);
	while (pp!=NULL) {
		key = awk_Buffer(pp->ldat.key, deli, 1);
		val = awk_Buffer(pp->ldat.key, deli, 2);
			
		if (lt==NULL) lt = add_tList_node_byBuffer(NULL, 0, 0, key, val, NULL, 0);
		else               add_tList_node_byBuffer(lt,   0, 0, key, val, NULL, 0);
	
		free_Buffer(&key);
		free_Buffer(&val);
		
		pp = pp->next;
	}
	del_all_tList(&pl);

	return lt;
}





/**
tList*  read_Buffer_tList_file(char* fname) 

	機能：ファイルから Buffer型変数を２つづつ読み込んで，リストのキー部とバッファ部に格納し返す．

	引数：fname -- ファイル名． 

	戻り値：格納したリストへのポインタ．
*/
tList*  read_Buffer_tList_file(char* fname) 
{
	tList* lp = NULL;
	FILE* fp;

	fp = fopen(fname, "rb");
	if (fp!=NULL) {
		lp = read_Buffer_tList_fp(fp);
		fclose(fp);
	}
	return lp;
}






/**
tList*  read_Buffer_tList_fp(FILE* fp) 

	機能：ファイルから Buffer型変数を２つづつ読み込んで，リストのキー部とバッファ部に格納し返す．

	引数：fp   -- ファイルポインタ． 

	戻り値：格納したリストへのポインタ．

*/
tList*  read_Buffer_tList_fp(FILE* fp) 
{
	int	cc;
	tList*  lp = NULL;
	tList*  lt = NULL;
	Buffer key, val;

	if (fp==NULL) return NULL;

	cc = read_Buffer2_fp(&key, &val, fp);
	while (!feof(fp) && cc) {
		lt = add_tList_node_Buffer(lt, key, val);
		if (lp==NULL) lp = lt;
		free_Buffer(&key);	
		free_Buffer(&val);	
		cc = read_Buffer2_fp(&key, &val, fp);
	}
	
	free_Buffer(&key);	
	free_Buffer(&val);	
	return lp;
}





/**
int  save_Buffer_tList_file(char* fname, tList* lp) 

	機能：リストのキー部とバッファ部の Buffer型変数をファイルへ書き込む
		  ファイルが既にある場合は，追加書き込みされる．

	引数：fname -- ファイル名． 

	戻り値：TRUE   書き込み成功．
			FALSE  書き込み失敗
*/
int  save_Buffer_tList_file(char* fname, tList* lp) 
{
	int   ret=FALSE;
	FILE* fp;

	fp = fopen(fname, "ab");
	if (fp!=NULL) {
		ret = save_Buffer_tList_fp(fp, lp);
		fclose(fp);
	}
	return ret;
}






/**
int   save_Buffer_tList_fp(FILE* fp, tList* lp) 

	機能：リストのキー部とバッファ部の Buffer型変数をファイルへ書き込む
		  ファイルが既にある場合は，追加書き込みされる．

	引数：fp   -- ファイルポインタ． 

	戻り値：TRUE   書き込み成功．
			FALSE  書き込み失敗

*/
int   save_Buffer_tList_fp(FILE* fp, tList* lp) 
{
	int cc=TRUE;

	if (fp==NULL) return FALSE;

	while (lp!=NULL && cc) {
		cc = save_Buffer2_fp(lp->ldat.key, lp->ldat.val, fp);	
		lp = lp->next;
	}

	if (!cc) return FALSE;
	return TRUE;
}









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

	Tiny Tree Graph



*/

/////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ノード操作
//

/**
tTree*  new_tTree_node(void)

	機能: ツリー用の空ノードを動的に生成．

	戻り値: 生成されたノードへのポインタ．

	#define new_tTree_node()     new_tList_node()

*/





/**
tTree   make_tTree_node(tList_data ldat)

	機能: ツリー用ノードを静的に生成．

	引数: ldat  -- ノードデータ

	戻り値: 作られたノード．

	#define make_tTree_node(d)     make_tList_node(d)
*/





/**
tTree*  add_tTree_node(tTree* pp, tTree* node) 

	機能: ツリー ppへノード nodeを追加．ポインタ ppが指すノードの子ノードとして node（そのもの）を追加する．
		  node が子ノードを持つ場合は，それも追加される．
		  node が姉妹ノードを持っていてもそれらは無視する．

	引数: pp    -- 追加するノードの親となるノードへのポインタ．
		  node  -- 追加するノードへのポインタ．node->next 以下がツリーでも良い．
		   
	戻り値: 追加したノードへのポインタ．失敗した場合は NULL
*/
tTree*  add_tTree_node(tTree* pp, tTree* node) 
{
	if (node==NULL) return NULL;
	if (pp==NULL) return node;

	node->prev = pp;
	node->ysis = NULL;
	node->esis = pp->back;

	if (pp->back!=NULL) pp->back->ysis = node;
	if (pp->next==NULL) pp->next = node;
	pp->back = node;

	node->depth = pp->depth + 1;
	pp->num++;
	
	if (node->next!=NULL) {
		node->next->depth = node->depth + 1;
		adjust_tTree_depth(node->next);
	}

	return node;
}





/**
tTree*  add_tTree_node_bydata(tTree* pp, tList_data ldat) 

	機能: データから Treeノードをつくり出し,それを ppの子ノードとして追加．
		  ldat は指定されたものがそのまま使用される．

	引数: pp   -- 追加するノードの親となるノードへのポインタ．
		  ldat -- 追加するノードデータ．このデータがそのまま使用される．
		   
	戻り値: 追加したノードへのポインタ．
*/
tTree*  add_tTree_node_bydata(tTree* pp, tList_data ldat) 
{
	tTree* pt;

	pt = new_tTree_node();
	pt->ldat  = ldat;
	pt->depth = 1;

	if (pp==NULL) return pt;

	pt->prev = pp;
	pt->esis = pp->back;

	if (pp->back!=NULL) pp->back->ysis = pt;
	if (pp->next==NULL) pp->next = pt;
	pp->back = pt;

	pt->depth = pp->depth + 1;
	pp->num++;
	
	return pt;
}





/**
tTree*  add_tTree_node_byBuffer(tTree* pp, int id, int lv, Buffer key, Buffer val, void* ptr, int sz) 

	機能: データからノードをつくり出し,それをリストに追加．
		  リストポインタ ppが指すノードの後につくり出した ノードを挿入する．

	引数: pp  -- 追加する場所の手前のノードへのポインタ．
		  id  -- 追加するデータ．
		  lv  -- 追加するデータ．
		  key -- 追加するデータ．		複製
		  val -- 追加するデータ．		複製
		　ptr -- 汎用データへのポインタ	複製
		  sz  -- *ptr のサイズ
		   
	戻り値: 追加したノードへのポインタ．
*/
tTree*  add_tTree_node_byBuffer(tTree* pp, int id, int lv, Buffer key, Buffer val, void* ptr, int sz) 
{
	tTree* pt;
	tList_data ldat;

	ldat = make_tListdata(id, lv, key, val, ptr, sz);
	pt   = add_tTree_node_bydata(pp, ldat);

	return pt;
}





/**
tTree*  add_tTree_node_bystr(tTree* pp, int id, int lv, char* key, char* val, void* ptr, int sz) 

	機能: データからノードをつくり出し,それをリストに追加．
		  リストポインタ ppが指すノードの後につくり出した ノードを挿入する．

	引数: pp  -- 追加する場所の手前のノードへのポインタ．
		  id  -- 追加するデータ．
		  lv  -- 追加するデータ．
		  key -- 追加するデータ．		複製
		  val -- 追加するデータ．		複製
		　ptr -- 汎用データへのポインタ	複製
		  sz  -- *ptr のサイズ
		   
	戻り値: 追加したノードへのポインタ．
*/
tTree*  add_tTree_node_bystr(tTree* pp, int id, int lv, char* key, char* val, void* ptr, int sz) 
{
	tTree* pt;
	tList_data ldat;

	ldat = make_tListdata_bystr(id, lv, key, val, ptr, sz);
	pt   = add_tTree_node_bydata(pp, ldat);

	return pt;
}





/**	
tTree*  free_tTree_node(tTree* node) 

	機能: ノードのバッファ部(データ)の開放．

	引数: node  -- 開放するノードへのポインタ．

	#define free_tTree_node(p)    free_tList_node(p)
*/





/**	
tTree*  del_tTree_node(tTree** node) 

	機能: ツリーノードの削除．削除されたノードが子ノードを持つ場合は，その子ノード
		　を格上げする（木構造を詰める）
		  node は動的に確保された変数でなければならない．

	引数: *node  -- 削除するノードへのポインタ．

	戻り値: 削除したノードの代わりに詰められた子ノードへのポインタ．
			もし該当ノードがない（削除ノードが子ノードを持たない）場合は NULL
*/
tTree*  del_tTree_node(tTree** node) 
{
	tTree* pp = NULL;

	if (node==NULL || *node==NULL) return pp;

	if ((*node)->next!=NULL) {	// 	子ノードを持つ場合
		tTree* ss;
		(*node)->next->depth--;
		adjust_tTree_depth((*node)->next);

		ss = (*node)->next;
		ss->prev = (*node)->prev;
		while (ss->ysis!=NULL) {
			ss = ss->ysis;
			ss->prev = (*node)->prev;
		} 

		ss->ysis = (*node)->ysis;
		(*node)->next->esis = (*node)->esis;
		if ((*node)->ysis!=NULL) (*node)->ysis->esis = ss;
		if ((*node)->esis!=NULL) (*node)->esis->ysis = (*node)->next;

		if ((*node)->prev!=NULL) {
			if ((*node)->prev->next==(*node)) (*node)->prev->next = (*node)->next;
			if ((*node)->prev->back==(*node)) (*node)->prev->back = ss;
		}
	}

	else {					// 子ノードを持たない場合
		if ((*node)->prev!=NULL) {
			if ((*node)->prev->next==(*node)) (*node)->prev->next = (*node)->ysis;
			if ((*node)->prev->back==(*node)) (*node)->prev->back = (*node)->esis;
		}
		if ((*node)->ysis!=NULL) (*node)->ysis->esis = (*node)->esis;
		if ((*node)->esis!=NULL) (*node)->esis->ysis = (*node)->ysis;
	}

	pp = (*node)->prev;
  	free_tListdata(&((*node)->ldat));
	if ((*node)->prev!=NULL) (*node)->prev->num += (*node)->num - 1;

	free(*node);
	*node = NULL;

	return pp;
}




/**	
tTree*  move_tTree_node(tTree* pp, tTree* node) 

	機能: nodeを現在のツリーから切り離し，ppへ移動する．
		　元のツリーに於いて，nodeが子ノードを持つ場合は，その子ノードを格上げする（木構造を詰める）
		  移動に於いては，node が姉妹ノードを持っていてもそれらは無視する．
		  nodeを削除しないで del_tTree_node(), add_tTree_node() を実行するようなもの．

	引数: pp    -- 移動先で親となるノードへのポインタ．
		  node  -- 移動するノードへのポインタ．node->next 以下がツリーでも良い．

	戻り値: 移動したノードノードへのポインタ．
*/
tTree*  move_tTree_node(tTree* pp, tTree* node) 
{
	if (node==NULL || pp==NULL) return NULL;

	// ノードの切り離し
	if (node->next!=NULL) {	// 	子ノードを持つ場合
		tTree* ss;
		node->next->depth--;
		adjust_tTree_depth(node->next);

		ss = node->next;
		ss->prev = node->prev;
		while (ss->ysis!=NULL) {
			ss = ss->ysis;
			ss->prev = node->prev;
		} 

		ss->ysis = node->ysis;
		node->next->esis = node->esis;
		if (node->ysis!=NULL) node->ysis->esis = ss;
		if (node->esis!=NULL) node->esis->ysis = node->next;

		if (node->prev!=NULL) {
			if (node->prev->next==node) node->prev->next = node->next;
			if (node->prev->back==node) node->prev->back = ss;
		}
	}
	else {					// 子ノードを持たない場合
		if (node->prev!=NULL) {
			if (node->prev->next==node) node->prev->next = node->ysis;
			if (node->prev->back==node) node->prev->back = node->esis;
		}
		if (node->ysis!=NULL) node->ysis->esis = node->esis;
		if (node->esis!=NULL) node->esis->ysis = node->ysis;
	}
	if (node->prev!=NULL) node->prev->num += node->num - 1;


	// ノードの再結合（移動）
	node->prev = pp;
	node->ysis = NULL;
	node->esis = pp->back;

	if (pp->back!=NULL) pp->back->ysis = node;
	if (pp->next==NULL) pp->next = node;
	pp->back = node;

	node->depth = pp->depth + 1;
	pp->num++;
	
	if (node->next!=NULL) {
		node->next->depth = node->depth + 1;
		adjust_tTree_depth(node->next);
	}

	return node;
}





/**
void  replace_all_tTree_node(tTree* pp, char* key, char* src, char* dst, int len)

	機能：ツリー pp内で keyをキー，srcをノード値として持つ全てのノードのノード値を dst に書き換える．

	引数：tp  -- 置換対象のツリー
		  key -- サーチキー
		  src -- 置換対象のノード値
		  dst -- 置換後のノード値
		  len -- 1以上: 一致させる長さ．
					 0: 完全一致．
					-1: ツリー中のキー値の長さに合わせる．
					-2: サーチキー key の長さに合わせる．

	戻り値：置き換えたノードの数

*/
int  replace_all_tTree_node(tTree* tp, char* key, char* src, char* dst, int len)
{
	int nn = 0;

	do { 
		if (ex_strncmp((char*)(tp->ldat).key.buf, (char*)key, len)) {
			if (ex_strncmp((char*)(tp->ldat.val.buf), (char*)src, len)) {
				free_Buffer(&(tp->ldat.val));
				tp->ldat.val = make_Buffer_bystr(dst);
				nn++;
			}
		}

		if (tp->next!=NULL) nn += replace_all_tTree_node(tp->next, key, src, dst, len);

		tp = tp->ysis;
	} while(tp!=NULL);

	return nn;
}







/////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ツリー操作
//

/**
tTree*  del_tTree(tTree** pp) 

	機能：指定したノード以下のツリーを削除する．

	引数：*pp -- 削除するツリーの先頭ノード

	戻り値：削除したツリーの親ノードへのポインタ．

*/
tTree*  del_tTree(tTree** pp) 
{
	tTree* pt;

	if (pp==NULL || *pp==NULL) return NULL;

	// 子ノードの削除
	if ((*pp)->next!=NULL) del_sisters_children_tTree(&((*pp)->next));

	// 自分自身の削除
	pt = (*pp)->prev;
	if (pt!=NULL) {
		if (pt->next==*pp) pt->next = (*pp)->ysis;
		if (pt->back==*pp) pt->back = (*pp)->esis;
		pt->num--;
	}
	if ((*pp)->ysis!=NULL) (*pp)->ysis->esis = (*pp)->esis;
	if ((*pp)->esis!=NULL) (*pp)->esis->ysis = (*pp)->ysis;

  	free_tListdata(&((*pp)->ldat));
	free(*pp);
	*pp = NULL;

	return pt;
}





/**
tTree*  del_children_tTree(tTree** pp) 

	機能：指定したノードの子ツリーを削除する．指定したノードは削除しない．

	引数：*pp -- 削除する子ツリーの親ノード

	戻り値：削除したツリーの親ノードへのポインタ．*pp がそのまま返る．

*/
tTree*  del_children_tTree(tTree** pp) 
{	
	if (pp==NULL || *pp==NULL) return NULL;

	if ((*pp)->next!=NULL) del_sisters_children_tTree(&((*pp)->next));

	(*pp)->num  = 0;
	(*pp)->next = NULL;
	(*pp)->back = NULL;

	return *pp;
}





/**
tTree*  del_sisters_children_tTree(tTree** pp) 

	機能：指定したノードの姉妹ツリー，子ツリーを削除する．
		  指定したノードも削除する．

	引数：*pp -- 削除するツリーの起点ノード

	戻り値：削除したツリー郡の親ノードへのポインタ．

	注）再帰処理用．親ノードに対する処理は行わないので，別途呼び出し側で行うこと．

*/
tTree*  del_sisters_children_tTree(tTree** pp) 
{
	tTree* pm;
	tTree* pt;

	if (pp!=NULL || *pp==NULL) return NULL;
	pt = (*pp)->prev;

	pm = *pp;
	while (pm->esis!=NULL) pm = pm->esis;
	while (pm!=NULL) {
		tTree* pw = pm;
		if (pm->next!=NULL) del_sisters_children_tTree(&(pm->next)); 
		pm = pm->ysis;

  		free_tListdata(&(pw->ldat));
		free(pw);
	}

	*pp = NULL;

	return pt;
}





/**
void  del_all_tTree(tTree** pp)

	機能: ツリーの全ノードの削除．
		  ポインタ ppのノードを含むツリー全体を削除する．
		  *pp はツリー中であれば，どこを指していても良い．

	引数: *pp -- 削除を開始するノードへのポインタ．
		   		 ツリー中であれば，どこを指していても良い．

	戻り値: なし．
*/
void  del_all_tTree(tTree** pp)
{
	tTree* pm;

	if (pp==NULL || *pp==NULL) return;

	pm = *pp;
	while (pm->prev!=NULL) pm = pm->prev;
	del_tTree(&pm);

	*pp = NULL;
	return;
}






/**
tTree*  add_tTree(tTree* tp, tTree* tt)

	機能: ツリー tpへ ツリー ttを追加．
		  add_tTree_node() との相違は，add_tTree()が先頭(tt)の姉妹ノードもツリー tpに追加する点にある．

	引数: tp  -- 追加するツリーの親となるノードへのポインタ．
		  tt  -- 追加するツリーへのポインタ．
		   
	戻り値: 追加したツリーのノードへのポインタ．失敗した場合は NULL
*/
tTree*  add_tTree(tTree* tp, tTree* tt)
{
	int	nn;
	tTree* tm;
	tTree* tw;

	if (tt==NULL) return NULL;
	if (tp==NULL) return tt;

	while(tt->esis!=NULL) tt = tt->esis;
	tt->esis = tp->back;
	if (tp->back!=NULL) tp->back->ysis = tt;
	if (tp->next==NULL) tp->next = tt;

	nn = 0;
	tm = tw = tt;
	while (tm!=NULL) {
		nn++;
		tm->prev  = tp;
		tm->depth = tp->depth + 1;

		if (tm->next!=NULL) {
			tm->next->depth = tm->depth + 1;
			adjust_tTree_depth(tm->next);
		}
		tw = tm;
		tm = tm->ysis;
	}

	tp->back = tw;
	tp->num += nn;

	return tt;
}





/**
tTree*  div_tTree(tTree* tp, tTree* tt)

	機能: ツリー tp から ツリー ttを分離する．

	引数: tt -- ツリーへの分離ポイント．
		   
	戻り値: 分離したツリーの元親ノードへのポインタ．失敗した場合は NULL
*/
tTree*  div_tTree(tTree* tt)
{
	if (tt==NULL) return NULL;
	if (tt->prev==NULL) return tt;

	if (tt->prev->next==tt) tt->prev->next = tt->ysis;
	if (tt->prev->back==tt) tt->prev->back = tt->esis;

	if (tt->ysis!=NULL) tt->ysis->esis = tt->esis;
	if (tt->esis!=NULL) tt->esis->ysis = tt->ysis;

	tt->depth = 1;
	if (tt->next!=NULL) {
		tt->next->depth = 2;
		adjust_tTree_depth(tt->next);
	}

	tt->prev->num--;
	tt->prev = NULL;

	return tt;
}





/**
tTree*  dup_merge_tTree(tTree* pp, tTree* tp)

	機能：ツリー ppの直下にツリー tpを複製する．
		  pp がNULLの場合は，ツリーの深さは調整されない

	引数：pp -- 複製されたツリーのトップとなるノード
		  tp -- 複製するツリー

	戻り値：複製されたツリーへのポインタ．
			pp がNULLでない場合は pp
			pp がNULLの場合は，新しく複製したツリーのトップ．

*/			 
tTree*  dup_merge_tTree(tTree* pp, tTree* tp)
{
	if (tp==NULL) return pp;

	if (pp!=NULL) {
		while(tp->esis!=NULL) tp = tp->esis;
		while(tp!=NULL) {
			tTree* pt = dup_tList_node(tp);
			pt->next = pt->prev = pt->back = pt->ysis = pt->esis = NULL;
			add_tTree(pp, pt);
			if (tp->next!=NULL) dup_merge_tTree(pt, tp->next);
			tp = tp->ysis;
		}		
	}
	else {
		pp = dup_tList_node(tp);
		pp->next = pp->prev = pp->back = pp->ysis = pp->esis = NULL;
		if (tp->next!=NULL) dup_merge_tTree(pp, tp->next);
	}

	return pp;
}







/**
void  merge_tTree(tTree* tp, tTree* tt)

	機能：ツリー tp にツリー tt を結合する．結合後，tt の内容は壊れる(tpとノードを交換した形になる)．
		  tt が tpの一部と同じ構造(キー値)を持つ場合，末端ノードは ttのノードで置き換える．
		  tp に存在しない枝は追加される．
		  ツリーの深さは tpを深さを元に再計算される．
		  
	引数：tp -- tt の結合ポイント
		　tt -- 結合するツリー

	戻り値：tp -- 結合後のツリー．
			tt -- 壊れる．要注意

	----------------------------------------------------------------
	例：	tp							tr
			A --> B --> M				A --> B --> X
			  --> C --> M --> X			  --> C --> M
						  --> Y			  --> D
					--> N

		の場合，merge_tTree(tp, tr) を実行すると以下のようになる．

			tp
			A --> B --> M 
					--> X (tr)
			  --> C --> M (tr)
					--> N 
			  --> D (tr)

			tt
			A --> B 
			  --> C --> M --> X (tp)
						  --> Y (tp)
*/
void  merge_tTree(tTree* tp, tTree* tt)
{
	tTree* tl;
	tTree* nt;
	tTree* nl;
	int	depth;

	if (tp==NULL || tt==NULL) return;

	depth = tp->depth;
	tl = tp;
	while (tt!=NULL) {
		if ((tt->ldat).key.buf==NULL) return;
		if (tl!=NULL && (tl->ldat).key.buf==NULL) return;
		while (tl!=NULL && strcmp((char*)((tl->ldat).key.buf), (char*)((tt->ldat).key.buf))) tl = tl->ysis;

		nt = tt;
		nl = tl;
		tt = tt->ysis;

		if (tl==NULL) {	
			div_tTree(nt);
			add_tTree(tp->prev, nt);
			tl = nt;
			return;
		}
		else if (nl->next!=NULL && nt->next!=NULL) {
			merge_tTree(nl->next, nt->next);
			tl = tl->ysis;
		}
		else {
			tl = tl->ysis;
			exchange_tTree(nl, nt);
		}
	}

	tp->depth = depth;
	adjust_tTree_depth(tp);

	return;
}





/**
void  exchange_tTree(tTree* tl, tTree* tt)

	機能：ツリー tlと ツリー ttを交換する．

	引数：tl -- 交換対象のツリー
		  tt -- 交換対象のツリー

	戻り値：なし．

*/
void  exchange_tTree(tTree* tl, tTree* tt)
{
	int	dt = tt->depth;
	tTree* pt = tt->prev;
	tTree* yt = tt->ysis;
	tTree* et = tt->esis;


	if (tl->esis!=NULL) tl->esis->ysis = tt;
	if (tl->ysis!=NULL) tl->ysis->esis = tt;
	if (tl->prev!=NULL) {
		if (tl->prev->next==tl) tl->prev->next = tt;
		if (tl->prev->back==tl) tl->prev->back = tt;
	}

	tt->ysis  = tl->ysis;
	tt->esis  = tl->esis;
	tt->prev  = tl->prev;
	tt->depth = tl->depth;
	if (tt->next!=NULL) {
		tt->next->depth = tt->depth + 1;
		adjust_tTree_depth(tt->next);
	}


	if (et!=NULL) et->ysis = tl;
	if (yt!=NULL) yt->esis = tl;
	if (pt!=NULL) {
		if (pt->next==tt) pt->next = tl;
		if (pt->back==tt) pt->back = tl;
	}

	tl->ysis  = yt;
	tl->esis  = et;
	tl->prev  = pt;
	tl->depth = dt;
	if (tl->next!=NULL) {
		tl->next->depth = dt + 1;
		adjust_tTree_depth(tl->next);
	}
}





/**
void   adjust_tTree_depth(tTree* pp)

	機能：指定したノード ppを基準にして，木の深さを測り直す

	引数：pp -- 基準となるノードへのポインタ

*/
void   adjust_tTree_depth(tTree* pp)
{
	int depth;
	tTree* pt;
	
	if (pp==NULL) return;

	depth = pp->depth;
	pt = pp;
	while (pt->ysis!=NULL) {
		pt = pt->ysis;
		pt->depth = depth;
		if (pt->next!=NULL) {
			pt->next->depth = depth + 1;
			adjust_tTree_depth(pt->next);
		}
	}

	pt = pp;
	while (pt->esis!=NULL) {
		pt = pt->esis;
		pt->depth = depth;
		if (pt->next!=NULL) {
			pt->next->depth = depth + 1;
			adjust_tTree_depth(pt->next);
		}
	}

	if (pp->next!=NULL) {
		pp->next->depth = depth + 1;
		adjust_tTree_depth(pp->next);
	}

	return;
}





/**
void   print_tTree(FILE* fp, tTree* pp, char* space)

	機能: ツリーの表示．
		  ポインタ pp以降の全てのノードのキー部のバッファを標準エラー出力に表示する．

	引数: fp    -- 出力するファイルへのポインタ．NULLの場合は stderr
		  pp	-- 表示を開始するノードへのポインタ．
		  space -- 出力の書式を揃えるための空白．

	戻り値: なし．

*/
void   print_tTree(FILE* fp, tTree* pp, char* space)
{
	if (fp==NULL) fp = stderr;

	if (pp!=NULL) {
		while(pp->esis!=NULL) pp = pp->esis;
		do { 
			int i;
			tList_data ld = pp->ldat;

			if (pp->depth>1) fprintf(fp, " -> ");
			fprintf(fp, "%d: %d %d %s %s", pp->depth, ld.id, ld.lv, ld.key.buf, ld.val.buf);
			//fprintf(fp, "%d: %d %d %s %s, %04x", pp->depth, ld.id, ld.lv, ld.key.buf, ld.val.buf, pp->altp);

			if (pp->next!=NULL) print_tTree(fp, pp->next, space);
			else fprintf(fp, "\n");

			pp = pp->ysis;
			if (pp!=NULL) {
				for(i=1; i<pp->depth; i++)   fprintf(fp, space);
				for(i=1; i<pp->depth-1; i++) fprintf(fp, "    "); 		// for " -> "
			}
		} while(pp!=NULL);
	}
	else {
		fprintf(fp, "(Tree is NULL)\n");
	}
	fflush(fp);

	return;
}





/**
tTree*  find_tTree_top(tTree* pp)

	機能：ツリーのトップ（ルート）を見つける

	#define find_tTree_top(p)   find_tList_top(p)
*/





/**
tTree*  find_tTree_end(tTree* pp)

	機能：ツリーの最終ノードを見つける．

*/
tTree*  find_tTree_end(tTree* pp)
{
	if (pp==NULL) return NULL;

	while(pp->prev!=NULL) pp = pp->prev;	// Top を探す
	while(pp->back!=NULL) pp = pp->back;

	return pp;
}





/**
int  count_tTree(tTree* pp)

	機能：ツリーの ppノード以降のノードの数を数える．

	引数: pp -- 数え始めるノードへのポインタ．姉妹ノードも数える．

	戻り値: ノードの数．
*/
int  count_tTree(tTree* pp)
{
	int cnt = 0;

	if (pp==NULL) return 0;
	while(pp->esis!=NULL) pp = pp->esis;

	do { 
		cnt++;
		if (pp->next!=NULL) cnt += count_tTree(pp->next);
		pp = pp->ysis;
	} while(pp!=NULL);

	return cnt;
}








////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Pattern Matching
//

/**
tTree*  strncmp_tTree(tTree* pp, char* key, int len, int no)

	機能: ツリーノードのキー値のサーチ．
		  ポインタ pp以降のノードで,キー部の文字列が keyと前方一致（部分的も可）するノードの
		  内 no番目にあるのを捜し出す．

	引数: pp   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）
		  len  -- 1以上: 一致させる長さ．
					  0: 完全一致．
					 -1: ツリー中のキー値の長さに合わせる．
					 -2: サーチキーkey の長さに合わせる．
		  no  -- 一致した物の中で何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tTree*  strncmp_tTree(tTree* pp, char* key, int len, int no)
{
	tTree* pt = NULL;
	int nn = 0;

	if (pp==NULL) return NULL;
	if (len<=-3)  return NULL;
	if (no<=0) no = 1;

	if (ex_strncmp((char*)(pp->ldat).key.buf, (char*)key, len)) {
		nn++;
		if (no==nn) return pp;
	}
	if (pp->next!=NULL) pt = next_strncmp_vertical_tTree(pp->next, key, len, no, &nn);

	return pt;
}





/**
tTree*  strncasecmp_tTree(tTree* pp, char* key, int len, int no)

	機能: ツリーノードのキー値のサーチ．大文字小文字を無視する．
		  ポインタ pp以降のノードで,キー部の文字列が keyと前方一致（部分的も可）するノードの
		  内 no番目にあるのを捜し出す．

	引数: pp   -- サーチを開始するノードへのポインタ．
		  key  -- サーチキー（文字列）．大文字，小文字を区別しない．
		  len  -- 1以上: 一致させる長さ．
				  0: 完全一致．
				 -1: ツリー中のキー値の長さに合わせる．
				 -2: サーチキーkey の長さに合わせる．
		  no  -- 一致した物の中で何番目の物を返すか指定する．1から数える．

	戻り値: 一致したノードへのポインタ．
			一致したものが無い場合は NULL．
*/
tTree*  strncasecmp_tTree(tTree* pp, char* key, int len, int no)
{
	tTree* pt = NULL;
	int nn = 0;

	if (pp==NULL) return NULL;
	if (len<=-3)  return NULL;
	if (no<=0) no = 1;

	if (ex_strncasecmp((char*)(pp->ldat).key.buf, (char*)key, len)) {
		nn++;
		if (no==nn) return pp;
	}
	if (pp->next!=NULL) pt = next_strncasecmp_vertical_tTree(pp->next, key, len, no, &nn);

	return pt;
}






/**
tTree*  cmp_sisters_tTree(tTree* tp, tTree* tr)

	機能：ノードtpの姉妹ノードが ノードtrの姉妹ノードと同じパターン（キー値を比較を持っているかどうかを検査する．
		  ただし，tr->ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE のノードは比べない(常に一致とする)．
		  また tp->ctrl が TREE_ALREADY_FOUND_NODE の場合は，常に一致しない．
		  もし同じノードパターンがある場合，trの各ノードの altpには対応する tpの各ノードへのポインタが格納される．

	引数：tp -- 比べる姉妹ノードの長女ノード
		  tr -- 探す姉妹ノードパターンの長女ノード

	戻り値：tp中で trと同じパターンが始まるノードへのポインタ．
		  	trの各ノードの altpには対応する tpの各ノードへのポインタが格納される．
			NULL: tpに同じ姉妹パターンは無い．この場合，trのaltpの値は不定となる．


	----------------------------------------------------------------
	例：	tp						tr
			--> A (1)				--> A 		A, B, X は キー値(ldat.key.buf)
			--> B (2)				--> X
			--> A (3)
			--> X (4)
			--> A (5)
			--> X (6)

		の場合，cmp_sisters_tTree(tp, tr) は (3)へのポインタを返す．また trの Aノード
		の altp には (3) へのポインタが，trの Xノードのaltpには(4)へのポインタが格納
		される．最初に見つかったパターンのみ評価される．

*/
tTree*  cmp_sisters_tTree(tTree* tp, tTree* tr)
{
	tTree* ta;
	tTree* tb = NULL;
	tTree* ts;

	ts = tp;
	while (ts!=NULL){
		ta = ts;
		tb = tr;
		while (ta!=NULL && tb!=NULL) {
			if (ta->ctrl==TREE_ALREADY_FOUND_NODE) break;
			if (tb->ctrl!=TREE_NOCMP_NODE && tb->ctrl!=TREE_NOCMP_COPY_NODE) {
				if ((ta->ldat).key.buf!=NULL && (tb->ldat).key.buf!=NULL) {
					if (strcmp((char*)((ta->ldat).key.buf), (char*)((tb->ldat).key.buf))) break;
				}
				else break;
			}
			tb->altp = ta;
			ta = ta->ysis;
			tb = tb->ysis;
		}

		if (tb==NULL) return ts;

		ts = ts->ysis;
	}
	if (tb!=NULL) return NULL;

	return ts;
}






/**
int  check_match_tTree(tTree* tp, tTree* tr)

	機能：ツリー tpが ツリー trと同じパターン(キー値)を持っているかどうかを検査する．
		  tp のトップと tr のトップはキー値が一致している必要がある．一致していなければ，同じパターンは無しとする．
		  ただし，tr->ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE のノードは比べない(常に一致とする)．

		  一度見つけた tpの枝の最後のノードに対しては ctrlを TREE_ALREADY_FOUND_NODE を設定するので，続けてチェックする
		　場合などは ctrl をクリアする必要がある．

		  もし同じツリーパターンがある場合，trの各ノードの altpには，一番最初に見つかった
		  対応する tpの各ノードへのポインタが格納される．

	引数：tp -- 検索対象のツリー
		  tr -- 検索パターンのツリー

	戻り値：TRUE:  tp中に trと同じいツリーパターンが存在する．
		  		   trの各ノードの altpには，一番最初に見つかった対応する tpの各ノードへのポインタが格納される．
			FALSE: tpに同じツリーパターンは無い．この場合，trのaltpの値は不定となる．

*/
int  check_match_tTree(tTree* tp, tTree* tr)
{
	int  ret;
	tTree* ts;
	tTree* tt;
	tTree* ta;
	tTree* tb;
	tTree* te;


	if (tp==NULL || tr==NULL) return FALSE;

	te = find_tList_end(tr);

	ts = tp;
	while (ts!=NULL) {
		tt = cmp_sisters_tTree(ts, tr);		// その階層でキー値が全て一致しているか確認
		if (tt==NULL) return FALSE;			// 一致していなければ，FALSE
		
		ta  = tt;							// 比べられるツリー
		tb  = tr;							// 比べるパターン
		ret = TRUE;
		while (tb!=NULL && ret) {
			if (tb->next==NULL) ret = TRUE;
			// ->ta, ->tb->tx: FALSE
			else if (tb->next!=NULL && ta->next==NULL) ret = FALSE;
			// ->ta->xa, ->tb->xb: xaとxbをチェック
			else ret = check_match_tTree(ta->next, tb->next);

			ta = ta->ysis;
			tb = tb->ysis;
		}

		if (ret) {
			if (tr==te) tt->ctrl = TREE_ALREADY_FOUND_NODE;
			return TRUE;
		}

		ts = tt->ysis;
	}

	return FALSE;
}






/**
int find_match_tTree(tTree* pp, tTree* pt)

	機能：ツリー pp内で ツリー ptと同じパターンの枝を探す， 
		  同じパターンの探索では キー値のみを比較し，ノード値は比較しない．
		  ただし，pt->ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE のノードは比べない(常に一致とする)．
	
		  もし同じツリーパターンがある場合，trの各ノードの altpには，一番最初に見つかった対応する ppの各ノードへ
		  のポインタが格納される．

	check_match_tTree() との違い．
		check_match_tTree() では比べる枝の開始ノードはppに固定される．
		find_match_tTree() は pp内を移動しながら検索できる．

	引数：pp -- 検索対象のツリー
		  pt -- 検索パターンのツリー

	戻り値：TRUE:  pp中に pt同じいツリーパターンが存在する．
		  		   ptの各ノードの altpには，一番最初に見つかった対応する ppの各ノードへのポインタが格納される．
			FALSE: ppに同じツリーパターンは無い．この場合，ptのaltpの値は不定となる．
*/
int  find_match_tTree(tTree* pp, tTree* pt)
{
	int   ret;
	tTree* pm;

	pm = pp;
	while(pp!=NULL) {
		ret = check_match_tTree(pp, pt);
		if (ret) return TRUE;

		if (pp->next!=NULL) {
			ret = find_match_tTree(pp->next, pt);
			if (ret) {
				clear_tTree_ctrl(pm);
				return TRUE;
			}
		}
		pp = pp->ysis;
	}

	return FALSE;
}







/**
void   clear_tTree_ctrl(tTree* pp)

	機能：pp のツリーも ctrl をクリアする．

*/
void   clear_tTree_ctrl(tTree* pp)
{
	while (pp->esis!=NULL) pp = pp->esis;

	while (pp!=NULL) {
		pp->ctrl = TREE_NOCTRL_NODE;
		if (pp->next!=NULL) clear_tTree_ctrl(pp->next);
		pp = pp->ysis;
	}
}







/**
tList*  find_match_tTree_endlist(tTree* pp, tTree* pt)

	機能：ツリー pp内で ツリー ptと同じパターンの枝を全て探して，その枝の最後のノードへの情報をリストにして返す．
		　該当ノードへのポインタは 返された各リストのaltp が保持している． 

		  比較では キー値のみを比較し，ノード値は比較しない．
		  また，pt->ctrl が TREE_NOCMP_NODE または TREE_NOCMP_COPY_NODE のノードは比べない(常に一致とする)．
	
	引数：pp -- 検索対象のツリー
		  pt -- 検索パターンのツリー

	戻り値：該当ノードへのポインタを保持するリスト．

*/
tList*  find_match_tTree_endlist(tTree* pp, tTree* pt)
{
	tTree* te;
	tList* lp;

	te = find_tTree_end(pt);
	while(pp->esis!=NULL) pp = pp->esis;

	lp = find_match_tTree_endlist_rcsv(pp, pt, te);
	if (lp!=NULL) clear_tTree_ctrl(pp);
	
	return lp;
}





/**
tList*  find_match_tTree_endlist_rcsv(tTree* pp, tTree* pt, tTree* te)

	機能：find_match_tTree_endlist() の補助関数

*/
tList*  find_match_tTree_endlist_rcsv(tTree* pp, tTree* pt, tTree* te)
{
	tList* lt = NULL;
	tList* lp = NULL;

	while(pp!=NULL) {
		int ret = check_match_tTree(pp, pt);
		if (ret && te->altp!=NULL) {
			tList* lm = new_tList_node();
			lm->altp = te->altp;
			lt = insert_tList(lt, lm);
			if (lp==NULL) lp = lt;
			te->altp = NULL;
		}
			
		if (pp->next!=NULL) {
			tList* lm = find_match_tTree_endlist_rcsv(pp->next, pt, te);
			if (lm!=NULL) {
				lt = insert_tList(lt, lm);
				if (lp==NULL) lp = lt;
				clear_tTree_ctrl(pp->next);
			}
		}
	
		if (!ret) pp = pp->ysis;	// 見つかった場合はもう一度．見つからなかった場合へ次へ．
	}
	
	return lp;
}






/**
void  replace_tTree_node(tTree* pp, tTree* pt)

	機能：ツリー pp内で ツリー ptと同じパターン（キー値を比較）の枝を検索し，ppに一致したパターンの枝があれば，
		  その枝の各ノードに対して，対応するそれぞれの（pt->ctrl が TREE_COPY_NODE または TREE_NOCMP_COPY_NODE である）
		  ptのノードの属性で置き換える．
		  パターンの一致（検索）では ldat.key（キー値）が比較される．

		　置き換える属性は ldat.id, ldat.lv, ldat.sz, ldat.key, ldat.val, ldat.ptr, ldat.lst
		  置き換えを行うのは pt->ctrl が TREE_COPY_NODE または TREE_NOCMP_COPY_NODE の場合のみである．(重要)
		　ldat.val, ldat.ptr, ldat.lst については，ptで値が設定されていなければ，置き換えを行わない．
	
	引数：pp -- 置き換え対象のツリー
		  pt -- 置き換えるツリー

	戻り値：TRUE : 置換する枝を見つけた．正常に置換されたかどうかは不明．
			FALSE: 置換する枝を見つけられなかった．

*/
int replace_tTree_node(tTree* pp, tTree* pt)
{
	int ret;

	if (pp==NULL || pt==NULL) return FALSE;
	while(pp->esis!=NULL) pp = pp->esis;
	
	ret = find_match_tTree(pp, pt);
	if (ret) {
		copy_tTree_byctrl(pt);
		adjust_tTree_depth(pp);
	}

	return ret;
}






/**
void  copy_tTree_byctrl(tTree* pt)

	機能：replace_tTree_node()の補助関数．
		  ツリー ptにおいて，pt->ctrl が TREE_COPY_NODE または TREE_NOCMP_COPY_NODE の場合，
		  pt->altp のノードへ ptの属性をコピーする．

		  pt->ldat.sz には正確に pt->ldat.ptrのサイズが設定されている必要がある．
*/
void  copy_tTree_byctrl(tTree* pt)
{
	while(pt!=NULL) {
		if (pt->altp!=NULL) {
			if (pt->ctrl==TREE_COPY_NODE || pt->ctrl==TREE_NOCMP_COPY_NODE) {
				pt->altp->ldat.id = pt->ldat.id;		
				pt->altp->ldat.lv = pt->ldat.lv;
				pt->altp->ldat.sz = pt->ldat.sz;

				if (pt->ldat.key.buf!=NULL) {
					free_Buffer(&(pt->altp->ldat.key));
					pt->altp->ldat.key = dup_Buffer(pt->ldat.key);
				}
				if (pt->ldat.val.buf!=NULL) {
					free_Buffer(&(pt->altp->ldat.val));
					pt->altp->ldat.val = dup_Buffer(pt->ldat.val);
				}

				if (pt->ldat.ptr!=NULL && pt->ldat.sz>0) {
					if (pt->altp->ldat.ptr!=NULL) free(pt->altp->ldat.ptr);
					pt->altp->ldat.ptr = (void*)malloc(pt->ldat.sz);
					if (pt->altp->ldat.ptr!=NULL) memcpy(pt->altp->ldat.ptr, pt->ldat.ptr, pt->ldat.sz);
				}

				if (pt->ldat.lst!=NULL) {
					del_all_tList(&(pt->altp->ldat.lst));
					pt->altp->ldat.lst = dup_tList(pt->ldat.lst);
				}
			}
		}

		if (pt->next!=NULL) copy_tTree_byctrl(pt->next);
		pt = pt->ysis;
	}

	return;
}






/**
Buffer  get_value_tTree(tTree* pp, tTree* pt)

	機能：ツリー pp内で ツリー ptと同じパターンの枝を検索し，ppに一致したパターンの
		  枝があれば，　その枝の最後のノードの値を返す．

	引数：pp -- 検索対象のツリー
		  pt -- 検索するパターン

	戻り値：ptの最後のノードに対応する ppのノードのノード値


	----------------------------------------------------------------
	例：	tp							tr
			A --> B --> M				C --> M --> Y
			  --> C --> M --> X 			  
						  --> Y(*)		 
					--> N

		の場合，Y(*) のノード値が返る．
*/
Buffer  get_value_tTree(tTree* pp, tTree* pt)
{
	int fnd;
	Buffer val;

	val = init_Buffer();
	if (pp==NULL || pt==NULL) return val;

	while(pp->esis!=NULL) pp = pp->esis;
	
	fnd = find_match_tTree(pp, pt);
	if (fnd) {
		tTree* tt = find_tTree_end(pt);
		if (tt->altp!=NULL) {
			val = dup_Buffer(tt->altp->ldat.val);
		}
	}

	return val;
}











/////////////////////////////////////////////////////////////////////////////////////////////
//
//
//

/**
tTree*  next_strncmp_vertical_tTree(tTree* pp, char* key, int len, int no, int* nn)
tTree*  next_strncmp_horizon_tTree (tTree* pp, char* key, int len, int no, int* nn)
tTree*  next_strncasecmp_vertical_tTree(tTree* pp, char* key, int len, int no, int* nn)
tTree*  next_strncasecmp_horizon_tTree (tTree* pp, char* key, int len, int no, int* nn)

	tTree 検索用補助関数．horizon は擬似的な横方向探索（完全な横方向探索ではない）

*/
tTree*  next_strncmp_vertical_tTree(tTree* pp, char* key, int len, int no, int* nn)
{
	do { 
		if (ex_strncmp((char*)(pp->ldat).key.buf, (char*)key, len)) {
			(*nn)++;
			if (no==*nn) return pp;
		}
		if (pp->next!=NULL) {
			tTree* tt = next_strncmp_vertical_tTree(pp->next, key, len, no, nn);
			if (tt!=NULL) return tt;
		}
		pp = pp->ysis;
	} while(pp!=NULL);

	return NULL;
}





tTree*  next_strncmp_horizon_tTree(tTree* pp, char* key, int len, int no, int* nn)
{
	do { 
		if (ex_strncmp((char*)(pp->ldat).key.buf, (char*)key, len)) {
			(*nn)++;
			if (no==*nn) return pp;
		}
		if (pp->ysis!=NULL) {
			tTree* tt = next_strncmp_horizon_tTree(pp->ysis, key, len, no, nn);
			if (tt!=NULL) return tt;
		}
		pp = pp->next;
	} while(pp!=NULL);

	return NULL;
}





tTree*  next_strncasecmp_vertical_tTree(tTree* pp, char* key, int len, int no, int* nn)
{
	do { 
		if (ex_strncasecmp((char*)(pp->ldat).key.buf, (char*)key, len)) {
			(*nn)++;
			if (no==*nn) return pp;
		}
		if (pp->next!=NULL) {
			tTree* tt = next_strncasecmp_vertical_tTree(pp->next, key, len, no, nn);
			if (tt!=NULL) return tt;
		}
		pp = pp->ysis;
	} while(pp!=NULL);

	return NULL;
}





tTree*  next_strncasecmp_horizon_tTree(tTree* pp, char* key, int len, int no, int* nn)
{
	do { 
		if (ex_strncasecmp((char*)(pp->ldat).key.buf, (char*)key, len)) {
			(*nn)++;
			if (no==*nn) return pp;
		}
		if (pp->ysis!=NULL) {
			tTree* tt = next_strncasecmp_horizon_tTree(pp->ysis, key, len, no, nn);
			if (tt!=NULL) return tt;
		}
		pp = pp->next;
	} while(pp!=NULL);

	return NULL;
}





