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


/** 
@brief   Tiny List 構造ライブラリ
@file    tlist.c
@version 
@author  Fumi.Iseki (C)
@date    2008 2/1
@see     _tList
*/



#include  "tlist.h"




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

/**
tList_data  init_tListdata(void)

空のノードデータを静的に作成．データを初期化するのに使用する．

@return 作られたノードデータ．
*/
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)

データを指定してノードデータを作成@n
sz>0 で ptr==NULL の場合は ptrの領域を確保し，0クリアする．

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

@return 作られたノードデータ．
*/
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, const char* key, const char* val, void* ptr, int sz)

データを指定してノードデータを作成@n
sz>0 で ptr==NULL の場合は ptrの領域を確保し，0クリアする．

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

@return 作られたノードデータ．
*/
tList_data  make_tListdata_bystr(int id, int lv, const char* key, const 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)

ノードデータのバッファ部をクリアする．データ自身は削除しない．

@param  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)

ノードデータの複製を作成する．@n
ldat.sz には正確に ldat.ptrのサイズが設定されている必要がある．

@param  ldat  複製するノードデータ
@return 複製したノードデータへのポインタ．
*/
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)

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

@return 生成されたノードへのポインタ．
*/
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)

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

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

@param  ldat  ノードデータ
@return 作られたノード．
*/
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),それを指定したリストの後ろに追加．@n

リストポインタ ppが指すノードの後につくり出した ノードを挿入する．
ldat は指定されたものがそのまま使用される．

@param  pp    追加する場所の手前のノードへのポインタ．
@param  ldat  追加するノードデータ．このデータがそのまま使用される．
		   
@return 追加したノードへのポインタ．
*/
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, const char* key, const char* val, void* ptr, int sz) 

データからリスト用ノードをつくり出し(new),それをリストに追加．

リストポインタ ppが指すノードの後につくり出した ノードを挿入する．
sz>0 で ptr==NULL の場合は ptrの領域を確保し，0クリアする．

@param  pp   追加する場所の手前のノードへのポインタ．
@param  id   追加するデータ．
@param  lv   追加するデータ．
@param  key  追加するデータ．        複製
@param  val  追加するデータ．        複製
@param  ptr  汎用データへのポインタ  複製
@param  sz   *ptr のサイズ
		   
@return 追加したノードへのポインタ．
*/
tList*  add_tList_node_bystr(tList* pp, int id, int lv, const char* key, const 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クリアする．

@param  pp    追加する場所の手前のノードへのポインタ．
@param  id    追加するデータ．
@param  lv    追加するデータ．
@param  key   追加するデータ．        複製
@param  val   追加するデータ．        複製
@param  *ptr  汎用データへのポインタ  複製
@param  sz    *ptr のサイズ
		   
@return 追加したノードへのポインタ．
*/
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;
}




/**	
void   free_tList_node(tList** node)

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

@param[in]  *node  開放するノードへのポインタ．
@param[out] *node  NULL
*/
void   free_tList_node(tList** node)
{
	if (node==NULL || *node==NULL) return;

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

	return;
}	




/**	
tList*  del_tList_node(tList* node) 

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

@param  node  削除するノードへのポインタ．
@return 削除したノードの直後のノードへのポインタ．
*/
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へ移動する．@n
nodeを削除しないで del_tList_node(), add_tList_node() を実行するようなもの．

@param  pp    移動先で親となるノードへのポインタ．
@param  node  移動するノードへのポインタ．
@return 移動したノードノードへのポインタ．
*/
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* node, tList_data dat)

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

@param  node  設定するノードへのポインタ．
@param  dat   設定するノードデータ．このデータがそのまま使用される．
*/
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, const char* key, const char* val, void* ptr, int sz)

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

@param  pp   ノード値を設定するノードへのポインタ
@param  id   ノードのID
@param  lv   ノードのデータ
@param  key  ノードのキー            複製
@param  val  ノードのデータ          複製
@param  ptr  汎用データへのポインタ  複製
@param  sz   *ptr のサイズ
*/
void	set_tList_node_bystr(tList* pp, int id, int lv, const char* key, const 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)

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

@param  pp   ノード値を設定するノードへのポインタ
@param  id   ノードのID
@param  lv   ノードのデータ
@param  key  ノードのキー   (Buffer) 複製
@param  val  ノードのデータ (Buffer) 複製
@param  ptr  汎用データへのポインタ  複製
@param  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)．

@param  pp  検索を開始するノードへのポインタ．
@param  pt  設定するノードへのポインタ．検索キーは pt->key
@return 設定または追加したノードへのポインタ
*/
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)．@n
ldat は指定されたものがそのまま使用される．

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

@return 設定または追加したノードへのポインタ
*/
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, const char* key, const char* val, void* ptr, int sz)

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

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

@return 設定または追加したノードへのポインタ
*/
tList*	update_tList_node_bystr(tList* pp, int id, int lv, const char* key, const 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)．@n
それぞれのデータは複製される．

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

