From 03cb7dd9dc57b1b715fc65676a02ccf69b15825a Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Fri, 5 Jan 2018 10:55:20 +0000 Subject: [PATCH] added QSE_XLI_ASSIGNWITHCOLON, QSE_XLI_TAGMARKER, QSE_XLI_ARRAYMARKE and added partial code for more extension work in progress --- qse/cmd/http/httpd.c | 2 +- qse/cmd/xli/xli.c | 9 +- qse/include/qse/xli/xli.h | 45 +++++++++- qse/lib/xli/err.c | 2 +- qse/lib/xli/read.c | 114 ++++++++++++++++++-------- qse/lib/xli/write.c | 167 ++++++++++++++++++++++++++++++-------- qse/lib/xli/xli.c | 26 +++++- qse/lib/xli/xli.h | 7 +- 8 files changed, 298 insertions(+), 74 deletions(-) diff --git a/qse/cmd/http/httpd.c b/qse/cmd/http/httpd.c index 42c84415..59062282 100644 --- a/qse/cmd/http/httpd.c +++ b/qse/cmd/http/httpd.c @@ -2020,7 +2020,7 @@ static void free_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server) if (server_xtn->cfgtab) { - qse_htb_close (server_xtn->cfgtab); + qse_htb_close (server_xtn->cfgtab); server_xtn->cfgtab = QSE_NULL; } } diff --git a/qse/cmd/xli/xli.c b/qse/cmd/xli/xli.c index bbb77d8f..b0834d5d 100644 --- a/qse/cmd/xli/xli.c +++ b/qse/cmd/xli/xli.c @@ -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; diff --git a/qse/include/qse/xli/xli.h b/qse/include/qse/xli/xli.h index 63ad7a75..b4d58d55 100644 --- a/qse/include/qse/xli/xli.h +++ b/qse/include/qse/xli/xli.h @@ -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; }; diff --git a/qse/lib/xli/err.c b/qse/lib/xli/err.c index 1eedce31..b8b8f16e 100644 --- a/qse/lib/xli/err.c +++ b/qse/lib/xli/err.c @@ -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"), diff --git a/qse/lib/xli/read.c b/qse/lib/xli/read.c index e012720a..6015ef6e 100644 --- a/qse/lib/xli/read.c +++ b/qse/lib/xli/read.c @@ -27,6 +27,18 @@ #include "xli.h" #include + +/* + "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,10 +312,11 @@ 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 }, - { QSE_NULL, 0, 0, } + { QSE_NULL, 0, 0, } }; struct ops_t* p; @@ -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,15 +636,17 @@ 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) { GET_CHAR_TO (xli, c); @@ -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,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_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); + key.ptr = qse_strdup(QSE_STR_PTR(xli->tok.name), xli->mmgr); if (key.ptr == 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); - 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) + 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_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); 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) { 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); 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; - if (get_token (xli) <= -1) goto oops; + if (get_token(xli) <= -1) goto oops; 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); @@ -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 (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_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); 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,12 +1098,17 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override) 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; 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) { 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; } - 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); return -1; } - x = read_pair (xli, keytag, 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; + 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; } @@ -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; } @@ -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; - link = qse_xli_makelistlink (xli, parlist); + link = qse_xli_makelistlink(xli, parlist); if (link == QSE_NULL) return -1; /* 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; } QSE_ASSERT (link == xli->parlink); - qse_xli_freelistlink (xli, link); + qse_xli_freelistlink(xli, link); return 0; } @@ -1138,17 +1187,18 @@ static int read_root_list (qse_xli_t* xli) { 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 (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; } QSE_ASSERT (link == xli->parlink); - qse_xli_freelistlink (xli, link); + qse_xli_freelistlink(xli, link); return 0; } diff --git a/qse/lib/xli/write.c b/qse/lib/xli/write.c index b393b609..09d136e6 100644 --- a/qse/lib/xli/write.c +++ b/qse/lib/xli/write.c @@ -25,6 +25,7 @@ */ #include "xli.h" +#include typedef struct arg_data_t arg_data_t; struct arg_data_t @@ -138,7 +139,7 @@ int qse_xli_closeactivewstream (qse_xli_t* xli, int* org_depth) 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_size_t i; @@ -174,22 +175,100 @@ static int write_indentation (qse_xli_t* xli, int depth) 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 { 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++) { - 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; } + +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,64 +277,84 @@ 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 (write_indentation(xli, depth) <= -1) return -1; if (pair->tag) { - if (write_to_current_stream (xli, QSE_T("["), 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; + 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, &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) { 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; case QSE_XLI_STR: { 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) { if (str->tag) { - 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, QSE_T("]"), 1, 0) <= -1) return -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, QSE_T("]"), 1, 0) <= -1) return -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, QSE_T("\""), 1, 0) <= -1) return -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, QSE_T("\""), 1, 0) <= -1) return -1; 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; } - 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; } 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_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; } } @@ -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++) { - 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 || - write_to_current_stream (xli, str, qse_strlen(str), 0) <= -1 || - write_to_current_stream (xli, QSE_T("\n"), 1, 0) <= -1) return -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, QSE_T("\n"), 1, 0) <= -1) return -1; 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++) { - 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 || - write_to_current_stream (xli, path, qse_strlen(path), 1) <= -1 || - write_to_current_stream (xli, QSE_T("\";\n"), 3, 0) <= -1) return -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, QSE_T("\";\n"), 3, 0) <= -1) return -1; if (qse_xli_openwstream (xli, ((qse_xli_file_t*)curatom)->path, depth) <= -1) return -1; depth = 0; diff --git a/qse/lib/xli/xli.c b/qse/lib/xli/xli.c index 09fe618e..1614c438 100644 --- a/qse/lib/xli/xli.c +++ b/qse/lib/xli/xli.c @@ -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; diff --git a/qse/lib/xli/xli.h b/qse/lib/xli/xli.h index 3fc1e7db..de80b7f4 100644 --- a/qse/lib/xli/xli.h +++ b/qse/lib/xli/xli.h @@ -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; @@ -133,7 +138,7 @@ int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr, qse_size_t rootxtnsize); void qse_xli_fini (qse_xli_t* xli); const qse_char_t* qse_xli_dflerrstr ( - const qse_xli_t* xli, qse_xli_errnum_t errnum); + const qse_xli_t* xli, qse_xli_errnum_t errnum); void qse_xli_clearrionames (qse_xli_t* xli); void qse_xli_clearwionames (qse_xli_t* xli);