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:
parent
dccad56ca5
commit
03cb7dd9dc
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,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;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include "xli.h"
|
||||
#include <qse/cmn/chr.h>
|
||||
|
||||
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;
|
||||
|
@ -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;
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user