added QSE_XLI_ASSIGNWITHCOLON, QSE_XLI_TAGMARKER, QSE_XLI_ARRAYMARKE and added partial code for more extension work in progress
This commit is contained in:
		| @ -168,6 +168,7 @@ static void print_usage (qse_sio_t* out, int argc, qse_char_t* argv[]) | |||||||
| 	qse_fprintf (out, QSE_T(" -l                        disallow lists\n")); | 	qse_fprintf (out, QSE_T(" -l                        disallow lists\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -K                        allow key tags\n")); | 	qse_fprintf (out, QSE_T(" -K                        allow key tags\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -S                        allow string tags\n")); | 	qse_fprintf (out, QSE_T(" -S                        allow string tags\n")); | ||||||
|  | 	qse_fprintf (out, QSE_T(" -c                        use a colon for assignment\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -v                        perform validation\n")); | 	qse_fprintf (out, QSE_T(" -v                        perform validation\n")); | ||||||
| 	qse_fprintf (out, QSE_T(" -m                 number specify the maximum amount of memory to use in bytes\n")); | 	qse_fprintf (out, QSE_T(" -m                 number specify the maximum amount of memory to use in bytes\n")); | ||||||
| #if defined(QSE_BUILD_DEBUG) | #if defined(QSE_BUILD_DEBUG) | ||||||
| @ -195,9 +196,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:uaftsdnlKSvm:X:"), | 		QSE_T("hi:o:I:O:uaftsdnlKScvm:X:"), | ||||||
| #else | #else | ||||||
| 		QSE_T("hi:o:I:O:uaftsdnlKSvm:"), | 		QSE_T("hi:o:I:O:uaftsdnlKScvm:"), | ||||||
| #endif | #endif | ||||||
| 		lng | 		lng | ||||||
| 	}; | 	}; | ||||||
| @ -291,6 +292,10 @@ static int handle_args (int argc, qse_char_t* argv[]) | |||||||
| 				g_trait |= QSE_XLI_STRTAG; | 				g_trait |= QSE_XLI_STRTAG; | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
|  | 			case QSE_T('c'): | ||||||
|  | 				g_trait |= QSE_XLI_ASSIGNWITHCOLON; | ||||||
|  | 				break; | ||||||
|  |  | ||||||
| 			case QSE_T('v'): | 			case QSE_T('v'): | ||||||
| 				g_trait |= QSE_XLI_VALIDATE; | 				g_trait |= QSE_XLI_VALIDATE; | ||||||
| 				break; | 				break; | ||||||
|  | |||||||
| @ -115,7 +115,20 @@ enum qse_xli_opt_t | |||||||
| 	 */ | 	 */ | ||||||
| 	QSE_XLI_ROOTXTNSIZE, | 	QSE_XLI_ROOTXTNSIZE, | ||||||
|  |  | ||||||
| 	QSE_XLI_KEYSPLITTER | 	/** | ||||||
|  | 	 * It is a character to put between a parent key and a nested key. | ||||||
|  | 	 * By default, it's a period and used like 'a.b.c' that means c under b under a.  | ||||||
|  | 	 */ | ||||||
|  | 	QSE_XLI_KEYSPLITTER, | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * The first character is in the tag marker speicifies the tag opener | ||||||
|  | 	 * and the second chracter specifies the tag closer. The are used when | ||||||
|  | 	 * key tags and/or string tags are enabled. By default, it is "[]". | ||||||
|  | 	 */ | ||||||
|  | 	QSE_XLI_TAGMARKER, | ||||||
|  |  | ||||||
|  | 	QSE_XLI_ARRAYMARKER | ||||||
| }; | }; | ||||||
| typedef enum qse_xli_opt_t qse_xli_opt_t; | typedef enum qse_xli_opt_t qse_xli_opt_t; | ||||||
|  |  | ||||||
| @ -145,14 +158,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),  | ||||||
|  |  | ||||||
|  | 	/** use a colon as an assignment character intead of an equal sign. | ||||||
|  | 	  * it doesn't apply when reading or writing in the ini format. */ | ||||||
|  | 	QSE_XLI_ASSIGNWITHCOLON = (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_str_t  qse_xli_str_t; | typedef struct qse_xli_str_t  qse_xli_str_t; | ||||||
|  | typedef struct qse_xli_int_t  qse_xli_int_t; | ||||||
|  | typedef struct qse_xli_array_t qse_xli_array_t; | ||||||
| typedef struct qse_xli_list_t qse_xli_list_t; | typedef struct qse_xli_list_t qse_xli_list_t; | ||||||
|  |  | ||||||
| typedef struct qse_xli_atom_t qse_xli_atom_t; | typedef struct qse_xli_atom_t qse_xli_atom_t; | ||||||
| @ -207,6 +226,26 @@ struct qse_xli_str_t | |||||||
| 	qse_xli_str_t*     next; | 	qse_xli_str_t*     next; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | struct qse_xli_int_t | ||||||
|  | { | ||||||
|  | 	QSE_XLI_VAL_HDR; | ||||||
|  | 	const qse_char_t*  tag; | ||||||
|  | 	const qse_char_t*  ptr; | ||||||
|  | 	qse_size_t         len;  | ||||||
|  | 	/* TODO: include a numeric value here???  | ||||||
|  | 	qse_intmax_t       val; | ||||||
|  | 	*/ | ||||||
|  | 	/* NEED TO SUPPORT MULTI NUBMER? */ | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct qse_xli_array_t | ||||||
|  | { | ||||||
|  | 	QSE_XLI_VAL_HDR; | ||||||
|  | 	const qse_char_t* tag; | ||||||
|  | 	qse_xli_val_t* ptr; | ||||||
|  | 	qse_size_t count; | ||||||
|  | }; | ||||||
|  |  | ||||||
| #define QSE_XLI_ATOM_HDR \ | #define QSE_XLI_ATOM_HDR \ | ||||||
| 	qse_xli_atom_type_t type; \ | 	qse_xli_atom_type_t type; \ | ||||||
| 	qse_xli_atom_t* prev; \ | 	qse_xli_atom_t* prev; \ | ||||||
| @ -225,6 +264,8 @@ struct qse_xli_pair_t | |||||||
| 	const qse_char_t* key; | 	const qse_char_t* key; | ||||||
| 	const qse_char_t* alias;  | 	const qse_char_t* alias;  | ||||||
| 	const qse_char_t* tag; | 	const qse_char_t* tag; | ||||||
|  | 	unsigned int _key_quoted: 2; /* used internally for output */ | ||||||
|  | 	unsigned int _alias_quoted: 2; /* used internally for output - in fact, an alias is always quoted */ | ||||||
| 	qse_xli_val_t*    val; | 	qse_xli_val_t*    val; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ const qse_char_t* qse_xli_dflerrstr ( | |||||||
| 		QSE_T("syntax error"), | 		QSE_T("syntax error"), | ||||||
| 		QSE_T("semicolon expected in place of '${0}'"), | 		QSE_T("semicolon expected in place of '${0}'"), | ||||||
| 		QSE_T("equal-sign expected in place of '${0}'"), | 		QSE_T("equal-sign expected in place of '${0}'"), | ||||||
| 		QSE_T("left-brace or equal-sign expected in place of '${0}'"), | 		QSE_T("left-brace or assignment token 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("pair value expected in place of '${0}'"), | 		QSE_T("pair value expected in place of '${0}'"), | ||||||
| 		QSE_T("string not closed"), | 		QSE_T("string not closed"), | ||||||
|  | |||||||
| @ -27,6 +27,18 @@ | |||||||
| #include "xli.h" | #include "xli.h" | ||||||
| #include <qse/cmn/chr.h> | #include <qse/cmn/chr.h> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | 	"key1" { | ||||||
|  | 		# comment | ||||||
|  | 		[keytag]key11 "alias" = [strtag]"test machine; | ||||||
|  | 		key1122 { | ||||||
|  | 			key112233 = "hello"; | ||||||
|  | 		} | ||||||
|  | 	  } | ||||||
|  | 	} | ||||||
|  | */ | ||||||
|  |  | ||||||
| static int get_token (qse_xli_t* xli); | static int get_token (qse_xli_t* xli); | ||||||
| static int read_list (qse_xli_t* xli, qse_xli_list_t* list, const qse_xli_scm_t* override); | static int read_list (qse_xli_t* xli, qse_xli_list_t* list, const qse_xli_scm_t* override); | ||||||
|  |  | ||||||
| @ -300,6 +312,7 @@ static int get_symbols (qse_xli_t* xli, qse_cint_t c, qse_xli_tok_t* tok) | |||||||
| 	{ | 	{ | ||||||
| 		{ QSE_T("="),   1, QSE_XLI_TOK_EQ          }, | 		{ QSE_T("="),   1, QSE_XLI_TOK_EQ          }, | ||||||
| 		{ QSE_T(","),   1, QSE_XLI_TOK_COMMA       }, | 		{ QSE_T(","),   1, QSE_XLI_TOK_COMMA       }, | ||||||
|  | 		{ QSE_T(":"),   1, QSE_XLI_TOK_COLON       }, | ||||||
| 		{ QSE_T(";"),   1, QSE_XLI_TOK_SEMICOLON   }, | 		{ QSE_T(";"),   1, QSE_XLI_TOK_SEMICOLON   }, | ||||||
| 		{ QSE_T("{"),   1, QSE_XLI_TOK_LBRACE      }, | 		{ QSE_T("{"),   1, QSE_XLI_TOK_LBRACE      }, | ||||||
| 		{ QSE_T("}"),   1, QSE_XLI_TOK_RBRACE      }, | 		{ QSE_T("}"),   1, QSE_XLI_TOK_RBRACE      }, | ||||||
| @ -511,6 +524,8 @@ retry: | |||||||
| 	          (xli->opt.trait & QSE_XLI_LEADDIGIT) &&  | 	          (xli->opt.trait & QSE_XLI_LEADDIGIT) &&  | ||||||
| 	          QSE_ISDIGIT(c))) | 	          QSE_ISDIGIT(c))) | ||||||
| 	{ | 	{ | ||||||
|  | 		/* if you change the rules here, you need to update | ||||||
|  | 		 * need_quoting() in write.c */ | ||||||
| 		int lead_digit = QSE_ISDIGIT(c); | 		int lead_digit = QSE_ISDIGIT(c); | ||||||
| 		int all_digits = 1; | 		int all_digits = 1; | ||||||
|  |  | ||||||
| @ -522,8 +537,8 @@ retry: | |||||||
| 			GET_CHAR_TO (xli, c); | 			GET_CHAR_TO (xli, c); | ||||||
|  |  | ||||||
| 			if (c == QSE_T('_') || c == QSE_T('-') ||  | 			if (c == QSE_T('_') || c == QSE_T('-') ||  | ||||||
| 			    c == QSE_T(':') || c == QSE_T('*') || | 			    (!(xli->opt.trait & QSE_XLI_ASSIGNWITHCOLON) && c == QSE_T(':')) ||  | ||||||
| 			    c == QSE_T('/') || QSE_ISALPHA (c))  | 			    c == QSE_T('*') || c == QSE_T('/') || QSE_ISALPHA (c))  | ||||||
| 			{ | 			{ | ||||||
| 				all_digits = 0; | 				all_digits = 0; | ||||||
| 			} | 			} | ||||||
| @ -536,7 +551,7 @@ retry: | |||||||
|  |  | ||||||
| 		if (lead_digit && all_digits) | 		if (lead_digit && all_digits) | ||||||
| 		{ | 		{ | ||||||
| 			/* if an identifier begins with a digit, it must contain a non-digits character */ | 			/* if an identifier begins with a digit, it must contain a non-digit character */ | ||||||
| 			qse_xli_seterror (xli, QSE_XLI_EIDENT, QSE_STR_XSTR(tok->name), &tok->loc); | 			qse_xli_seterror (xli, QSE_XLI_EIDENT, QSE_STR_XSTR(tok->name), &tok->loc); | ||||||
| 			return -1; | 			return -1; | ||||||
| 		} | 		} | ||||||
| @ -621,13 +636,15 @@ retry: | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	else if ((xli->opt.trait & (QSE_XLI_KEYTAG | QSE_XLI_STRTAG)) && c == QSE_T('[')) | 	else if ((xli->opt.trait & (QSE_XLI_KEYTAG | QSE_XLI_STRTAG)) && c == xli->opt.tag_marker[0]) /* [ */ | ||||||
| 	{ | 	{ | ||||||
| 		/* a string tag is a bracketed word placed in front of a string value. | 		/* a string tag is a bracketed word placed in front of a string value. | ||||||
| 		 *   A = [tg] "abc";  | 		 *   A = [tg] "abc";  | ||||||
| 		 * "tg" is stored into the tag field of qse_xli_str_t.  | 		 * "tg" is stored into the tag field of qse_xli_str_t.  | ||||||
|  | 		 *  | ||||||
|  | 		 * however, the tag opener and the closer are not hard-coded. you may | ||||||
|  | 		 * use a different opener and closer depending on your requirement. | ||||||
| 		 */ | 		 */ | ||||||
|  |  | ||||||
| 		SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_TAG); | 		SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_TAG); | ||||||
|  |  | ||||||
| 		while (1) | 		while (1) | ||||||
| @ -641,7 +658,7 @@ retry: | |||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (c == QSE_T(']')) | 			if (c == xli->opt.tag_marker[1]) /* ] */ | ||||||
| 			{ | 			{ | ||||||
| 				/* terminating quote */ | 				/* terminating quote */ | ||||||
| 				GET_CHAR (xli); | 				GET_CHAR (xli); | ||||||
| @ -724,6 +741,7 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
|  |  | ||||||
| 	const qse_xli_scm_t* scm = QSE_NULL; | 	const qse_xli_scm_t* scm = QSE_NULL; | ||||||
| 	int key_nodup = 0, key_alias = 0, val_iffy = 0; | 	int key_nodup = 0, key_alias = 0, val_iffy = 0; | ||||||
|  | 	/*int key_quoted = 0, alias_quoted = 0;*/ | ||||||
|  |  | ||||||
| 	key.ptr = QSE_NULL; | 	key.ptr = QSE_NULL; | ||||||
| 	name = QSE_NULL; | 	name = QSE_NULL; | ||||||
| @ -735,9 +753,11 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 	if (xli->opt.trait & QSE_XLI_KEYNODUP) key_nodup = 1; | 	if (xli->opt.trait & QSE_XLI_KEYNODUP) key_nodup = 1; | ||||||
| 	if (xli->opt.trait & QSE_XLI_KEYALIAS) key_alias = 1; | 	if (xli->opt.trait & QSE_XLI_KEYALIAS) key_alias = 1; | ||||||
|  |  | ||||||
|  | 	/*if (MATCH(xli, QSE_XLI_TOK_SQSTR)) key_quoted = 1; | ||||||
|  | 	else if (MATCH(xli, QSE_XLI_TOK_DQSTR)) key_quoted = 2;*/ | ||||||
| 	kloc = xli->tok.loc; | 	kloc = xli->tok.loc; | ||||||
| 	key.len = QSE_STR_LEN(xli->tok.name); | 	key.len = QSE_STR_LEN(xli->tok.name); | ||||||
| 	key.ptr = qse_strdup (QSE_STR_PTR(xli->tok.name), xli->mmgr); | 	key.ptr = qse_strdup(QSE_STR_PTR(xli->tok.name), xli->mmgr); | ||||||
| 	if (key.ptr == QSE_NULL)  | 	if (key.ptr == QSE_NULL)  | ||||||
| 	{ | 	{ | ||||||
| 		qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);  | 		qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);  | ||||||
| @ -745,8 +765,8 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	dotted_curkey_len = QSE_STR_LEN (xli->dotted_curkey); | 	dotted_curkey_len = QSE_STR_LEN (xli->dotted_curkey); | ||||||
| 	if ((dotted_curkey_len > 0 && qse_str_cat (xli->dotted_curkey, QSE_T(".")) == (qse_size_t)-1) || | 	if ((dotted_curkey_len > 0 && qse_str_cat(xli->dotted_curkey, QSE_T(".")) == (qse_size_t)-1) || | ||||||
| 	    qse_str_cat (xli->dotted_curkey, key.ptr) == (qse_size_t)-1) | 	    qse_str_cat(xli->dotted_curkey, key.ptr) == (qse_size_t)-1) | ||||||
| 	{ | 	{ | ||||||
| 		qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);  | 		qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);  | ||||||
| 		goto oops; | 		goto oops; | ||||||
| @ -784,7 +804,7 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 		while (atom) | 		while (atom) | ||||||
| 		{ | 		{ | ||||||
| 			if (atom->type == QSE_XLI_PAIR && | 			if (atom->type == QSE_XLI_PAIR && | ||||||
| 			    qse_strcmp (((qse_xli_pair_t*)atom)->key, QSE_STR_PTR(xli->tok.name)) == 0) | 			    qse_strcmp(((qse_xli_pair_t*)atom)->key, QSE_STR_PTR(xli->tok.name)) == 0) | ||||||
| 			{ | 			{ | ||||||
| 				qse_xli_seterror (xli, QSE_XLI_EEXIST, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | 				qse_xli_seterror (xli, QSE_XLI_EEXIST, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | ||||||
| 				goto oops; | 				goto oops; | ||||||
| @ -794,15 +814,15 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/* once the key name is read, enable the numeric string for a value */ | 	/* once the key name is read, enable the numeric string for a key alias and a value */ | ||||||
| 	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; | ||||||
|  |  | ||||||
| 	if (key_alias) | 	if (key_alias) | ||||||
| 	{ | 	{ | ||||||
| 		/* the alias part must be unique for the same key(s) */ | 		/* the alias part must be unique for the same key(s) */ | ||||||
| 		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)) | 		if (MATCH(xli, QSE_XLI_TOK_IDENT) || MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_NSTR)) | ||||||
| 		{ | 		{ | ||||||
| 			qse_xli_atom_t* atom; | 			qse_xli_atom_t* atom; | ||||||
|  |  | ||||||
| @ -827,6 +847,9 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 				goto oops; | 				goto oops; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | 			/*if (MATCH(xli, QSE_XLI_TOK_SQSTR)) alias_quoted = 1; | ||||||
|  | 			else if (MATCH(xli, QSE_XLI_TOK_DQSTR)) alias_quoted = 2;*/ | ||||||
|  |  | ||||||
| 			if (get_token (xli) <= -1) goto oops; | 			if (get_token (xli) <= -1) goto oops; | ||||||
| 		} | 		} | ||||||
| 		else if (key_alias == 2) | 		else if (key_alias == 2) | ||||||
| @ -838,10 +861,12 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (MATCH (xli, QSE_XLI_TOK_EQ)) | 	if (MATCH(xli, xli->opt._assign_tok)) /* either QSE_XLI_TOK_EQ or QSE_XLI_TOK_COLON */ | ||||||
| 	{ | 	{ | ||||||
| 		if (get_token (xli) <= -1) goto oops; | 		if (get_token (xli) <= -1) goto oops; | ||||||
|  |  | ||||||
|  | 		if (!(xli->opt.trait & QSE_XLI_NOLIST) && MATCH(xli, QSE_XLI_TOK_LBRACE)) goto handle_list; | ||||||
|  |  | ||||||
| 		if ((xli->opt.trait & QSE_XLI_STRTAG) && MATCH (xli, QSE_XLI_TOK_TAG)) | 		if ((xli->opt.trait & QSE_XLI_STRTAG) && MATCH (xli, QSE_XLI_TOK_TAG)) | ||||||
| 		{ | 		{ | ||||||
| 			strtag = qse_strxdup (QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr); | 			strtag = qse_strxdup (QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr); | ||||||
| @ -854,7 +879,7 @@ 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_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; | ||||||
| @ -870,6 +895,11 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 			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 0 | ||||||
|  | 			pair->_key_quoted = key_quoted; /* store this for easier output support */ | ||||||
|  | 			pair->_alias_quoted = alias_quoted; | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 			segcount++; | 			segcount++; | ||||||
| 			curstrseg = (qse_xli_str_t*)pair->val; | 			curstrseg = (qse_xli_str_t*)pair->val; | ||||||
|  |  | ||||||
| @ -939,12 +969,12 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | |||||||
| 			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)) | ||||||
| 	{ | 	{ | ||||||
|  | 	handle_list: | ||||||
| 		if (scm && !(scm->flags & QSE_XLI_SCM_VALLIST)) | 		if (scm && !(scm->flags & QSE_XLI_SCM_VALLIST)) | ||||||
| 		{ | 		{ | ||||||
| 			/* check the value type */ | 			/* check the value type */ | ||||||
| @ -1050,8 +1080,10 @@ void qse_xli_freelistlink (qse_xli_t* xli, qse_xli_list_link_t* link) | |||||||
| 	qse_xli_freemem (xli, link); | 	qse_xli_freemem (xli, link); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override) | static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override, int opt_outer_brace) | ||||||
| { | { | ||||||
|  | 	qse_size_t pair_count = 0;  | ||||||
|  |  | ||||||
| 	while (1) | 	while (1) | ||||||
| 	{ | 	{ | ||||||
| 		if (MATCH (xli, QSE_XLI_TOK_XINCLUDE)) | 		if (MATCH (xli, QSE_XLI_TOK_XINCLUDE)) | ||||||
| @ -1066,12 +1098,17 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override) | |||||||
|  |  | ||||||
| 			if (begin_include (xli) <= -1) return -1; | 			if (begin_include (xli) <= -1) return -1; | ||||||
| 		} | 		} | ||||||
| 		else if ((xli->opt.trait & QSE_XLI_KEYTAG) && MATCH (xli, QSE_XLI_TOK_TAG)) | 		else if (opt_outer_brace == 1 && pair_count == 0 && MATCH(xli, QSE_XLI_TOK_LBRACE)) | ||||||
|  | 		{ | ||||||
|  | 			opt_outer_brace++; | ||||||
|  | 			if (get_token(xli) <= -1) return -1; | ||||||
|  | 		} | ||||||
|  | 		else if ((xli->opt.trait & QSE_XLI_KEYTAG) && MATCH(xli, QSE_XLI_TOK_TAG)) | ||||||
| 		{ | 		{ | ||||||
| 			qse_char_t* keytag; | 			qse_char_t* keytag; | ||||||
| 			int x; | 			int x; | ||||||
|  |  | ||||||
| 			keytag = qse_strxdup (QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr); | 			keytag = qse_strxdup(QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr); | ||||||
| 			if (keytag == QSE_NULL) | 			if (keytag == QSE_NULL) | ||||||
| 			{ | 			{ | ||||||
| 				qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);  | 				qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);  | ||||||
| @ -1084,22 +1121,24 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override) | |||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (!MATCH(xli,QSE_XLI_TOK_IDENT)) | 			if (!MATCH(xli,QSE_XLI_TOK_IDENT) && !MATCH(xli,QSE_XLI_TOK_SQSTR) && !MATCH(xli,QSE_XLI_TOK_DQSTR)) | ||||||
| 			{ | 			{ | ||||||
| 				QSE_MMGR_FREE (xli->mmgr, keytag); | 				QSE_MMGR_FREE (xli->mmgr, keytag); | ||||||
| 				qse_xli_seterror (xli, QSE_XLI_ENOKEY, QSE_NULL, &xli->tok.loc); | 				qse_xli_seterror (xli, QSE_XLI_ENOKEY, QSE_NULL, &xli->tok.loc); | ||||||
| 				return -1; | 				return -1; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			x = read_pair (xli, keytag, override); | 			x = read_pair(xli, keytag, override); | ||||||
| 			QSE_MMGR_FREE (xli->mmgr, keytag); | 			QSE_MMGR_FREE (xli->mmgr, keytag); | ||||||
| 			if (x <= -1) return -1; | 			if (x <= -1) return -1; | ||||||
|  | 			pair_count++; | ||||||
| 		} | 		} | ||||||
| 		else if (MATCH (xli, QSE_XLI_TOK_IDENT)) | 		else if (MATCH(xli, QSE_XLI_TOK_IDENT) || MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_DQSTR)) | ||||||
| 		{ | 		{ | ||||||
| 			if (read_pair (xli, QSE_NULL, override) <= -1) return -1; | 			if (read_pair(xli, QSE_NULL, override) <= -1) return -1; | ||||||
|  | 			pair_count++; | ||||||
| 		} | 		} | ||||||
| 		else if (MATCH (xli, QSE_XLI_TOK_TEXT)) | 		else if (MATCH(xli, QSE_XLI_TOK_TEXT)) | ||||||
| 		{ | 		{ | ||||||
| 			if (get_token(xli) <= -1) return -1; | 			if (get_token(xli) <= -1) return -1; | ||||||
| 		} | 		} | ||||||
| @ -1109,6 +1148,16 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override) | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if (opt_outer_brace >= 2) | ||||||
|  | 	{ | ||||||
|  | 		if (!MATCH(xli, QSE_XLI_TOK_RBRACE)) | ||||||
|  | 		{ | ||||||
|  | 			qse_xli_seterror (xli, QSE_XLI_ERBRCE, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 		if (get_token(xli) <= -1) return -1; | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -1116,20 +1165,20 @@ static int read_list (qse_xli_t* xli, qse_xli_list_t* parlist, const qse_xli_scm | |||||||
| { | { | ||||||
| 	qse_xli_list_link_t* link; | 	qse_xli_list_link_t* link; | ||||||
|  |  | ||||||
| 	link = qse_xli_makelistlink (xli, parlist); | 	link = qse_xli_makelistlink(xli, parlist); | ||||||
| 	if (link == QSE_NULL) return -1; | 	if (link == QSE_NULL) return -1; | ||||||
|  |  | ||||||
| 	/* get_token() here is to read the token after the left brace. | 	/* get_token() here is to read the token after the left brace. | ||||||
| 	 * it must be called after the xli->parlink has been updated | 	 * it must be called after the xli->parlink has been updated | ||||||
| 	 * in case there are comments at the beginning of the list */ | 	 * in case there are comments at the beginning of the list */ | ||||||
| 	if (get_token (xli) <= -1 || __read_list (xli, override) <= -1)  | 	if (get_token(xli) <= -1 || __read_list(xli, override, 0) <= -1)  | ||||||
| 	{ | 	{ | ||||||
| 		qse_xli_freelistlink (xli, link); | 		qse_xli_freelistlink (xli, link); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	QSE_ASSERT (link == xli->parlink); | 	QSE_ASSERT (link == xli->parlink); | ||||||
| 	qse_xli_freelistlink (xli, link); | 	qse_xli_freelistlink(xli, link); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| @ -1138,17 +1187,18 @@ static int read_root_list (qse_xli_t* xli) | |||||||
| { | { | ||||||
| 	qse_xli_list_link_t* link; | 	qse_xli_list_link_t* link; | ||||||
|  |  | ||||||
| 	link = qse_xli_makelistlink (xli, &xli->root->list); | 	link = qse_xli_makelistlink(xli, &xli->root->list); | ||||||
| 	if (!link) return -1; | 	if (!link) return -1; | ||||||
|  |  | ||||||
| 	if (qse_xli_getchar (xli) <= -1 || get_token (xli) <= -1 || __read_list (xli, QSE_NULL) <= -1) | /* TODO: pass opt_outer_brace 1 to __read_list only if a certian option is enabled */ | ||||||
|  | 	if (qse_xli_getchar(xli) <= -1 || get_token(xli) <= -1 || __read_list(xli, QSE_NULL, 1) <= -1) | ||||||
| 	{ | 	{ | ||||||
| 		qse_xli_freelistlink (xli, link); | 		qse_xli_freelistlink (xli, link); | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	QSE_ASSERT (link == xli->parlink); | 	QSE_ASSERT (link == xli->parlink); | ||||||
| 	qse_xli_freelistlink (xli, link); | 	qse_xli_freelistlink(xli, link); | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ | |||||||
|  */ |  */ | ||||||
|  |  | ||||||
| #include "xli.h" | #include "xli.h" | ||||||
|  | #include <qse/cmn/chr.h> | ||||||
|  |  | ||||||
| typedef struct arg_data_t arg_data_t; | typedef struct arg_data_t arg_data_t; | ||||||
| struct arg_data_t | struct arg_data_t | ||||||
| @ -138,7 +139,7 @@ int qse_xli_closeactivewstream (qse_xli_t* xli, int* org_depth) | |||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| static int write_to_current_stream (qse_xli_t* xli, const qse_char_t* ptr, qse_size_t len, int escape) | static int write_to_current_stream(qse_xli_t* xli, const qse_char_t* ptr, qse_size_t len, int escape) | ||||||
| { | { | ||||||
| 	qse_xli_io_arg_t* arg; | 	qse_xli_io_arg_t* arg; | ||||||
| 	qse_size_t i; | 	qse_size_t i; | ||||||
| @ -174,22 +175,100 @@ static int write_indentation (qse_xli_t* xli, int depth) | |||||||
|  |  | ||||||
| 	if (depth <= QSE_COUNTOF(tabs)) | 	if (depth <= QSE_COUNTOF(tabs)) | ||||||
| 	{ | 	{ | ||||||
| 		if (write_to_current_stream (xli, tabs, depth, 0) <= -1) return -1; | 		if (write_to_current_stream(xli, tabs, depth, 0) <= -1) return -1; | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		int i; | 		int i; | ||||||
| 		if (write_to_current_stream (xli, tabs, QSE_COUNTOF(tabs), 0) <= -1) return -1; | 		if (write_to_current_stream(xli, tabs, QSE_COUNTOF(tabs), 0) <= -1) return -1; | ||||||
| 		for (i = QSE_COUNTOF(tabs); i < depth; i++)  | 		for (i = QSE_COUNTOF(tabs); i < depth; i++)  | ||||||
| 		{ | 		{ | ||||||
| 			if (write_to_current_stream (xli, QSE_T("\t"), 1, 0) <= -1) return -1; | 			if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static int key_needs_quoting (qse_xli_t* xli, const qse_char_t* str, int nstr) | ||||||
|  | { | ||||||
|  | 	/* this determines if a key or an alias requires quoting for output. | ||||||
|  | 	 * NSTR is not taken into account because it's only allowed as a value */ | ||||||
|  |  | ||||||
|  | 	/* refer to the tokenization rule in get_token_into() in read.c */ | ||||||
|  | 	qse_char_t c; | ||||||
|  |  | ||||||
|  | 	c = *str++; | ||||||
|  | 	if (c == QSE_T('\0')) return 1; /* an empty string requires a quoting */ | ||||||
|  |  | ||||||
|  | 	if (c == QSE_T('_') || QSE_ISALPHA(c) || (!nstr && (xli->opt.trait & QSE_XLI_LEADDIGIT) && QSE_ISDIGIT(c))) | ||||||
|  | 	{ | ||||||
|  | 		int lead_digit = QSE_ISDIGIT(c); | ||||||
|  | 		int all_digits = 1; | ||||||
|  |  | ||||||
|  | 		/* a normal identifier can be composed of wider varieties of  | ||||||
|  | 		 * characters than a keyword/directive */ | ||||||
|  | 		while (1) | ||||||
|  | 		{ | ||||||
|  | 			c = *str++; | ||||||
|  | 			if (c == QSE_T('\0')) break; | ||||||
|  |  | ||||||
|  | 			if (c == QSE_T('_') || c == QSE_T('-') ||  | ||||||
|  | 			    (!(xli->opt.trait & QSE_XLI_ASSIGNWITHCOLON) && c == QSE_T(':')) || | ||||||
|  | 			    c == QSE_T('*') || c == QSE_T('/') || QSE_ISALPHA(c))  | ||||||
|  | 			{ | ||||||
|  | 				all_digits = 0; | ||||||
|  | 			} | ||||||
|  | 			else if (QSE_ISDIGIT(c))  | ||||||
|  | 			{ | ||||||
|  | 				/* nothing to do */ | ||||||
|  | 			} | ||||||
|  | 			else  | ||||||
|  | 			{ | ||||||
|  | 				/* a disallowed character for an identifier */ | ||||||
|  | 				return 1; /* quote it */ | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		if (lead_digit && all_digits) | ||||||
|  | 		{ | ||||||
|  | 			/* if an identifier begins with a digit, it must contain a non-digit character */ | ||||||
|  | 			/* in fact, it is not a valid identifer. so quote it */ | ||||||
|  | 			return 1; | ||||||
|  | 		} | ||||||
|  | 		else | ||||||
|  | 		{ | ||||||
|  | 			/* this must be a normal identifer */ | ||||||
|  | 			return 0; /* no quoting needed */ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	else if (nstr && QSE_ISDIGIT(c)) | ||||||
|  | 	{ | ||||||
|  | 		do  | ||||||
|  | 		{ | ||||||
|  | 			c = *str++; | ||||||
|  | 			if (c == QSE_T('\0')) return 0; /* it's a numeric string */ | ||||||
|  | 		} | ||||||
|  | 		while (QSE_ISDIGIT(c)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* quote all the rest */ | ||||||
|  | 	return 1; | ||||||
|  | } | ||||||
|  |  | ||||||
| static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | ||||||
| { | { | ||||||
|  | 	static struct | ||||||
|  | 	{ | ||||||
|  | 		qse_char_t* qptr; | ||||||
|  | 		qse_size_t  qlen; | ||||||
|  | 	} quotes[] = | ||||||
|  | 	{ | ||||||
|  | 		{ QSE_T(""),   0 }, | ||||||
|  | 		{ QSE_T("\'"), 1 }, | ||||||
|  | 		{ QSE_T("\""), 1 } | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	qse_xli_atom_t* curatom; | 	qse_xli_atom_t* curatom; | ||||||
|  |  | ||||||
| 	for (curatom = list->head; curatom; curatom = curatom->next) | 	for (curatom = list->head; curatom; curatom = curatom->next) | ||||||
| @ -198,64 +277,84 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | |||||||
| 		{ | 		{ | ||||||
| 			case QSE_XLI_PAIR: | 			case QSE_XLI_PAIR: | ||||||
| 			{ | 			{ | ||||||
|  | 				int qtype; | ||||||
| 				qse_xli_pair_t* pair = (qse_xli_pair_t*)curatom; | 				qse_xli_pair_t* pair = (qse_xli_pair_t*)curatom; | ||||||
|  |  | ||||||
| 				if (write_indentation (xli, depth) <= -1) return -1; | 				if (write_indentation(xli, depth) <= -1) return -1; | ||||||
|  |  | ||||||
| 				if (pair->tag) | 				if (pair->tag) | ||||||
| 				{ | 				{ | ||||||
| 					if (write_to_current_stream (xli, QSE_T("["), 1, 0) <= -1 || | 					if (write_to_current_stream(xli, &xli->opt.tag_marker[0], 1, 0) <= -1 || | ||||||
| 					    write_to_current_stream (xli, pair->tag, qse_strlen(pair->tag), 0) <= -1 ||  | 					    write_to_current_stream(xli, pair->tag, qse_strlen(pair->tag), 0) <= -1 ||  | ||||||
| 					    write_to_current_stream (xli, QSE_T("]"), 1, 0) <= -1) return -1; | 					    write_to_current_stream(xli, &xli->opt.tag_marker[1], 1, 0) <= -1) return -1; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				if (write_to_current_stream (xli, pair->key, qse_strlen(pair->key), 0) <= -1) return -1; | 				QSE_ASSERT(pair->_key_quoted >= 0 && pair->_key_quoted < QSE_COUNTOF(quotes)); | ||||||
|  | 				qtype = pair->_key_quoted; | ||||||
|  | 				if (qtype <= 0 && key_needs_quoting(xli, pair->key, 0)) qtype = 2; /* force double quoting */ | ||||||
|  |  | ||||||
|  | 				if (write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1 || | ||||||
|  | 				    write_to_current_stream(xli, pair->key, qse_strlen(pair->key), (qtype >= 2)) <= -1 || | ||||||
|  | 				    write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1) return -1; | ||||||
|  |  | ||||||
| 				if (pair->alias)  | 				if (pair->alias)  | ||||||
| 				{ | 				{ | ||||||
| 					if (write_to_current_stream (xli, QSE_T(" \""), 2, 0) <= -1 || | 					QSE_ASSERT(pair->_alias_quoted >= 0 && pair->_alias_quoted < QSE_COUNTOF(quotes)); | ||||||
| 					    write_to_current_stream (xli, pair->alias, qse_strlen(pair->alias), 1) <= -1 || | 					qtype = pair->_alias_quoted; | ||||||
| 					    write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) return -1; | 					if (qtype <= 0 && key_needs_quoting(xli, pair->alias, 1)) qtype = 2; | ||||||
|  |  | ||||||
|  | 					if (write_to_current_stream(xli, QSE_T(" "), 1, 0) <= -1 || | ||||||
|  | 					    write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1 || | ||||||
|  | 					    write_to_current_stream(xli, pair->alias, qse_strlen(pair->alias), (qtype >= 2)) <= -1 || | ||||||
|  | 					    write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1) return -1; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				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(";\n"), 2, 0) <= -1) return -1; | ||||||
| 						break; | 						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; | ||||||
|  |  | ||||||
| 						if (write_to_current_stream (xli, QSE_T(" = "), 3, 0) <= -1) return -1; | 						if (xli->opt.trait & QSE_XLI_ASSIGNWITHCOLON) | ||||||
|  | 						{ | ||||||
|  | 							if (write_to_current_stream(xli, QSE_T(": "), 2, 0) <= -1) return -1; | ||||||
|  | 						} | ||||||
|  | 						else | ||||||
|  | 						{ | ||||||
|  | 							if (write_to_current_stream(xli, QSE_T(" = "), 3, 0) <= -1) return -1; | ||||||
|  | 						} | ||||||
|  |  | ||||||
| 						while (1) | 						while (1) | ||||||
| 						{ | 						{ | ||||||
| 							if (str->tag) | 							if (str->tag) | ||||||
| 							{ | 							{ | ||||||
| 								if (write_to_current_stream (xli, QSE_T("["), 1, 0) <= -1 || | 								if (write_to_current_stream(xli, QSE_T("["), 1, 0) <= -1 || | ||||||
| 								    write_to_current_stream (xli, str->tag, qse_strlen(str->tag), 0) <= -1 ||  | 								    write_to_current_stream(xli, str->tag, qse_strlen(str->tag), 0) <= -1 ||  | ||||||
| 								    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 (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; | 							    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; | ||||||
| 							str = str->next; | 							str = str->next; | ||||||
| 						} | 						} | ||||||
| 						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_LIST: | 					case QSE_XLI_LIST: | ||||||
| 					{ | 					{ | ||||||
| 						if (write_to_current_stream (xli, QSE_T(" {\n"), 3, 0) <= -1 || | 						if (write_to_current_stream(xli, QSE_T(" {\n"), 3, 0) <= -1 || | ||||||
| 						    write_list (xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1 || | 						    write_list (xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1 || | ||||||
| 						    write_indentation (xli, depth) <= -1 || | 						    write_indentation (xli, depth) <= -1 || | ||||||
| 						    write_to_current_stream (xli, QSE_T("}\n"), 2, 0) <= -1) return -1; | 						    write_to_current_stream(xli, QSE_T("}\n"), 2, 0) <= -1) return -1; | ||||||
| 						break; | 						break; | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| @ -269,12 +368,12 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | |||||||
|  |  | ||||||
| 				for (i = 0; i < depth; i++)  | 				for (i = 0; i < depth; i++)  | ||||||
| 				{ | 				{ | ||||||
| 					if (write_to_current_stream (xli, QSE_T("\t"), 1, 0) <= -1) return -1; | 					if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				if (write_to_current_stream (xli, QSE_T("#"), 1, 0) <= -1 || | 				if (write_to_current_stream(xli, QSE_T("#"), 1, 0) <= -1 || | ||||||
| 				    write_to_current_stream (xli, str, qse_strlen(str), 0) <= -1 || | 				    write_to_current_stream(xli, str, qse_strlen(str), 0) <= -1 || | ||||||
| 				    write_to_current_stream (xli, QSE_T("\n"), 1, 0) <= -1) return -1; | 				    write_to_current_stream(xli, QSE_T("\n"), 1, 0) <= -1) return -1; | ||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| @ -285,12 +384,12 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | |||||||
|  |  | ||||||
| 				for (i = 0; i < depth; i++)  | 				for (i = 0; i < depth; i++)  | ||||||
| 				{ | 				{ | ||||||
| 					if (write_to_current_stream (xli, QSE_T("\t"), 1, 0) <= -1) return -1; | 					if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				if (write_to_current_stream (xli, QSE_T("@include \""), 10, 0) <= -1 || | 				if (write_to_current_stream(xli, QSE_T("@include \""), 10, 0) <= -1 || | ||||||
| 				    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; | ||||||
|  | |||||||
| @ -70,6 +70,11 @@ int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr, qse_size_t rootxtnsize) | |||||||
| 	xli->errstr = qse_xli_dflerrstr; | 	xli->errstr = qse_xli_dflerrstr; | ||||||
| 	xli->opt.root_xtnsize = rootxtnsize; | 	xli->opt.root_xtnsize = rootxtnsize; | ||||||
| 	xli->opt.key_splitter = QSE_T('.'); | 	xli->opt.key_splitter = QSE_T('.'); | ||||||
|  | 	xli->opt.tag_marker[0] = QSE_T('['); | ||||||
|  | 	xli->opt.tag_marker[1] = QSE_T(']'); | ||||||
|  | 	xli->opt.array_marker[0] = QSE_T('('); | ||||||
|  | 	xli->opt.array_marker[1] = QSE_T(')'); | ||||||
|  | 	xli->opt._assign_tok = QSE_XLI_TOK_EQ; | ||||||
|  |  | ||||||
| 	xli->dotted_curkey = qse_str_open (mmgr, 0, 128); | 	xli->dotted_curkey = qse_str_open (mmgr, 0, 128); | ||||||
| 	if (xli->dotted_curkey == QSE_NULL) goto oops; | 	if (xli->dotted_curkey == QSE_NULL) goto oops; | ||||||
| @ -121,6 +126,7 @@ int qse_xli_setopt (qse_xli_t* xli, qse_xli_opt_t id, const void* value) | |||||||
| 	{ | 	{ | ||||||
| 		case QSE_XLI_TRAIT: | 		case QSE_XLI_TRAIT: | ||||||
| 			xli->opt.trait = *(const int*)value; | 			xli->opt.trait = *(const int*)value; | ||||||
|  | 			xli->opt._assign_tok = (xli->opt.trait & QSE_XLI_ASSIGNWITHCOLON)? QSE_XLI_TOK_COLON: QSE_XLI_TOK_EQ; | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
| 		case QSE_XLI_PAIRXTNSIZE: | 		case QSE_XLI_PAIRXTNSIZE: | ||||||
| @ -134,6 +140,16 @@ int qse_xli_setopt (qse_xli_t* xli, qse_xli_opt_t id, const void* value) | |||||||
| 		case QSE_XLI_KEYSPLITTER: | 		case QSE_XLI_KEYSPLITTER: | ||||||
| 			xli->opt.key_splitter = *(const qse_char_t*)value; | 			xli->opt.key_splitter = *(const qse_char_t*)value; | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_XLI_TAGMARKER: | ||||||
|  | 			xli->opt.tag_marker[0] = ((const qse_char_t*)value)[0]; | ||||||
|  | 			xli->opt.tag_marker[1] = ((const qse_char_t*)value)[1]; | ||||||
|  | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_XLI_ARRAYMARKER: | ||||||
|  | 			xli->opt.array_marker[0] = ((const qse_char_t*)value)[0]; | ||||||
|  | 			xli->opt.array_marker[1] = ((const qse_char_t*)value)[1]; | ||||||
|  | 			return 0; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); | 	qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); | ||||||
| @ -159,6 +175,14 @@ int qse_xli_getopt (qse_xli_t* xli, qse_xli_opt_t  id, void* value) | |||||||
| 		case QSE_XLI_KEYSPLITTER: | 		case QSE_XLI_KEYSPLITTER: | ||||||
| 			*(qse_char_t*)value = xli->opt.key_splitter; | 			*(qse_char_t*)value = xli->opt.key_splitter; | ||||||
| 			return 0; | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_XLI_TAGMARKER: | ||||||
|  | 			((qse_char_t*)value)[0] = xli->opt.tag_marker[1]; | ||||||
|  | 			return 0; | ||||||
|  |  | ||||||
|  | 		case QSE_XLI_ARRAYMARKER: | ||||||
|  | 			((qse_char_t*)value)[0] = xli->opt.array_marker[1]; | ||||||
|  | 			return 0; | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); | 	qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL); | ||||||
| @ -1024,7 +1048,7 @@ int qse_xli_undefinepair (qse_xli_t* xli, const qse_char_t* fqpn) | |||||||
| 	if (qse_rbt_delete (xli->schema, fqpn, qse_strlen(fqpn)) <= -1) | 	if (qse_rbt_delete (xli->schema, fqpn, qse_strlen(fqpn)) <= -1) | ||||||
| 	{ | 	{ | ||||||
| 		qse_cstr_t ea; | 		qse_cstr_t ea; | ||||||
| 		ea.ptr = fqpn; | 		ea.ptr = (qse_char_t*)fqpn; | ||||||
| 		ea.len = qse_strlen (ea.ptr); | 		ea.len = qse_strlen (ea.ptr); | ||||||
| 		qse_xli_seterrnum (xli, QSE_XLI_ENOENT, &ea); | 		qse_xli_seterrnum (xli, QSE_XLI_ENOENT, &ea); | ||||||
| 		return -1; | 		return -1; | ||||||
|  | |||||||
| @ -37,6 +37,7 @@ 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_SEMICOLON, | 	QSE_XLI_TOK_SEMICOLON, | ||||||
|  | 	QSE_XLI_TOK_COLON, | ||||||
| 	QSE_XLI_TOK_LBRACE, | 	QSE_XLI_TOK_LBRACE, | ||||||
| 	QSE_XLI_TOK_RBRACE, | 	QSE_XLI_TOK_RBRACE, | ||||||
| 	QSE_XLI_TOK_EQ, | 	QSE_XLI_TOK_EQ, | ||||||
| @ -93,6 +94,10 @@ struct qse_xli_t | |||||||
| 		qse_size_t pair_xtnsize; | 		qse_size_t pair_xtnsize; | ||||||
| 		qse_size_t root_xtnsize; | 		qse_size_t root_xtnsize; | ||||||
| 		qse_char_t key_splitter; /**< character to use to split a key in the fqpn format */ | 		qse_char_t key_splitter; /**< character to use to split a key in the fqpn format */ | ||||||
|  | 		qse_char_t tag_marker[2]; | ||||||
|  | 		qse_char_t array_marker[2]; | ||||||
|  |  | ||||||
|  | 		qse_xli_tok_type_t _assign_tok; | ||||||
| 	} opt; | 	} opt; | ||||||
|  |  | ||||||
| 	qse_xli_ecb_t* ecb; | 	qse_xli_ecb_t* ecb; | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user