finished implementing the initial ini-format reader.
added qse_xli_readinistd()
This commit is contained in:
parent
7cda6152f3
commit
9532597507
@ -413,7 +413,7 @@ static int xli_main (int argc, qse_char_t* argv[])
|
|||||||
in.u.file.path = g_input_file;
|
in.u.file.path = g_input_file;
|
||||||
in.u.file.cmgr = g_infile_cmgr;
|
in.u.file.cmgr = g_infile_cmgr;
|
||||||
|
|
||||||
if (qse_xli_readstd (xli, &in) <= -1)
|
if (qse_xli_readinistd (xli, &in) <= -1)
|
||||||
{
|
{
|
||||||
const qse_xli_loc_t* errloc;
|
const qse_xli_loc_t* errloc;
|
||||||
|
|
||||||
|
@ -129,6 +129,11 @@ QSE_EXPORT int qse_xli_readstd (
|
|||||||
qse_xli_iostd_t* in
|
qse_xli_iostd_t* in
|
||||||
);
|
);
|
||||||
|
|
||||||
|
QSE_EXPORT int qse_xli_readinistd (
|
||||||
|
qse_xli_t* xli,
|
||||||
|
qse_xli_iostd_t* in
|
||||||
|
);
|
||||||
|
|
||||||
QSE_EXPORT int qse_xli_writestd (
|
QSE_EXPORT int qse_xli_writestd (
|
||||||
qse_xli_t* xli,
|
qse_xli_t* xli,
|
||||||
qse_xli_iostd_t* out
|
qse_xli_iostd_t* out
|
||||||
|
@ -71,7 +71,7 @@ enum qse_xli_errnum_t
|
|||||||
QSE_XLI_ERBRCE, /**< } expected in place of '${0}' */
|
QSE_XLI_ERBRCE, /**< } expected in place of '${0}' */
|
||||||
QSE_XLI_EPAVAL, /**< pair value expected in place of '${0}' */
|
QSE_XLI_EPAVAL, /**< pair value expected in place of '${0}' */
|
||||||
QSE_XLI_ESTRNC, /**< string not closed */
|
QSE_XLI_ESTRNC, /**< string not closed */
|
||||||
QSE_XLI_ETAGNC, /**< string tag not closed */
|
QSE_XLI_ETAGNC, /**< tag not closed */
|
||||||
QSE_XLI_EINCLSTR ,/**< '@include' not followed by a string */
|
QSE_XLI_EINCLSTR ,/**< '@include' not followed by a string */
|
||||||
QSE_XLI_ELXCHR, /**< invalid character '${0} */
|
QSE_XLI_ELXCHR, /**< invalid character '${0} */
|
||||||
QSE_XLI_ETAGCHR, /**< invalid tag character '${0} */
|
QSE_XLI_ETAGCHR, /**< invalid tag character '${0} */
|
||||||
|
@ -67,7 +67,7 @@ const qse_char_t* qse_xli_dflerrstr (
|
|||||||
QSE_T("illegal value for '${0}'"),
|
QSE_T("illegal value for '${0}'"),
|
||||||
QSE_T("no value for '${0}'"),
|
QSE_T("no value for '${0}'"),
|
||||||
QSE_T("uncomplying number of string segments for '${0}'"),
|
QSE_T("uncomplying number of string segments for '${0}'"),
|
||||||
QSE_T("section tag expected in place of '${0}'"),
|
QSE_T("section tag expected in place of '${0}'")
|
||||||
};
|
};
|
||||||
|
|
||||||
return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))?
|
return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))?
|
||||||
|
@ -81,11 +81,20 @@ enum
|
|||||||
do { (tok)->type = (code); } while (0)
|
do { (tok)->type = (code); } while (0)
|
||||||
|
|
||||||
#define MATCH(xli,tok_type) ((xli)->tok.type == (tok_type))
|
#define MATCH(xli,tok_type) ((xli)->tok.type == (tok_type))
|
||||||
|
#define MATCH(xli,tok_type) ((xli)->tok.type == (tok_type))
|
||||||
|
|
||||||
static int skip_spaces (qse_xli_t* xli)
|
static int skip_spaces (qse_xli_t* xli)
|
||||||
{
|
{
|
||||||
qse_cint_t c = xli->rio.last.c;
|
qse_cint_t c = xli->rio.last.c;
|
||||||
|
if (xli->tok_status & TOK_STATUS_SAME_LINE)
|
||||||
|
{
|
||||||
|
while (QSE_ISSPACE(c) && c != QSE_T('\n')) GET_CHAR_TO (xli, c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
while (QSE_ISSPACE(c)) GET_CHAR_TO (xli, c);
|
while (QSE_ISSPACE(c)) GET_CHAR_TO (xli, c);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +105,6 @@ static int skip_comment (qse_xli_t* xli, qse_xli_tok_t* tok)
|
|||||||
if (c == QSE_T(';'))
|
if (c == QSE_T(';'))
|
||||||
{
|
{
|
||||||
/* skip up to \n */
|
/* skip up to \n */
|
||||||
/* TODO: support a different line terminator */
|
|
||||||
qse_str_clear (tok->name);
|
qse_str_clear (tok->name);
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -149,14 +157,21 @@ static int get_token_into (qse_xli_t* xli, qse_xli_tok_t* tok)
|
|||||||
|
|
||||||
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_SQSTR);
|
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_SQSTR);
|
||||||
|
|
||||||
while (1)
|
do
|
||||||
{
|
{
|
||||||
GET_CHAR_TO (xli, c);
|
|
||||||
if (c == QSE_CHAR_EOF || c == QSE_T(';')) break;
|
if (c == QSE_CHAR_EOF || c == QSE_T(';')) break;
|
||||||
|
if (c == QSE_T('\n'))
|
||||||
|
{
|
||||||
|
GET_CHAR (xli);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ADD_TOKEN_CHAR (xli, tok, c);
|
ADD_TOKEN_CHAR (xli, tok, c);
|
||||||
if (!QSE_ISSPACE(c)) xlen = QSE_STR_LEN(tok->name);
|
if (!QSE_ISSPACE(c)) xlen = QSE_STR_LEN(tok->name);
|
||||||
|
|
||||||
|
GET_CHAR_TO (xli, c);
|
||||||
}
|
}
|
||||||
|
while (1);
|
||||||
|
|
||||||
/* trim away trailing spaces */
|
/* trim away trailing spaces */
|
||||||
qse_str_setlen (tok->name, xlen);
|
qse_str_setlen (tok->name, xlen);
|
||||||
@ -172,7 +187,7 @@ static int get_token_into (qse_xli_t* xli, qse_xli_tok_t* tok)
|
|||||||
{
|
{
|
||||||
GET_CHAR_TO (xli, c);
|
GET_CHAR_TO (xli, c);
|
||||||
|
|
||||||
if (c == QSE_CHAR_EOF)
|
if (c == QSE_CHAR_EOF || c == QSE_T('\n'))
|
||||||
{
|
{
|
||||||
/* the string tag is not closed */
|
/* the string tag is not closed */
|
||||||
qse_xli_seterror (xli, QSE_XLI_ETAGNC, QSE_NULL, &xli->tok.loc);
|
qse_xli_seterror (xli, QSE_XLI_ETAGNC, QSE_NULL, &xli->tok.loc);
|
||||||
@ -238,16 +253,24 @@ static int get_token_into (qse_xli_t* xli, qse_xli_tok_t* tok)
|
|||||||
{
|
{
|
||||||
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_EQ);
|
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_EQ);
|
||||||
ADD_TOKEN_CHAR (xli, tok, c);
|
ADD_TOKEN_CHAR (xli, tok, c);
|
||||||
|
GET_CHAR (xli);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if ((xli->tok_status & TOK_STATUS_SAME_LINE) && c == QSE_T('\n'))
|
||||||
|
{
|
||||||
|
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_NL);
|
||||||
|
ADD_TOKEN_STR (xli, tok, QSE_T("<NL>"), 4);
|
||||||
|
GET_CHAR (xli);
|
||||||
|
}
|
||||||
/* not handled yet */
|
/* not handled yet */
|
||||||
if (c == QSE_T('\0'))
|
else if (c == QSE_T('\0'))
|
||||||
{
|
{
|
||||||
qse_cstr_t ea;
|
qse_cstr_t ea;
|
||||||
ea.ptr = QSE_T("<NUL>");
|
ea.ptr = QSE_T("<NUL>");
|
||||||
ea.len = 5;
|
ea.len = 5;
|
||||||
qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc);
|
qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -256,9 +279,9 @@ static int get_token_into (qse_xli_t* xli, qse_xli_tok_t* tok)
|
|||||||
ea.ptr = &cc;
|
ea.ptr = &cc;
|
||||||
ea.len = 1;
|
ea.len = 1;
|
||||||
qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc);
|
qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc);
|
||||||
}
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -270,17 +293,34 @@ static int get_token (qse_xli_t* xli)
|
|||||||
|
|
||||||
static int read_list (qse_xli_t* xli)
|
static int read_list (qse_xli_t* xli)
|
||||||
{
|
{
|
||||||
|
qse_xli_pair_t* pair;
|
||||||
|
qse_cstr_t key;
|
||||||
|
qse_xli_list_t* curlist;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
if (MATCH(xli, QSE_XLI_TOK_EOF)) break;
|
if (MATCH(xli, QSE_XLI_TOK_EOF)) break;
|
||||||
|
|
||||||
if (MATCH(xli, QSE_XLI_TOK_TAG))
|
if (MATCH(xli, QSE_XLI_TOK_TAG))
|
||||||
|
{
|
||||||
|
/* insert a pair with an empty list */
|
||||||
|
pair = qse_xli_insertpairwithemptylist (xli, &xli->root->list, QSE_NULL, QSE_STR_PTR(xli->tok.name), QSE_NULL, QSE_NULL);
|
||||||
|
if (pair == QSE_NULL) return -1;
|
||||||
|
curlist = (qse_xli_list_t*)pair->val;
|
||||||
|
|
||||||
|
while (1)
|
||||||
{
|
{
|
||||||
if (get_token(xli) <= -1) return -1;
|
if (get_token(xli) <= -1) return -1;
|
||||||
|
|
||||||
if (MATCH(xli, QSE_XLI_TOK_EOF)) break;
|
if (MATCH(xli, QSE_XLI_TOK_EOF)) break;
|
||||||
if (MATCH(xli, QSE_XLI_TOK_TAG)) continue;
|
if (MATCH(xli, QSE_XLI_TOK_TAG))
|
||||||
|
{
|
||||||
|
/* switch to a new tag */
|
||||||
|
pair = qse_xli_insertpairwithemptylist (xli, &xli->root->list, QSE_NULL, QSE_STR_PTR(xli->tok.name), QSE_NULL, QSE_NULL);
|
||||||
|
if (pair == QSE_NULL) return -1;
|
||||||
|
curlist = (qse_xli_list_t*)pair->val;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!MATCH(xli, QSE_XLI_TOK_IDENT))
|
if (!MATCH(xli, QSE_XLI_TOK_IDENT))
|
||||||
{
|
{
|
||||||
@ -288,33 +328,84 @@ static int read_list (qse_xli_t* xli)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* key is the token... */
|
if (xli->opt.trait & QSE_XLI_KEYNODUP)
|
||||||
xli->tok_status |= TOK_STATUS_SAME_LINE;
|
{
|
||||||
if (get_token (xli) <= -1) return -1;
|
qse_xli_atom_t* atom;
|
||||||
|
|
||||||
|
/* find any key conflicts in the current scope */
|
||||||
|
/* TODO: optimization. no sequential search */
|
||||||
|
atom = curlist->tail;
|
||||||
|
while (atom)
|
||||||
|
{
|
||||||
|
if (atom->type == QSE_XLI_PAIR &&
|
||||||
|
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);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
atom = atom->prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xli->tok_status |= TOK_STATUS_SAME_LINE;
|
||||||
|
if (get_token (xli) <= -1)
|
||||||
|
{
|
||||||
|
QSE_MMGR_FREE (xli->mmgr, key.ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (!MATCH(xli, QSE_XLI_TOK_EQ))
|
if (!MATCH(xli, QSE_XLI_TOK_EQ))
|
||||||
{
|
{
|
||||||
|
QSE_MMGR_FREE (xli->mmgr, key.ptr);
|
||||||
qse_xli_seterror (xli, QSE_XLI_EEQ, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
|
qse_xli_seterror (xli, QSE_XLI_EEQ, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* read the value */
|
||||||
xli->tok_status |= TOK_STATUS_UPTO_EOL;
|
xli->tok_status |= TOK_STATUS_UPTO_EOL;
|
||||||
if (get_token (xli) <= -1) return -1;
|
if (get_token (xli) <= -1)
|
||||||
|
{
|
||||||
|
QSE_MMGR_FREE (xli->mmgr, key.ptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
xli->tok_status &= ~(TOK_STATUS_SAME_LINE | TOK_STATUS_UPTO_EOL);
|
xli->tok_status &= ~(TOK_STATUS_SAME_LINE | TOK_STATUS_UPTO_EOL);
|
||||||
|
|
||||||
if (MATCH(xli, QSE_XLI_TOK_EOF))
|
if (MATCH(xli, QSE_XLI_TOK_EOF))
|
||||||
{
|
{
|
||||||
/* empty value */
|
/* empty value */
|
||||||
|
qse_cstr_t empty;
|
||||||
|
|
||||||
|
empty.ptr = QSE_T("");
|
||||||
|
empty.len = 0;
|
||||||
|
|
||||||
|
pair = qse_xli_insertpairwithstr (xli, curlist, QSE_NULL, key.ptr, QSE_NULL, QSE_NULL, &empty, QSE_NULL);
|
||||||
|
QSE_MMGR_FREE (xli->mmgr, key.ptr);
|
||||||
|
if (pair == QSE_NULL) return -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MATCH(xli, QSE_XLI_TOK_SQSTR))
|
if (MATCH(xli, QSE_XLI_TOK_SQSTR))
|
||||||
|
{
|
||||||
|
/* add a new pair with the initial string segment */
|
||||||
|
pair = qse_xli_insertpairwithstr (xli, curlist, QSE_NULL, key.ptr, QSE_NULL, QSE_NULL, QSE_STR_XSTR(xli->tok.name), QSE_NULL);
|
||||||
|
QSE_MMGR_FREE (xli->mmgr, key.ptr);
|
||||||
|
if (pair == QSE_NULL) return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
qse_xli_seterror (xli, QSE_XLI_EVAL, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
|
qse_xli_seterror (xli, QSE_XLI_EVAL, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qse_xli_seterror (xli, QSE_XLI_ESECTAG, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
|
qse_xli_seterror (xli, QSE_XLI_ESECTAG, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
|
||||||
|
@ -234,7 +234,7 @@ static int skip_comment (qse_xli_t* xli, qse_xli_tok_t* tok)
|
|||||||
if (c == QSE_T('#'))
|
if (c == QSE_T('#'))
|
||||||
{
|
{
|
||||||
/* skip up to \n */
|
/* skip up to \n */
|
||||||
/* TODO: support a different line terminator */
|
|
||||||
qse_str_clear (tok->name);
|
qse_str_clear (tok->name);
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -635,7 +635,7 @@ retry:
|
|||||||
{
|
{
|
||||||
GET_CHAR_TO (xli, c);
|
GET_CHAR_TO (xli, c);
|
||||||
|
|
||||||
if (c == QSE_CHAR_EOF)
|
if (c == QSE_CHAR_EOF || c == QSE_T('\n'))
|
||||||
{
|
{
|
||||||
/* the string tag is not closed */
|
/* the string tag is not closed */
|
||||||
qse_xli_seterror (xli, QSE_XLI_ETAGNC, QSE_NULL, &xli->tok.loc);
|
qse_xli_seterror (xli, QSE_XLI_ETAGNC, QSE_NULL, &xli->tok.loc);
|
||||||
|
@ -597,12 +597,6 @@ static qse_ssize_t sf_out (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int qse_xli_readstd (qse_xli_t* xli, qse_xli_iostd_t* in)
|
int qse_xli_readstd (qse_xli_t* xli, qse_xli_iostd_t* in)
|
||||||
{
|
{
|
||||||
xtn_t* xtn = (xtn_t*) QSE_XTN (xli);
|
xtn_t* xtn = (xtn_t*) QSE_XTN (xli);
|
||||||
@ -620,6 +614,25 @@ int qse_xli_readstd (qse_xli_t* xli, qse_xli_iostd_t* in)
|
|||||||
return qse_xli_read (xli, sf_in);
|
return qse_xli_read (xli, sf_in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int qse_xli_readinistd (qse_xli_t* xli, qse_xli_iostd_t* in)
|
||||||
|
{
|
||||||
|
xtn_t* xtn = (xtn_t*) QSE_XTN (xli);
|
||||||
|
|
||||||
|
if (in == QSE_NULL || (in->type != QSE_XLI_IOSTD_FILE &&
|
||||||
|
in->type != QSE_XLI_IOSTD_STR))
|
||||||
|
{
|
||||||
|
/* the input is a must. at least 1 file or 1 string
|
||||||
|
* must be specified */
|
||||||
|
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xtn->s.in.x = in;
|
||||||
|
return qse_xli_readini (xli, sf_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int qse_xli_writestd (qse_xli_t* xli, qse_xli_iostd_t* out)
|
int qse_xli_writestd (qse_xli_t* xli, qse_xli_iostd_t* out)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
@ -46,7 +46,8 @@ enum qse_xli_tok_type_t
|
|||||||
QSE_XLI_TOK_NSTR,
|
QSE_XLI_TOK_NSTR,
|
||||||
QSE_XLI_TOK_IDENT,
|
QSE_XLI_TOK_IDENT,
|
||||||
QSE_XLI_TOK_TEXT,
|
QSE_XLI_TOK_TEXT,
|
||||||
QSE_XLI_TOK_TAG
|
QSE_XLI_TOK_TAG,
|
||||||
|
QSE_XLI_TOK_NL
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum qse_xli_tok_type_t qse_xli_tok_type_t;
|
typedef enum qse_xli_tok_type_t qse_xli_tok_type_t;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user