added quite some xli code to read the json formatted data
This commit is contained in:
		| @ -164,6 +164,7 @@ static void print_usage (qse_sio_t* out, int argc, qse_char_t* argv[]) | |||||||
| 	qse_fprintf (out, QSE_T(" -J                 file   specify a json output file\n")); | 	qse_fprintf (out, QSE_T(" -J                 file   specify a json output file\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -u                        disallow duplicate keys\n")); | 	qse_fprintf (out, QSE_T(" -u                        disallow duplicate keys\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -a                        allow a key alias\n")); | 	qse_fprintf (out, QSE_T(" -a                        allow a key alias\n")); | ||||||
|  | 	qse_fprintf (out, QSE_T(" -b                        allow true and false as boolean values\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -f                        keep file inclusion info\n")); | 	qse_fprintf (out, QSE_T(" -f                        keep file inclusion info\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -t                        keep comment text\n")); | 	qse_fprintf (out, QSE_T(" -t                        keep comment text\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -s                        allow multi-segmented strings\n")); | 	qse_fprintf (out, QSE_T(" -s                        allow multi-segmented strings\n")); | ||||||
| @ -199,9 +200,9 @@ static int handle_args (int argc, qse_char_t* argv[]) | |||||||
| 	static qse_opt_t opt =  | 	static qse_opt_t opt =  | ||||||
| 	{ | 	{ | ||||||
| #if defined(QSE_BUILD_DEBUG) | #if defined(QSE_BUILD_DEBUG) | ||||||
| 		QSE_T("hi:o:I:O:j:J:uaftsdnlKSvm:X:"), | 		QSE_T("hi:o:I:O:j:J:uabftsdnlKSvm:X:"), | ||||||
| #else | #else | ||||||
| 		QSE_T("hi:o:I:O:j:J:uaftsdnlKSvm:"), | 		QSE_T("hi:o:I:O:j:J:uabftsdnlKSvm:"), | ||||||
| #endif | #endif | ||||||
| 		lng | 		lng | ||||||
| 	}; | 	}; | ||||||
| @ -273,6 +274,10 @@ static int handle_args (int argc, qse_char_t* argv[]) | |||||||
| 				g_trait |= QSE_XLI_KEYALIAS; | 				g_trait |= QSE_XLI_KEYALIAS; | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
|  | 			case QSE_T('b'): | ||||||
|  | 				g_trait |= QSE_XLI_BOOLEAN; | ||||||
|  | 				break; | ||||||
|  |  | ||||||
| 			case QSE_T('f'): | 			case QSE_T('f'): | ||||||
| 				g_trait |= QSE_XLI_KEEPFILE; | 				g_trait |= QSE_XLI_KEEPFILE; | ||||||
| 				break; | 				break; | ||||||
| @ -547,7 +552,15 @@ static int xli_main (int argc, qse_char_t* argv[]) | |||||||
| 				} | 				} | ||||||
| 				else if (pair->val->type == QSE_XLI_NIL) | 				else if (pair->val->type == QSE_XLI_NIL) | ||||||
| 				{ | 				{ | ||||||
| 					qse_printf (QSE_T("#NIL\n")); | 					qse_printf (QSE_T("nil\n")); | ||||||
|  | 				} | ||||||
|  | 				else if (pair->val->type == QSE_XLI_TRUE) | ||||||
|  | 				{ | ||||||
|  | 					qse_printf (QSE_T("true\n")); | ||||||
|  | 				} | ||||||
|  | 				else if (pair->val->type == QSE_XLI_FALSE) | ||||||
|  | 				{ | ||||||
|  | 					qse_printf (QSE_T("false\n")); | ||||||
| 				} | 				} | ||||||
| 				else | 				else | ||||||
| 				{ | 				{ | ||||||
| @ -567,6 +580,11 @@ static int xli_main (int argc, qse_char_t* argv[]) | |||||||
| 	ret = (g_io_flags & IO_FLAG_JSON_OUTPUT)? qse_xli_writejsonstd(xli, QSE_NULL, &out): | 	ret = (g_io_flags & IO_FLAG_JSON_OUTPUT)? qse_xli_writejsonstd(xli, QSE_NULL, &out): | ||||||
| 	      (g_io_flags & IO_FLAG_INI_OUTPUT)?  qse_xli_writeinistd(xli, QSE_NULL, &out): | 	      (g_io_flags & IO_FLAG_INI_OUTPUT)?  qse_xli_writeinistd(xli, QSE_NULL, &out): | ||||||
| 	                                          qse_xli_writestd(xli, QSE_NULL, &out); | 	                                          qse_xli_writestd(xli, QSE_NULL, &out); | ||||||
|  | 	if (ret <= -1) | ||||||
|  | 	{ | ||||||
|  | 		qse_fprintf (QSE_STDERR, QSE_T("WARNING: cannot write - %s\n"), qse_xli_geterrmsg(xli)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| oops: | oops: | ||||||
| 	if (xli) qse_xli_close (xli); | 	if (xli) qse_xli_close (xli); | ||||||
| 	if (xma_mmgr.ctx) qse_xma_close (xma_mmgr.ctx); | 	if (xma_mmgr.ctx) qse_xma_close (xma_mmgr.ctx); | ||||||
|  | |||||||
| @ -71,7 +71,8 @@ enum qse_xli_errnum_t | |||||||
| 	QSE_XLI_ELBREQ,   /**< { or = expected in place of '${0}' */ | 	QSE_XLI_ELBREQ,   /**< { or = expected in place of '${0}' */ | ||||||
| 	QSE_XLI_ERBRACE,  /**< } expected in place of '${0}' */ | 	QSE_XLI_ERBRACE,  /**< } expected in place of '${0}' */ | ||||||
| 	QSE_XLI_ERBRACK,  /**< ] expected in place of '${0}' */ | 	QSE_XLI_ERBRACK,  /**< ] expected in place of '${0}' */ | ||||||
| 	QSE_XLI_EPAVAL,   /**< pair value expected in place of '${0}' */ | 	QSE_XLI_ECOMMA,   /**< , expected in place of '${0}' */ | ||||||
|  | 	QSE_XLI_EVALUE,   /**< value expected in place of '${0}' */ | ||||||
| 	QSE_XLI_ESTRNC,   /**< string not closed */ | 	QSE_XLI_ESTRNC,   /**< string not closed */ | ||||||
| 	QSE_XLI_ETAGNC,   /**< tag not closed */ | 	QSE_XLI_ETAGNC,   /**< tag not closed */ | ||||||
| 	QSE_XLI_EINCLSTR ,/**< '@include' not followed by a string */ | 	QSE_XLI_EINCLSTR ,/**< '@include' not followed by a string */ | ||||||
| @ -147,13 +148,20 @@ enum qse_xli_trait_t | |||||||
| 	 *  "tg" is stored into the tag field of qse_xli_str_t. */ | 	 *  "tg" is stored into the tag field of qse_xli_str_t. */ | ||||||
| 	QSE_XLI_STRTAG    = (1 << 10),  | 	QSE_XLI_STRTAG    = (1 << 10),  | ||||||
|  |  | ||||||
|  | 	/** enable the keyword 'true' and 'false' in the xli format. | ||||||
|  | 	 *  the json format always supports these keywords regardless of this option. | ||||||
|  | 	 *  the ini format doesn't support these regardless of this option. */ | ||||||
|  | 	QSE_XLI_BOOLEAN   = (1 << 11), | ||||||
|  |  | ||||||
| 	/** enable pair validation against pair definitions while reading */ | 	/** enable pair validation against pair definitions while reading */ | ||||||
| 	QSE_XLI_VALIDATE  = (1 << 11) | 	QSE_XLI_VALIDATE  = (1 << 12) | ||||||
| }; | }; | ||||||
| typedef enum qse_xli_trait_t qse_xli_trait_t; | typedef enum qse_xli_trait_t qse_xli_trait_t; | ||||||
|  |  | ||||||
| typedef struct qse_xli_val_t    qse_xli_val_t; | typedef struct qse_xli_val_t    qse_xli_val_t; | ||||||
| typedef struct qse_xli_nil_t    qse_xli_nil_t; | typedef struct qse_xli_nil_t    qse_xli_nil_t; | ||||||
|  | typedef struct qse_xli_true_t   qse_xli_true_t; | ||||||
|  | typedef struct qse_xli_false_t  qse_xli_false_t; | ||||||
| typedef struct qse_xli_str_t    qse_xli_str_t; | typedef struct qse_xli_str_t    qse_xli_str_t; | ||||||
| typedef struct qse_xli_list_t   qse_xli_list_t; | typedef struct qse_xli_list_t   qse_xli_list_t; | ||||||
|  |  | ||||||
| @ -166,11 +174,20 @@ typedef struct qse_xli_eof_t  qse_xli_eof_t; | |||||||
| enum qse_xli_val_type_t | enum qse_xli_val_type_t | ||||||
| { | { | ||||||
| 	QSE_XLI_NIL, | 	QSE_XLI_NIL, | ||||||
|  | 	QSE_XLI_TRUE, | ||||||
|  | 	QSE_XLI_FALSE, | ||||||
| 	QSE_XLI_STR, | 	QSE_XLI_STR, | ||||||
| 	QSE_XLI_LIST, | 	QSE_XLI_LIST, | ||||||
| }; | }; | ||||||
| typedef enum qse_xli_val_type_t qse_xli_val_type_t; | typedef enum qse_xli_val_type_t qse_xli_val_type_t; | ||||||
|  |  | ||||||
|  | enum qse_xli_str_flag_t | ||||||
|  | { | ||||||
|  | 	QSE_XLI_STR_NSTR  = (1 << 0), | ||||||
|  | 	QSE_XLI_STR_RADIX = (1 << 1), | ||||||
|  | 	QSE_XLI_STR_FLOAT = (1 << 2) | ||||||
|  | }; | ||||||
|  |  | ||||||
| enum qse_xli_atom_type_t | enum qse_xli_atom_type_t | ||||||
| { | { | ||||||
| 	QSE_XLI_PAIR, | 	QSE_XLI_PAIR, | ||||||
| @ -193,6 +210,16 @@ struct qse_xli_nil_t | |||||||
| 	QSE_XLI_VAL_HDR; | 	QSE_XLI_VAL_HDR; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct qse_xli_true_t | ||||||
|  | { | ||||||
|  | 	QSE_XLI_VAL_HDR; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct qse_xli_false_t | ||||||
|  | { | ||||||
|  | 	QSE_XLI_VAL_HDR; | ||||||
|  | }; | ||||||
|  |  | ||||||
| struct qse_xli_list_t | struct qse_xli_list_t | ||||||
| { | { | ||||||
| 	QSE_XLI_VAL_HDR; | 	QSE_XLI_VAL_HDR; | ||||||
| @ -203,6 +230,7 @@ struct qse_xli_list_t | |||||||
| struct qse_xli_str_t | struct qse_xli_str_t | ||||||
| { | { | ||||||
| 	QSE_XLI_VAL_HDR; | 	QSE_XLI_VAL_HDR; | ||||||
|  | 	int                flags; | ||||||
| 	const qse_char_t*  tag; | 	const qse_char_t*  tag; | ||||||
| 	const qse_char_t*  ptr; | 	const qse_char_t*  ptr; | ||||||
| 	qse_size_t         len;  | 	qse_size_t         len;  | ||||||
|  | |||||||
| @ -51,7 +51,8 @@ const qse_char_t* qse_xli_dflerrstr (const qse_xli_t* xli, qse_xli_errnum_t errn | |||||||
| 		QSE_T("left-brace or equal-sign expected in place of '${0}'"), | 		QSE_T("left-brace or equal-sign expected in place of '${0}'"), | ||||||
| 		QSE_T("right-brace expected in place of '${0}'"), | 		QSE_T("right-brace expected in place of '${0}'"), | ||||||
| 		QSE_T("right-bracket expected in place of '${0}'"), | 		QSE_T("right-bracket expected in place of '${0}'"), | ||||||
| 		QSE_T("pair value expected in place of '${0}'"), | 		QSE_T("comma expected in place of '${0}'"), | ||||||
|  | 		QSE_T("value expected in place of '${0}'"), | ||||||
| 		QSE_T("string not closed"), | 		QSE_T("string not closed"), | ||||||
| 		QSE_T("string tag not closed"), | 		QSE_T("string tag not closed"), | ||||||
| 		QSE_T("'@include' not followed by a string"), | 		QSE_T("'@include' not followed by a string"), | ||||||
|  | |||||||
| @ -84,14 +84,17 @@ typedef struct kwent_t kwent_t; | |||||||
| struct kwent_t  | struct kwent_t  | ||||||
| {  | {  | ||||||
| 	qse_cstr_t name; | 	qse_cstr_t name; | ||||||
| 	int type;  | 	qse_xli_tok_type_t type;  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* note that the keyword must start with @. */ | /* note that the keyword must start with @. */ | ||||||
| static kwent_t kwtab[] =  | static kwent_t kwtab[] =  | ||||||
| { | { | ||||||
| 	/* keep it sorted by the first field for binary search */ | 	/* keep it sorted by the first field for binary search */ | ||||||
| 	{ { QSE_T("@include"),     8 }, QSE_XLI_TOK_XINCLUDE } | 	{ { QSE_T("@include"),     8 }, QSE_XLI_TOK_XINCLUDE }, | ||||||
|  | 	{ { QSE_T("false"),        5 }, QSE_XLI_TOK_FALSE    }, | ||||||
|  | 	{ { QSE_T("nil"),          3 }, QSE_XLI_TOK_NIL      }, | ||||||
|  | 	{ { QSE_T("true"),         4 }, QSE_XLI_TOK_TRUE     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static int skip_spaces (qse_xli_t* xli) | static int skip_spaces (qse_xli_t* xli) | ||||||
| @ -130,7 +133,7 @@ static int skip_comment (qse_xli_t* xli, qse_xli_tok_t* tok) | |||||||
| 	return 0;  | 	return 0;  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int classify_ident (qse_xli_t* xli, const qse_cstr_t* name) | static qse_xli_tok_type_t classify_ident (qse_xli_t* xli, const qse_cstr_t* name) | ||||||
| { | { | ||||||
| 	/* perform binary search */ | 	/* perform binary search */ | ||||||
|  |  | ||||||
| @ -287,7 +290,7 @@ static int begin_include (qse_xli_t* xli) | |||||||
| 	/* read in the first character in the included file.  | 	/* read in the first character in the included file.  | ||||||
| 	 * so the next call to get_token() sees the character read | 	 * so the next call to get_token() sees the character read | ||||||
| 	 * from this file. */ | 	 * from this file. */ | ||||||
| 	if (qse_xli_getchar (xli) <= -1 || get_token (xli) <= -1)  | 	if (qse_xli_getchar(xli) <= -1 || get_token(xli) <= -1)  | ||||||
| 	{ | 	{ | ||||||
| 		end_include (xli, 1);  | 		end_include (xli, 1);  | ||||||
| 		/* i don't jump to oops since i've called  | 		/* i don't jump to oops since i've called  | ||||||
| @ -296,7 +299,7 @@ static int begin_include (qse_xli_t* xli) | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if ((xli->opt.trait & QSE_XLI_KEEPFILE) && | 	if ((xli->opt.trait & QSE_XLI_KEEPFILE) && | ||||||
| 	    qse_xli_insertfile (xli, xli->parlink->list, QSE_NULL, arg->name) == QSE_NULL)  | 	    qse_xli_insertfile(xli, xli->parlink->list, QSE_NULL, arg->name) == QSE_NULL)  | ||||||
| 	{ | 	{ | ||||||
| 		end_include (xli, 1); | 		end_include (xli, 1); | ||||||
| 		return -1; | 		return -1; | ||||||
| @ -316,7 +319,6 @@ static int get_token_into (qse_xli_t* xli, qse_xli_tok_t* tok) | |||||||
| { | { | ||||||
| 	qse_cint_t c; | 	qse_cint_t c; | ||||||
| 	int n; | 	int n; | ||||||
| 	int skip_semicolon_after_include = 0; |  | ||||||
|  |  | ||||||
| retry: | retry: | ||||||
| 	do  | 	do  | ||||||
| @ -341,7 +343,6 @@ retry: | |||||||
| 		{ | 		{ | ||||||
| 			/*xli->rio.last = xli->rio.inp->last;*/ | 			/*xli->rio.last = xli->rio.inp->last;*/ | ||||||
| 			/* mark that i'm retrying after end of an included file */ | 			/* mark that i'm retrying after end of an included file */ | ||||||
| 			skip_semicolon_after_include = 1;  |  | ||||||
| 			goto retry; | 			goto retry; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @ -352,7 +353,7 @@ retry: | |||||||
| 	{ | 	{ | ||||||
| 		/* keyword/directive - start with @ */ | 		/* keyword/directive - start with @ */ | ||||||
|  |  | ||||||
| 		int type; | 		qse_xli_tok_type_t type; | ||||||
|  |  | ||||||
| 		ADD_TOKEN_CHAR (xli, tok, c); | 		ADD_TOKEN_CHAR (xli, tok, c); | ||||||
| 		GET_CHAR_TO (xli, c); | 		GET_CHAR_TO (xli, c); | ||||||
| @ -373,7 +374,7 @@ retry: | |||||||
| 		}  | 		}  | ||||||
| 		while (QSE_ISALPHA (c)); | 		while (QSE_ISALPHA (c)); | ||||||
|  |  | ||||||
| 		type = classify_ident (xli, QSE_STR_XSTR(tok->name)); | 		type = classify_ident(xli, QSE_STR_XSTR(tok->name)); | ||||||
| 		if (type == QSE_XLI_TOK_IDENT) | 		if (type == QSE_XLI_TOK_IDENT) | ||||||
| 		{ | 		{ | ||||||
| 			/* this keyword/directive is not recognized */ | 			/* this keyword/directive is not recognized */ | ||||||
| @ -382,43 +383,22 @@ retry: | |||||||
| 		} | 		} | ||||||
| 		SET_TOKEN_TYPE (xli, tok, type); | 		SET_TOKEN_TYPE (xli, tok, type); | ||||||
| 	} | 	} | ||||||
| 	else if (c == QSE_T('_') || QSE_ISALPHA (c) ||  | 	else if (c == QSE_T('_') || QSE_ISALPHA (c)) | ||||||
| 	         (!(xli->tok_status & TOK_STATUS_ENABLE_NSTR) && |  | ||||||
| 	          (xli->opt.trait & QSE_XLI_LEADDIGIT) &&  |  | ||||||
| 	          QSE_ISDIGIT(c))) |  | ||||||
| 	{ | 	{ | ||||||
| 		int lead_digit = QSE_ISDIGIT(c); | 		qse_xli_tok_type_t type; | ||||||
| 		int all_digits = 1; |  | ||||||
|  |  | ||||||
| 		/* a normal identifier can be composed of wider varieties of  | 		do | ||||||
| 		 * characters than a keyword/directive */ |  | ||||||
| 		while (1) |  | ||||||
| 		{ | 		{ | ||||||
| 			ADD_TOKEN_CHAR (xli, tok, c); | 			ADD_TOKEN_CHAR (xli, tok, c); | ||||||
| 			GET_CHAR_TO (xli, c); | 			GET_CHAR_TO (xli, c); | ||||||
|  |  | ||||||
| 			if (c == QSE_T('_') || c == QSE_T('-') || c == QSE_T('*') || |  | ||||||
| 			    c == QSE_T('/') || QSE_ISALPHA (c))  |  | ||||||
| 			{ |  | ||||||
| 				all_digits = 0; |  | ||||||
| 		} | 		} | ||||||
|  | 		while (c == QSE_T('_') || QSE_ISALNUM (c)); | ||||||
|  |  | ||||||
|  | 		type = classify_ident(xli, QSE_STR_XSTR(tok->name)); | ||||||
|  | 		SET_TOKEN_TYPE (xli, tok, type); | ||||||
|  | 	} | ||||||
|  | 	/* TODO: negative number, floating-point number, etc */ | ||||||
| 	else if (QSE_ISDIGIT(c)) | 	else if (QSE_ISDIGIT(c)) | ||||||
| 			{ |  | ||||||
| 				/* nothing to do */ |  | ||||||
| 			} |  | ||||||
| 			else break; |  | ||||||
| 		}  |  | ||||||
|  |  | ||||||
| 		if (lead_digit && all_digits) |  | ||||||
| 		{ |  | ||||||
| 			/* if an identifier begins with a digit, it must contain a non-digits character */ |  | ||||||
| 			qse_xli_seterror (xli, QSE_XLI_EIDENT, QSE_STR_XSTR(tok->name), &tok->loc); |  | ||||||
| 			return -1; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_IDENT); |  | ||||||
| 	} |  | ||||||
| 	else if ((xli->tok_status & TOK_STATUS_ENABLE_NSTR) && QSE_ISDIGIT(c)) |  | ||||||
| 	{ | 	{ | ||||||
| 		SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_NSTR); | 		SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_NSTR); | ||||||
| 		do | 		do | ||||||
| @ -520,24 +500,8 @@ retry: | |||||||
| 			} | 			} | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (skip_semicolon_after_include && tok->type == QSE_XLI_TOK_SEMICOLON) |  | ||||||
| 		{ |  | ||||||
| 			/* this handles the optional semicolon after the  |  | ||||||
| 			 * included file named as in @include "file-name"; */ |  | ||||||
| 			skip_semicolon_after_include = 0; |  | ||||||
| 			goto retry; |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (skip_semicolon_after_include) |  | ||||||
| 	{ |  | ||||||
| 		/* semiclon has not been skipped yet */ |  | ||||||
| 		qse_xli_seterror (xli, QSE_XLI_ESCOLON, QSE_STR_XSTR(tok->name), &tok->loc); |  | ||||||
| 		return -1; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| printf ("TOKEN: %ls\n",QSE_STR_PTR(tok->name)); |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -587,9 +551,19 @@ static qse_xli_val_t* __read_value (qse_xli_t* xli) | |||||||
|  |  | ||||||
| 			if (begin_include(xli) <= -1) return QSE_NULL; | 			if (begin_include(xli) <= -1) return QSE_NULL; | ||||||
| 		} | 		} | ||||||
| 		else if (/*MATCH(xli, QSE_XLI_TOK_IDENT) || */MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_SQSTR)) | 		else if (/*MATCH(xli, QSE_XLI_TOK_IDENT) || */MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_NSTR)) | ||||||
| 		{ | 		{ | ||||||
| 			return (qse_xli_val_t*)qse_xli_makestrval(xli, QSE_STR_XSTR(xli->tok.name), QSE_NULL); | 			qse_xli_str_t* sv; | ||||||
|  |  | ||||||
|  | 			sv = qse_xli_makestrval(xli, QSE_STR_XSTR(xli->tok.name), QSE_NULL); | ||||||
|  | 			if (!sv) return QSE_NULL; | ||||||
|  |  | ||||||
|  | 			if (MATCH(xli, QSE_XLI_TOK_NSTR)) | ||||||
|  | 			{ | ||||||
|  | 				sv->flags |= QSE_XLI_STR_NSTR; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return (qse_xli_val_t*)sv; | ||||||
| 		} | 		} | ||||||
| 		else if (MATCH(xli, QSE_XLI_TOK_LBRACE)) | 		else if (MATCH(xli, QSE_XLI_TOK_LBRACE)) | ||||||
| 		{ | 		{ | ||||||
| @ -610,17 +584,29 @@ static qse_xli_val_t* __read_value (qse_xli_t* xli) | |||||||
| 		{ | 		{ | ||||||
| 			qse_xli_list_t* lv; | 			qse_xli_list_t* lv; | ||||||
|  |  | ||||||
| 			lv = qse_xli_makelistval (xli); | 			lv = qse_xli_makelistval(xli); | ||||||
| 			if (!lv) return QSE_NULL; | 			if (!lv) return QSE_NULL; | ||||||
|  |  | ||||||
| 			if (get_token(xli) <= -1 || read_array(xli, lv) <= -1) | 			if (get_token(xli) <= -1 || read_array(xli, lv) <= -1) | ||||||
| 			if (!lv)  |  | ||||||
| 			{ | 			{ | ||||||
| 				qse_xli_freeval (xli, (qse_xli_val_t*)lv); | 				qse_xli_freeval (xli, (qse_xli_val_t*)lv); | ||||||
|  | 				return QSE_NULL; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			return (qse_xli_val_t*)lv; | 			return (qse_xli_val_t*)lv; | ||||||
| 		} | 		} | ||||||
|  | 		else if (MATCH(xli, QSE_XLI_TOK_NIL)) | ||||||
|  | 		{ | ||||||
|  | 			return (qse_xli_val_t*)&xli->root->xnil; | ||||||
|  | 		} | ||||||
|  | 		else if (MATCH(xli, QSE_XLI_TOK_TRUE)) | ||||||
|  | 		{ | ||||||
|  | 			return (qse_xli_val_t*)&xli->root->xtrue; | ||||||
|  | 		} | ||||||
|  | 		else if (MATCH(xli, QSE_XLI_TOK_FALSE)) | ||||||
|  | 		{ | ||||||
|  | 			return (qse_xli_val_t*)&xli->root->xfalse; | ||||||
|  | 		} | ||||||
| 		else if (MATCH(xli, QSE_XLI_TOK_TEXT)) | 		else if (MATCH(xli, QSE_XLI_TOK_TEXT)) | ||||||
| 		{ | 		{ | ||||||
| 			if (get_token(xli) <= -1) return QSE_NULL; | 			if (get_token(xli) <= -1) return QSE_NULL; | ||||||
| @ -631,10 +617,10 @@ static qse_xli_val_t* __read_value (qse_xli_t* xli) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	qse_xli_seterror (xli, QSE_XLI_EVALUE, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | ||||||
| 	return QSE_NULL; | 	return QSE_NULL; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| struct rpair_t | struct rpair_t | ||||||
| { | { | ||||||
| 	qse_char_t* key; | 	qse_char_t* key; | ||||||
| @ -697,17 +683,17 @@ static int __read_array (qse_xli_t* xli) | |||||||
|  |  | ||||||
| 		if (get_token(xli) <= -1) return -1; | 		if (get_token(xli) <= -1) return -1; | ||||||
|  |  | ||||||
| 		if (MATCH(xli, QSE_XLI_TOK_COMMA))  | 		if (MATCH(xli, QSE_XLI_TOK_RBRACK)) break; | ||||||
|  | 		if (!MATCH(xli, QSE_XLI_TOK_COMMA))  | ||||||
| 		{ | 		{ | ||||||
| 			if (get_token(xli) <= -1) return -1; | 			qse_xli_seterror (xli, QSE_XLI_ECOMMA, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | ||||||
| 			continue; | 			return -1; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (MATCH(xli, QSE_XLI_TOK_RBRACK)) break; | 		if (get_token(xli) <= -1) return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int read_array (qse_xli_t* xli, qse_xli_list_t* lv) | static int read_array (qse_xli_t* xli, qse_xli_list_t* lv) | ||||||
| @ -754,7 +740,7 @@ static int __read_list (qse_xli_t* xli) | |||||||
| 			rpair_t rpair; | 			rpair_t rpair; | ||||||
| 			if (read_pair(xli, &rpair) <= -1) return -1; | 			if (read_pair(xli, &rpair) <= -1) return -1; | ||||||
|  |  | ||||||
| 			if (!qse_xli_insertpair (xli, xli->parlink->list, QSE_NULL, rpair.key, QSE_NULL, QSE_NULL, rpair.val))  | 			if (!qse_xli_insertpair(xli, xli->parlink->list, QSE_NULL, rpair.key, QSE_NULL, QSE_NULL, rpair.val))  | ||||||
| 			{ | 			{ | ||||||
| 				QSE_MMGR_FREE (xli->mmgr, rpair.key); | 				QSE_MMGR_FREE (xli->mmgr, rpair.key); | ||||||
| 				qse_xli_freeval (xli, rpair.val); | 				qse_xli_freeval (xli, rpair.val); | ||||||
| @ -858,8 +844,17 @@ int qse_xli_readjson (qse_xli_t* xli, qse_xli_io_impl_t io) | |||||||
| 	QSE_ASSERT (xli->parlink == QSE_NULL); | 	QSE_ASSERT (xli->parlink == QSE_NULL); | ||||||
|  |  | ||||||
| 	if (!MATCH (xli, QSE_XLI_TOK_EOF)) | 	if (!MATCH (xli, QSE_XLI_TOK_EOF)) | ||||||
|  | 	{ | ||||||
|  | 		 | ||||||
|  | 		if (MATCH(xli, QSE_XLI_TOK_LBRACE) || MATCH(xli, QSE_XLI_TOK_LBRACK) ||  | ||||||
|  | 		    MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_SQSTR)) | ||||||
|  | 		{ | ||||||
|  | 			qse_xli_seterror (xli, QSE_XLI_ECOMMA, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
| 		{ | 		{ | ||||||
| 			qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc); | 			qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc); | ||||||
|  | 		} | ||||||
| 		goto oops; | 		goto oops; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | |||||||
| @ -104,7 +104,7 @@ typedef struct kwent_t kwent_t; | |||||||
| struct kwent_t  | struct kwent_t  | ||||||
| {  | {  | ||||||
| 	qse_cstr_t name; | 	qse_cstr_t name; | ||||||
| 	int type;  | 	qse_xli_tok_type_t type;  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* note that the keyword must start with @. */ | /* note that the keyword must start with @. */ | ||||||
| @ -114,6 +114,13 @@ static kwent_t kwtab[] = | |||||||
| 	{ { QSE_T("@include"),     8 }, QSE_XLI_TOK_XINCLUDE } | 	{ { QSE_T("@include"),     8 }, QSE_XLI_TOK_XINCLUDE } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | static kwent_t boolkwtab[] =  | ||||||
|  | { | ||||||
|  | 	/* keep it sorted by the first field for binary search */ | ||||||
|  | 	{ { QSE_T("false"),     5 }, QSE_XLI_TOK_FALSE }, | ||||||
|  | 	{ { QSE_T("true"),      4 }, QSE_XLI_TOK_TRUE } | ||||||
|  | }; | ||||||
|  |  | ||||||
| int qse_xli_getchar (qse_xli_t* xli) | int qse_xli_getchar (qse_xli_t* xli) | ||||||
| { | { | ||||||
| 	qse_ssize_t n; | 	qse_ssize_t n; | ||||||
| @ -254,14 +261,21 @@ static int skip_comment (qse_xli_t* xli, qse_xli_tok_t* tok) | |||||||
| 	return 0;  | 	return 0;  | ||||||
| } | } | ||||||
|  |  | ||||||
| static int classify_ident (qse_xli_t* xli, const qse_cstr_t* name) | static qse_xli_tok_type_t classify_ident (qse_xli_t* xli, const qse_cstr_t* name) | ||||||
| { | { | ||||||
| 	/* perform binary search */ | 	/* perform binary search */ | ||||||
|  |  | ||||||
| 	/* declaring left, right, mid to be the int type is ok | 	/* declaring left, right, mid to be the int type is ok | ||||||
| 	 * because we know kwtab is small enough. */ | 	 * because we know kwtab is small enough. */ | ||||||
| 	int left = 0, right = QSE_COUNTOF(kwtab) - 1, mid; | 	int left, right, mid; | ||||||
|  | 	int bool_checked = 0; | ||||||
|  | 	kwent_t* kwtabp; | ||||||
|  |  | ||||||
|  | 	left = 0; | ||||||
|  | 	right = QSE_COUNTOF(kwtab) - 1; | ||||||
|  | 	kwtabp = kwtab; | ||||||
|  |  | ||||||
|  | retry: | ||||||
| 	while (left <= right) | 	while (left <= right) | ||||||
| 	{ | 	{ | ||||||
| 		int n; | 		int n; | ||||||
| @ -269,7 +283,7 @@ static int classify_ident (qse_xli_t* xli, const qse_cstr_t* name) | |||||||
|  |  | ||||||
| 		/*mid = (left + right) / 2;*/ | 		/*mid = (left + right) / 2;*/ | ||||||
| 		mid = left + (right - left) / 2; | 		mid = left + (right - left) / 2; | ||||||
| 		kwp = &kwtab[mid]; | 		kwp = &kwtabp[mid]; | ||||||
|  |  | ||||||
| 		n = qse_strxncmp (kwp->name.ptr, kwp->name.len, name->ptr, name->len); | 		n = qse_strxncmp (kwp->name.ptr, kwp->name.len, name->ptr, name->len); | ||||||
| 		if (n > 0)  | 		if (n > 0)  | ||||||
| @ -284,6 +298,15 @@ static int classify_ident (qse_xli_t* xli, const qse_cstr_t* name) | |||||||
| 		else return kwp->type; | 		else return kwp->type; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (!bool_checked && (xli->opt.trait & QSE_XLI_BOOLEAN)) | ||||||
|  | 	{ | ||||||
|  | 		bool_checked = 1; | ||||||
|  | 		kwtabp = boolkwtab; | ||||||
|  | 		left = 0; | ||||||
|  | 		right = QSE_COUNTOF(boolkwtab) - 1; | ||||||
|  | 		goto retry; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return QSE_XLI_TOK_IDENT; | 	return QSE_XLI_TOK_IDENT; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -513,6 +536,7 @@ retry: | |||||||
| 	{ | 	{ | ||||||
| 		int lead_digit = QSE_ISDIGIT(c); | 		int lead_digit = QSE_ISDIGIT(c); | ||||||
| 		int all_digits = 1; | 		int all_digits = 1; | ||||||
|  | 		qse_xli_tok_type_t type; | ||||||
|  |  | ||||||
| 		/* a normal identifier can be composed of wider varieties of  | 		/* a normal identifier can be composed of wider varieties of  | ||||||
| 		 * characters than a keyword/directive */ | 		 * characters than a keyword/directive */ | ||||||
| @ -541,7 +565,8 @@ retry: | |||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_IDENT); | 		type = classify_ident (xli, QSE_STR_XSTR(tok->name)); | ||||||
|  | 		SET_TOKEN_TYPE (xli, tok, type); | ||||||
| 	} | 	} | ||||||
| 	else if ((xli->tok_status & TOK_STATUS_ENABLE_NSTR) && QSE_ISDIGIT(c)) | 	else if ((xli->tok_status & TOK_STATUS_ENABLE_NSTR) && QSE_ISDIGIT(c)) | ||||||
| 	{ | 	{ | ||||||
| @ -854,7 +879,26 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 			if (get_token (xli) <= -1) goto oops; | 			if (get_token (xli) <= -1) goto oops; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_NSTR) || MATCH(xli, QSE_XLI_TOK_IDENT)) | 		if (MATCH(xli, QSE_XLI_TOK_TRUE) || MATCH(xli, QSE_XLI_TOK_FALSE)) | ||||||
|  | 		{ | ||||||
|  | 			qse_xli_val_t* v; | ||||||
|  |  | ||||||
|  | 			v = MATCH(xli, QSE_XLI_TOK_TRUE)? (qse_xli_val_t*)&xli->root->xtrue: | ||||||
|  | 			                                  (qse_xli_val_t*)&xli->root->xfalse; | ||||||
|  | 			pair = qse_xli_insertpair(xli, parlist, QSE_NULL, key.ptr, name, keytag, v); | ||||||
|  | 			if (pair == QSE_NULL) goto oops; | ||||||
|  |  | ||||||
|  | 			if (get_token (xli) <= -1) goto oops; /* skip the value */ | ||||||
|  |  | ||||||
|  | 			if (!MATCH(xli, QSE_XLI_TOK_SEMICOLON)) | ||||||
|  | 			{ | ||||||
|  | 				qse_xli_seterror (xli, QSE_XLI_ESCOLON, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | ||||||
|  | 				goto oops; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			if (get_token (xli) <= -1) goto oops; /* skip the value */ | ||||||
|  | 		} | ||||||
|  | 		else if (MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_NSTR) || MATCH(xli, QSE_XLI_TOK_IDENT)) | ||||||
| 		{ | 		{ | ||||||
| 			qse_xli_str_t* curstrseg; | 			qse_xli_str_t* curstrseg; | ||||||
| 			qse_size_t segcount = 0; | 			qse_size_t segcount = 0; | ||||||
| @ -867,9 +911,14 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			/* add a new pair with the initial string segment */ | 			/* add a new pair with the initial string segment */ | ||||||
| 			pair = qse_xli_insertpairwithstr (xli, parlist, QSE_NULL, key.ptr, name, keytag, QSE_STR_XSTR(xli->tok.name), strtag); | 			pair = qse_xli_insertpairwithstr(xli, parlist, QSE_NULL, key.ptr, name, keytag, QSE_STR_XSTR(xli->tok.name), strtag); | ||||||
| 			if (pair == QSE_NULL) goto oops; | 			if (pair == QSE_NULL) goto oops; | ||||||
|  |  | ||||||
|  | 			if (MATCH(xli, QSE_XLI_TOK_NSTR)) | ||||||
|  | 			{ | ||||||
|  | 				((qse_xli_str_t*)pair->val)->flags |= QSE_XLI_STR_NSTR; | ||||||
|  | 			} | ||||||
|  |  | ||||||
| 			segcount++; | 			segcount++; | ||||||
| 			curstrseg = (qse_xli_str_t*)pair->val; | 			curstrseg = (qse_xli_str_t*)pair->val; | ||||||
|  |  | ||||||
| @ -931,17 +980,14 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
|  |  | ||||||
| 			/* semicolon read. turn off NSTR */ | 			/* semicolon read. turn off NSTR */ | ||||||
| 			xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR; | 			xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR; | ||||||
| 			if (get_token (xli) <= -1) goto oops; | 			if (get_token(xli) <= -1) goto oops; | ||||||
| 		} | 		} | ||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			qse_xli_seterror (xli, QSE_XLI_EPAVAL, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | 			qse_xli_seterror (xli, QSE_XLI_EVALUE, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | ||||||
| 			goto oops; | 			goto oops; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  |  | ||||||
| 		/* TODO: check against schema */ | 		/* TODO: check against schema */ | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
| 	else if (!(xli->opt.trait & QSE_XLI_NOLIST) && MATCH(xli, QSE_XLI_TOK_LBRACE)) | 	else if (!(xli->opt.trait & QSE_XLI_NOLIST) && MATCH(xli, QSE_XLI_TOK_LBRACE)) | ||||||
| 	{ | 	{ | ||||||
|  | |||||||
| @ -468,8 +468,10 @@ static qse_ssize_t sf_out_open (qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xt | |||||||
| 		if (arg->handle == QSE_NULL) | 		if (arg->handle == QSE_NULL) | ||||||
| 		{ | 		{ | ||||||
| 			qse_cstr_t ea; | 			qse_cstr_t ea; | ||||||
| 			ea.ptr = (qse_char_t*)arg->name; | 			/*ea.ptr = (qse_char_t*)arg->name; | ||||||
| 			ea.len = qse_strlen(ea.ptr); | 			ea.len = qse_strlen(ea.ptr);*/ | ||||||
|  | 			ea.ptr = (qse_char_t*)path; | ||||||
|  | 			ea.len = qse_strlen(path); | ||||||
| 			qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea); | 			qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea); | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
|  | |||||||
| @ -83,6 +83,14 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | |||||||
| 						if (write_to_current_stream (xli, QSE_T("\n"), 1) <= -1) return -1; | 						if (write_to_current_stream (xli, QSE_T("\n"), 1) <= -1) return -1; | ||||||
| 						break; | 						break; | ||||||
|  |  | ||||||
|  | 					case QSE_XLI_TRUE: | ||||||
|  | 						if (write_to_current_stream (xli, QSE_T("true\n"), 5) <= -1) return -1; | ||||||
|  | 						break; | ||||||
|  |  | ||||||
|  | 					case QSE_XLI_FALSE: | ||||||
|  | 						if (write_to_current_stream (xli, QSE_T("false\n"), 6) <= -1) return -1; | ||||||
|  | 						break; | ||||||
|  |  | ||||||
| 					case QSE_XLI_STR: | 					case QSE_XLI_STR: | ||||||
| 					{ | 					{ | ||||||
| 						qse_xli_str_t* str = (qse_xli_str_t*)pair->val; | 						qse_xli_str_t* str = (qse_xli_str_t*)pair->val; | ||||||
|  | |||||||
| @ -232,7 +232,15 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | |||||||
| 				switch (pair->val->type) | 				switch (pair->val->type) | ||||||
| 				{ | 				{ | ||||||
| 					case QSE_XLI_NIL: | 					case QSE_XLI_NIL: | ||||||
| 						if (write_to_current_stream(xli, QSE_T(";\n"), 2, 0) <= -1) return -1; | 						if (write_to_current_stream(xli, QSE_T("nil;\n"), 5, 0) <= -1) return -1; | ||||||
|  | 						break; | ||||||
|  |  | ||||||
|  | 					case QSE_XLI_TRUE: | ||||||
|  | 						if (write_to_current_stream(xli, QSE_T("true;\n"), 6, 0) <= -1) return -1; | ||||||
|  | 						break; | ||||||
|  |  | ||||||
|  | 					case QSE_XLI_FALSE: | ||||||
|  | 						if (write_to_current_stream(xli, QSE_T("false;\n"), 7, 0) <= -1) return -1; | ||||||
| 						break; | 						break; | ||||||
|  |  | ||||||
| 					case QSE_XLI_STR: | 					case QSE_XLI_STR: | ||||||
|  | |||||||
| @ -296,6 +296,14 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | |||||||
| 						if (write_to_current_stream (xli, QSE_T(";\n"), 2, 0) <= -1) return -1; | 						if (write_to_current_stream (xli, QSE_T(";\n"), 2, 0) <= -1) return -1; | ||||||
| 						break; | 						break; | ||||||
|  |  | ||||||
|  | 					case QSE_XLI_TRUE: | ||||||
|  | 						if (write_to_current_stream (xli, QSE_T(" = true;\n"), 9, 0) <= -1) return -1; | ||||||
|  | 						break; | ||||||
|  |  | ||||||
|  | 					case QSE_XLI_FALSE: | ||||||
|  | 						if (write_to_current_stream (xli, QSE_T(" = false;\n"), 10, 0) <= -1) return -1; | ||||||
|  | 						break; | ||||||
|  |  | ||||||
| 					case QSE_XLI_STR: | 					case QSE_XLI_STR: | ||||||
| 					{ | 					{ | ||||||
| 						qse_xli_str_t* str = (qse_xli_str_t*)pair->val; | 						qse_xli_str_t* str = (qse_xli_str_t*)pair->val; | ||||||
| @ -310,9 +318,11 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | |||||||
| 								    write_to_current_stream (xli, QSE_T("]"), 1, 0) <= -1) return -1; | 								    write_to_current_stream (xli, QSE_T("]"), 1, 0) <= -1) return -1; | ||||||
| 							} | 							} | ||||||
|  |  | ||||||
| 							if (write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1 || | 							if ((!(str->flags & QSE_XLI_STR_NSTR) &&  | ||||||
|  | 							     write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) || | ||||||
| 							    write_to_current_stream (xli, str->ptr, str->len, 1) <= -1 || | 							    write_to_current_stream (xli, str->ptr, str->len, 1) <= -1 || | ||||||
| 							    write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) return -1; | 							    (!(str->flags & QSE_XLI_STR_NSTR) &&  | ||||||
|  | 							     write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1)) return -1; | ||||||
| 							if (!str->next) break; | 							if (!str->next) break; | ||||||
|  |  | ||||||
| 							if (write_to_current_stream (xli, QSE_T(", "), 2, 0) <= -1) return -1; | 							if (write_to_current_stream (xli, QSE_T(", "), 2, 0) <= -1) return -1; | ||||||
| @ -364,7 +374,7 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | |||||||
| 				    write_to_current_stream (xli, path, qse_strlen(path), 1) <= -1 || | 				    write_to_current_stream (xli, path, qse_strlen(path), 1) <= -1 || | ||||||
| 				    write_to_current_stream (xli, QSE_T("\";\n"), 3, 0) <= -1) return -1; | 				    write_to_current_stream (xli, QSE_T("\";\n"), 3, 0) <= -1) return -1; | ||||||
|  |  | ||||||
| 				if (qse_xli_openwstream (xli, ((qse_xli_file_t*)curatom)->path, depth) <= -1) return -1; | 				if (qse_xli_openwstream(xli, ((qse_xli_file_t*)curatom)->path, depth) <= -1) return -1; | ||||||
| 				depth = 0; | 				depth = 0; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  | |||||||
| @ -320,7 +320,7 @@ void qse_xli_deletepair (qse_xli_t* xli, qse_xli_pair_t* pair) | |||||||
| 	} | 	} | ||||||
| 	else  | 	else  | ||||||
| 	{ | 	{ | ||||||
| 		QSE_ASSERT (list->head == pair); | 		QSE_ASSERT (list->head == (qse_xli_atom_t*)pair); | ||||||
| 		list->head = pair->next; | 		list->head = pair->next; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -330,7 +330,7 @@ void qse_xli_deletepair (qse_xli_t* xli, qse_xli_pair_t* pair) | |||||||
| 	} | 	} | ||||||
| 	else  | 	else  | ||||||
| 	{ | 	{ | ||||||
| 		QSE_ASSERT (list->tail == pair); | 		QSE_ASSERT (list->tail == (qse_xli_atom_t*)pair); | ||||||
| 		list->tail = pair->prev; | 		list->tail = pair->prev; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @ -352,6 +352,7 @@ qse_xli_str_t* qse_xli_makestrval (qse_xli_t* xli, const qse_cstr_t* value, cons | |||||||
| 	if (!val) return QSE_NULL; | 	if (!val) return QSE_NULL; | ||||||
|  |  | ||||||
| 	val->type = QSE_XLI_STR; | 	val->type = QSE_XLI_STR; | ||||||
|  | 	val->flags = 0; | ||||||
|  |  | ||||||
| 	qse_strncpy ((qse_char_t*)(val + 1), value->ptr, value->len); | 	qse_strncpy ((qse_char_t*)(val + 1), value->ptr, value->len); | ||||||
| 	val->ptr = (const qse_char_t*)(val + 1); | 	val->ptr = (const qse_char_t*)(val + 1); | ||||||
| @ -380,6 +381,81 @@ qse_xli_list_t* qse_xli_makelistval (qse_xli_t* xli) | |||||||
| 	return val; | 	return val; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static void free_val (qse_xli_root_list_t* root, qse_xli_val_t* val) | ||||||
|  | { | ||||||
|  | 	switch (val->type) | ||||||
|  | 	{ | ||||||
|  | 		case QSE_XLI_NIL: | ||||||
|  | 			QSE_ASSERT (val == (qse_xli_val_t*)&root->xnil); | ||||||
|  | 			return; | ||||||
|  | 		case QSE_XLI_TRUE: | ||||||
|  | 			QSE_ASSERT (val == (qse_xli_val_t*)&root->xtrue); | ||||||
|  | 			return; | ||||||
|  | 		case QSE_XLI_FALSE: | ||||||
|  | 			QSE_ASSERT (val == (qse_xli_val_t*)&root->xfalse); | ||||||
|  | 			return; | ||||||
|  |  | ||||||
|  | 		case QSE_XLI_LIST: | ||||||
|  | 			free_list (root, (qse_xli_list_t*)val); | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 		case QSE_XLI_STR: | ||||||
|  | 		{ | ||||||
|  | 			qse_xli_str_t* cur, * next;  | ||||||
|  |  | ||||||
|  | 			cur = ((qse_xli_str_t*)val)->next; | ||||||
|  | 			while (cur) | ||||||
|  | 			{ | ||||||
|  | 				next = cur->next; | ||||||
|  | 				QSE_MMGR_FREE (root->mmgr, cur); | ||||||
|  | 				cur = next; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	QSE_MMGR_FREE (root->mmgr, val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void free_atom (qse_xli_root_list_t* root, qse_xli_atom_t* atom) | ||||||
|  | { | ||||||
|  | 	/* Among all atom type, QSE_XLI_PAIR has a value to dispose of specially. | ||||||
|  | 	 * A tag and an alise are inlined to the atom itself. see insert_atom()  | ||||||
|  | 	 * above for details. | ||||||
|  | 	 * | ||||||
|  | 	 * for QSE_XLI_TEXT, QSE_XLI_FILE, QSE_XLI_EOF, data are inlined to  | ||||||
|  | 	 * the atom itself as well. | ||||||
|  | 	 */ | ||||||
|  |  | ||||||
|  | 	if (atom->type == QSE_XLI_PAIR) free_val (root, ((qse_xli_pair_t*)atom)->val); | ||||||
|  | 	QSE_MMGR_FREE (root->mmgr, atom); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void free_list (qse_xli_root_list_t* root, qse_xli_list_t* list) | ||||||
|  | { | ||||||
|  | 	qse_xli_atom_t* p, * n; | ||||||
|  |  | ||||||
|  | 	p = list->head; | ||||||
|  | 	while (p) | ||||||
|  | 	{ | ||||||
|  | 		n = p->next; | ||||||
|  | 		free_atom (root, p); | ||||||
|  | 		p = n; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	list->head = QSE_NULL; | ||||||
|  | 	list->tail = QSE_NULL; | ||||||
|  |  | ||||||
|  | 	/* this doesn't destroy the list itself.  | ||||||
|  | 	 * the caller must destory the list if necessary. */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void qse_xli_freeval (qse_xli_t* xli, qse_xli_val_t* val) | ||||||
|  | { | ||||||
|  | 	free_val (xli->root, val); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* ------------------------------------------------------ */ | /* ------------------------------------------------------ */ | ||||||
|  |  | ||||||
| qse_xli_pair_t* qse_xli_insertpairwithemptylist ( | qse_xli_pair_t* qse_xli_insertpairwithemptylist ( | ||||||
| @ -517,80 +593,13 @@ static qse_xli_root_list_t* make_root (qse_xli_t* xli) | |||||||
| 	QSE_MEMSET (tmp, 0, QSE_SIZEOF(*tmp) + xli->opt.root_xtnsize); | 	QSE_MEMSET (tmp, 0, QSE_SIZEOF(*tmp) + xli->opt.root_xtnsize); | ||||||
| 	tmp->list.type = QSE_XLI_LIST; | 	tmp->list.type = QSE_XLI_LIST; | ||||||
| 	tmp->xnil.type = QSE_XLI_NIL; | 	tmp->xnil.type = QSE_XLI_NIL; | ||||||
|  | 	tmp->xtrue.type = QSE_XLI_TRUE; | ||||||
|  | 	tmp->xfalse.type = QSE_XLI_FALSE; | ||||||
| 	tmp->mmgr = xli->mmgr; | 	tmp->mmgr = xli->mmgr; | ||||||
|  |  | ||||||
| 	return tmp; | 	return tmp; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| static void unsafe_free_val (qse_xli_root_list_t* root, qse_xli_val_t* val) |  | ||||||
| { |  | ||||||
| 	if (val->type == QSE_XLI_LIST) |  | ||||||
| 	{ |  | ||||||
| 		free_list (root, (qse_xli_list_t*)val); |  | ||||||
| 	} |  | ||||||
| 	else if (val->type == QSE_XLI_STR) |  | ||||||
| 	{ |  | ||||||
| 		qse_xli_str_t* cur, * next;  |  | ||||||
|  |  | ||||||
| 		cur = ((qse_xli_str_t*)val)->next; |  | ||||||
| 		while (cur) |  | ||||||
| 		{ |  | ||||||
| 			next = cur->next; |  | ||||||
| 			QSE_MMGR_FREE (root->mmgr, cur); |  | ||||||
| 			cur = next; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	QSE_MMGR_FREE (root->mmgr, val); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void qse_xli_freeval (qse_xli_t* xli, qse_xli_val_t* val) |  | ||||||
| { |  | ||||||
| 	unsafe_free_val (xli->root, val); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void free_val (qse_xli_root_list_t* root, qse_xli_val_t* val) |  | ||||||
| { |  | ||||||
| 	if ((qse_xli_nil_t*)val != &root->xnil) |  | ||||||
| 	{ |  | ||||||
| 		unsafe_free_val (root, val); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void free_atom (qse_xli_root_list_t* root, qse_xli_atom_t* atom) |  | ||||||
| { |  | ||||||
| 	/* Among all atom type, QSE_XLI_PAIR has a value to dispose of specially. |  | ||||||
| 	 * A tag and an alise are inlined to the atom itself. see insert_atom()  |  | ||||||
| 	 * above for details. |  | ||||||
| 	 * |  | ||||||
| 	 * for QSE_XLI_TEXT, QSE_XLI_FILE, QSE_XLI_EOF, data are inlined to  |  | ||||||
| 	 * the atom itself as well. |  | ||||||
| 	 */ |  | ||||||
|  |  | ||||||
| 	if (atom->type == QSE_XLI_PAIR) free_val (root, ((qse_xli_pair_t*)atom)->val); |  | ||||||
| 	QSE_MMGR_FREE (root->mmgr, atom); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| static void free_list (qse_xli_root_list_t* root, qse_xli_list_t* list) |  | ||||||
| { |  | ||||||
| 	qse_xli_atom_t* p, * n; |  | ||||||
|  |  | ||||||
| 	p = list->head; |  | ||||||
| 	while (p) |  | ||||||
| 	{ |  | ||||||
| 		n = p->next; |  | ||||||
| 		free_atom (root, p); |  | ||||||
| 		p = n; |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	list->head = QSE_NULL; |  | ||||||
| 	list->tail = QSE_NULL; |  | ||||||
|  |  | ||||||
| 	/* this doesn't destroy the list itself.  |  | ||||||
| 	 * the caller must destory the list if necessary. */ |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void qse_xli_clear (qse_xli_t* xli) | void qse_xli_clear (qse_xli_t* xli) | ||||||
| { | { | ||||||
| 	free_list (xli->root, &xli->root->list); | 	free_list (xli->root, &xli->root->list); | ||||||
| @ -726,7 +735,8 @@ const qse_char_t* get_next_fqpn_segment (qse_xli_t* xli, const qse_char_t* fqpn, | |||||||
| { | { | ||||||
| 	const qse_char_t* ptr; | 	const qse_char_t* ptr; | ||||||
|  |  | ||||||
| 	seg->key.ptr = ptr = fqpn; | 	ptr = fqpn; | ||||||
|  | 	seg->key.ptr = (qse_char_t*)ptr; | ||||||
| 	while (*ptr != QSE_T('\0') && *ptr != xli->opt.key_splitter && *ptr != QSE_T('[') && *ptr != QSE_T('{')) ptr++; | 	while (*ptr != QSE_T('\0') && *ptr != xli->opt.key_splitter && *ptr != QSE_T('[') && *ptr != QSE_T('{')) ptr++; | ||||||
| 	if (ptr == seg->key.ptr) goto inval; /* no key part */ | 	if (ptr == seg->key.ptr) goto inval; /* no key part */ | ||||||
| 	seg->key.len = ptr - seg->key.ptr; | 	seg->key.len = ptr - seg->key.ptr; | ||||||
|  | |||||||
| @ -36,6 +36,9 @@ enum qse_xli_tok_type_t | |||||||
| { | { | ||||||
| 	QSE_XLI_TOK_EOF, | 	QSE_XLI_TOK_EOF, | ||||||
| 	QSE_XLI_TOK_XINCLUDE, | 	QSE_XLI_TOK_XINCLUDE, | ||||||
|  | 	QSE_XLI_TOK_TRUE, | ||||||
|  | 	QSE_XLI_TOK_FALSE, | ||||||
|  | 	QSE_XLI_TOK_NIL, | ||||||
| 	QSE_XLI_TOK_COLON, | 	QSE_XLI_TOK_COLON, | ||||||
| 	QSE_XLI_TOK_SEMICOLON, | 	QSE_XLI_TOK_SEMICOLON, | ||||||
| 	QSE_XLI_TOK_LBRACE, | 	QSE_XLI_TOK_LBRACE, | ||||||
| @ -80,6 +83,8 @@ struct qse_xli_root_list_t | |||||||
| { | { | ||||||
| 	qse_xli_list_t list; | 	qse_xli_list_t list; | ||||||
| 	qse_xli_nil_t xnil; | 	qse_xli_nil_t xnil; | ||||||
|  | 	qse_xli_true_t xtrue; | ||||||
|  | 	qse_xli_false_t xfalse; | ||||||
| 	qse_mmgr_t* mmgr; | 	qse_mmgr_t* mmgr; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @ -157,7 +162,6 @@ void qse_xli_freelistlink (qse_xli_t* xli, qse_xli_list_link_t* link); | |||||||
|  |  | ||||||
| qse_xli_str_t* qse_xli_makestrval (qse_xli_t* xli, const qse_cstr_t* value, const qse_char_t* strtag); | qse_xli_str_t* qse_xli_makestrval (qse_xli_t* xli, const qse_cstr_t* value, const qse_char_t* strtag); | ||||||
| qse_xli_list_t* qse_xli_makelistval (qse_xli_t* xli); | qse_xli_list_t* qse_xli_makelistval (qse_xli_t* xli); | ||||||
| qse_xli_pair_t* qse_xli_makepairval (qse_xli_t* xli); |  | ||||||
| void qse_xli_freeval (qse_xli_t* xli, qse_xli_val_t* val); | void qse_xli_freeval (qse_xli_t* xli, qse_xli_val_t* val); | ||||||
|  |  | ||||||
| #if defined(__cplusplus) | #if defined(__cplusplus) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user