added code to accept a number as a xli value.

renamed pair->name to pair->alias and related functions.
enhanced xli reader to support string escaping
This commit is contained in:
2013-07-01 15:16:19 +00:00
parent 3e21bc4f98
commit d2505bdbcd
7 changed files with 186 additions and 139 deletions

View File

@ -25,6 +25,12 @@ static int get_char (qse_xli_t* xli);
static int get_token (qse_xli_t* xli);
static int read_list (qse_xli_t* xli, qse_xli_list_t* list);
enum
{
TOK_STATUS_ENABLE_NSTR = (1 << 0)
};
static int close_current_stream (qse_xli_t* xli)
{
qse_ssize_t n;
@ -51,6 +57,7 @@ enum tok_t
TOK_COMMA,
TOK_DQSTR,
TOK_SQSTR,
TOK_NSTR,
TOK_IDENT,
TOK_TEXT,
@ -458,12 +465,10 @@ retry:
type = classify_ident (xli, QSE_STR_CSTR(tok->name));
SET_TOKEN_TYPE (xli, tok, type);
}
else if (c == QSE_T('\'') || c == QSE_T('\"'))
else if (c == QSE_T('\''))
{
/* single-quoted string - no escaping */
qse_cint_t cc = c;
SET_TOKEN_TYPE (xli, tok, ((cc == QSE_T('\''))? TOK_SQSTR: TOK_DQSTR));
SET_TOKEN_TYPE (xli, tok, TOK_SQSTR);
while (1)
{
@ -476,7 +481,7 @@ retry:
return -1;
}
if (c == cc)
if (c == QSE_T('\''))
{
/* terminating quote */
GET_CHAR (xli);
@ -486,6 +491,58 @@ retry:
ADD_TOKEN_CHAR (xli, tok, c);
}
}
else if (c == QSE_T('\"'))
{
/* double-quoted string - support escaping */
int escaped = 0;
SET_TOKEN_TYPE (xli, tok, TOK_DQSTR);
while (1)
{
GET_CHAR_TO (xli, c);
if (c == QSE_CHAR_EOF)
{
/* the string is not closed */
qse_xli_seterror (xli, QSE_XLI_ESTRNC, QSE_NULL, &xli->tok.loc);
return -1;
}
if (!escaped)
{
if (c == QSE_T('\\'))
{
escaped = 1;
continue;
}
if (c == QSE_T('\"'))
{
/* terminating quote */
GET_CHAR (xli);
break;
}
ADD_TOKEN_CHAR (xli, tok, c);
}
else
{
ADD_TOKEN_CHAR (xli, tok, c);
escaped = 0;
}
}
}
else if ((xli->tok_status & TOK_STATUS_ENABLE_NSTR) && QSE_ISDIGIT(c))
{
SET_TOKEN_TYPE (xli, tok, TOK_NSTR);
do
{
ADD_TOKEN_CHAR (xli, tok, c);
GET_CHAR_TO (xli, c);
}
while (QSE_ISDIGIT(c));
}
else
{
n = get_symbols (xli, c, tok);
@ -570,12 +627,14 @@ static int read_pair (qse_xli_t* xli)
goto oops;
}
xli->tok_status |= TOK_STATUS_ENABLE_NSTR;
if (get_token (xli) <= -1) goto oops;
if (xli->opt.trait & QSE_XLI_KEYNAME)
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))
if (MATCH (xli, TOK_IDENT) || MATCH (xli, TOK_DQSTR) || MATCH (xli, TOK_SQSTR) || MATCH(xli, TOK_NSTR))
{
qse_xli_atom_t* atom;
@ -583,9 +642,9 @@ static int read_pair (qse_xli_t* xli)
while (atom)
{
if (atom->type == QSE_XLI_PAIR &&
((qse_xli_pair_t*)atom)->name &&
((qse_xli_pair_t*)atom)->alias &&
qse_strcmp (((qse_xli_pair_t*)atom)->key, key) == 0 &&
qse_strcmp (((qse_xli_pair_t*)atom)->name, QSE_STR_PTR(xli->tok.name)) == 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);
goto oops;
@ -608,7 +667,7 @@ static int read_pair (qse_xli_t* xli)
{
if (get_token (xli) <= -1) goto oops;
if (MATCH (xli, TOK_SQSTR) || MATCH (xli, TOK_DQSTR) || MATCH (xli, TOK_IDENT))
if (MATCH (xli, TOK_SQSTR) || MATCH (xli, TOK_DQSTR) || MATCH(xli, TOK_NSTR) || MATCH (xli, TOK_IDENT))
{
qse_xli_str_t* curstrseg;
@ -626,7 +685,7 @@ static int read_pair (qse_xli_t* xli)
{
if (get_token (xli) <= -1) goto oops; /* skip the comma */
if (!MATCH (xli, TOK_SQSTR) && !MATCH (xli, TOK_DQSTR) && !MATCH (xli, TOK_IDENT))
if (!MATCH (xli, TOK_SQSTR) && !MATCH (xli, TOK_DQSTR) && !MATCH (xli, TOK_NSTR) && !MATCH (xli, TOK_IDENT))
{
qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc);
goto oops;
@ -656,9 +715,12 @@ static int read_pair (qse_xli_t* xli)
qse_xli_seterror (xli, QSE_XLI_EPAVAL, QSE_STR_CSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
}
else if (MATCH (xli, TOK_LBRACE))
{
xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR;
if (get_token (xli) <= -1) goto oops;
/* insert a pair with an empty list */
@ -684,8 +746,10 @@ static int read_pair (qse_xli_t* xli)
}
else if (MATCH (xli, TOK_SEMICOLON))
{
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, &xli->xnil);
pair = qse_xli_insertpair (xli, parlist, QSE_NULL, key, name, (qse_xli_val_t*)&xli->xnil);
if (pair == QSE_NULL) goto oops;
/* skip the semicolon */
@ -702,6 +766,7 @@ static int read_pair (qse_xli_t* xli)
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);
return -1;

View File

@ -145,13 +145,12 @@ static int write_to_current_stream (qse_xli_t* xli, const qse_char_t* ptr, qse_s
{
if (arg->b.len + 2 > QSE_COUNTOF(arg->b.buf) && flush (xli, arg) <= -1) return -1;
arg->b.buf[arg->b.len++] = QSE_T('\\');
arg->b.buf[arg->b.len++] = ptr[i];
}
else
{
if (arg->b.len + 1 > QSE_COUNTOF(arg->b.buf) && flush (xli, arg) <= -1) return -1;
arg->b.buf[arg->b.len++] = ptr[i];
}
arg->b.buf[arg->b.len++] = ptr[i];
}
return 0;
@ -177,10 +176,10 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth)
if (write_to_current_stream (xli, pair->key, qse_strlen(pair->key), 0) <= -1) return -1;
if (pair->name)
if (pair->alias)
{
if (write_to_current_stream (xli, QSE_T(" \""), 2, 0) <= -1 ||
write_to_current_stream (xli, pair->name, qse_strlen(pair->name), 1) <= -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;
}

View File

@ -52,18 +52,10 @@ void qse_xli_close (qse_xli_t* xli)
int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr)
{
qse_size_t i;
QSE_MEMSET (xli, 0, QSE_SIZEOF(*xli));
xli->mmgr = mmgr;
xli->errstr = qse_xli_dflerrstr;
for (i = 0; i < QSE_COUNTOF(xli->tmp); i++)
{
xli->tmp[i] = qse_str_open (mmgr, 0, 128);
if (xli->tmp[i] == QSE_NULL) goto oops;
}
xli->tok.name = qse_str_open (mmgr, 0, 128);
if (xli->tok.name == QSE_NULL) goto oops;
@ -74,26 +66,14 @@ int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr)
oops:
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
if (xli->tok.name) qse_str_close (xli->tok.name);
for (i = QSE_COUNTOF(xli->tmp); i > 0; )
{
if (xli->tmp[--i]) qse_str_close (xli->tmp[i]);
}
return -1;
}
void qse_xli_fini (qse_xli_t* xli)
{
qse_size_t i;
qse_xli_clear (xli);
qse_str_close (xli->tok.name);
for (i = QSE_COUNTOF(xli->tmp); i > 0; )
{
if (xli->tmp[--i]) qse_str_close (xli->tmp[i]);
}
qse_xli_clearrionames (xli);
qse_xli_clearwionames (xli);
}
@ -181,7 +161,6 @@ qse_xli_list_t* qse_xli_getroot (qse_xli_t* xli)
return &xli->root;
}
/* ------------------------------------------------------ */
static void insert_atom (
@ -218,19 +197,19 @@ static void insert_atom (
qse_xli_pair_t* qse_xli_insertpair (
qse_xli_t* xli, qse_xli_list_t* parent, qse_xli_atom_t* peer,
const qse_char_t* key, const qse_char_t* name, qse_xli_val_t* value)
const qse_char_t* key, const qse_char_t* alias, qse_xli_val_t* value)
{
qse_xli_pair_t* pair;
qse_size_t klen, nlen;
qse_char_t* kptr, * nptr;
klen = qse_strlen (key);
nlen = name? qse_strlen (name): 0;
nlen = alias? qse_strlen (alias): 0;
pair = qse_xli_callocmem (xli,
QSE_SIZEOF(*pair) +
((klen + 1) * QSE_SIZEOF(*key)) +
((nlen + 1) * QSE_SIZEOF(*name)));
((nlen + 1) * QSE_SIZEOF(*alias)));
if (pair == QSE_NULL) return QSE_NULL;
kptr = (qse_char_t*)(pair + 1);
@ -238,11 +217,11 @@ qse_xli_pair_t* qse_xli_insertpair (
pair->type = QSE_XLI_PAIR;
pair->key = kptr;
if (name)
if (alias)
{
nptr = kptr + klen + 1;
qse_strcpy (nptr, name);
pair->name = nptr;
qse_strcpy (nptr, alias);
pair->alias = nptr;
}
pair->val = value; /* this assumes it points to a dynamically allocated atom */
@ -252,7 +231,7 @@ qse_xli_pair_t* qse_xli_insertpair (
qse_xli_pair_t* qse_xli_insertpairwithemptylist (
qse_xli_t* xli, qse_xli_list_t* parent, qse_xli_atom_t* peer,
const qse_char_t* key, const qse_char_t* name)
const qse_char_t* key, const qse_char_t* alias)
{
qse_xli_list_t* val;
qse_xli_pair_t* tmp;
@ -261,14 +240,14 @@ qse_xli_pair_t* qse_xli_insertpairwithemptylist (
if (val == QSE_NULL) return QSE_NULL;
val->type = QSE_XLI_LIST;
tmp = qse_xli_insertpair (xli, parent, peer, key, name, (qse_xli_val_t*)val);
tmp = qse_xli_insertpair (xli, parent, peer, key, alias, (qse_xli_val_t*)val);
if (tmp == QSE_NULL) qse_xli_freemem (xli, val);
return tmp;
}
qse_xli_pair_t* qse_xli_insertpairwithstr (
qse_xli_t* xli, qse_xli_list_t* parent, qse_xli_atom_t* peer,
const qse_char_t* key, const qse_char_t* name, const qse_cstr_t* value)
const qse_char_t* key, const qse_char_t* alias, const qse_cstr_t* value)
{
qse_xli_str_t* val;
qse_xli_pair_t* tmp;
@ -282,7 +261,7 @@ qse_xli_pair_t* qse_xli_insertpairwithstr (
val->ptr = (const qse_char_t*)(val + 1);
val->len = value->len;
tmp = qse_xli_insertpair (xli, parent, peer, key, name, (qse_xli_val_t*)val);
tmp = qse_xli_insertpair (xli, parent, peer, key, alias, (qse_xli_val_t*)val);
if (tmp == QSE_NULL) qse_xli_freemem (xli, val);
return tmp;
}
@ -398,9 +377,9 @@ void qse_xli_clear (qse_xli_t* xli)
free_list (xli, &xli->root);
}
static qse_size_t count_pair_byname (
static qse_size_t count_pair_byalias (
qse_xli_t* xli, const qse_xli_list_t* list,
const qse_cstr_t* key, const qse_cstr_t* name)
const qse_cstr_t* key, const qse_cstr_t* alias)
{
qse_xli_atom_t* p;
qse_size_t count = 0;
@ -414,8 +393,8 @@ static qse_size_t count_pair_byname (
qse_xli_pair_t* pair = (qse_xli_pair_t*)p;
if (qse_strxcmp (key->ptr, key->len, pair->key) == 0)
{
if (name == QSE_NULL ||
qse_strxcmp (name->ptr, name->len, pair->name) == 0) count++;
if (alias == QSE_NULL ||
qse_strxcmp (alias->ptr, alias->len, pair->alias) == 0) count++;
}
}
@ -425,9 +404,9 @@ static qse_size_t count_pair_byname (
return count;
}
static qse_xli_pair_t* find_pair_byname (
static qse_xli_pair_t* find_pair_byalias (
qse_xli_t* xli, const qse_xli_list_t* list,
const qse_cstr_t* key, const qse_cstr_t* name)
const qse_cstr_t* key, const qse_cstr_t* alias)
{
qse_xli_atom_t* p;
@ -440,8 +419,8 @@ static qse_xli_pair_t* find_pair_byname (
qse_xli_pair_t* pair = (qse_xli_pair_t*)p;
if (qse_strxcmp (key->ptr, key->len, pair->key) == 0)
{
if (name == QSE_NULL ||
qse_strxcmp (name->ptr, name->len, pair->name) == 0) return pair;
if (alias == QSE_NULL ||
qse_strxcmp (alias->ptr, alias->len, pair->alias) == 0) return pair;
}
}
@ -478,7 +457,7 @@ static qse_xli_pair_t* find_pair_byindex (
return QSE_NULL;
}
qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name)
qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* alias)
{
const qse_char_t* ptr;
const qse_xli_list_t* curlist;
@ -487,7 +466,7 @@ qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* li
curlist = list? list: &xli->root;
ptr = name;
ptr = alias;
while (1)
{
seg.ptr = ptr;
@ -500,7 +479,7 @@ qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* li
/* 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 name easily. */
* to provide the segment alias easily. */
goto noent;
}
@ -540,7 +519,7 @@ qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* li
if (*ptr != QSE_T(']')) goto inval;
pair = find_pair_byname (xli, curlist, &seg, &idx);
pair = find_pair_byalias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 2; /* adjustment for error message */
@ -559,7 +538,7 @@ qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* li
if (*ptr != cc) goto inval;
if (*++ptr != QSE_T(']')) goto inval;
pair = find_pair_byname (xli, curlist, &seg, &idx);
pair = find_pair_byalias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 4; /* adjustment for error message */
@ -575,7 +554,7 @@ qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* li
}
else
{
pair = find_pair_byname (xli, curlist, &seg, QSE_NULL);
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
if (pair == QSE_NULL) goto noent;
if (*ptr == QSE_T('\0')) break; /* no more segments */
@ -587,7 +566,7 @@ qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* li
/* 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 name */
* just after having gotten the next segment alias */
curlist = (qse_xli_list_t*)pair->val;
}
@ -602,7 +581,7 @@ noent:
return QSE_NULL;
}
qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* name)
qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* alias)
{
const qse_char_t* ptr;
const qse_xli_list_t* curlist;
@ -611,7 +590,7 @@ qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list
curlist = list? list: &xli->root;
ptr = name;
ptr = alias;
while (1)
{
seg.ptr = ptr;
@ -624,7 +603,7 @@ qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list
/* 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 name easily. */
* to provide the segment alias easily. */
goto noent;
}
@ -664,7 +643,7 @@ qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list
if (*ptr != QSE_T(']')) goto inval;
pair = find_pair_byname (xli, curlist, &seg, &idx);
pair = find_pair_byalias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 2; /* adjustment for error message */
@ -683,7 +662,7 @@ qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list
if (*ptr != cc) goto inval;
if (*++ptr != QSE_T(']')) goto inval;
pair = find_pair_byname (xli, curlist, &seg, &idx);
pair = find_pair_byalias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 4; /* adjustment for error message */
@ -703,16 +682,16 @@ qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list
}
else
{
pair = find_pair_byname (xli, curlist, &seg, QSE_NULL);
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
if (pair == QSE_NULL) goto noent;
if (*ptr == QSE_T('\0'))
{
return count_pair_byname (xli, curlist, &seg, QSE_NULL);
return count_pair_byalias (xli, curlist, &seg, QSE_NULL);
}
else
{
pair = find_pair_byname (xli, curlist, &seg, QSE_NULL);
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
if (pair == QSE_NULL) goto noent;
}
}
@ -723,7 +702,7 @@ qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list
/* 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 name */
* just after having gotten the next segment alias */
curlist = (qse_xli_list_t*)pair->val;
}
@ -776,7 +755,6 @@ qse_char_t* qse_xli_dupflatstr (qse_xli_t* xli, qse_xli_str_t* str, qse_size_t*
}
tmp[x] = QSE_T('\0');
if (len) *len = x;
if (nsegs) *nsegs = y;

View File

@ -59,11 +59,11 @@ struct qse_xli_t
qse_xli_ecb_t* ecb;
qse_xli_nil_t xnil;
qse_xli_list_t root;
qse_xli_list_t root;
qse_xli_list_link_t* parlink;
qse_str_t* tmp[1];
qse_xli_tok_t tok;
int tok_status;
struct
{
qse_xli_io_impl_t impl; /* input handler */