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