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

#ifndef  __JBXL_TINY_XML_H_
#define  __JBXL_TINY_XML_H_


/** 
@brief   Tiny XML ライブラリヘッダ 
@file    txml.h
@version 1.0
@author  Fumi.Iseki (C)
@date    2009 2/10


@par タイトル
Tiny XML txml.h v1.0 @n
サブセット版　整形式XML 簡易パーサ ライブラリヘッダ

@see tXML

@attention
全てのパターンのパース可能性を保障するものではありません@n
複雑な XMLは（恐らく）パースできません．@n
<?xml ... ?> 以外の <? ..... ?> と <! .....  > は処理しない（読み込みは行う）@n
エンティティは処理しない．@n
*/


#include "ttree.h"


/** 
typedef  tTree  tXML;

@b tXML  (@b tList, @b tTree, @b _tList と同じもの)
@see tTree 

1. タグデータ tXML：

	int	 	ldat.id		タグの種別．XML_ANCHOR_TAG, XML_TAG_NAME, XML_TAG_CONTENT, ..........
	int	 	ldat.lv		種別がタグ値である子ノードの個数
	int	 	ldat.sz		未使用
	Buffer  ldat.key	タグ名またはタグ値
	Buffer  ldat.val	<! ... > の未処理データと <!-- ... -->のコメント情報を格納 
	void*	ldat.ptr	未使用 
	tXML*	ldat.lst	属性リストへのポインタ．ldat.lst->ldat.keyに属性名，ldat.lst->ldat.valに属性値("'付き)を格納

	tXML*	next		子タグ（長女）へのポインタ
	tXML*	prev		親タグへのポインタ
	tXML*	altp		その他へのポインタ（汎用） 
	tXML*	back		子タグ（末っ子）へのポインタ 
	tXML*	esis		前の姉妹（姉）タグへのポインタ
	tXML*	ysis		次の姉妹（妹）タグへのポインタ

	int		depth   	深さ					
	int		num	 		子ノードの数（全ての子ノードの数）	
	int		ctrl		制御用
	int		state   	ノードの状態  XML_PARSED, XM_TAG_OPEND, XML_TAG_ENDED, XML_PARSE_ERROR, ....


2. パースしたXML情報を格納するツリー構造

	<?xml version="1.0" ?><A><B><C>ABC</C><D />EFG</B><E /><!-- comment --></A> 
	
  	NULL (XML_ANCHOR_TAG) -> xml (XML_DOC_TAG)
						  -> A (XML_TAG_NAME) -> B (XML_TAG_NAME) -> C (XML_TAG_NAME) -> ABC (XML_TAG_CONTENT)
                                                                  -> D (XML_TAG_NAME)
																  -> EFG (XML_TAG_CONTENT)
											  -> E (XML_TAG_NAME)
											  -> @COMMENT_TAG (XML_COMMENT_TAG) 	// ただしコメントの処理は暫定的


3, タグ（ノード）種別 (ldat.id)

	XML_ANCHOR_TAG			アンカータグ
	XML_TAG_NAME			タグネーム
	XML_TAG_CONTENT			タグの内容（コンテント）
	XML_DOC_TAG				<? xml... ?> タグ
	XML_COMMENT_TAG			コメントタグ
	XML_DATA_TAG			<! ... > タグ
	XML_PROCESS_TAG 		XML_DOC_TAG 以外の <? ... ?>タグ


4. 状態 (state)

	XML_DEFAULT_STATE		ノードは，正常にパースされたかどうかの判定はまだ行われていない．
	XML_PARSED				アンカータグにのみ設定される．このXMLツリーは正常にパースされたことを示す．
	XML_TAG_STARTED			このノードはオープン状態にある． <tagname>
	XML_TAG_ENDED			このノードは正常にクローズした． </tagname>
	XML_TAG_EMPTY			このノードは空要素タグである <  />, <!--  -->, <!   >, <?   ?> の型

	XML_NOT_CLOSED			最終的にタグが閉じなかったが，解釈できるところまでは解釈した．
	XML_MULTI_ROOT			アンカータグにのみ設定される．このXMLツリーは 2つ以上の独立したツリーを持つ

	XML_PARSE_ERROR			解釈エラー
	XML_SEQUENCE_ERROR		アンカーを越えてツリーを作ろうとした．
	XML_MEMORY_ERROR		メモリの確保エラー
*/
typedef  tTree  tXML;





