started adding simple xli validation
This commit is contained in:
@ -156,6 +156,7 @@ int qse_gettime (qse_ntime_t* t)
|
||||
struct timeval tv;
|
||||
int n;
|
||||
|
||||
/* TODO: consider using clock_gettime() if it's avaialble.. -lrt may be needed */
|
||||
n = QSE_GETTIMEOFDAY (&tv, QSE_NULL);
|
||||
if (n == -1) return -1;
|
||||
|
||||
@ -227,13 +228,12 @@ int qse_settime (const qse_ntime_t* t)
|
||||
tv.tv_usec = QSE_NSEC_TO_USEC(t->nsec);
|
||||
|
||||
/*
|
||||
#if defined CLOCK_REALTIME && HAVE_CLOCK_SETTIME
|
||||
#if defined(CLOCK_REALTIME) && defined(HAVE_CLOCK_SETTIME)
|
||||
{
|
||||
int r = clock_settime (CLOCK_REALTIME, ts);
|
||||
if (r == 0 || errno == EPERM)
|
||||
return r;
|
||||
if (r == 0 || errno == EPERM) return r;
|
||||
}
|
||||
#elif HAVE_STIME
|
||||
#elif defined(HAVE_STIME)
|
||||
return stime (&ts->tv_sec);
|
||||
#else
|
||||
*/
|
||||
|
@ -48,7 +48,10 @@ const qse_char_t* qse_xli_dflerrstr (
|
||||
QSE_T("'@include' not followed by a string"),
|
||||
QSE_T("invalid character '${0}'"),
|
||||
QSE_T("'${0}' not recognized"),
|
||||
QSE_T("@ not followed by a valid word")
|
||||
QSE_T("@ not followed by a valid word"),
|
||||
QSE_T("illegal key '${0}'"),
|
||||
QSE_T("illegal value for '${0}'"),
|
||||
QSE_T("too many string segments for '${0}'")
|
||||
};
|
||||
|
||||
return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))?
|
||||
|
@ -594,10 +594,17 @@ static int get_token (qse_xli_t* xli)
|
||||
|
||||
static int read_pair (qse_xli_t* xli)
|
||||
{
|
||||
qse_char_t* key = QSE_NULL;
|
||||
qse_char_t* name = QSE_NULL;
|
||||
qse_xstr_t key;
|
||||
qse_xli_loc_t kloc;
|
||||
qse_char_t* name;
|
||||
qse_xli_pair_t* pair;
|
||||
qse_xli_list_t* parlist;
|
||||
qse_size_t dotted_curkey_len;
|
||||
qse_xli_scm_t* scm = QSE_NULL;
|
||||
|
||||
key.ptr = QSE_NULL;
|
||||
name = QSE_NULL;
|
||||
dotted_curkey_len = (qse_size_t)-1;
|
||||
|
||||
parlist = xli->parlink->list;
|
||||
|
||||
@ -606,6 +613,7 @@ static int read_pair (qse_xli_t* xli)
|
||||
qse_xli_atom_t* atom;
|
||||
|
||||
/* find any key conflicts in the current scope */
|
||||
/* TODO: optimization. no sequential search */
|
||||
atom = parlist->tail;
|
||||
while (atom)
|
||||
{
|
||||
@ -620,18 +628,47 @@ static int read_pair (qse_xli_t* xli)
|
||||
}
|
||||
}
|
||||
|
||||
key = qse_strdup (QSE_STR_PTR(xli->tok.name), xli->mmgr);
|
||||
if (key == QSE_NULL)
|
||||
kloc = xli->tok.loc;
|
||||
key.len = QSE_STR_LEN(xli->tok.name);
|
||||
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);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
|
||||
if (xli->opt.trait & QSE_XLI_VALIDATE)
|
||||
{
|
||||
qse_rbt_pair_t* pair;
|
||||
|
||||
pair = qse_rbt_search (xli->schema, QSE_STR_PTR(xli->dotted_curkey), QSE_STR_LEN(xli->dotted_curkey));
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
qse_xli_seterror (xli, QSE_XLI_EILKEY, (const qse_cstr_t*)&key, &kloc);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
scm = (qse_xli_scm_t*)QSE_RBT_VPTR(pair);
|
||||
|
||||
if (scm->flags & QSE_XLI_SCM_KEY_NODUP)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
xli->tok_status |= TOK_STATUS_ENABLE_NSTR;
|
||||
|
||||
if (get_token (xli) <= -1) goto oops;
|
||||
|
||||
if (xli->opt.trait & QSE_XLI_KEYALIAS)
|
||||
if (xli->opt.trait & QSE_XLI_KEYALIAS)
|
||||
{
|
||||
/* the name part must be unique for the same key(s) */
|
||||
if (MATCH (xli, TOK_IDENT) || MATCH (xli, TOK_DQSTR) || MATCH (xli, TOK_SQSTR) || MATCH(xli, TOK_NSTR))
|
||||
@ -643,7 +680,7 @@ static int read_pair (qse_xli_t* xli)
|
||||
{
|
||||
if (atom->type == QSE_XLI_PAIR &&
|
||||
((qse_xli_pair_t*)atom)->alias &&
|
||||
qse_strcmp (((qse_xli_pair_t*)atom)->key, key) == 0 &&
|
||||
qse_strcmp (((qse_xli_pair_t*)atom)->key, key.ptr) == 0 &&
|
||||
qse_strcmp (((qse_xli_pair_t*)atom)->alias, QSE_STR_PTR(xli->tok.name)) == 0)
|
||||
{
|
||||
qse_xli_seterror (xli, QSE_XLI_EEXIST, QSE_STR_CSTR(xli->tok.name), &xli->tok.loc);
|
||||
@ -670,11 +707,20 @@ static int read_pair (qse_xli_t* xli)
|
||||
if (MATCH (xli, TOK_SQSTR) || MATCH (xli, TOK_DQSTR) || MATCH(xli, TOK_NSTR) || MATCH (xli, TOK_IDENT))
|
||||
{
|
||||
qse_xli_str_t* curstrseg;
|
||||
qse_size_t segcount = 0;
|
||||
|
||||
if (scm && !(scm->flags & QSE_XLI_SCM_VAL_STR))
|
||||
{
|
||||
/* check the value type */
|
||||
qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
/* add a new pair with the initial string segment */
|
||||
pair = qse_xli_insertpairwithstr (xli, parlist, QSE_NULL, key, name, QSE_STR_CSTR(xli->tok.name));
|
||||
pair = qse_xli_insertpairwithstr (xli, parlist, QSE_NULL, key.ptr, name, QSE_STR_CSTR(xli->tok.name));
|
||||
if (pair == QSE_NULL) goto oops;
|
||||
|
||||
segcount++;
|
||||
curstrseg = (qse_xli_str_t*)pair->val;
|
||||
|
||||
if (get_token (xli) <= -1) goto oops;
|
||||
@ -691,11 +737,11 @@ static int read_pair (qse_xli_t* xli)
|
||||
goto oops;
|
||||
}
|
||||
|
||||
|
||||
/* add an additional segment to the string */
|
||||
curstrseg = qse_xli_addsegtostr (xli, curstrseg, QSE_STR_CSTR(xli->tok.name));
|
||||
if (curstrseg == QSE_NULL) goto oops;
|
||||
|
||||
segcount++;
|
||||
if (get_token (xli) <= -1) goto oops; /* skip the value */
|
||||
}
|
||||
while (MATCH (xli, TOK_COMMA));
|
||||
@ -708,6 +754,13 @@ static int read_pair (qse_xli_t* xli)
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (scm && (segcount < scm->str_minseg || segcount > scm->str_maxseg))
|
||||
{
|
||||
/* too many string segments for the key */
|
||||
qse_xli_seterror (xli, QSE_XLI_ESTRSEG, (const qse_cstr_t*)&key, &kloc);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
if (get_token (xli) <= -1) goto oops;
|
||||
}
|
||||
else
|
||||
@ -716,13 +769,23 @@ static int read_pair (qse_xli_t* xli)
|
||||
goto oops;
|
||||
}
|
||||
|
||||
|
||||
/* TODO: check against schema */
|
||||
|
||||
}
|
||||
else if (MATCH (xli, TOK_LBRACE))
|
||||
{
|
||||
if (scm && !(scm->flags & QSE_XLI_SCM_VAL_LIST))
|
||||
{
|
||||
/* check the value type */
|
||||
qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR;
|
||||
|
||||
/* insert a pair with an empty list */
|
||||
pair = qse_xli_insertpairwithemptylist (xli, parlist, QSE_NULL, key, name);
|
||||
pair = qse_xli_insertpairwithemptylist (xli, parlist, QSE_NULL, key.ptr, name);
|
||||
if (pair == QSE_NULL) goto oops;
|
||||
|
||||
if (read_list (xli, (qse_xli_list_t*)pair->val) <= -1) goto oops;
|
||||
@ -741,17 +804,28 @@ static int read_pair (qse_xli_t* xli)
|
||||
/* skip the semicolon */
|
||||
if (get_token (xli) <= -1) goto oops;
|
||||
}
|
||||
|
||||
/* TODO: check against schema */
|
||||
}
|
||||
else if (MATCH (xli, TOK_SEMICOLON))
|
||||
{
|
||||
if (scm && !(scm->flags & QSE_XLI_SCM_VAL_NIL))
|
||||
{
|
||||
/* check the value type */
|
||||
qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc);
|
||||
goto oops;
|
||||
}
|
||||
|
||||
xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR;
|
||||
|
||||
/* no value has been specified for the pair */
|
||||
pair = qse_xli_insertpair (xli, parlist, QSE_NULL, key, name, (qse_xli_val_t*)&xli->xnil);
|
||||
pair = qse_xli_insertpair (xli, parlist, QSE_NULL, key.ptr, name, (qse_xli_val_t*)&xli->xnil);
|
||||
if (pair == QSE_NULL) goto oops;
|
||||
|
||||
/* skip the semicolon */
|
||||
if (get_token (xli) <= -1) goto oops;
|
||||
|
||||
/* TODO: check against schema */
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -760,13 +834,16 @@ static int read_pair (qse_xli_t* xli)
|
||||
}
|
||||
|
||||
QSE_MMGR_FREE (xli->mmgr, name);
|
||||
QSE_MMGR_FREE (xli->mmgr, key);
|
||||
QSE_MMGR_FREE (xli->mmgr, key.ptr);
|
||||
qse_str_setlen (xli->dotted_curkey, dotted_curkey_len);
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR;
|
||||
if (name) QSE_MMGR_FREE (xli->mmgr, name);
|
||||
if (key) QSE_MMGR_FREE (xli->mmgr, key);
|
||||
if (key.ptr) QSE_MMGR_FREE (xli->mmgr, key.ptr);
|
||||
if (dotted_curkey_len != (qse_size_t)-1)
|
||||
qse_str_setlen (xli->dotted_curkey, dotted_curkey_len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -894,6 +971,8 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io)
|
||||
qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL);
|
||||
qse_xli_clearrionames (xli);
|
||||
|
||||
QSE_ASSERT (QSE_STR_LEN(xli->dotted_curkey) == 0);
|
||||
|
||||
n = xli->rio.impl (xli, QSE_XLI_IO_OPEN, xli->rio.inp, QSE_NULL, 0);
|
||||
if (n <= -1)
|
||||
{
|
||||
@ -915,6 +994,7 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io)
|
||||
|
||||
QSE_ASSERT (xli->rio.inp == &xli->rio.top);
|
||||
close_current_stream (xli);
|
||||
qse_str_clear (xli->tok.name);
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
@ -935,5 +1015,6 @@ oops:
|
||||
}
|
||||
|
||||
close_current_stream (xli);
|
||||
qse_str_clear (xli->tok.name);
|
||||
return -1;
|
||||
}
|
||||
|
@ -56,26 +56,35 @@ int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr)
|
||||
xli->mmgr = mmgr;
|
||||
xli->errstr = qse_xli_dflerrstr;
|
||||
|
||||
xli->dotted_curkey = qse_str_open (mmgr, 0, 128);
|
||||
if (xli->dotted_curkey == QSE_NULL) goto oops;
|
||||
|
||||
xli->tok.name = qse_str_open (mmgr, 0, 128);
|
||||
if (xli->tok.name == QSE_NULL) goto oops;
|
||||
|
||||
xli->schema = qse_rbt_open (mmgr, 0, QSE_SIZEOF(qse_char_t), 1);
|
||||
if (xli->schema == QSE_NULL) goto oops;
|
||||
|
||||
xli->root.type = QSE_XLI_LIST;
|
||||
xli->xnil.type = QSE_XLI_NIL;
|
||||
|
||||
return 0;
|
||||
|
||||
oops:
|
||||
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
|
||||
if (xli->schema) qse_rbt_close (xli->schema);
|
||||
if (xli->tok.name) qse_str_close (xli->tok.name);
|
||||
if (xli->dotted_curkey) qse_str_close (xli->dotted_curkey);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void qse_xli_fini (qse_xli_t* xli)
|
||||
{
|
||||
qse_xli_clear (xli);
|
||||
qse_str_close (xli->tok.name);
|
||||
|
||||
qse_xli_clearrionames (xli);
|
||||
qse_xli_clearwionames (xli);
|
||||
qse_rbt_close (xli->schema);
|
||||
qse_str_close (xli->tok.name);
|
||||
qse_str_close (xli->dotted_curkey);
|
||||
}
|
||||
|
||||
qse_mmgr_t* qse_xli_getmmgr (qse_xli_t* xli)
|
||||
@ -156,13 +165,6 @@ void qse_xli_freemem (qse_xli_t* xli, void* ptr)
|
||||
}
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
qse_xli_list_t* qse_xli_getroot (qse_xli_t* xli)
|
||||
{
|
||||
return &xli->root;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
static void insert_atom (
|
||||
qse_xli_t* xli, qse_xli_list_t* parent,
|
||||
qse_xli_atom_t* peer, qse_xli_atom_t* atom)
|
||||
@ -375,9 +377,31 @@ static void free_list (qse_xli_t* xli, qse_xli_list_t* list)
|
||||
void qse_xli_clear (qse_xli_t* xli)
|
||||
{
|
||||
free_list (xli, &xli->root);
|
||||
qse_rbt_clear (xli->schema);
|
||||
|
||||
qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL);
|
||||
qse_xli_clearrionames (xli);
|
||||
qse_xli_clearwionames (xli);
|
||||
}
|
||||
|
||||
static qse_size_t count_pair_byalias (
|
||||
qse_xli_list_t* qse_xli_getroot (qse_xli_t* xli)
|
||||
{
|
||||
return &xli->root;
|
||||
}
|
||||
|
||||
void qse_xli_clearroot (qse_xli_t* xli)
|
||||
{
|
||||
free_list (xli, &xli->root);
|
||||
}
|
||||
|
||||
void qse_xli_clearschema (qse_xli_t* xli)
|
||||
{
|
||||
qse_rbt_clear (xli->schema);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
|
||||
static qse_size_t count_pairs_by_key_and_alias (
|
||||
qse_xli_t* xli, const qse_xli_list_t* list,
|
||||
const qse_cstr_t* key, const qse_cstr_t* alias)
|
||||
{
|
||||
@ -404,7 +428,7 @@ static qse_size_t count_pair_byalias (
|
||||
return count;
|
||||
}
|
||||
|
||||
static qse_xli_pair_t* find_pair_byalias (
|
||||
static qse_xli_pair_t* find_pair_by_key_and_alias (
|
||||
qse_xli_t* xli, const qse_xli_list_t* list,
|
||||
const qse_cstr_t* key, const qse_cstr_t* alias)
|
||||
{
|
||||
@ -430,7 +454,7 @@ static qse_xli_pair_t* find_pair_byalias (
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
static qse_xli_pair_t* find_pair_byindex (
|
||||
static qse_xli_pair_t* find_pair_by_key_and_index (
|
||||
qse_xli_t* xli, const qse_xli_list_t* list,
|
||||
const qse_cstr_t* key, qse_size_t index)
|
||||
{
|
||||
@ -457,7 +481,7 @@ static qse_xli_pair_t* find_pair_byindex (
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* alias)
|
||||
qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* dotted_name)
|
||||
{
|
||||
const qse_char_t* ptr;
|
||||
const qse_xli_list_t* curlist;
|
||||
@ -466,11 +490,11 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l
|
||||
|
||||
curlist = list? list: &xli->root;
|
||||
|
||||
ptr = alias;
|
||||
ptr = dotted_name;
|
||||
while (1)
|
||||
{
|
||||
seg.ptr = ptr;
|
||||
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++;
|
||||
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[') && *ptr != QSE_T('{')) ptr++;
|
||||
if (ptr == seg.ptr) goto inval;
|
||||
seg.len = ptr - seg.ptr;
|
||||
|
||||
@ -479,14 +503,14 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l
|
||||
/* check the type of curlist. this check is needed
|
||||
* because of the unconditional switching at the bottom of the
|
||||
* this loop. this implementation strategy has been chosen
|
||||
* to provide the segment alias easily. */
|
||||
* to provide the segment name easily. */
|
||||
goto noent;
|
||||
}
|
||||
|
||||
if (*ptr == QSE_T('['))
|
||||
{
|
||||
/* index is specified */
|
||||
ptr++;
|
||||
ptr++; /* skip [ */
|
||||
|
||||
if (QSE_ISDIGIT(*ptr))
|
||||
{
|
||||
@ -501,50 +525,13 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l
|
||||
|
||||
if (*ptr != QSE_T(']')) goto inval;
|
||||
|
||||
pair = find_pair_byindex (xli, curlist, &seg, index);
|
||||
pair = find_pair_by_key_and_index (xli, curlist, &seg, index);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
seg.len += count + 2; /* adjustment for error message */
|
||||
goto noent;
|
||||
}
|
||||
}
|
||||
else if (QSE_ISALPHA(*ptr))
|
||||
{
|
||||
/* word index */
|
||||
qse_cstr_t idx;
|
||||
|
||||
idx.ptr = ptr;
|
||||
do ptr++; while (QSE_ISALNUM(*ptr) || *ptr == QSE_T('_') || *ptr == QSE_T('-'));
|
||||
idx.len = ptr - idx.ptr;
|
||||
|
||||
if (*ptr != QSE_T(']')) goto inval;
|
||||
|
||||
pair = find_pair_byalias (xli, curlist, &seg, &idx);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
seg.len += idx.len + 2; /* adjustment for error message */
|
||||
goto noent;
|
||||
}
|
||||
}
|
||||
else if (*ptr == QSE_T('\'') || *ptr == QSE_T('\"'))
|
||||
{
|
||||
qse_cstr_t idx;
|
||||
qse_char_t cc = *ptr++;
|
||||
|
||||
idx.ptr = ptr;
|
||||
do ptr++; while (*ptr != cc && *ptr != QSE_T('\0'));
|
||||
idx.len = ptr - idx.ptr;
|
||||
|
||||
if (*ptr != cc) goto inval;
|
||||
if (*++ptr != QSE_T(']')) goto inval;
|
||||
|
||||
pair = find_pair_byalias (xli, curlist, &seg, &idx);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
seg.len += idx.len + 4; /* adjustment for error message */
|
||||
goto noent;
|
||||
}
|
||||
}
|
||||
else goto inval;
|
||||
|
||||
ptr++; /* skip ] */
|
||||
@ -552,9 +539,37 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l
|
||||
if (*ptr == QSE_T('\0')) break; /* no more segments */
|
||||
else if (*ptr != QSE_T('.')) goto inval;
|
||||
}
|
||||
else if (*ptr == QSE_T('{'))
|
||||
{
|
||||
/* word index - alias */
|
||||
qse_cstr_t idx;
|
||||
|
||||
ptr++; /* skip { */
|
||||
|
||||
/* no escaping is supported for the alias inside {}.
|
||||
* so if your alias contains these characters (in a quoted string),
|
||||
* you can't reference it using a dotted key name. */
|
||||
idx.ptr = ptr;
|
||||
while (*ptr != QSE_T('}') && *ptr != QSE_T('\0')) ptr++;
|
||||
idx.len = ptr - idx.ptr;
|
||||
|
||||
if (*ptr != QSE_T('}') || idx.len == 0) goto inval;
|
||||
|
||||
pair = find_pair_by_key_and_alias (xli, curlist, &seg, &idx);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
seg.len += idx.len + 2; /* adjustment for error message */
|
||||
goto noent;
|
||||
}
|
||||
|
||||
ptr++; /* skip } */
|
||||
|
||||
if (*ptr == QSE_T('\0')) break; /* no more segments */
|
||||
else if (*ptr != QSE_T('.')) goto inval;
|
||||
}
|
||||
else
|
||||
{
|
||||
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
|
||||
pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL);
|
||||
if (pair == QSE_NULL) goto noent;
|
||||
|
||||
if (*ptr == QSE_T('\0')) break; /* no more segments */
|
||||
@ -581,7 +596,7 @@ noent:
|
||||
return QSE_NULL;
|
||||
}
|
||||
|
||||
qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* alias)
|
||||
qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* dotted_name)
|
||||
{
|
||||
const qse_char_t* ptr;
|
||||
const qse_xli_list_t* curlist;
|
||||
@ -590,11 +605,11 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
|
||||
|
||||
curlist = list? list: &xli->root;
|
||||
|
||||
ptr = alias;
|
||||
ptr = dotted_name;
|
||||
while (1)
|
||||
{
|
||||
seg.ptr = ptr;
|
||||
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++;
|
||||
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[') && *ptr != QSE_T('{')) ptr++;
|
||||
if (ptr == seg.ptr) goto inval;
|
||||
seg.len = ptr - seg.ptr;
|
||||
|
||||
@ -603,14 +618,14 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
|
||||
/* check the type of curlist. this check is needed
|
||||
* because of the unconditional switching at the bottom of the
|
||||
* this loop. this implementation strategy has been chosen
|
||||
* to provide the segment alias easily. */
|
||||
* to provide the segment name easily. */
|
||||
goto noent;
|
||||
}
|
||||
|
||||
if (*ptr == QSE_T('['))
|
||||
{
|
||||
/* index is specified */
|
||||
ptr++;
|
||||
ptr++; /* skip [ */
|
||||
|
||||
if (QSE_ISDIGIT(*ptr))
|
||||
{
|
||||
@ -625,50 +640,13 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
|
||||
|
||||
if (*ptr != QSE_T(']')) goto inval;
|
||||
|
||||
pair = find_pair_byindex (xli, curlist, &seg, index);
|
||||
pair = find_pair_by_key_and_index (xli, curlist, &seg, index);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
seg.len += count + 2; /* adjustment for error message */
|
||||
goto noent;
|
||||
}
|
||||
}
|
||||
else if (QSE_ISALPHA(*ptr))
|
||||
{
|
||||
/* word index */
|
||||
qse_cstr_t idx;
|
||||
|
||||
idx.ptr = ptr;
|
||||
do ptr++; while (QSE_ISALNUM(*ptr) || *ptr == QSE_T('_') || *ptr == QSE_T('-'));
|
||||
idx.len = ptr - idx.ptr;
|
||||
|
||||
if (*ptr != QSE_T(']')) goto inval;
|
||||
|
||||
pair = find_pair_byalias (xli, curlist, &seg, &idx);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
seg.len += idx.len + 2; /* adjustment for error message */
|
||||
goto noent;
|
||||
}
|
||||
}
|
||||
else if (*ptr == QSE_T('\'') || *ptr == QSE_T('\"'))
|
||||
{
|
||||
qse_cstr_t idx;
|
||||
qse_char_t cc = *ptr++;
|
||||
|
||||
idx.ptr = ptr;
|
||||
do ptr++; while (*ptr != cc && *ptr != QSE_T('\0'));
|
||||
idx.len = ptr - idx.ptr;
|
||||
|
||||
if (*ptr != cc) goto inval;
|
||||
if (*++ptr != QSE_T(']')) goto inval;
|
||||
|
||||
pair = find_pair_byalias (xli, curlist, &seg, &idx);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
seg.len += idx.len + 4; /* adjustment for error message */
|
||||
goto noent;
|
||||
}
|
||||
}
|
||||
else goto inval;
|
||||
|
||||
ptr++; /* skip ] */
|
||||
@ -680,18 +658,47 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
|
||||
}
|
||||
else if (*ptr != QSE_T('.')) goto inval;
|
||||
}
|
||||
else if (*ptr == QSE_T('{'))
|
||||
{
|
||||
/* word index - alias */
|
||||
qse_cstr_t idx;
|
||||
|
||||
ptr++; /* skip { */
|
||||
|
||||
idx.ptr = ptr;
|
||||
while (*ptr != QSE_T('}') && *ptr != QSE_T('\0')) ptr++;
|
||||
idx.len = ptr - idx.ptr;
|
||||
|
||||
if (*ptr != QSE_T('}') || idx.len == 0) goto inval;
|
||||
|
||||
pair = find_pair_by_key_and_alias (xli, curlist, &seg, &idx);
|
||||
if (pair == QSE_NULL)
|
||||
{
|
||||
seg.len += idx.len + 2; /* adjustment for error message */
|
||||
goto noent;
|
||||
}
|
||||
|
||||
ptr++; /* skip } */
|
||||
|
||||
if (*ptr == QSE_T('\0'))
|
||||
{
|
||||
/* no more segments */
|
||||
return 1;
|
||||
}
|
||||
else if (*ptr != QSE_T('.')) goto inval;
|
||||
}
|
||||
else
|
||||
{
|
||||
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
|
||||
pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL);
|
||||
if (pair == QSE_NULL) goto noent;
|
||||
|
||||
if (*ptr == QSE_T('\0'))
|
||||
{
|
||||
return count_pair_byalias (xli, curlist, &seg, QSE_NULL);
|
||||
return count_pairs_by_key_and_alias (xli, curlist, &seg, QSE_NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
|
||||
pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL);
|
||||
if (pair == QSE_NULL) goto noent;
|
||||
}
|
||||
}
|
||||
@ -702,7 +709,7 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
|
||||
|
||||
/* switch to the value regardless of its type.
|
||||
* check if it is a list in the beginning of the loop
|
||||
* just after having gotten the next segment alias */
|
||||
* just after having gotten the next segment name */
|
||||
curlist = (qse_xli_list_t*)pair->val;
|
||||
}
|
||||
|
||||
@ -760,3 +767,25 @@ qse_char_t* qse_xli_dupflatstr (qse_xli_t* xli, qse_xli_str_t* str, qse_size_t*
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
int qse_xli_setschema (qse_xli_t* xli, const qse_char_t* dotted_name, const qse_xli_scm_t* scm)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
tmp = scm->flags & (QSE_XLI_SCM_VAL_LIST | QSE_XLI_SCM_VAL_STR | QSE_XLI_SCM_VAL_NIL);
|
||||
if (tmp != QSE_XLI_SCM_VAL_LIST && tmp != QSE_XLI_SCM_VAL_STR && tmp != QSE_XLI_SCM_VAL_NIL)
|
||||
{
|
||||
/* VAL_LIST, VAL_STR, VAL_NIL can't co-exist */
|
||||
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qse_rbt_upsert (xli->schema, dotted_name, qse_strlen(dotted_name), scm, QSE_SIZEOF(scm)) == QSE_NULL)
|
||||
{
|
||||
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <qse/xli/xli.h>
|
||||
#include <qse/cmn/str.h>
|
||||
#include <qse/cmn/rbt.h>
|
||||
#include "../cmn/mem.h"
|
||||
|
||||
typedef struct qse_xli_tok_t qse_xli_tok_t;
|
||||
@ -60,7 +61,11 @@ struct qse_xli_t
|
||||
|
||||
qse_xli_nil_t xnil;
|
||||
qse_xli_list_t root;
|
||||
qse_xli_list_link_t* parlink;
|
||||
|
||||
qse_xli_list_link_t* parlink; /* link that points to the list being read currently */
|
||||
|
||||
qse_str_t* dotted_curkey;
|
||||
qse_rbt_t* schema;
|
||||
|
||||
qse_xli_tok_t tok;
|
||||
int tok_status;
|
||||
|
Reference in New Issue
Block a user