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(" -K                        allow key 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(" -m                 number specify the maximum amount of memory to use in bytes\n")); | ||||
| #if defined(QSE_BUILD_DEBUG) | ||||
| @ -195,9 +196,9 @@ static int handle_args (int argc, qse_char_t* argv[]) | ||||
| 	static qse_opt_t opt =  | ||||
| 	{ | ||||
| #if defined(QSE_BUILD_DEBUG) | ||||
| 		QSE_T("hi:o:I:O:uaftsdnlKSvm:X:"), | ||||
| 		QSE_T("hi:o:I:O:uaftsdnlKScvm:X:"), | ||||
| #else | ||||
| 		QSE_T("hi:o:I:O:uaftsdnlKSvm:"), | ||||
| 		QSE_T("hi:o:I:O:uaftsdnlKScvm:"), | ||||
| #endif | ||||
| 		lng | ||||
| 	}; | ||||
| @ -291,6 +292,10 @@ static int handle_args (int argc, qse_char_t* argv[]) | ||||
| 				g_trait |= QSE_XLI_STRTAG; | ||||
| 				break; | ||||
|  | ||||
| 			case QSE_T('c'): | ||||
| 				g_trait |= QSE_XLI_ASSIGNWITHCOLON; | ||||
| 				break; | ||||
|  | ||||
| 			case QSE_T('v'): | ||||
| 				g_trait |= QSE_XLI_VALIDATE; | ||||
| 				break; | ||||
|  | ||||
| @ -115,7 +115,20 @@ enum qse_xli_opt_t | ||||
| 	 */ | ||||
| 	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; | ||||
|  | ||||
| @ -145,14 +158,20 @@ enum qse_xli_trait_t | ||||
| 	 *  "tg" is stored into the tag field of qse_xli_str_t. */ | ||||
| 	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 */ | ||||
| 	QSE_XLI_VALIDATE  = (1 << 11) | ||||
| 	QSE_XLI_VALIDATE  = (1 << 12) | ||||
| }; | ||||
| typedef enum qse_xli_trait_t qse_xli_trait_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_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_atom_t qse_xli_atom_t; | ||||
| @ -207,6 +226,26 @@ struct qse_xli_str_t | ||||
| 	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 \ | ||||
| 	qse_xli_atom_type_t type; \ | ||||
| 	qse_xli_atom_t* prev; \ | ||||
| @ -225,6 +264,8 @@ struct qse_xli_pair_t | ||||
| 	const qse_char_t* key; | ||||
| 	const qse_char_t* alias;  | ||||
| 	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; | ||||
| }; | ||||
|  | ||||
|  | ||||
| @ -48,7 +48,7 @@ const qse_char_t* qse_xli_dflerrstr ( | ||||
| 		QSE_T("syntax error"), | ||||
| 		QSE_T("semicolon 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("pair value expected in place of '${0}'"), | ||||
| 		QSE_T("string not closed"), | ||||
|  | ||||
| @ -27,6 +27,18 @@ | ||||
| #include "xli.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 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_COMMA       }, | ||||
| 		{ QSE_T(":"),   1, QSE_XLI_TOK_COLON       }, | ||||
| 		{ QSE_T(";"),   1, QSE_XLI_TOK_SEMICOLON   }, | ||||
| 		{ QSE_T("{"),   1, QSE_XLI_TOK_LBRACE      }, | ||||
| 		{ QSE_T("}"),   1, QSE_XLI_TOK_RBRACE      }, | ||||
| @ -511,6 +524,8 @@ retry: | ||||
| 	          (xli->opt.trait & QSE_XLI_LEADDIGIT) &&  | ||||
| 	          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 all_digits = 1; | ||||
|  | ||||
| @ -522,8 +537,8 @@ retry: | ||||
| 			GET_CHAR_TO (xli, c); | ||||
|  | ||||
| 			if (c == QSE_T('_') || c == QSE_T('-') ||  | ||||
| 			    c == QSE_T(':') || c == QSE_T('*') || | ||||
| 			    c == QSE_T('/') || QSE_ISALPHA (c))  | ||||
| 			    (!(xli->opt.trait & QSE_XLI_ASSIGNWITHCOLON) && c == QSE_T(':')) ||  | ||||
| 			    c == QSE_T('*') || c == QSE_T('/') || QSE_ISALPHA (c))  | ||||
| 			{ | ||||
| 				all_digits = 0; | ||||
| 			} | ||||
| @ -536,7 +551,7 @@ retry: | ||||
|  | ||||
| 		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); | ||||
| 			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 = [tg] "abc";  | ||||
| 		 * "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); | ||||
|  | ||||
| 		while (1) | ||||
| @ -641,7 +658,7 @@ retry: | ||||
| 				return -1; | ||||
| 			} | ||||
|  | ||||
| 			if (c == QSE_T(']')) | ||||
| 			if (c == xli->opt.tag_marker[1]) /* ] */ | ||||
| 			{ | ||||
| 				/* terminating quote */ | ||||
| 				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; | ||||
| 	int key_nodup = 0, key_alias = 0, val_iffy = 0; | ||||
| 	/*int key_quoted = 0, alias_quoted = 0;*/ | ||||
|  | ||||
| 	key.ptr = QSE_NULL; | ||||
| 	name = QSE_NULL; | ||||
| @ -735,6 +753,8 @@ 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_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; | ||||
| 	key.len = QSE_STR_LEN(xli->tok.name); | ||||
| 	key.ptr = qse_strdup(QSE_STR_PTR(xli->tok.name), xli->mmgr); | ||||
| @ -794,7 +814,7 @@ 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; | ||||
|  | ||||
| 	if (get_token(xli) <= -1) goto oops; | ||||
| @ -802,7 +822,7 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | ||||
| 	if (key_alias) | ||||
| 	{ | ||||
| 		/* 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; | ||||
|  | ||||
| @ -827,6 +847,9 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc | ||||
| 				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; | ||||
| 		} | ||||
| 		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 (!(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)) | ||||
| 		{ | ||||
| 			strtag = qse_strxdup (QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr); | ||||
| @ -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); | ||||
| 			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++; | ||||
| 			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; | ||||
| 		} | ||||
|  | ||||
|  | ||||
| 		/* TODO: check against schema */ | ||||
|  | ||||
| 	} | ||||
| 	else if (!(xli->opt.trait & QSE_XLI_NOLIST) && MATCH (xli, QSE_XLI_TOK_LBRACE)) | ||||
| 	{ | ||||
| 	handle_list: | ||||
| 		if (scm && !(scm->flags & QSE_XLI_SCM_VALLIST)) | ||||
| 		{ | ||||
| 			/* 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); | ||||
| } | ||||
|  | ||||
| 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) | ||||
| 	{ | ||||
| 		if (MATCH (xli, QSE_XLI_TOK_XINCLUDE)) | ||||
| @ -1066,6 +1098,11 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override) | ||||
|  | ||||
| 			if (begin_include (xli) <= -1) return -1; | ||||
| 		} | ||||
| 		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; | ||||
| @ -1084,7 +1121,7 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override) | ||||
| 				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_xli_seterror (xli, QSE_XLI_ENOKEY, QSE_NULL, &xli->tok.loc); | ||||
| @ -1094,10 +1131,12 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override) | ||||
| 			x = read_pair(xli, keytag, override); | ||||
| 			QSE_MMGR_FREE (xli->mmgr, keytag); | ||||
| 			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; | ||||
| 			pair_count++; | ||||
| 		} | ||||
| 		else if (MATCH(xli, QSE_XLI_TOK_TEXT)) | ||||
| 		{ | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -1122,7 +1171,7 @@ static int read_list (qse_xli_t* xli, qse_xli_list_t* parlist, const qse_xli_scm | ||||
| 	/* get_token() here is to read the token after the left brace. | ||||
| 	 * it must be called after the xli->parlink has been updated | ||||
| 	 * 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); | ||||
| 		return -1; | ||||
| @ -1141,7 +1190,8 @@ static int read_root_list (qse_xli_t* xli) | ||||
| 	link = qse_xli_makelistlink(xli, &xli->root->list); | ||||
| 	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); | ||||
| 		return -1; | ||||
|  | ||||
| @ -25,6 +25,7 @@ | ||||
|  */ | ||||
|  | ||||
| #include "xli.h" | ||||
| #include <qse/cmn/chr.h> | ||||
|  | ||||
| typedef struct arg_data_t arg_data_t; | ||||
| struct arg_data_t | ||||
| @ -188,8 +189,86 @@ static int write_indentation (qse_xli_t* xli, int depth) | ||||
| 	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 struct | ||||
| 	{ | ||||
| 		qse_char_t* qptr; | ||||
| 		qse_size_t  qlen; | ||||
| 	} quotes[] = | ||||
| 	{ | ||||
| 		{ QSE_T(""),   0 }, | ||||
| 		{ QSE_T("\'"), 1 }, | ||||
| 		{ QSE_T("\""), 1 } | ||||
| 	}; | ||||
|  | ||||
| 	qse_xli_atom_t* curatom; | ||||
|  | ||||
| 	for (curatom = list->head; curatom; curatom = curatom->next) | ||||
| @ -198,24 +277,36 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | ||||
| 		{ | ||||
| 			case QSE_XLI_PAIR: | ||||
| 			{ | ||||
| 				int qtype; | ||||
| 				qse_xli_pair_t* pair = (qse_xli_pair_t*)curatom; | ||||
|  | ||||
| 				if (write_indentation(xli, depth) <= -1) return -1; | ||||
|  | ||||
| 				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, 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 (write_to_current_stream (xli, QSE_T(" \""), 2, 0) <= -1 || | ||||
| 					    write_to_current_stream (xli, pair->alias, qse_strlen(pair->alias), 1) <= -1 || | ||||
| 					    write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) return -1; | ||||
| 					QSE_ASSERT(pair->_alias_quoted >= 0 && pair->_alias_quoted < QSE_COUNTOF(quotes)); | ||||
| 					qtype = pair->_alias_quoted; | ||||
| 					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) | ||||
| @ -228,7 +319,15 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth) | ||||
| 					{ | ||||
| 						qse_xli_str_t* str = (qse_xli_str_t*)pair->val; | ||||
|  | ||||
| 						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) | ||||
| 						{ | ||||
| 							if (str->tag) | ||||
|  | ||||
| @ -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->opt.root_xtnsize = rootxtnsize; | ||||
| 	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); | ||||
| 	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: | ||||
| 			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; | ||||
|  | ||||
| 		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: | ||||
| 			xli->opt.key_splitter = *(const qse_char_t*)value; | ||||
| 			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); | ||||
| @ -159,6 +175,14 @@ int qse_xli_getopt (qse_xli_t* xli, qse_xli_opt_t  id, void* value) | ||||
| 		case QSE_XLI_KEYSPLITTER: | ||||
| 			*(qse_char_t*)value = xli->opt.key_splitter; | ||||
| 			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); | ||||
| @ -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) | ||||
| 	{ | ||||
| 		qse_cstr_t ea; | ||||
| 		ea.ptr = fqpn; | ||||
| 		ea.ptr = (qse_char_t*)fqpn; | ||||
| 		ea.len = qse_strlen (ea.ptr); | ||||
| 		qse_xli_seterrnum (xli, QSE_XLI_ENOENT, &ea); | ||||
| 		return -1; | ||||
|  | ||||
| @ -37,6 +37,7 @@ enum qse_xli_tok_type_t | ||||
| 	QSE_XLI_TOK_EOF, | ||||
| 	QSE_XLI_TOK_XINCLUDE, | ||||
| 	QSE_XLI_TOK_SEMICOLON, | ||||
| 	QSE_XLI_TOK_COLON, | ||||
| 	QSE_XLI_TOK_LBRACE, | ||||
| 	QSE_XLI_TOK_RBRACE, | ||||
| 	QSE_XLI_TOK_EQ, | ||||
| @ -93,6 +94,10 @@ struct qse_xli_t | ||||
| 		qse_size_t pair_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 tag_marker[2]; | ||||
| 		qse_char_t array_marker[2]; | ||||
|  | ||||
| 		qse_xli_tok_type_t _assign_tok; | ||||
| 	} opt; | ||||
|  | ||||
| 	qse_xli_ecb_t* ecb; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user