// タグ種別	(ldat.id)
#define  XML_ANCHOR_TAG				0
#define  XML_TAG_NAME				1
#define  XML_TAG_CONTENT			2
#define  XML_DOC_TAG				3
#define  XML_COMMENT_TAG			4
#define  XML_DATA_TAG				5
#define  XML_PROCESS_TAG			6


// タグ(ノード)の状態．エラーは 0以下にする．(state)
#define  XML_DEFAULT_STATE			0
#define  XML_PARSED					1	
#define  XML_TAG_STARTED			2
#define  XML_TAG_ENDED				3
#define  XML_TAG_EMPTY				4
#define  XML_MULTI_ROOT				9
// warning
#define  XML_NOT_CLOSED				101
// error
#define  XML_PARSE_ERROR			-1
#define  XML_SEQUENCE_ERROR			-2
#define  XML_MEMORY_ERROR			-9


// XML Format
#define  XML_ONELINE_FORMAT			0
#define  XML_CRLF_FORMAT			1
#define  XML_INDENT_FORMAT			2


// 代用タグ名 (ldat.key.buf)
#define  XML_COMMENT_TAG_KEY		"@COMMENT_TAG"
#define  XML_DATA_TAG_KEY			"@DATA_TAG"




/////////////////////////////////////////////////////////////////////////////////////////////
//
// XML Functions
//

#define new_xml_node()	new_tTree_node()


// Paser
tXML*	xml_parse(char* pp);
tXML*	xml_parse_file(const char* pp);
tXML*	xml_parse_seq(tXML* xml,  char* pp);
tXML*	xml_main_parse(tXML* xml, char* pp, int skip);

int 	xml_parse_content(char* pp, char** content);
tList*	xml_parse_attr(char* pp);
int  	xml_parse_start_tag(char* pp, char** tag_name, char** tag_attr, int* tag_end);
int  	xml_parse_end_tag(char* pp, char** tag_name);
int  	xml_parse_processing_tag(char* pp, char** tag_name, char** tag_attr);
int  	xml_parse_comment_tag(char* pp, char** comment);
int  	xml_parse_data_tag(char* pp, char** data);

void 	close_xml(tXML* pp);
int	 	isnot_xml_name(unsigned char* pp);

tXML*	init_xml_doc(void);
char*   get_first_tag_name(tXML* xml);

#define find_xml_top(p)		find_tList_top(p)
#define find_xml_end(p)		find_tTree_end(p)


// 逆パース
Buffer	xml_inverse_parse(tXML* pp, int mode);
void	xml_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent);
void	xml_opentag_to_Buffer (tXML* pp, Buffer* buf, int mode, int indent);
void	xml_closetag_to_Buffer(tXML* pp, Buffer* buf, int mode, int indent);
void	xml_attr_to_Buffer(tList* pp, Buffer* buf);


// Operation
tXML* 	add_xml_tag(tXML* xml, const char* name);
tXML* 	insert_xml_tag(tXML* xml, const char* name);

tXML* 	add_xml_attr(tXML* xml, const char* attr);
tXML* 	add_xml_attr_str  (tXML* xml, const char* name, const char* value);
tXML* 	add_xml_attr_int  (tXML* xml, const char* name, int   value);
tXML* 	add_xml_attr_float(tXML* xml, const char* name, float value);

tXML* 	add_xml_content(tXML* xml, const char* value);
tXML* 	append_xml_content(tXML* xml, const char* value);
int		add_xml_content_area(tXML* xml, int len);

