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} */
@ -543,9 +543,9 @@ QSE_EXPORT void qse_xli_seterrnum (
* message for a given error number. * message for a given error number.
*/ */
QSE_EXPORT void qse_xli_seterrmsg ( QSE_EXPORT void qse_xli_seterrmsg (
qse_xli_t* xli, /**< stream editor */ qse_xli_t* xli, /**< stream editor */
qse_xli_errnum_t errnum, /**< error number */ qse_xli_errnum_t errnum, /**< error number */
const qse_char_t* errmsg, /**< error message */ const qse_char_t* errmsg, /**< error message */
const qse_xli_loc_t* errloc /**< error location */ const qse_xli_loc_t* errloc /**< error location */
); );
@ -630,27 +630,27 @@ QSE_EXPORT qse_xli_pair_t* qse_xli_insertpairwithstrs (
); );
QSE_EXPORT qse_xli_text_t* qse_xli_inserttext ( QSE_EXPORT qse_xli_text_t* qse_xli_inserttext (
qse_xli_t* xli, qse_xli_t* xli,
qse_xli_list_t* parent, qse_xli_list_t* parent,
qse_xli_atom_t* peer, qse_xli_atom_t* peer,
const qse_char_t* str const qse_char_t* str
); );
QSE_EXPORT qse_xli_file_t* qse_xli_insertfile ( QSE_EXPORT qse_xli_file_t* qse_xli_insertfile (
qse_xli_t* xli, qse_xli_t* xli,
qse_xli_list_t* parent, qse_xli_list_t* parent,
qse_xli_atom_t* peer, qse_xli_atom_t* peer,
const qse_char_t* path const qse_char_t* path
); );
QSE_EXPORT qse_xli_eof_t* qse_xli_inserteof ( QSE_EXPORT qse_xli_eof_t* qse_xli_inserteof (
qse_xli_t* xli, qse_xli_t* xli,
qse_xli_list_t* parent, qse_xli_list_t* parent,
qse_xli_atom_t* peer qse_xli_atom_t* peer
); );
QSE_EXPORT qse_xli_pair_t* qse_xli_findpair ( QSE_EXPORT qse_xli_pair_t* qse_xli_findpair (
qse_xli_t* xli, qse_xli_t* xli,
const qse_xli_list_t* list, const qse_xli_list_t* list,
const qse_char_t* fqpn const qse_char_t* fqpn
); );
@ -681,10 +681,10 @@ QSE_EXPORT qse_xli_str_t* qse_xli_addsegtostr (
* segment is delimited by double '\0's. The string tags are not included. * segment is delimited by double '\0's. The string tags are not included.
*/ */
QSE_EXPORT qse_char_t* qse_xli_dupflatstr ( QSE_EXPORT qse_char_t* qse_xli_dupflatstr (
qse_xli_t* xli, qse_xli_t* xli,
qse_xli_str_t* str, qse_xli_str_t* str,
qse_size_t* len, qse_size_t* len,
qse_size_t* nsegs qse_size_t* nsegs
); );
QSE_EXPORT qse_xli_list_t* qse_xli_getroot ( QSE_EXPORT qse_xli_list_t* qse_xli_getroot (

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;
while (QSE_ISSPACE(c)) GET_CHAR_TO (xli, 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);
}
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,8 +279,8 @@ 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,6 +293,9 @@ 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)
{ {
@ -277,42 +303,107 @@ static int read_list (qse_xli_t* xli)
if (MATCH(xli, QSE_XLI_TOK_TAG)) if (MATCH(xli, QSE_XLI_TOK_TAG))
{ {
if (get_token(xli) <= -1) return -1; /* 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;
if (MATCH(xli, QSE_XLI_TOK_EOF)) break; while (1)
if (MATCH(xli, QSE_XLI_TOK_TAG)) continue;
if (!MATCH(xli, QSE_XLI_TOK_IDENT))
{ {
qse_xli_seterror (xli, QSE_XLI_EKEY, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); if (get_token(xli) <= -1) return -1;
return -1;
}
/* key is the token... */ if (MATCH(xli, QSE_XLI_TOK_EOF)) break;
xli->tok_status |= TOK_STATUS_SAME_LINE; if (MATCH(xli, QSE_XLI_TOK_TAG))
if (get_token (xli) <= -1) return -1; {
/* 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_EQ)) if (!MATCH(xli, QSE_XLI_TOK_IDENT))
{ {
qse_xli_seterror (xli, QSE_XLI_EEQ, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); qse_xli_seterror (xli, QSE_XLI_EKEY, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
return -1; return -1;
} }
xli->tok_status |= TOK_STATUS_UPTO_EOL; if (xli->opt.trait & QSE_XLI_KEYNODUP)
if (get_token (xli) <= -1) return -1; {
qse_xli_atom_t* atom;
xli->tok_status &= ~(TOK_STATUS_SAME_LINE | TOK_STATUS_UPTO_EOL); /* 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;
}
if (MATCH(xli, QSE_XLI_TOK_EOF)) atom = atom->prev;
{ }
/* empty value */ }
break;
}
if (!MATCH(xli, QSE_XLI_TOK_SQSTR)) key.len = QSE_STR_LEN(xli->tok.name);
{ key.ptr = qse_strdup (QSE_STR_PTR(xli->tok.name), xli->mmgr);
qse_xli_seterror (xli, QSE_XLI_EVAL, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc); if (key.ptr == QSE_NULL)
return -1; {
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))
{
QSE_MMGR_FREE (xli->mmgr, key.ptr);
qse_xli_seterror (xli, QSE_XLI_EEQ, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
return -1;
}
/* read the value */
xli->tok_status |= TOK_STATUS_UPTO_EOL;
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);
if (MATCH(xli, QSE_XLI_TOK_EOF))
{
/* 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;
}
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);
return -1;
}
} }
} }
else else

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;