@return 設定または追加したノードへのポインタ
*/
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) 

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

@param[in]  *pp  削除するノードへのポインタ．
@param[out] *pp  NULL

@return 削除したノード(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のノードを含むリスト全体を削除する．@n
pp はりスト中であれば，どこを指していても良い．

@param[in]  *pp  削除を開始するノードへのポインタ．
@param[out] *pp  NULL
*/
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, const char* key, int no)
		
plからサーチして，no番目の keyのノードを削除する．
		
@param  pl   サーチを開始するノードへのポインタ．
@param  key  サーチキー（文字列）．大文字，小文字を区別しない．	
@param  no   一致した物の中で何番目の物を削除するか指定する．1から数える．0の場合は全て削除する．
		
@return 削除したノードの数．
*/	  
int  del_tList_key(tList** pl, const 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, 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)

リストを複製する．

@param  pp  複製元のリストへのポインタ．
@return 複製されたリストへのポインタ．
*/			 
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を追加する．

@param  pp  先頭のリストへのポインタ
@param  pt  追加するリストへのポインタ
@return リストの先頭へのポインタ

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

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を挿入する．
	
@param  pp  先頭のリストへのポインタ
@param  pt  挿入するリストへのポインタ
@return 挿入した先頭のリストへのアドレス．

@code
pp->1->2->3, pt->4->5 => pp->pt->4->5->1->2->3
@endcode
*/
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以降の全てのノードのキー部のバッファを標準エラー出力に表示する．

@param  fp  出力するファイルへのポインタ．NULLの場合は stderr
@param  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ノード以降のノードの数を数える．

@param  pp  数え始めるノードへのポインタ．
@return ノードの数．
*/
int  count_tList(tList* pp)
{
	int cnt = 0;

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






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

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

char*型変数によるノードのサーチ．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strncmp_tList(tList* pl, const 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, key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->next;
	}
	return NULL;
}





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

char*型変数によるノードのサーチ．大文字小文字を無視する．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strncasecmp_tList(tList* pl, const 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, key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->next;
	}
	return NULL;
}




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

char*型変数によるノードのサーチ．後方から比べる．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strnrvscmp_tList(tList* pl, const 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, key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->next;
	}
	return NULL;
}





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

char*型変数によるノードのサーチ．後方から比べる．大文字小文字を無視．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strncaservscmp_tList(tList* pl, const 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, key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->next;
	}
	return NULL;
}




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

char*型変数によるノードの部分文字列サーチ．

ポインタ pl以降のノードで,キー部の文字列または keyの文字列が相手の文字列に含まれるノードの内，
no番目にあるのを捜し出す．

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strstr_tList(tList* pl, const 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, key)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}
		else if (len<0) {
			if (strstr(key, (char*)(pl->ldat).key.buf)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}

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




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

char*型変数によるノードの部分文字列サーチ．大文字小文字を無視．

ポインタ pl以降のノードで,キー部の文字列または keyの文字列が相手の文字列に含まれるノードの内，
no番目にあるのを捜し出す．

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strstrcase_tList(tList* pl, const 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, key)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}
		else if (len<0) {
			if (strstrcase(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, const char* key, int len, int no)

char*型変数による後方からのノードのサーチ．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strncmp_back_tList(tList* pl, const 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, key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->prev;
	}
	return NULL;
}




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

char*型変数による後方からのノードのサーチ．大文字小文字を無視する．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strncasecmp_back_tList(tList* pl, const 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, key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->prev;
	}
	return NULL;
}




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

char*型変数による後方からのノードのサーチ．文字を後ろから比べる．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strnrvscmp_back_tList(tList* pl, const 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, key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->prev;
	}
	return NULL;
}




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

char*型変数による後方からのノードのサーチ．文字を後ろから比べる．大文字小文字を無視．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strncaservscmp_back_tList(tList* pl, const 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, key, len)) {
			nn++;
			if (no==nn) return pl;
		}
		pl = pl->prev;
	}
	return NULL;
}




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

char*型変数による後方からのノードの部分文字列サーチ．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strstr_back_tList(tList* pl, const 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, key)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}
		else if (len<0) {
			if (strstr(key, (char*)(pl->ldat).key.buf)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}

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




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

char*型変数による後方からのノードの部分文字列サーチ．大文字小文字を無視．

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

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

@return 一致したノードへのポインタ
@retval NULL 一致したものが無い
*/
tList*  strstrcase_back_tList(tList* pl, const 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, key)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}
		else if (len<0) {
			if (strstrcase(key, (char*)(pl->ldat).key.buf)!=NULL) {
				nn++;
				if (no==nn) return pl;
			}
		}

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







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

/**
tList*  find_tList_top(tList* pl)

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

@param  pl  サーチを開始するノードへのポインタ．
@return リストの最初のノードへのポインタ．
*/
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)