Buffer 	make_xml_attr_bystr  (const char* name, const char* value);
Buffer 	make_xml_attr_byint  (const char* name, int   value);
Buffer 	make_xml_attr_byfloat(const char* name, float value);

#define make_xml_attr_str(n, v) 	make_xml_attr_bystr  ((n), (v))
#define make_xml_attr_int(n, v) 	make_xml_attr_byint  ((n), (v))
#define make_xml_attr_float(n, v) 	make_xml_attr_byfloat((n), (v))

char*	xml_get_tag_content(tXML* tag);
char*	xml_get_tag_attr(tXML* tag, const char* attr);

tXML*	dup_merge_xml(tXML* pp, tXML* tp);

tXML* 	del_xml(tXML** pp);
void  	del_all_xml(tXML** pp);
tXML* 	del_sister_xml(tXML** pp);
tXML*	del_sisters_children_xml(tXML** pp);

#define free_xml(p)  del_xml((p))

void 	print_xml(FILE* fp, tXML* pp, int mode);
void 	print_xml_node(FILE* fp, tXML* pp);
void 	print_xml_tree(FILE* fp, tXML* pp, const char* space);
void 	print_sister_xml_tree(FILE* fp, tXML* pp, const char* space);



///////////////////////////////////////////////////////////////////////////////////////////
// Search and Get/Set	操作対象は１番最初に一致したもの

tXML*	get_xml_tag(tXML* pp, tXML* pt);
int		set_xml_tag(tXML* pp, tXML* pt, const char* val);
int 	set_xml_end_tag(tXML* pp, tXML* pt);

tXML*	get_xml_content(tXML* pp, tXML* pt);
int 	set_xml_content(tXML* pp, tXML* pt, const char* val);
tList*	get_xml_attr(tXML* pp, tXML* pt);
int		set_xml_attr(tXML* pp, tXML* pt, tList* at);

tXML*	get_xml_tag_bystr(tXML* pp, const char* str);
int		set_xml_tag_bystr(tXML* pp, const char* str, const char* val);
int 	set_xml_end_tag_bystr(tXML* pp, const char* str);

tXML*	get_xml_content_bystr(tXML* pp, const char* str);
int 	set_xml_content_bystr(tXML* pp, const char* str, const char* val);
tList*	get_xml_attr_bystr(tXML* pp, const char* str);
int		set_xml_attr_bystr(tXML* pp, const char* pt, tList* at);

int		get_xml_int_content(tXML* pp, tXML* pt);
int		get_xml_int_content_bystr(tXML* pp, const char* str);
float	get_xml_float_content(tXML* pp, tXML* pt);
float	get_xml_float_content_bystr(tXML* pp, const char* str);
double	get_xml_double_content(tXML* pp, tXML* pt);
double	get_xml_double_content_bystr(tXML* pp, const char* str);
char*	get_xml_char_content(tXML* pp, tXML* pt);								// free してはいけない
char*	get_xml_char_content_bystr(tXML* pp, const char* str);					// free してはいけない

char*   get_xml_char_attr(tXML* pp, tXML* pt, const char* attr);				// free してはいけない．
char*   get_xml_char_attr_bystr(tXML* pp, const char* str, const char* attr);	// free してはいけない．
int     get_xml_int_attr(tXML* pp, tXML* pt, const char* attr);	
int     get_xml_int_attr_bystr(tXML* pp, const char* str, const char* attr);
double  get_xml_double_attr(tXML* pp, tXML* pt, const char* attr);
double  get_xml_double_attr_bystr(tXML* pp, const char* str, const char* attr);

int		replace_xml_content(tXML*pp, tXML* pt, const char* src, const char* dst);
int		replace_xml_content_bystr(tXML*pp, const char* str, const char* src, const char* dst);

