finished implementing the initial ini-format reader.

added qse_xli_readinistd()
This commit is contained in:
hyung-hwan 2015-08-31 13:31:30 +00:00
parent 7cda6152f3
commit 9532597507
8 changed files with 174 additions and 64 deletions

View File

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

View File

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

View File

@ -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} */

View File

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

View File

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

View File

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

View File

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

View File

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