リストの最後のノードへを探す．

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

@param  pl  サーチを開始するノードへのポインタ．
@return リストの最後のノードへのポインタ．
*/
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, const char* key, int no) 

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

@param  list  検索を行うリストへのポインタ．
@param  key   ヘッダ種別．大文字，小文字を区別しない．
@param  no    何番目のノードを取り出すか指定する．1から数える．

@return ldat.val データのコピー．
*/
Buffer  search_key_tList(tList* list, const 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, const char* key, char* data, int no) 

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

@param  list  検索を行うリストへのポインタ．
@param  key   ヘッダ種別． 大文字，小文字を区別しない．
@param  data  検索するヘッダ値の最初の文字．
@param  no    何番目のノードを取り出すか指定する．1から数える．

@return ノード値の格納された Buffer型変数．
*/
Buffer  search_key_value_tList(tList* list, const 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, const char* key, int no, const char* value, int add_mode)

リスト(lt)中の no番目の keyノードの値に valueを設定する．

no が 0以下の場合は，全ての keyノードの値に対して設定が行われる．
keyノードが存在せず，かつ mode==ON の場合は，リストの最後に追加される．

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

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

*/
int   set_value_tList(tList* list, const char* key, int no, const 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, const 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, const char* key, int no, const char* srcval, char* value)

リスト(lt)中の no番目の keyノードの値の srcvalの部分を value に置き換える．

no が 0以下の場合は，全ての keyノードの値に対して置き換えが行われる．

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

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

*/
int	 replace_value_tList(tList* list, const char* key, int no, const 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, const char* srcval, const 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)

文字列を区切り文字で区切って，各項目をリストのキー部に入れて返す．@n
項目が存在しない場合でもリストは返す（キー部の bufが NULL）．

@param  str  処理する文字列
@param  cc   項目の区切り文字
@return 項目をキー部に入れたリスト．項目が存在しない場合でもリストは返す．
@see cawk_tList
*/
tList*	awk_tList(char* str, char cc)
{
	int    nn = 1;
	char*  item;
	tList* lp = NULL;

	if (str==NULL) return NULL;

	lp = add_tList_node_bystr(NULL, 1, 0, NULL, NULL, NULL, 0);

	// first item
	item = awk(str, cc, nn);
	if (item==NULL) return lp;
	lp->ldat.key = make_Buffer_bystr(item);

	//
	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)

文字列を区切り文字で区切って，各項目をリストのキー部に入れて返す．
複数の区切り文字も1個と見なす．@n
項目が存在しない場合でもリストは返す（キー部の bufが NULL）．

@param  str  処理する文字列
@param  cc   項目の区切り文字
@return 項目をキー部に入れたリスト．項目が存在しない場合でもリストは返す．
*/
tList*	cawk_tList(char* str, char cc)
{
	int    nn = 1;
	char*  item;
	tList* lp = NULL;

	if (str==NULL) return NULL;

	lp = add_tList_node_bystr(NULL, 1, 0, NULL, NULL, NULL, 0);

	// first item
	item = cawk(str, cc, nn);
	if (item==NULL) return lp;
	lp->ldat.key = make_Buffer_bystr(item);

	//
	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, const char* deli)
{
	Buffer buf = get_Buffer_join_tList(lp, deli);
	return (char*)buf.buf;
}



Buffer  get_Buffer_join_tList(tList* lp, const 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, const char* key, const 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, const 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, const 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, const 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, const 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(const char* fname, int mode) 

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

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

@return 格納したリストへのポインタ．
*/
tList*  read_tList_file(const 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) 

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

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

@return 格納したリストへのポインタ．

@bug ディレクトリを読ませると，戻ってこない．
*/
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(const char* fname, char deli) 

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

@param  fname  ファイル名． 
@param  deli   区切り文字

@return 格納したリストへのポインタ．
*/
tList*  read_index_tList_file(const 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_fp(FILE* fp, char deli)

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

@param  fp    ファイルポインタ． 
@param  deli  区切り文字

@return 格納したリストへのポインタ．
*/
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(const char* fname) 

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

@param  fname  ファイル名． 
@return 格納したリストへのポインタ．
*/
tList*  read_Buffer_tList_file(const 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型変数を 2つづつ読み込んで，リストのキー部とバッファ部に格納し返す．

@param  fp  ファイルポインタ． 
@return 格納したリストへのポインタ．
*/
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(const char* fname, tList* lp) 

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

@param  fname  ファイル名． 
@param  lp     書き込みを行うリストデータへのポインタ．

@retval TRUE   書き込み成功．
@retval FALSE  書き込み失敗
*/
int  save_Buffer_tList_file(const 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型変数をファイルへ書き込む．
ファイルが既にある場合は，追加書き込みされる．

@param  fp     ファイルポインタ． 
@param  lp     書き込みを行うリストデータへのポインタ．

@retval TRUE   書き込み成功．
@retval 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;
}



