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:
hyung-hwan 2018-01-05 10:55:20 +00:00
parent dccad56ca5
commit 03cb7dd9dc
8 changed files with 298 additions and 74 deletions

View File

@ -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;

View File

@ -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;
};

View File

@ -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"),

View File

@ -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,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,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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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);