#define get_xml_tag_str(p, s) 				get_xml_tag_bystr((p), (s))
#define set_xml_tag_str(p, s, v) 			set_xml_tag_bystr((p), (s), (v))
#define set_xml_end_tag_str(p, s)  			set_xml_end_tag_bystr((p), (s))
#define get_xml_content_str(p, s) 	 		get_xml_content_bystr((p), (s))
#define set_xml_content_str(p, s, v) 		set_xml_content_bystr((p), (s), (v))
#define get_xml_attr_str(p, s) 		 		get_xml_attr_bystr((p), (s))
#define set_xml_attr_str(p, t, a) 	 		set_xml_attr_bystr((p), (t), (a))
#define replace_xml_content_str(p, t, r, d) replace_xml_content_bystr((p), (t), (r), (d))


#define get_xml_int_content_str(p, s) 		get_xml_int_content_bystr((p), (s))
#define	get_xml_double_content_str(p, s) 	get_xml_double_content_bystr((p), (s));
#define get_xml_char_content_str(p, s)		get_xml_char_content_bystr((p), (s));
#define get_xml_char_attr_str(p, s, v)		get_xml_char_sttr_bystr((p), (s), (v));

#define get_xml_str_content(p, s)			get_xml_char_content((p), (s));
#define get_xml_str_content_str(p, s)		get_xml_char_content_bystr((p), (s));
#define get_xml_str_content_bystr(p, s)		get_xml_char_content_bystr((p), (s));
#define get_xml_str_attr(p, s)				get_xml_char_attr((p), (s));
#define get_xml_str_attr_str(p, s, v)		get_xml_char_attr_bystr((p), (s), (v));
#define get_xml_str_attr_bystr(p, s, v)		get_xml_char_attr_bystr((p), (s), (v));
#define get_xml_int_attr_str(p, s, v)		get_xml_int_attr_bystr((p), (s), (v));
#define get_xml_double_attr_str(p, s, v)	get_xml_double_attr_bystr((p), (s), (v));


// Operation for Multi Tags
tList*	get_xml_tag_list(tXML* pp, tXML* pt);
tList*	get_xml_content_list(tXML* pp, tXML* pt);
int		set_xml_content_list(tXML* pp, tXML* pt, const char* content);

tList*	get_xml_tag_list_bystr(tXML* pp, const char* str);
tList*	get_xml_content_list_bystr(tXML* pp, const char* str);
int		set_xml_content_list_bystr(tXML* pp, const char* str, const char* content);

#define	get_xml_tag_list_str(p, s) 			get_xml_tag_list_bystr((p), (s))
#define	get_xml_content_list_str(p, s) 		get_xml_content_list_bystr((p), (s))
#define	set_xml_content_list_str(p, s, c)	set_xml_content_list_bystr((p), (s), (c))



///////////////////////////////////////////////////////////////////////////////////////////
// Search XML Tag (tTree用の関数とほぼ同じ)

int  	find_match_xml(tXML* pp, tXML* pt);
tXML*  	find_match_xml_endlist(tXML* pp, tXML* pt);
tList*  find_match_xml_endlist_rcsv(tXML* pp, tXML* pt, tXML* te);
tXML*  	find_match_xml_end_tag(tXML* pp, tXML* pt);

int  	check_match_xml(tXML* tp, tXML* tr);
tXML*  	cmp_sisters_xml(tXML* tp, tXML* tr);




/////////////////////////////////////////////////////////////////////////////////////////////
//
// Simple Tag Functions.
//
int		get_tag_integer(tXML* tp, const char* name, int no);
Buffer  get_tag_content(tXML* tp, const char* name, int no);

int		return_exist_tag(tXML* tp, const char* name, int no, Buffer* value);

int		replace_all_tag_integer (tXML* tp, const char* name, int src, int dst);
int		replace_all_tag_contents(tXML* tp, const char* name, const char* src, const char* dst);
int 	replace_all_tag_contents_rcsv(tXML* tp, const char* name, const char* src, const char* dst);

int 	replace_all_tag_byid(tXML* tp, const char* src, const char* dst, int id);
int 	replace_all_tag_byid_rcsv(tXML* tp, const char* src, const char* dst, int id);




/**/

#endif
