reverted previous 2 commits for support json format in xli.

instead, i'm writing a different json format reader
This commit is contained in:
hyung-hwan 2018-01-09 10:45:43 +00:00
parent 6237b43441
commit 779b335710
15 changed files with 1583 additions and 403 deletions

View File

@ -58,6 +58,8 @@
#define IO_FLAG_INI_INPUT (1 << 0)
#define IO_FLAG_INI_OUTPUT (1 << 1)
#define IO_FLAG_JSON_INPUT (1 << 2)
#define IO_FLAG_JSON_OUTPUT (1 << 3)
static int g_io_flags = 0;
static qse_char_t* g_input_file = QSE_NULL;
@ -158,6 +160,8 @@ static void print_usage (qse_sio_t* out, int argc, qse_char_t* argv[])
qse_fprintf (out, QSE_T(" -o file specify an output file\n"));
qse_fprintf (out, QSE_T(" -I file specify an ini input file\n"));
qse_fprintf (out, QSE_T(" -O file specify an ini output file\n"));
qse_fprintf (out, QSE_T(" -j file specify a json input file\n"));
qse_fprintf (out, QSE_T(" -J file specify a json output file\n"));
qse_fprintf (out, QSE_T(" -u disallow duplicate keys\n"));
qse_fprintf (out, QSE_T(" -a allow a key alias\n"));
qse_fprintf (out, QSE_T(" -f keep file inclusion info\n"));
@ -168,7 +172,6 @@ static void print_usage (qse_sio_t* out, int argc, qse_char_t* argv[])
qse_fprintf (out, QSE_T(" -l disallow lists\n"));
qse_fprintf (out, QSE_T(" -K allow key tags\n"));
qse_fprintf (out, QSE_T(" -S allow string tags\n"));
qse_fprintf (out, QSE_T(" -j input and output in json format\n"));
qse_fprintf (out, QSE_T(" -v perform validation\n"));
qse_fprintf (out, QSE_T(" -m number specify the maximum amount of memory to use in bytes\n"));
#if defined(QSE_BUILD_DEBUG)
@ -196,15 +199,15 @@ static int handle_args (int argc, qse_char_t* argv[])
static qse_opt_t opt =
{
#if defined(QSE_BUILD_DEBUG)
QSE_T("hi:o:I:O:uaftsdnlKSjvm:X:"),
QSE_T("hi:o:I:O:j:J:uaftsdnlKSvm:X:"),
#else
QSE_T("hi:o:I:O:uaftsdnlKSjvm:"),
QSE_T("hi:o:I:O:j:J:uaftsdnlKSvm:"),
#endif
lng
};
qse_cint_t c;
while ((c = qse_getopt (argc, argv, &opt)) != QSE_CHAR_EOF)
while ((c = qse_getopt(argc, argv, &opt)) != QSE_CHAR_EOF)
{
switch (c)
{
@ -234,7 +237,7 @@ static int handle_args (int argc, qse_char_t* argv[])
case QSE_T('i'):
g_input_file = opt.arg;
g_io_flags &= ~IO_FLAG_INI_INPUT;
g_io_flags &= ~(IO_FLAG_INI_INPUT | IO_FLAG_JSON_OUTPUT);
break;
case QSE_T('I'):
@ -242,9 +245,14 @@ static int handle_args (int argc, qse_char_t* argv[])
g_io_flags |= IO_FLAG_INI_INPUT;
break;
case QSE_T('j'):
g_input_file = opt.arg;
g_io_flags |= IO_FLAG_JSON_INPUT;
break;
case QSE_T('o'):
g_output_file = opt.arg;
g_io_flags &= ~IO_FLAG_INI_OUTPUT;
g_io_flags &= ~(IO_FLAG_INI_OUTPUT | IO_FLAG_JSON_OUTPUT);
break;
case QSE_T('O'):
@ -252,6 +260,11 @@ static int handle_args (int argc, qse_char_t* argv[])
g_io_flags |= IO_FLAG_INI_OUTPUT;
break;
case QSE_T('J'):
g_output_file = opt.arg;
g_io_flags |= IO_FLAG_JSON_OUTPUT;
break;
case QSE_T('u'):
g_trait |= QSE_XLI_KEYNODUP;
break;
@ -292,10 +305,6 @@ static int handle_args (int argc, qse_char_t* argv[])
g_trait |= QSE_XLI_STRTAG;
break;
case QSE_T('j'):
g_trait |= QSE_XLI_JSON;
break;
case QSE_T('v'):
g_trait |= QSE_XLI_VALIDATE;
break;
@ -444,7 +453,9 @@ static int xli_main (int argc, qse_char_t* argv[])
in.u.file.path = g_input_file;
in.u.file.cmgr = g_infile_cmgr;
n = (g_io_flags & IO_FLAG_INI_INPUT)? qse_xli_readinistd(xli, &in): qse_xli_readstd(xli, &in);
n = (g_io_flags & IO_FLAG_JSON_INPUT)? qse_xli_readjsonstd(xli, &in):
(g_io_flags & IO_FLAG_INI_INPUT)? qse_xli_readinistd(xli, &in):
qse_xli_readstd(xli, &in);
if (n <= -1)
{
const qse_xli_loc_t* errloc;
@ -553,8 +564,9 @@ static int xli_main (int argc, qse_char_t* argv[])
out.u.file.path = g_output_file? g_output_file: QSE_T("-");
out.u.file.cmgr = g_outfile_cmgr;
ret = (g_io_flags & IO_FLAG_INI_OUTPUT)? qse_xli_writeinistd(xli, QSE_NULL, &out): qse_xli_writestd(xli, QSE_NULL, &out);
ret = (g_io_flags & IO_FLAG_JSON_OUTPUT)? qse_xli_writejsonstd(xli, QSE_NULL, &out):
(g_io_flags & IO_FLAG_INI_OUTPUT)? qse_xli_writeinistd(xli, QSE_NULL, &out):
qse_xli_writestd(xli, QSE_NULL, &out);
oops:
if (xli) qse_xli_close (xli);
if (xma_mmgr.ctx) qse_xma_close (xma_mmgr.ctx);

View File

@ -134,6 +134,12 @@ QSE_EXPORT int qse_xli_readinistd (
qse_xli_iostd_t* in
);
QSE_EXPORT int qse_xli_readjsonstd (
qse_xli_t* xli,
qse_xli_iostd_t* in
);
QSE_EXPORT int qse_xli_writestd (
qse_xli_t* xli,
qse_xli_list_t* root_list,
@ -146,6 +152,12 @@ QSE_EXPORT int qse_xli_writeinistd (
qse_xli_iostd_t* out
);
QSE_EXPORT int qse_xli_writejsonstd (
qse_xli_t* xli,
qse_xli_list_t* root_list,
qse_xli_iostd_t* out
);
#if defined(__cplusplus)
}
#endif

View File

@ -65,10 +65,12 @@ enum qse_xli_errnum_t
QSE_XLI_EIOUSR, /**< i/o handler error */
QSE_XLI_ESYNTAX, /**< syntax error */
QSE_XLI_ECOLON, /**< colon expected in place of '${0}' */
QSE_XLI_ESCOLON, /**< semicolon expected in place of '${0}' */
QSE_XLI_EASSIGN, /**< = expected in place of '${0}' */
QSE_XLI_EEQ, /**< = expected in place of '${0}' */
QSE_XLI_ELBREQ, /**< { or = expected in place of '${0}' */
QSE_XLI_ERBRCE, /**< } expected in place of '${0}' */
QSE_XLI_ERBRACE, /**< } expected in place of '${0}' */
QSE_XLI_ERBRACK, /**< ] expected in place of '${0}' */
QSE_XLI_EPAVAL, /**< pair value expected in place of '${0}' */
QSE_XLI_ESTRNC, /**< string not closed */
QSE_XLI_ETAGNC, /**< tag not closed */
@ -115,18 +117,7 @@ enum qse_xli_opt_t
*/
QSE_XLI_ROOTXTNSIZE,
/**
* It is a character to put between a parent key and a nested key.
* By default, it's a period and used like 'a.b.c' that means c under b under a.
*/
QSE_XLI_KEYSPLITTER,
/**
* The first character is in the tag marker speicifies the tag opener
* and the second chracter specifies the tag closer. The are used when
* key tags and/or string tags are enabled. By default, it is "[]".
*/
QSE_XLI_TAGMARKER
QSE_XLI_KEYSPLITTER
};
typedef enum qse_xli_opt_t qse_xli_opt_t;
@ -156,19 +147,14 @@ enum qse_xli_trait_t
* "tg" is stored into the tag field of qse_xli_str_t. */
QSE_XLI_STRTAG = (1 << 10),
/** support the json format */
QSE_XLI_JSON = (1 << 11),
/** enable pair validation against pair definitions while reading */
QSE_XLI_VALIDATE = (1 << 12)
QSE_XLI_VALIDATE = (1 << 11)
};
typedef enum qse_xli_trait_t qse_xli_trait_t;
typedef struct qse_xli_val_t qse_xli_val_t;
typedef struct qse_xli_nil_t qse_xli_nil_t;
typedef struct qse_xli_str_t qse_xli_str_t;
typedef struct qse_xli_int_t qse_xli_int_t;
typedef struct qse_xli_array_t qse_xli_array_t;
typedef struct qse_xli_list_t qse_xli_list_t;
typedef struct qse_xli_atom_t qse_xli_atom_t;
@ -223,26 +209,6 @@ struct qse_xli_str_t
qse_xli_str_t* next;
};
struct qse_xli_int_t
{
QSE_XLI_VAL_HDR;
const qse_char_t* tag;
const qse_char_t* ptr;
qse_size_t len;
/* TODO: include a numeric value here???
qse_intmax_t val;
*/
/* NEED TO SUPPORT MULTI NUBMER? */
};
struct qse_xli_array_t
{
QSE_XLI_VAL_HDR;
const qse_char_t* tag;
qse_xli_val_t* ptr;
qse_size_t count;
};
#define QSE_XLI_ATOM_HDR \
qse_xli_atom_type_t type; \
qse_xli_atom_t* prev; \
@ -261,8 +227,6 @@ struct qse_xli_pair_t
const qse_char_t* key;
const qse_char_t* alias;
const qse_char_t* tag;
unsigned int _key_quoted: 2; /* used internally for output */
unsigned int _alias_quoted: 2; /* used internally for output - in fact, an alias is always quoted */
qse_xli_val_t* val;
};
@ -404,10 +368,9 @@ enum qse_xli_scm_flag_t
QSE_XLI_SCM_VALNIL = (1 << 1),
QSE_XLI_SCM_VALSTR = (1 << 2),
QSE_XLI_SCM_VALLIST = (1 << 3),
QSE_XLI_SCM_VALARRAY = (1 << 4),
QSE_XLI_SCM_KEYNODUP = (1 << 5),
QSE_XLI_SCM_KEYALIAS = (1 << 6),
QSE_XLI_SCM_KEYNODUP = (1 << 4),
QSE_XLI_SCM_KEYALIAS = (1 << 5),
/** Indicates that the value is a list with uncertain definitions with
* the following constraints:
@ -418,7 +381,7 @@ enum qse_xli_scm_flag_t
* is specified.
*
* Applies only if #QSE_XLI_SCM_VALLIST is set. */
QSE_XLI_SCM_VALIFFY = (1 << 7)
QSE_XLI_SCM_VALIFFY = (1 << 6)
};
typedef enum qse_xli_scm_flag_t qse_xli_scm_flag_t;
@ -786,6 +749,11 @@ QSE_EXPORT int qse_xli_readini (
qse_xli_io_impl_t io
);
QSE_EXPORT int qse_xli_readjson (
qse_xli_t* xli,
qse_xli_io_impl_t io
);
QSE_EXPORT int qse_xli_write (
qse_xli_t* xli,
qse_xli_list_t* root_list,
@ -798,6 +766,12 @@ QSE_EXPORT int qse_xli_writeini (
qse_xli_io_impl_t io
);
QSE_EXPORT int qse_xli_writejson (
qse_xli_t* xli,
qse_xli_list_t* root_list,
qse_xli_io_impl_t io
);
QSE_EXPORT void* qse_getxlipairxtn (
qse_xli_pair_t* pair
);

View File

@ -5,7 +5,10 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/include
lib_LTLIBRARIES = libqsexli.la
libqsexli_la_SOURCES = xli.h xli.c err.c read.c read-ini.c write.c write-ini.c std.c
libqsexli_la_SOURCES = xli.h xli.c err.c \
read.c read-ini.c read-json.c \
write.c write-ini.c write-json.c \
std.c
libqsexli_la_LDFLAGS = -L../cmn -L../si -version-info 1:0:0 -no-undefined
libqsexli_la_LIBADD = -lqsesi -lqsecmn

View File

@ -135,8 +135,8 @@ am__uninstall_files_from_dir = { \
am__installdirs = "$(DESTDIR)$(libdir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libqsexli_la_DEPENDENCIES =
am_libqsexli_la_OBJECTS = xli.lo err.lo read.lo read-ini.lo write.lo \
write-ini.lo std.lo
am_libqsexli_la_OBJECTS = xli.lo err.lo read.lo read-ini.lo \
read-json.lo write.lo write-ini.lo write-json.lo std.lo
libqsexli_la_OBJECTS = $(am_libqsexli_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
@ -393,7 +393,11 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/include
lib_LTLIBRARIES = libqsexli.la
libqsexli_la_SOURCES = xli.h xli.c err.c read.c read-ini.c write.c write-ini.c std.c
libqsexli_la_SOURCES = xli.h xli.c err.c \
read.c read-ini.c read-json.c \
write.c write-ini.c write-json.c \
std.c
libqsexli_la_LDFLAGS = -L../cmn -L../si -version-info 1:0:0 -no-undefined
libqsexli_la_LIBADD = -lqsesi -lqsecmn
all: all-am
@ -476,9 +480,11 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/err.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read-ini.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read-json.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/read.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/std.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/write-ini.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/write-json.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/write.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xli.Plo@am__quote@

View File

@ -27,8 +27,7 @@
#include "xli.h"
#include "../cmn/mem-prv.h"
const qse_char_t* qse_xli_dflerrstr (
const qse_xli_t* xli, qse_xli_errnum_t errnum)
const qse_char_t* qse_xli_dflerrstr (const qse_xli_t* xli, qse_xli_errnum_t errnum)
{
static const qse_char_t* errstr[] =
{
@ -46,10 +45,12 @@ const qse_char_t* qse_xli_dflerrstr (
QSE_T("error returned by user I/O handler"),
QSE_T("syntax error"),
QSE_T("colon expected in place of '${0}'"),
QSE_T("semicolon expected in place of '${0}'"),
QSE_T("assignment symbol expected in place of '${0}'"),
QSE_T("left-brace or assignment token expected in place of '${0}'"),
QSE_T("equal-sign expected in place of '${0}'"),
QSE_T("left-brace or equal-sign expected in place of '${0}'"),
QSE_T("right-brace expected in place of '${0}'"),
QSE_T("right-bracket expected in place of '${0}'"),
QSE_T("pair value expected in place of '${0}'"),
QSE_T("string not closed"),
QSE_T("string tag not closed"),

View File

@ -378,7 +378,7 @@ static int read_list (qse_xli_t* xli)
if (!MATCH(xli, QSE_XLI_TOK_EQ))
{
qse_xli_seterror (xli, QSE_XLI_EASSIGN, 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);
goto oops;
}

891
qse/lib/xli/read-json.c Normal file
View File

@ -0,0 +1,891 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xli.h"
#include <qse/cmn/chr.h>
/*
"key1" {
# comment
[keytag]key11 "alias" = [strtag]"test machine;
key1122 {
key112233 = "hello";
}
}
}
*/
static int get_token (qse_xli_t* xli);
static int read_list (qse_xli_t* xli, qse_xli_list_t* lv);
static int read_array (qse_xli_t* xli, qse_xli_list_t* lv);
enum
{
TOK_STATUS_ENABLE_NSTR = (1 << 0)
};
#define GET_CHAR(xli) \
do { if (qse_xli_getchar(xli) <= -1) return -1; } while(0)
#define GET_CHAR_TO(xli,c) \
do { \
if (qse_xli_getchar(xli) <= -1) return -1; \
c = (xli)->rio.last.c; \
} while(0)
#define ADD_TOKEN_CHAR(xli,tok,c) \
do { \
if (qse_str_ccat((tok)->name,(c)) == (qse_size_t)-1) \
{ \
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); \
return -1; \
} \
} while (0)
#define ADD_TOKEN_STR(xli,tok,s,l) \
do { \
if (qse_str_ncat((tok)->name,(s),(l)) == (qse_size_t)-1) \
{ \
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL); \
return -1; \
} \
} while (0)
#define SET_TOKEN_TYPE(xli,tok,code) \
do { (tok)->type = (code); } while (0)
#define MATCH(xli,tok_type) ((xli)->tok.type == (tok_type))
typedef struct kwent_t kwent_t;
struct kwent_t
{
qse_cstr_t name;
int type;
};
/* note that the keyword must start with @. */
static kwent_t kwtab[] =
{
/* keep it sorted by the first field for binary search */
{ { QSE_T("@include"), 8 }, QSE_XLI_TOK_XINCLUDE }
};
static int skip_spaces (qse_xli_t* xli)
{
qse_cint_t c = xli->rio.last.c;
while (QSE_ISSPACE(c)) GET_CHAR_TO (xli, c);
return 0;
}
static int skip_comment (qse_xli_t* xli, qse_xli_tok_t* tok)
{
qse_cint_t c = xli->rio.last.c;
if (c == QSE_T('#'))
{
/* skip up to \n */
qse_str_clear (tok->name);
do
{
GET_CHAR_TO (xli, c);
if (c == QSE_T('\n') || c == QSE_CHAR_EOF) break;
if (xli->opt.trait & QSE_XLI_KEEPTEXT) ADD_TOKEN_CHAR (xli, tok, c);
}
while (1);
if ((xli->opt.trait & QSE_XLI_KEEPTEXT) &&
qse_xli_inserttext(xli, xli->parlink->list, QSE_NULL, QSE_STR_PTR(tok->name)) == QSE_NULL) return -1;
GET_CHAR (xli); /* eat the new line letter */
return 1; /* comment by # */
}
return 0;
}
static int classify_ident (qse_xli_t* xli, const qse_cstr_t* name)
{
/* perform binary search */
/* declaring left, right, mid to be the int type is ok
* because we know kwtab is small enough. */
int left = 0, right = QSE_COUNTOF(kwtab) - 1, mid;
while (left <= right)
{
int n;
kwent_t* kwp;
/*mid = (left + right) / 2;*/
mid = left + (right - left) / 2;
kwp = &kwtab[mid];
n = qse_strxncmp (kwp->name.ptr, kwp->name.len, name->ptr, name->len);
if (n > 0)
{
/* if left, right, mid were of qse_size_t,
* you would need the following line.
if (mid == 0) break;
*/
right = mid - 1;
}
else if (n < 0) left = mid + 1;
else return kwp->type;
}
return QSE_XLI_TOK_IDENT;
}
static int get_symbols (qse_xli_t* xli, qse_cint_t c, qse_xli_tok_t* tok)
{
struct ops_t
{
const qse_char_t* str;
qse_size_t len;
int tid;
};
static struct ops_t ops[] =
{
{ QSE_T(","), 1, QSE_XLI_TOK_COMMA },
{ QSE_T(":"), 1, QSE_XLI_TOK_COLON },
{ QSE_T(";"), 1, QSE_XLI_TOK_SEMICOLON },
{ QSE_T("{"), 1, QSE_XLI_TOK_LBRACE },
{ QSE_T("}"), 1, QSE_XLI_TOK_RBRACE },
{ QSE_T("["), 1, QSE_XLI_TOK_LBRACK },
{ QSE_T("]"), 1, QSE_XLI_TOK_RBRACK },
{ QSE_NULL, 0, 0, }
};
struct ops_t* p;
int idx = 0;
/* note that the loop below is not generaic enough.
* you must keep the operators strings in a particular order */
for (p = ops; p->str != QSE_NULL; )
{
if (p->str[idx] == QSE_T('\0'))
{
ADD_TOKEN_STR (xli, tok, p->str, p->len);
SET_TOKEN_TYPE (xli, tok, p->tid);
return 1;
}
if (c == p->str[idx])
{
idx++;
GET_CHAR_TO (xli, c);
continue;
}
p++;
}
return 0;
}
static int end_include (qse_xli_t* xli, int noeof)
{
int x;
qse_xli_io_arg_t* cur;
if (xli->rio.inp == &xli->rio.top) return 0; /* no include */
/* if it is an included file, close it and
* retry to read a character from an outer file */
x = xli->rio.impl (
xli, QSE_XLI_IO_CLOSE,
xli->rio.inp, QSE_NULL, 0);
/* if closing has failed, still destroy the
* sio structure first as normal and return
* the failure below. this way, the caller
* does not call QSE_XLI_SIO_CLOSE on
* xli->rio.inp again. */
cur = xli->rio.inp;
xli->rio.inp = xli->rio.inp->prev;
QSE_ASSERT (cur->name != QSE_NULL);
QSE_MMGR_FREE (xli->mmgr, cur);
/* xli->parse.depth.incl--; */
if ((xli->opt.trait & QSE_XLI_KEEPFILE) && !noeof &&
qse_xli_inserteof (xli, xli->parlink->list, QSE_NULL) == QSE_NULL) return -1;
if (x != 0)
{
/* the failure mentioned above is returned here */
if (xli->errnum == QSE_XLI_ENOERR)
qse_xli_seterrnum (xli, QSE_XLI_EIOUSR, QSE_NULL);
return -1;
}
xli->rio.last = xli->rio.inp->last;
return 1; /* ended the included file successfully */
}
static int begin_include (qse_xli_t* xli)
{
qse_link_t* link;
qse_xli_io_arg_t* arg = QSE_NULL;
link = (qse_link_t*) qse_xli_callocmem (xli,
QSE_SIZEOF(*link) + QSE_SIZEOF(qse_char_t) * (QSE_STR_LEN(xli->tok.name) + 1));
if (link == QSE_NULL) goto oops;
qse_strncpy ((qse_char_t*)(link + 1), QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name));
link->link = xli->rio_names;
xli->rio_names = link;
arg = (qse_xli_io_arg_t*) qse_xli_callocmem (xli, QSE_SIZEOF(*arg));
if (arg == QSE_NULL) goto oops;
arg->name = (const qse_char_t*)(link + 1);
arg->line = 1;
arg->colm = 1;
/* let the argument's prev point field to the current */
arg->prev = xli->rio.inp;
if (qse_xli_openrstream(xli, arg) <= -1) goto oops;
/* i update the current pointer after opening is successful */
xli->rio.inp = arg;
/* xli->parse.depth.incl++; */
/* read in the first character in the included file.
* so the next call to get_token() sees the character read
* from this file. */
if (qse_xli_getchar (xli) <= -1 || get_token (xli) <= -1)
{
end_include (xli, 1);
/* i don't jump to oops since i've called
* end_include() where xli->rio.inp/arg is freed. */
return -1;
}
if ((xli->opt.trait & QSE_XLI_KEEPFILE) &&
qse_xli_insertfile (xli, xli->parlink->list, QSE_NULL, arg->name) == QSE_NULL)
{
end_include (xli, 1);
return -1;
}
return 0;
oops:
/* i don't need to free 'link' since it's linked to
* xli->rio_names that's freed at the beginning of qse_xli_read()
* or by qse_xli_fini() */
if (arg) QSE_MMGR_FREE (xli->mmgr, arg);
return -1;
}
static int get_token_into (qse_xli_t* xli, qse_xli_tok_t* tok)
{
qse_cint_t c;
int n;
int skip_semicolon_after_include = 0;
retry:
do
{
if (skip_spaces (xli) <= -1) return -1;
if ((n = skip_comment (xli, tok)) <= -1) return -1;
}
while (n >= 1);
qse_str_clear (tok->name);
tok->loc.file = xli->rio.last.file;
tok->loc.line = xli->rio.last.line;
tok->loc.colm = xli->rio.last.colm;
c = xli->rio.last.c;
if (c == QSE_CHAR_EOF)
{
n = end_include (xli, 0);
if (n <= -1) return -1;
if (n >= 1)
{
/*xli->rio.last = xli->rio.inp->last;*/
/* mark that i'm retrying after end of an included file */
skip_semicolon_after_include = 1;
goto retry;
}
ADD_TOKEN_STR (xli, tok, QSE_T("<EOF>"), 5);
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_EOF);
}
else if (c == QSE_T('@'))
{
/* keyword/directive - start with @ */
int type;
ADD_TOKEN_CHAR (xli, tok, c);
GET_CHAR_TO (xli, c);
if (!QSE_ISALPHA (c))
{
/* this directive is empty, not followed by a valid word */
qse_xli_seterror (xli, QSE_XLI_EXKWEM, QSE_NULL, &tok->loc);
return -1;
}
/* expect an identifier starting with an alphabet. the identifier
* forming a keyword/directory is composed of alphabets. */
do
{
ADD_TOKEN_CHAR (xli, tok, c);
GET_CHAR_TO (xli, c);
}
while (QSE_ISALPHA (c));
type = classify_ident (xli, QSE_STR_XSTR(tok->name));
if (type == QSE_XLI_TOK_IDENT)
{
/* this keyword/directive is not recognized */
qse_xli_seterror (xli, QSE_XLI_EXKWNR, QSE_STR_XSTR(tok->name), &tok->loc);
return -1;
}
SET_TOKEN_TYPE (xli, tok, type);
}
else if (c == QSE_T('_') || QSE_ISALPHA (c) ||
(!(xli->tok_status & TOK_STATUS_ENABLE_NSTR) &&
(xli->opt.trait & QSE_XLI_LEADDIGIT) &&
QSE_ISDIGIT(c)))
{
int lead_digit = QSE_ISDIGIT(c);
int all_digits = 1;
/* a normal identifier can be composed of wider varieties of
* characters than a keyword/directive */
while (1)
{
ADD_TOKEN_CHAR (xli, tok, c);
GET_CHAR_TO (xli, c);
if (c == QSE_T('_') || c == QSE_T('-') || c == QSE_T('*') ||
c == QSE_T('/') || QSE_ISALPHA (c))
{
all_digits = 0;
}
else if (QSE_ISDIGIT(c))
{
/* nothing to do */
}
else break;
}
if (lead_digit && all_digits)
{
/* if an identifier begins with a digit, it must contain a non-digits character */
qse_xli_seterror (xli, QSE_XLI_EIDENT, QSE_STR_XSTR(tok->name), &tok->loc);
return -1;
}
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_IDENT);
}
else if ((xli->tok_status & TOK_STATUS_ENABLE_NSTR) && QSE_ISDIGIT(c))
{
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_NSTR);
do
{
ADD_TOKEN_CHAR (xli, tok, c);
GET_CHAR_TO (xli, c);
}
while (QSE_ISDIGIT(c));
}
else if (c == QSE_T('\''))
{
/* single-quoted string - no escaping */
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_SQSTR);
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, &tok->loc);
return -1;
}
if (c == QSE_T('\''))
{
/* terminating quote */
GET_CHAR (xli);
break;
}
ADD_TOKEN_CHAR (xli, tok, c);
}
}
else if (c == QSE_T('\"'))
{
/* double-quoted string - support escaping */
int escaped = 0;
SET_TOKEN_TYPE (xli, tok, QSE_XLI_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, &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
{
n = get_symbols (xli, c, tok);
if (n <= -1) return -1; /* hard failure */
if (n == 0)
{
/* not handled yet */
if (c == QSE_T('\0'))
{
qse_cstr_t ea;
ea.ptr = QSE_T("<NUL>");
ea.len = 5;
qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc);
}
else
{
qse_char_t cc = (qse_char_t)c;
qse_cstr_t ea;
ea.ptr = &cc;
ea.len = 1;
qse_xli_seterror (xli, QSE_XLI_ELXCHR, &ea, &tok->loc);
}
return -1;
}
if (skip_semicolon_after_include && tok->type == QSE_XLI_TOK_SEMICOLON)
{
/* this handles the optional semicolon after the
* included file named as in @include "file-name"; */
skip_semicolon_after_include = 0;
goto retry;
}
}
if (skip_semicolon_after_include)
{
/* semiclon has not been skipped yet */
qse_xli_seterror (xli, QSE_XLI_ESCOLON, QSE_STR_XSTR(tok->name), &tok->loc);
return -1;
}
printf ("TOKEN: %ls\n",QSE_STR_PTR(tok->name));
return 0;
}
static int get_token (qse_xli_t* xli)
{
return get_token_into (xli, &xli->tok);
}
static int check_token_for_key_eligibility (qse_xli_t* xli, qse_xli_list_t* parlist)
{
if (xli->opt.trait & QSE_XLI_KEYNODUP)
{
qse_xli_atom_t* atom;
/* find any key conflicts in the current scope */
/* TODO: optimization. no sequential search */
atom = parlist->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;
}
}
return 0;
}
static qse_xli_val_t* __read_value (qse_xli_t* xli)
{
while (1)
{
if (MATCH(xli, QSE_XLI_TOK_XINCLUDE))
{
if (get_token(xli) <= -1) return QSE_NULL;
if (!MATCH(xli,QSE_XLI_TOK_SQSTR) && !MATCH(xli,QSE_XLI_TOK_DQSTR))
{
qse_xli_seterror (xli, QSE_XLI_EINCLSTR, QSE_NULL, &xli->tok.loc);
return QSE_NULL;
}
if (begin_include(xli) <= -1) return QSE_NULL;
}
else if (/*MATCH(xli, QSE_XLI_TOK_IDENT) || */MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_SQSTR))
{
return (qse_xli_val_t*)qse_xli_makestrval(xli, QSE_STR_XSTR(xli->tok.name), QSE_NULL);
}
else if (MATCH(xli, QSE_XLI_TOK_LBRACE))
{
qse_xli_list_t* lv;
lv = qse_xli_makelistval (xli);
if (!lv) return QSE_NULL;
if (get_token(xli) <= -1 || read_list(xli, lv) <= -1)
{
qse_xli_freeval (xli, (qse_xli_val_t*)lv);
return QSE_NULL;
}
return (qse_xli_val_t*)lv;
}
else if (MATCH(xli, QSE_XLI_TOK_LBRACK))
{
qse_xli_list_t* lv;
lv = qse_xli_makelistval (xli);
if (!lv) return QSE_NULL;
if (get_token(xli) <= -1 || read_array(xli, lv) <= -1)
if (!lv)
{
qse_xli_freeval (xli, (qse_xli_val_t*)lv);
}
return (qse_xli_val_t*)lv;
}
else if (MATCH(xli, QSE_XLI_TOK_TEXT))
{
if (get_token(xli) <= -1) return QSE_NULL;
}
else
{
break;
}
}
return QSE_NULL;
}
struct rpair_t
{
qse_char_t* key;
qse_xli_val_t* val;
};
typedef struct rpair_t rpair_t;
static int read_pair (qse_xli_t* xli, rpair_t* pair)
{
qse_char_t* key = QSE_NULL;
qse_xli_val_t* val = QSE_NULL;
if (check_token_for_key_eligibility(xli, xli->parlink->list) <= -1) goto oops;
key = qse_strdup(QSE_STR_PTR(xli->tok.name), xli->mmgr);
if (key == QSE_NULL)
{
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
goto oops;
}
if (get_token(xli) <= -1) goto oops;
if (!MATCH(xli, QSE_XLI_TOK_COLON))
{
qse_xli_seterror (xli, QSE_XLI_ECOLON, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
if (get_token(xli) <= -1) goto oops;
val = __read_value(xli);
if (!val) goto oops;
pair->key = key;
pair->val = val;
return 0;
oops:
if (val) qse_xli_freeval (xli, val);
if (key) QSE_MMGR_FREE (xli->mmgr, key);
return -1;
}
static int __read_array (qse_xli_t* xli)
{
qse_xli_val_t* val;
qse_size_t index = 0;
qse_char_t key[64];
while (1)
{
val = __read_value(xli);
if (!val) return -1;
qse_strxfmt (key, QSE_COUNTOF(key), QSE_T("%zu"), index);
if (!qse_xli_insertpair (xli, xli->parlink->list, QSE_NULL, key, QSE_NULL, QSE_NULL, val)) return -1;
index++;
if (get_token(xli) <= -1) return -1;
if (MATCH(xli, QSE_XLI_TOK_COMMA))
{
if (get_token(xli) <= -1) return -1;
continue;
}
if (MATCH(xli, QSE_XLI_TOK_RBRACK)) break;
}
return 0;
}
static int read_array (qse_xli_t* xli, qse_xli_list_t* lv)
{
qse_xli_list_link_t* ll;
int n;
ll = qse_xli_makelistlink (xli, lv);
if (!ll) return -1;
n = __read_array(xli);
qse_xli_freelistlink (xli, ll);
if (n <= -1) return -1;
if (!MATCH(xli, QSE_XLI_TOK_RBRACK))
{
qse_xli_seterror (xli, QSE_XLI_ERBRACK, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
return -1;
}
return 0;
}
static int __read_list (qse_xli_t* xli)
{
while (1)
{
if (MATCH(xli, QSE_XLI_TOK_XINCLUDE))
{
if (get_token(xli) <= -1) return -1;
if (!MATCH(xli,QSE_XLI_TOK_SQSTR) && !MATCH(xli,QSE_XLI_TOK_DQSTR))
{
qse_xli_seterror (xli, QSE_XLI_EINCLSTR, QSE_NULL, &xli->tok.loc);
return -1;
}
if (begin_include (xli) <= -1) return -1;
}
else if (/*MATCH(xli, QSE_XLI_TOK_IDENT) ||*/ MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_SQSTR))
{
rpair_t rpair;
if (read_pair(xli, &rpair) <= -1) return -1;
if (!qse_xli_insertpair (xli, xli->parlink->list, QSE_NULL, rpair.key, QSE_NULL, QSE_NULL, rpair.val))
{
QSE_MMGR_FREE (xli->mmgr, rpair.key);
qse_xli_freeval (xli, rpair.val);
return -1;
}
/* clear the duplicated key. the key is also duplicated in qse_xli_insertpair(). don't need it */
QSE_MMGR_FREE (xli->mmgr, rpair.key);
if (get_token(xli) <= -1) return -1;
if (MATCH(xli, QSE_XLI_TOK_COMMA))
{
if (get_token(xli) <= -1) return -1;
continue;
}
break;
}
else if (MATCH(xli, QSE_XLI_TOK_TEXT))
{
if (get_token(xli) <= -1) return -1;
}
else
{
break;
}
}
return 0;
}
static int read_list (qse_xli_t* xli, qse_xli_list_t* lv)
{
qse_xli_list_link_t* ll;
int n;
ll = qse_xli_makelistlink (xli, lv);
if (!ll) return -1;
n = __read_list(xli);
qse_xli_freelistlink (xli, ll);
if (n <= -1) return -1;
if (!MATCH(xli, QSE_XLI_TOK_RBRACE))
{
qse_xli_seterror (xli, QSE_XLI_ERBRACE, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
return -1;
}
return 0;
}
static int read_root_list (qse_xli_t* xli)
{
qse_xli_list_link_t* link;
link = qse_xli_makelistlink (xli, &xli->root->list);
if (!link) return -1;
if (qse_xli_getchar(xli) <= -1 || get_token(xli) <= -1 || __read_list(xli) <= -1)
{
qse_xli_freelistlink (xli, link);
return -1;
}
QSE_ASSERT (link == xli->parlink);
qse_xli_freelistlink (xli, link);
return 0;
}
int qse_xli_readjson (qse_xli_t* xli, qse_xli_io_impl_t io)
{
if (!io)
{
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
QSE_MEMSET (&xli->rio, 0, QSE_SIZEOF(xli->rio));
xli->rio.impl = io;
xli->rio.top.line = 1;
xli->rio.top.colm = 1;
xli->rio.inp = &xli->rio.top;
xli->tok_status = 0;
qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL);
qse_xli_clearrionames (xli);
QSE_ASSERT (QSE_STR_LEN(xli->dotted_curkey) == 0);
if (qse_xli_openrstream (xli, xli->rio.inp) <= -1) return -1;
/* the input stream is open now */
if (read_root_list (xli) <= -1) goto oops;
QSE_ASSERT (xli->parlink == QSE_NULL);
if (!MATCH (xli, QSE_XLI_TOK_EOF))
{
qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc);
goto oops;
}
QSE_ASSERT (xli->rio.inp == &xli->rio.top);
qse_xli_closeactiverstream (xli);
qse_str_clear (xli->tok.name);
return 0;
oops:
/* an error occurred and control has reached here
* probably, some included files might not have been
* closed. close them */
while (xli->rio.inp != &xli->rio.top)
{
qse_xli_io_arg_t* prev;
/* nothing much to do about a close error */
qse_xli_closeactiverstream (xli);
prev = xli->rio.inp->prev;
QSE_ASSERT (xli->rio.inp->name != QSE_NULL);
QSE_MMGR_FREE (xli->mmgr, xli->rio.inp);
xli->rio.inp = prev;
}
qse_xli_closeactiverstream (xli);
qse_str_clear (xli->tok.name);
return -1;
}

View File

@ -27,20 +27,6 @@
#include "xli.h"
#include <qse/cmn/chr.h>
/*
"key1" {
# comment
[keytag]key11 "alias" = [strtag]"test machine;
key1122 {
key112233 = "hello";
}
}
}
*/
static qse_char_t tag_opener[] = { QSE_T('['), QSE_T('(') };
static qse_char_t tag_closer[] = { QSE_T(']'), QSE_T(')') };
static int get_token (qse_xli_t* xli);
static int read_list (qse_xli_t* xli, qse_xli_list_t* list, const qse_xli_scm_t* override);
@ -307,37 +293,32 @@ static int get_symbols (qse_xli_t* xli, qse_cint_t c, qse_xli_tok_t* tok)
{
const qse_char_t* str;
qse_size_t len;
int tid[2]; /* normal id, alternative id */
int tid;
};
static struct ops_t ops[] =
{
{ QSE_T("="), 1, { QSE_XLI_TOK_EQ, QSE_XLI_TOK_COLON } },
{ QSE_T(":"), 1, { QSE_XLI_TOK_COLON, QSE_XLI_TOK_EQ } },
{ QSE_T(","), 1, { QSE_XLI_TOK_COMMA, QSE_XLI_TOK_COMMA } },
{ QSE_T(";"), 1, { QSE_XLI_TOK_SEMICOLON, QSE_XLI_TOK_SEMICOLON } },
{ QSE_T("{"), 1, { QSE_XLI_TOK_LBRACE, QSE_XLI_TOK_LBRACE } },
{ QSE_T("}"), 1, { QSE_XLI_TOK_RBRACE, QSE_XLI_TOK_RBRACE } },
{ QSE_T("["), 1, { QSE_XLI_TOK_LBRACK, QSE_XLI_TOK_LPAREN } },
{ QSE_T("]"), 1, { QSE_XLI_TOK_RBRACK, QSE_XLI_TOK_RPAREN } },
{ QSE_T("("), 1, { QSE_XLI_TOK_LPAREN, QSE_XLI_TOK_LBRACK } },
{ QSE_T(")"), 1, { QSE_XLI_TOK_RPAREN, QSE_XLI_TOK_RBRACK } },
{ QSE_NULL, 0, { 0, 0 } }
{ QSE_T("="), 1, QSE_XLI_TOK_EQ },
{ QSE_T(","), 1, QSE_XLI_TOK_COMMA },
{ QSE_T(";"), 1, QSE_XLI_TOK_SEMICOLON },
{ QSE_T("{"), 1, QSE_XLI_TOK_LBRACE },
{ QSE_T("}"), 1, QSE_XLI_TOK_RBRACE },
{ QSE_NULL, 0, 0, }
};
struct ops_t* p;
int idx = 0;
int tid_mode = (xli->opt.trait & QSE_XLI_JSON)? 1: 0;
/* note that the loop below is not generaic enough.
* you must keep the operators strings in a particular order */
for (p = ops; p->str != QSE_NULL; )
{
if (p->str[idx] == QSE_T('\0'))
{
ADD_TOKEN_STR (xli, tok, p->str, p->len);
SET_TOKEN_TYPE (xli, tok, p->tid[tid_mode]);
SET_TOKEN_TYPE (xli, tok, p->tid);
return 1;
}
@ -458,7 +439,7 @@ oops:
static int get_token_into (qse_xli_t* xli, qse_xli_tok_t* tok)
{
qse_cint_t c;
int n, tag_mode = (xli->opt.trait & QSE_XLI_JSON)? 1: 0;
int n;
int skip_semicolon_after_include = 0;
retry:
@ -530,8 +511,6 @@ retry:
(xli->opt.trait & QSE_XLI_LEADDIGIT) &&
QSE_ISDIGIT(c)))
{
/* if you change the rules here, you need to update
* need_quoting() in write.c */
int lead_digit = QSE_ISDIGIT(c);
int all_digits = 1;
@ -543,8 +522,8 @@ retry:
GET_CHAR_TO (xli, c);
if (c == QSE_T('_') || c == QSE_T('-') ||
(!(xli->opt.trait & QSE_XLI_JSON) && c == QSE_T(':')) ||
c == QSE_T('*') || c == QSE_T('/') || QSE_ISALPHA (c))
c == QSE_T(':') || c == QSE_T('*') ||
c == QSE_T('/') || QSE_ISALPHA (c))
{
all_digits = 0;
}
@ -557,7 +536,7 @@ retry:
if (lead_digit && all_digits)
{
/* if an identifier begins with a digit, it must contain a non-digit character */
/* if an identifier begins with a digit, it must contain a non-digits character */
qse_xli_seterror (xli, QSE_XLI_EIDENT, QSE_STR_XSTR(tok->name), &tok->loc);
return -1;
}
@ -642,17 +621,15 @@ retry:
}
}
}
else if ((xli->opt.trait & (QSE_XLI_KEYTAG | QSE_XLI_STRTAG)) && c == tag_opener[tag_mode]) /* [ */
else if ((xli->opt.trait & (QSE_XLI_KEYTAG | QSE_XLI_STRTAG)) && c == QSE_T('['))
{
/* a string tag is a bracketed word placed in front of a string value.
* A = [tg] "abc";
* "tg" is stored into the tag field of qse_xli_str_t.
*
* however, the tag opener and the closer are not hard-coded. you may
* use a different opener and closer depending on your requirement.
*/
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_TAG);
SET_TOKEN_TYPE (xli, tok, QSE_XLI_TOK_TAG);
while (1)
{
GET_CHAR_TO (xli, c);
@ -664,7 +641,7 @@ retry:
return -1;
}
if (c == tag_closer[tag_mode]) /* ] */
if (c == QSE_T(']'))
{
/* terminating quote */
GET_CHAR (xli);
@ -747,7 +724,6 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
const qse_xli_scm_t* scm = QSE_NULL;
int key_nodup = 0, key_alias = 0, val_iffy = 0;
/*int key_quoted = 0, alias_quoted = 0;*/
key.ptr = QSE_NULL;
name = QSE_NULL;
@ -759,11 +735,9 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
if (xli->opt.trait & QSE_XLI_KEYNODUP) key_nodup = 1;
if (xli->opt.trait & QSE_XLI_KEYALIAS) key_alias = 1;
/*if (MATCH(xli, QSE_XLI_TOK_SQSTR)) key_quoted = 1;
else if (MATCH(xli, QSE_XLI_TOK_DQSTR)) key_quoted = 2;*/
kloc = xli->tok.loc;
key.len = QSE_STR_LEN(xli->tok.name);
key.ptr = qse_strdup(QSE_STR_PTR(xli->tok.name), xli->mmgr);
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);
@ -771,8 +745,8 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
}
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)
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;
@ -810,7 +784,7 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
while (atom)
{
if (atom->type == QSE_XLI_PAIR &&
qse_strcmp(((qse_xli_pair_t*)atom)->key, QSE_STR_PTR(xli->tok.name)) == 0)
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);
goto oops;
@ -820,15 +794,15 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
}
}
/* once the key name is read, enable the numeric string for a key alias and a value */
/* once the key name is read, enable the numeric string for a value */
xli->tok_status |= TOK_STATUS_ENABLE_NSTR;
if (get_token(xli) <= -1) goto oops;
if (get_token (xli) <= -1) goto oops;
if (key_alias)
{
/* the alias part must be unique for the same key(s) */
if (MATCH(xli, QSE_XLI_TOK_IDENT) || MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_NSTR))
if (MATCH(xli, QSE_XLI_TOK_IDENT) || MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_NSTR))
{
qse_xli_atom_t* atom;
@ -853,9 +827,6 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
goto oops;
}
/*if (MATCH(xli, QSE_XLI_TOK_SQSTR)) alias_quoted = 1;
else if (MATCH(xli, QSE_XLI_TOK_DQSTR)) alias_quoted = 2;*/
if (get_token (xli) <= -1) goto oops;
}
else if (key_alias == 2)
@ -871,9 +842,7 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
{
if (get_token (xli) <= -1) goto oops;
if (!(xli->opt.trait & QSE_XLI_NOLIST) && MATCH(xli, QSE_XLI_TOK_LBRACE)) goto handle_list;
if ((xli->opt.trait & QSE_XLI_STRTAG) && MATCH (xli, QSE_XLI_TOK_TAG))
if ((xli->opt.trait & QSE_XLI_STRTAG) && MATCH(xli, QSE_XLI_TOK_TAG))
{
strtag = qse_strxdup (QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr);
if (strtag == QSE_NULL)
@ -901,11 +870,6 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
pair = qse_xli_insertpairwithstr (xli, parlist, QSE_NULL, key.ptr, name, keytag, QSE_STR_XSTR(xli->tok.name), strtag);
if (pair == QSE_NULL) goto oops;
#if 0
pair->_key_quoted = key_quoted; /* store this for easier output support */
pair->_alias_quoted = alias_quoted;
#endif
segcount++;
curstrseg = (qse_xli_str_t*)pair->val;
@ -923,7 +887,7 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
strtag = QSE_NULL;
}
if ((xli->opt.trait & QSE_XLI_STRTAG) && MATCH (xli, QSE_XLI_TOK_TAG))
if ((xli->opt.trait & QSE_XLI_STRTAG) && MATCH(xli, QSE_XLI_TOK_TAG))
{
strtag = qse_strxdup (QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr);
if (strtag == QSE_NULL)
@ -935,7 +899,7 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
if (get_token (xli) <= -1) goto oops;
}
if (!MATCH (xli, QSE_XLI_TOK_SQSTR) && !MATCH (xli, QSE_XLI_TOK_DQSTR) && !MATCH (xli, QSE_XLI_TOK_NSTR) && !MATCH (xli, QSE_XLI_TOK_IDENT))
if (!MATCH(xli, QSE_XLI_TOK_SQSTR) && !MATCH(xli, QSE_XLI_TOK_DQSTR) && !MATCH(xli, QSE_XLI_TOK_NSTR) && !MATCH(xli, QSE_XLI_TOK_IDENT))
{
qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc);
goto oops;
@ -948,11 +912,11 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
segcount++;
if (get_token (xli) <= -1) goto oops; /* skip the value */
}
while (MATCH (xli, QSE_XLI_TOK_COMMA));
while (MATCH(xli, QSE_XLI_TOK_COMMA));
}
/* semicolon is mandatory for a string */
if (!MATCH (xli, QSE_XLI_TOK_SEMICOLON))
if (!MATCH(xli, QSE_XLI_TOK_SEMICOLON))
{
qse_xli_seterror (xli, QSE_XLI_ESCOLON, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
@ -975,17 +939,12 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
goto oops;
}
/* TODO: check against schema */
}
else if (xli->opt.trait & QSE_XLI_JSON)
else if (!(xli->opt.trait & QSE_XLI_NOLIST) && MATCH(xli, QSE_XLI_TOK_LBRACE))
{
/* the assignment operator is mandator */
qse_xli_seterror (xli, QSE_XLI_EASSIGN, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
else if (!(xli->opt.trait & QSE_XLI_NOLIST) && MATCH (xli, QSE_XLI_TOK_LBRACE))
{
handle_list:
if (scm && !(scm->flags & QSE_XLI_SCM_VALLIST))
{
/* check the value type */
@ -996,25 +955,25 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR;
/* insert a pair with an empty list */
pair = qse_xli_insertpairwithemptylist (xli, parlist, QSE_NULL, key.ptr, name, keytag);
pair = qse_xli_insertpairwithemptylist(xli, parlist, QSE_NULL, key.ptr, name, keytag);
if (pair == QSE_NULL) goto oops;
/* skip validations of child pairs if the schema for the
* current pair is set with QSE_XLI_SCM_VALIFFY.
* the schema for the child pairs, if specified, must not
* take effect. */
if (read_list (xli, (qse_xli_list_t*)pair->val, (val_iffy? &scm_val_iffy: QSE_NULL)) <= -1) goto oops;
if (!MATCH (xli, QSE_XLI_TOK_RBRACE))
if (read_list(xli, (qse_xli_list_t*)pair->val, (val_iffy? &scm_val_iffy: QSE_NULL)) <= -1) goto oops;
if (!MATCH(xli, QSE_XLI_TOK_RBRACE))
{
qse_xli_seterror (xli, QSE_XLI_ERBRCE, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
qse_xli_seterror (xli, QSE_XLI_ERBRACE, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
goto oops;
}
if (get_token (xli) <= -1) goto oops;
if (get_token(xli) <= -1) goto oops;
/* semicolon is optional for a list */
if (MATCH (xli, QSE_XLI_TOK_SEMICOLON))
if (MATCH(xli, QSE_XLI_TOK_SEMICOLON))
{
/* skip the semicolon */
if (get_token (xli) <= -1) goto oops;
@ -1022,7 +981,7 @@ static int read_pair (qse_xli_t* xli, const qse_char_t* keytag, const qse_xli_sc
/* TODO: check against schema */
}
else if (MATCH (xli, QSE_XLI_TOK_SEMICOLON))
else if (MATCH(xli, QSE_XLI_TOK_SEMICOLON))
{
if (xli->opt.trait & QSE_XLI_NONIL)
{
@ -1087,18 +1046,16 @@ qse_xli_list_link_t* qse_xli_makelistlink (qse_xli_t* xli, qse_xli_list_t* parli
void qse_xli_freelistlink (qse_xli_t* xli, qse_xli_list_link_t* link)
{
QSE_ASSERT (xli->parlink == link);
xli->parlink = link->next;
qse_xli_freemem (xli, link);
}
#if 0
static int __read_array (qse_xli_t* xli, int opt_outer_brace)
static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override)
{
qse_size_t pair_count = 0;
while (1)
{
if (MATCH (xli, QSE_XLI_TOK_XINCLUDE))
if (MATCH(xli, QSE_XLI_TOK_XINCLUDE))
{
if (get_token(xli) <= -1) return -1;
@ -1110,85 +1067,12 @@ static int __read_array (qse_xli_t* xli, int opt_outer_brace)
if (begin_include (xli) <= -1) return -1;
}
else if (opt_outer_brace == 1 && pair_count == 0 && MATCH(xli, QSE_XLI_TOK_LBRACK))
{
opt_outer_brace++;
if (get_token(xli) <= -1) return -1;
}
else if (MATCH(xli, QSE_XLI_TOK_IDENT) || MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_DQSTR))
{
//if (read_pair(xli, QSE_NULL, override) <= -1) return -1;
pair_count++;
}
else if (MATCH(xli, QSE_XLI_TOK_LBRACE))
{
}
else if (MATCH(xli, QSE_XLI_TOK_LBRACK))
{
if (get_token(xli) <= -1) return -1;
if (__read_array(xli, 0) <= -1) return -1;
if (!MATCH(xli, QSE_XLI_TOK_RBRACK))
{
}
if (get_token(xli) <= -1) return -1;
}
else if (MATCH(xli, QSE_XLI_TOK_TEXT))
{
if (get_token(xli) <= -1) return -1;
}
else
{
break;
}
}
if (opt_outer_brace >= 2)
{
if (!MATCH(xli, QSE_XLI_TOK_RBRACE))
{
qse_xli_seterror (xli, QSE_XLI_ERBRCE, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
return -1;
}
if (get_token(xli) <= -1) return -1;
}
return 0;
}
#endif
static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override, int opt_outer_brace)
{
qse_size_t pair_count = 0;
while (1)
{
if (MATCH (xli, QSE_XLI_TOK_XINCLUDE))
{
if (get_token(xli) <= -1) return -1;
if (!MATCH(xli,QSE_XLI_TOK_SQSTR) && !MATCH(xli,QSE_XLI_TOK_DQSTR))
{
qse_xli_seterror (xli, QSE_XLI_EINCLSTR, QSE_NULL, &xli->tok.loc);
return -1;
}
if (begin_include (xli) <= -1) return -1;
}
else if (opt_outer_brace == 1 && pair_count == 0 && MATCH(xli, QSE_XLI_TOK_LBRACE))
{
opt_outer_brace++;
if (get_token(xli) <= -1) return -1;
}
else if ((xli->opt.trait & QSE_XLI_KEYTAG) && MATCH(xli, QSE_XLI_TOK_TAG))
{
qse_char_t* keytag;
int x;
keytag = qse_strxdup(QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr);
keytag = qse_strxdup (QSE_STR_PTR(xli->tok.name), QSE_STR_LEN(xli->tok.name), xli->mmgr);
if (keytag == QSE_NULL)
{
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
@ -1201,7 +1085,7 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override, int opt_o
return -1;
}
if (!MATCH(xli,QSE_XLI_TOK_IDENT) && !MATCH(xli,QSE_XLI_TOK_SQSTR) && !MATCH(xli,QSE_XLI_TOK_DQSTR))
if (!MATCH(xli, QSE_XLI_TOK_IDENT) && !MATCH(xli, QSE_XLI_TOK_DQSTR) && !MATCH(xli, QSE_XLI_TOK_SQSTR))
{
QSE_MMGR_FREE (xli->mmgr, keytag);
qse_xli_seterror (xli, QSE_XLI_ENOKEY, QSE_NULL, &xli->tok.loc);
@ -1211,12 +1095,10 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override, int opt_o
x = read_pair(xli, keytag, override);
QSE_MMGR_FREE (xli->mmgr, keytag);
if (x <= -1) return -1;
pair_count++;
}
else if (MATCH(xli, QSE_XLI_TOK_IDENT) || MATCH(xli, QSE_XLI_TOK_SQSTR) || MATCH(xli, QSE_XLI_TOK_DQSTR))
else if (MATCH(xli, QSE_XLI_TOK_IDENT) || MATCH(xli, QSE_XLI_TOK_DQSTR) || MATCH(xli, QSE_XLI_TOK_SQSTR))
{
if (read_pair(xli, QSE_NULL, override) <= -1) return -1;
pair_count++;
}
else if (MATCH(xli, QSE_XLI_TOK_TEXT))
{
@ -1228,16 +1110,6 @@ static int __read_list (qse_xli_t* xli, const qse_xli_scm_t* override, int opt_o
}
}
if (opt_outer_brace >= 2)
{
if (!MATCH(xli, QSE_XLI_TOK_RBRACE))
{
qse_xli_seterror (xli, QSE_XLI_ERBRCE, QSE_STR_XSTR(xli->tok.name), &xli->tok.loc);
return -1;
}
if (get_token(xli) <= -1) return -1;
}
return 0;
}
@ -1248,17 +1120,19 @@ static int read_list (qse_xli_t* xli, qse_xli_list_t* parlist, const qse_xli_scm
link = qse_xli_makelistlink(xli, parlist);
if (link == QSE_NULL) return -1;
QSE_ASSERT (link == xli->parlink);
/* get_token() here is to read the token after the left brace.
* it must be called after the xli->parlink has been updated
* in case there are comments at the beginning of the list */
if (get_token(xli) <= -1 || __read_list(xli, override, 0) <= -1)
if (get_token(xli) <= -1 || __read_list(xli, override) <= -1)
{
qse_xli_freelistlink (xli, link);
return -1;
}
QSE_ASSERT (link == xli->parlink);
qse_xli_freelistlink(xli, link);
qse_xli_freelistlink (xli, link);
return 0;
}
@ -1267,18 +1141,19 @@ static int read_root_list (qse_xli_t* xli)
{
qse_xli_list_link_t* link;
link = qse_xli_makelistlink(xli, &xli->root->list);
link = qse_xli_makelistlink (xli, &xli->root->list);
if (!link) return -1;
/* TODO: pass opt_outer_brace 1 to __read_list only if a certian option is enabled */
if (qse_xli_getchar(xli) <= -1 || get_token(xli) <= -1 || __read_list(xli, QSE_NULL, 1) <= -1)
QSE_ASSERT (link == xli->parlink);
if (qse_xli_getchar(xli) <= -1 || get_token(xli) <= -1 || __read_list(xli, QSE_NULL) <= -1)
{
qse_xli_freelistlink (xli, link);
return -1;
}
QSE_ASSERT (link == xli->parlink);
qse_xli_freelistlink(xli, link);
qse_xli_freelistlink (xli, link);
return 0;
}
@ -1322,7 +1197,7 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io)
QSE_ASSERT (xli->parlink == QSE_NULL);
if (!MATCH (xli, QSE_XLI_TOK_EOF))
if (!MATCH(xli, QSE_XLI_TOK_EOF))
{
qse_xli_seterror (xli, QSE_XLI_ESYNTAX, QSE_NULL, &xli->tok.loc);
goto oops;

View File

@ -123,7 +123,7 @@ static qse_sio_t* open_sio (qse_xli_t* xli, const qse_char_t* file, int flags)
if (sio == QSE_NULL)
{
qse_cstr_t errarg;
errarg.ptr = file;
errarg.ptr = (qse_char_t*)file;
errarg.len = qse_strlen(file);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &errarg);
}
@ -241,7 +241,7 @@ static qse_ssize_t sf_in_open (qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xtn
if (arg->handle == QSE_NULL)
{
qse_cstr_t ea;
ea.ptr = arg->name;
ea.ptr = (qse_char_t*)arg->name;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
return -1;
@ -299,7 +299,7 @@ static qse_ssize_t sf_in_read (
if (n <= -1)
{
qse_cstr_t ea;
ea.ptr = xtn->s.in.x->u.file.path;
ea.ptr = (qse_char_t*)xtn->s.in.x->u.file.path;
if (ea.ptr == QSE_NULL) ea.ptr = sio_std_names[QSE_SIO_STDIN].ptr;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
@ -335,7 +335,7 @@ static qse_ssize_t sf_in_read (
if (n <= -1)
{
qse_cstr_t ea;
ea.ptr = arg->name;
ea.ptr = (qse_char_t*)arg->name;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
}
@ -468,7 +468,7 @@ static qse_ssize_t sf_out_open (qse_xli_t* xli, qse_xli_io_arg_t* arg, xtn_t* xt
if (arg->handle == QSE_NULL)
{
qse_cstr_t ea;
ea.ptr = arg->name;
ea.ptr = (qse_char_t*)arg->name;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
return -1;
@ -526,7 +526,7 @@ static qse_ssize_t sf_out_write (
if (n <= -1)
{
qse_cstr_t ea;
ea.ptr = xtn->s.out.x->u.file.path;
ea.ptr = (qse_char_t*)xtn->s.out.x->u.file.path;
if (ea.ptr == QSE_NULL) ea.ptr = sio_std_names[QSE_SIO_STDOUT].ptr;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
@ -564,7 +564,7 @@ static qse_ssize_t sf_out_write (
if (n <= -1)
{
qse_cstr_t ea;
ea.ptr = arg->name;
ea.ptr = (qse_char_t*)arg->name;
ea.len = qse_strlen(ea.ptr);
qse_xli_seterrnum (xli, QSE_XLI_EIOFIL, &ea);
}
@ -611,7 +611,7 @@ int qse_xli_readstd (qse_xli_t* xli, qse_xli_iostd_t* in)
}
xtn->s.in.x = in;
return qse_xli_read (xli, sf_in);
return qse_xli_read(xli, sf_in);
}
@ -629,9 +629,25 @@ int qse_xli_readinistd (qse_xli_t* xli, qse_xli_iostd_t* in)
}
xtn->s.in.x = in;
return qse_xli_readini (xli, sf_in);
return qse_xli_readini(xli, sf_in);
}
int qse_xli_readjsonstd (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_readjson(xli, sf_in);
}
int qse_xli_writestd (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_iostd_t* out)
{
@ -692,3 +708,33 @@ int qse_xli_writeinistd (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_iost
return n;
}
int qse_xli_writejsonstd (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_iostd_t* out)
{
int n;
xtn_t* xtn = (xtn_t*) QSE_XTN (xli);
if (out == QSE_NULL || (out->type != QSE_XLI_IOSTD_FILE &&
out->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.out.x = out;
n = qse_xli_writejson (xli, root_list, sf_out);
if (out->type == QSE_XLI_IOSTD_STR)
{
if (n >= 0)
{
QSE_ASSERT (xtn->s.out.u.str.buf != QSE_NULL);
qse_str_yield (xtn->s.out.u.str.buf, &out->u.str, 0);
}
if (xtn->s.out.u.str.buf) qse_str_close (xtn->s.out.u.str.buf);
}
return n;
}

View File

@ -119,7 +119,16 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth)
}
case QSE_XLI_LIST:
if (write_list (xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1) return -1;
if (depth < 1)
{
if (write_list(xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1 ||
write_to_current_stream (xli, QSE_T("\n"), 1) <= -1) return -1;
}
else
{
/* the ini format doesn't support deep nesting */
if (write_to_current_stream (xli, QSE_T("={}\n"), 4) <= -1) return -1;
}
break;
}
break;
@ -129,9 +138,9 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth)
{
const qse_char_t* str = ((qse_xli_text_t*)curatom)->ptr;
if (write_to_current_stream (xli, QSE_T(";"), 1) <= -1 ||
write_to_current_stream (xli, str, qse_strlen(str)) <= -1 ||
write_to_current_stream (xli, QSE_T("\n"), 1) <= -1) return -1;
if (write_to_current_stream(xli, QSE_T(";"), 1) <= -1 ||
write_to_current_stream(xli, str, qse_strlen(str)) <= -1 ||
write_to_current_stream(xli, QSE_T("\n"), 1) <= -1) return -1;
break;
}

357
qse/lib/xli/write-json.c Normal file
View File

@ -0,0 +1,357 @@
/*
* $Id$
*
Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "xli.h"
#include <qse/cmn/chr.h>
typedef struct arg_data_t arg_data_t;
struct arg_data_t
{
int org_depth;
};
#if 0
static int write_to_current_stream(qse_xli_t* xli, const qse_char_t* ptr, qse_size_t len, int escape)
{
qse_xli_io_arg_t* arg;
qse_size_t i;
arg = xli->wio.inp;
for (i = 0; i < len; i++)
{
if (escape && (ptr[i] == QSE_T('\\') || ptr[i] == QSE_T('\"')))
{
if (arg->b.len + 2 > QSE_COUNTOF(arg->b.buf) && qse_xli_flushwstream (xli, arg) <= -1) return -1;
arg->b.buf[arg->b.len++] = QSE_T('\\');
}
else
{
if (arg->b.len + 1 > QSE_COUNTOF(arg->b.buf) && qse_xli_flushwstream (xli, arg) <= -1) return -1;
}
arg->b.buf[arg->b.len++] = ptr[i];
}
return 0;
}
static int write_indentation (qse_xli_t* xli, int depth)
{
static const qse_char_t tabs[16] =
{
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t'),
QSE_T('\t'), QSE_T('\t'), QSE_T('\t'), QSE_T('\t')
};
if (depth <= QSE_COUNTOF(tabs))
{
if (write_to_current_stream(xli, tabs, depth, 0) <= -1) return -1;
}
else
{
int i;
if (write_to_current_stream(xli, tabs, QSE_COUNTOF(tabs), 0) <= -1) return -1;
for (i = QSE_COUNTOF(tabs); i < depth; i++)
{
if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1;
}
}
return 0;
}
static int key_needs_quoting (qse_xli_t* xli, const qse_char_t* str, int nstr)
{
/* this determines if a key or an alias requires quoting for output.
* NSTR is not taken into account because it's only allowed as a value */
/* refer to the tokenization rule in get_token_into() in read.c */
qse_char_t c;
c = *str++;
if (c == QSE_T('\0')) return 1; /* an empty string requires a quoting */
if (c == QSE_T('_') || QSE_ISALPHA(c) || (!nstr && (xli->opt.trait & QSE_XLI_LEADDIGIT) && QSE_ISDIGIT(c)))
{
int lead_digit = QSE_ISDIGIT(c);
int all_digits = 1;
/* a normal identifier can be composed of wider varieties of
* characters than a keyword/directive */
while (1)
{
c = *str++;
if (c == QSE_T('\0')) break;
if (c == QSE_T('_') || c == QSE_T('-') ||
(!(xli->opt.trait & QSE_XLI_JSON) && c == QSE_T(':')) ||
c == QSE_T('*') || c == QSE_T('/') || QSE_ISALPHA(c))
{
all_digits = 0;
}
else if (QSE_ISDIGIT(c))
{
/* nothing to do */
}
else
{
/* a disallowed character for an identifier */
return 1; /* quote it */
}
}
if (lead_digit && all_digits)
{
/* if an identifier begins with a digit, it must contain a non-digit character */
/* in fact, it is not a valid identifer. so quote it */
return 1;
}
else
{
/* this must be a normal identifer */
return 0; /* no quoting needed */
}
}
else if (nstr && QSE_ISDIGIT(c))
{
do
{
c = *str++;
if (c == QSE_T('\0')) return 0; /* it's a numeric string */
}
while (QSE_ISDIGIT(c));
}
/* quote all the rest */
return 1;
}
static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth)
{
static struct
{
qse_char_t* qptr;
qse_size_t qlen;
} quotes[] =
{
{ QSE_T(""), 0 },
{ QSE_T("\'"), 1 },
{ QSE_T("\""), 1 }
};
static qse_char_t tag_opener[] = { QSE_T('['), QSE_T('(') };
static qse_char_t tag_closer[] = { QSE_T(']'), QSE_T(')') };
static struct
{
qse_char_t* ptr;
qse_size_t len;
} assign_symbol[] =
{
{ QSE_T(" = "), 3 },
{ QSE_T(": "), 2 }
};
static struct
{
qse_char_t* ptr;
qse_size_t len;
} list_assign_symbol[] =
{
{ QSE_T(" "), 1 },
{ QSE_T(": "), 2 }
};
qse_xli_atom_t* curatom;
int tag_mode = (xli->opt.trait & QSE_XLI_JSON)? 1: 0;
for (curatom = list->head; curatom; curatom = curatom->next)
{
switch (curatom->type)
{
case QSE_XLI_PAIR:
{
int qtype;
qse_xli_pair_t* pair = (qse_xli_pair_t*)curatom;
if (write_indentation(xli, depth) <= -1) return -1;
if (pair->tag)
{
if (write_to_current_stream(xli, &tag_opener[tag_mode], 1, 0) <= -1 ||
write_to_current_stream(xli, pair->tag, qse_strlen(pair->tag), 0) <= -1 ||
write_to_current_stream(xli, &tag_closer[tag_mode], 1, 0) <= -1) return -1;
}
QSE_ASSERT(pair->_key_quoted >= 0 && pair->_key_quoted < QSE_COUNTOF(quotes));
qtype = pair->_key_quoted;
if (qtype <= 0 && key_needs_quoting(xli, pair->key, 0)) qtype = 2; /* force double quoting */
if (write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1 ||
write_to_current_stream(xli, pair->key, qse_strlen(pair->key), (qtype >= 2)) <= -1 ||
write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1) return -1;
if (pair->alias)
{
QSE_ASSERT(pair->_alias_quoted >= 0 && pair->_alias_quoted < QSE_COUNTOF(quotes));
qtype = pair->_alias_quoted;
if (qtype <= 0 && key_needs_quoting(xli, pair->alias, 1)) qtype = 2;
if (write_to_current_stream(xli, QSE_T(" "), 1, 0) <= -1 ||
write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1 ||
write_to_current_stream(xli, pair->alias, qse_strlen(pair->alias), (qtype >= 2)) <= -1 ||
write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1) return -1;
}
switch (pair->val->type)
{
case QSE_XLI_NIL:
if (write_to_current_stream(xli, QSE_T(";\n"), 2, 0) <= -1) return -1;
break;
case QSE_XLI_STR:
{
qse_xli_str_t* str = (qse_xli_str_t*)pair->val;
if (write_to_current_stream(xli, assign_symbol[tag_mode].ptr, assign_symbol[tag_mode].len, 0) <= -1) return -1;
while (1)
{
if (str->tag)
{
if (write_to_current_stream(xli, &tag_opener[tag_mode], 1, 0) <= -1 ||
write_to_current_stream(xli, str->tag, qse_strlen(str->tag), 0) <= -1 ||
write_to_current_stream(xli, &tag_closer[tag_mode], 1, 0) <= -1) return -1;
}
if (write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -1 ||
write_to_current_stream(xli, str->ptr, str->len, 1) <= -1 ||
write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -1) return -1;
if (!str->next) break;
if (write_to_current_stream(xli, QSE_T(", "), 2, 0) <= -1) return -1;
str = str->next;
}
if (write_to_current_stream(xli, QSE_T(";\n"), 2, 0) <= -1) return -1;
break;
}
case QSE_XLI_LIST:
{
if (write_to_current_stream(xli, list_assign_symbol[tag_mode].ptr, list_assign_symbol[tag_mode].len, 0) <= -1) return -1;
if (write_to_current_stream(xli, QSE_T("{\n"), 2, 0) <= -1 ||
write_list (xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1 ||
write_indentation (xli, depth) <= -1 ||
write_to_current_stream(xli, QSE_T("}\n"), 2, 0) <= -1) return -1;
break;
}
}
break;
}
case QSE_XLI_TEXT:
{
int i;
const qse_char_t* str = ((qse_xli_text_t*)curatom)->ptr;
for (i = 0; i < depth; i++)
{
if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1;
}
if (write_to_current_stream(xli, QSE_T("#"), 1, 0) <= -1 ||
write_to_current_stream(xli, str, qse_strlen(str), 0) <= -1 ||
write_to_current_stream(xli, QSE_T("\n"), 1, 0) <= -1) return -1;
break;
}
case QSE_XLI_FILE:
{
int i;
const qse_char_t* path = ((qse_xli_file_t*)curatom)->path;
for (i = 0; i < depth; i++)
{
if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1;
}
if (write_to_current_stream(xli, QSE_T("@include \""), 10, 0) <= -1 ||
write_to_current_stream(xli, path, qse_strlen(path), 1) <= -1 ||
write_to_current_stream(xli, QSE_T("\";\n"), 3, 0) <= -1) return -1;
if (qse_xli_openwstream (xli, ((qse_xli_file_t*)curatom)->path, depth) <= -1) return -1;
depth = 0;
break;
}
case QSE_XLI_EOF:
if (qse_xli_closeactivewstream (xli, &depth) <= -1) return -1;
break;
}
}
return 0;
}
#endif
int qse_xli_writejson (qse_xli_t* xli, qse_xli_list_t* root_list, qse_xli_io_impl_t io)
{
int n;
#if 0
if (io == QSE_NULL)
{
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
QSE_MEMSET (&xli->wio, 0, QSE_SIZEOF(xli->wio));
xli->wio.impl = io;
xli->wio.inp = &xli->wio.top;
qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL);
qse_xli_clearwionames (xli);
/* open the top level stream */
if (qse_xli_openwstream (xli, QSE_NULL, 0) <= -1) return -1;
/* begin writing the root list */
n = write_list (xli, (root_list? root_list: &xli->root->list), 0);
/* close all open streams. there should be only the
* top-level stream here if there occurred no errors */
while (xli->wio.inp) qse_xli_closeactivewstream (xli, QSE_NULL);
#endif
return n;
}

View File

@ -139,7 +139,7 @@ int qse_xli_closeactivewstream (qse_xli_t* xli, int* org_depth)
return 0;
}
static int write_to_current_stream(qse_xli_t* xli, const qse_char_t* ptr, qse_size_t len, int escape)
static int write_to_current_stream (qse_xli_t* xli, const qse_char_t* ptr, qse_size_t len, int escape)
{
qse_xli_io_arg_t* arg;
qse_size_t i;
@ -175,21 +175,20 @@ static int write_indentation (qse_xli_t* xli, int depth)
if (depth <= QSE_COUNTOF(tabs))
{
if (write_to_current_stream(xli, tabs, depth, 0) <= -1) return -1;
if (write_to_current_stream (xli, tabs, depth, 0) <= -1) return -1;
}
else
{
int i;
if (write_to_current_stream(xli, tabs, QSE_COUNTOF(tabs), 0) <= -1) return -1;
if (write_to_current_stream (xli, tabs, QSE_COUNTOF(tabs), 0) <= -1) return -1;
for (i = QSE_COUNTOF(tabs); i < depth; i++)
{
if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T("\t"), 1, 0) <= -1) return -1;
}
}
return 0;
}
static int key_needs_quoting (qse_xli_t* xli, const qse_char_t* str, int nstr)
{
/* this determines if a key or an alias requires quoting for output.
@ -213,8 +212,7 @@ static int key_needs_quoting (qse_xli_t* xli, const qse_char_t* str, int nstr)
c = *str++;
if (c == QSE_T('\0')) break;
if (c == QSE_T('_') || c == QSE_T('-') ||
(!(xli->opt.trait & QSE_XLI_JSON) && c == QSE_T(':')) ||
if (c == QSE_T('_') || c == QSE_T('-') || c == QSE_T(':') ||
c == QSE_T('*') || c == QSE_T('/') || QSE_ISALPHA(c))
{
all_digits = 0;
@ -258,122 +256,78 @@ static int key_needs_quoting (qse_xli_t* xli, const qse_char_t* str, int nstr)
static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth)
{
static struct
{
qse_char_t* qptr;
qse_size_t qlen;
} quotes[] =
{
{ QSE_T(""), 0 },
{ QSE_T("\'"), 1 },
{ QSE_T("\""), 1 }
};
static qse_char_t tag_opener[] = { QSE_T('['), QSE_T('(') };
static qse_char_t tag_closer[] = { QSE_T(']'), QSE_T(')') };
static struct
{
qse_char_t* ptr;
qse_size_t len;
} assign_symbol[] =
{
{ QSE_T(" = "), 3 },
{ QSE_T(": "), 2 }
};
static struct
{
qse_char_t* ptr;
qse_size_t len;
} list_assign_symbol[] =
{
{ QSE_T(" "), 1 },
{ QSE_T(": "), 2 }
};
qse_xli_atom_t* curatom;
int tag_mode = (xli->opt.trait & QSE_XLI_JSON)? 1: 0;
for (curatom = list->head; curatom; curatom = curatom->next)
{
int quote_key = 0;
switch (curatom->type)
{
case QSE_XLI_PAIR:
{
int qtype;
qse_xli_pair_t* pair = (qse_xli_pair_t*)curatom;
if (write_indentation(xli, depth) <= -1) return -1;
if (write_indentation (xli, depth) <= -1) return -1;
if (pair->tag)
{
if (write_to_current_stream(xli, &tag_opener[tag_mode], 1, 0) <= -1 ||
write_to_current_stream(xli, pair->tag, qse_strlen(pair->tag), 0) <= -1 ||
write_to_current_stream(xli, &tag_closer[tag_mode], 1, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T("["), 1, 0) <= -1 ||
write_to_current_stream (xli, pair->tag, qse_strlen(pair->tag), 0) <= -1 ||
write_to_current_stream (xli, QSE_T("]"), 1, 0) <= -1) return -1;
}
QSE_ASSERT(pair->_key_quoted >= 0 && pair->_key_quoted < QSE_COUNTOF(quotes));
qtype = pair->_key_quoted;
if (qtype <= 0 && key_needs_quoting(xli, pair->key, 0)) qtype = 2; /* force double quoting */
if (key_needs_quoting(xli, pair->key, 0)) quote_key = 1;
if (write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1 ||
write_to_current_stream(xli, pair->key, qse_strlen(pair->key), (qtype >= 2)) <= -1 ||
write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1) return -1;
if ((quote_key && write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) ||
write_to_current_stream (xli, pair->key, qse_strlen(pair->key), 0) <= -1 ||
(quote_key && write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1)) return -1;
if (pair->alias)
{
QSE_ASSERT(pair->_alias_quoted >= 0 && pair->_alias_quoted < QSE_COUNTOF(quotes));
qtype = pair->_alias_quoted;
if (qtype <= 0 && key_needs_quoting(xli, pair->alias, 1)) qtype = 2;
if (write_to_current_stream(xli, QSE_T(" "), 1, 0) <= -1 ||
write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1 ||
write_to_current_stream(xli, pair->alias, qse_strlen(pair->alias), (qtype >= 2)) <= -1 ||
write_to_current_stream(xli, quotes[qtype].qptr, quotes[qtype].qlen, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T(" \""), 2, 0) <= -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;
}
switch (pair->val->type)
{
case QSE_XLI_NIL:
if (write_to_current_stream(xli, QSE_T(";\n"), 2, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T(";\n"), 2, 0) <= -1) return -1;
break;
case QSE_XLI_STR:
{
qse_xli_str_t* str = (qse_xli_str_t*)pair->val;
if (write_to_current_stream(xli, assign_symbol[tag_mode].ptr, assign_symbol[tag_mode].len, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T(" = "), 3, 0) <= -1) return -1;
while (1)
{
if (str->tag)
{
if (write_to_current_stream(xli, QSE_T("["), 1, 0) <= -1 ||
write_to_current_stream(xli, str->tag, qse_strlen(str->tag), 0) <= -1 ||
write_to_current_stream(xli, QSE_T("]"), 1, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T("["), 1, 0) <= -1 ||
write_to_current_stream (xli, str->tag, qse_strlen(str->tag), 0) <= -1 ||
write_to_current_stream (xli, QSE_T("]"), 1, 0) <= -1) return -1;
}
if (write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -1 ||
write_to_current_stream(xli, str->ptr, str->len, 1) <= -1 ||
write_to_current_stream(xli, QSE_T("\""), 1, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1 ||
write_to_current_stream (xli, str->ptr, str->len, 1) <= -1 ||
write_to_current_stream (xli, QSE_T("\""), 1, 0) <= -1) return -1;
if (!str->next) break;
if (write_to_current_stream(xli, QSE_T(", "), 2, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T(", "), 2, 0) <= -1) return -1;
str = str->next;
}
if (write_to_current_stream(xli, QSE_T(";\n"), 2, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T(";\n"), 2, 0) <= -1) return -1;
break;
}
case QSE_XLI_LIST:
{
if (write_to_current_stream(xli, list_assign_symbol[tag_mode].ptr, list_assign_symbol[tag_mode].len, 0) <= -1) return -1;
if (write_to_current_stream(xli, QSE_T("{\n"), 2, 0) <= -1 ||
if (write_to_current_stream (xli, QSE_T(" {\n"), 3, 0) <= -1 ||
write_list (xli, (qse_xli_list_t*)pair->val, depth + 1) <= -1 ||
write_indentation (xli, depth) <= -1 ||
write_to_current_stream(xli, QSE_T("}\n"), 2, 0) <= -1) return -1;
write_to_current_stream (xli, QSE_T("}\n"), 2, 0) <= -1) return -1;
break;
}
}
@ -387,12 +341,12 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth)
for (i = 0; i < depth; i++)
{
if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T("\t"), 1, 0) <= -1) return -1;
}
if (write_to_current_stream(xli, QSE_T("#"), 1, 0) <= -1 ||
write_to_current_stream(xli, str, qse_strlen(str), 0) <= -1 ||
write_to_current_stream(xli, QSE_T("\n"), 1, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T("#"), 1, 0) <= -1 ||
write_to_current_stream (xli, str, qse_strlen(str), 0) <= -1 ||
write_to_current_stream (xli, QSE_T("\n"), 1, 0) <= -1) return -1;
break;
}
@ -403,12 +357,12 @@ static int write_list (qse_xli_t* xli, qse_xli_list_t* list, int depth)
for (i = 0; i < depth; i++)
{
if (write_to_current_stream(xli, QSE_T("\t"), 1, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T("\t"), 1, 0) <= -1) return -1;
}
if (write_to_current_stream(xli, QSE_T("@include \""), 10, 0) <= -1 ||
write_to_current_stream(xli, path, qse_strlen(path), 1) <= -1 ||
write_to_current_stream(xli, QSE_T("\";\n"), 3, 0) <= -1) return -1;
if (write_to_current_stream (xli, QSE_T("@include \""), 10, 0) <= -1 ||
write_to_current_stream (xli, path, qse_strlen(path), 1) <= -1 ||
write_to_current_stream (xli, QSE_T("\";\n"), 3, 0) <= -1) return -1;
if (qse_xli_openwstream (xli, ((qse_xli_file_t*)curatom)->path, depth) <= -1) return -1;
depth = 0;

View File

@ -28,9 +28,9 @@
#include <qse/cmn/chr.h>
static qse_xli_root_list_t* make_root (qse_xli_t* xli);
static void free_val (qse_xli_root_list_t* xli, qse_xli_val_t* val);
static void free_list (qse_xli_root_list_t* xli, qse_xli_list_t* list);
static void free_atom (qse_xli_root_list_t* xli, qse_xli_atom_t* atom);
static void free_val (qse_xli_root_list_t* root, qse_xli_val_t* val);
static void free_list (qse_xli_root_list_t* root, qse_xli_list_t* list);
static void free_atom (qse_xli_root_list_t* root, qse_xli_atom_t* atom);
qse_xli_t* qse_xli_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_size_t rootxtnsize, qse_xli_errnum_t* errnum)
{
@ -289,18 +289,18 @@ qse_xli_pair_t* qse_xli_insertpair (
qse_cstr_t a, * ap = QSE_NULL;
qse_cstr_t t, * tp = QSE_NULL;
k.ptr = key;
k.len = qse_strlen (key);
k.ptr = (qse_char_t*)key;
k.len = qse_strlen(key);
if (alias)
{
a.ptr = alias;
a.ptr = (qse_char_t*)alias;
a.len = qse_strlen (alias);
ap = &a;
}
if (keytag)
{
t.ptr = keytag;
t.ptr = (qse_char_t*)keytag;
t.len = qse_strlen (keytag);
tp = &t;
}
@ -339,29 +339,10 @@ void qse_xli_deletepair (qse_xli_t* xli, qse_xli_pair_t* pair)
}
/* ------------------------------------------------------ */
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* alias, const qse_char_t* keytag)
{
qse_xli_list_t* val;
qse_xli_pair_t* tmp;
val = qse_xli_callocmem (xli, QSE_SIZEOF(*val));
if (!val) return QSE_NULL;
val->type = QSE_XLI_LIST;
tmp = qse_xli_insertpair (xli, parent, peer, key, alias, keytag, (qse_xli_val_t*)val);
if (!tmp) 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* alias, const qse_char_t* keytag,
const qse_cstr_t* value, const qse_char_t* strtag)
qse_xli_str_t* qse_xli_makestrval (qse_xli_t* xli, const qse_cstr_t* value, const qse_char_t* strtag)
{
qse_xli_str_t* val;
qse_xli_pair_t* tmp;
qse_size_t reqlen;
reqlen = QSE_SIZEOF(*val) + ((value->len + 1) * QSE_SIZEOF(*value->ptr));
@ -381,7 +362,52 @@ qse_xli_pair_t* qse_xli_insertpairwithstr (
val->tag = val->ptr + val->len + 1;
qse_strcpy ((qse_char_t*)val->tag, strtag);
}
return val;
}
qse_xli_list_t* qse_xli_makelistval (qse_xli_t* xli)
{
qse_xli_list_t* val;
val = qse_xli_callocmem (xli, QSE_SIZEOF(*val));
if (!val) return QSE_NULL;
val->type = QSE_XLI_LIST;
val->head = QSE_NULL;
val->tail = QSE_NULL;
return val;
}
/* ------------------------------------------------------ */
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* alias, const qse_char_t* keytag)
{
qse_xli_list_t* val;
qse_xli_pair_t* tmp;
val = qse_xli_makelistval(xli);
if (!val) return QSE_NULL;
tmp = qse_xli_insertpair (xli, parent, peer, key, alias, keytag, (qse_xli_val_t*)val);
if (!tmp) 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* alias, const qse_char_t* keytag,
const qse_cstr_t* value, const qse_char_t* strtag)
{
qse_xli_str_t* val;
qse_xli_pair_t* tmp;
val = qse_xli_makestrval (xli, value, strtag);
if (!val) return QSE_NULL;
tmp = qse_xli_insertpair (xli, parent, peer, key, alias, keytag, (qse_xli_val_t*)val);
if (!tmp) qse_xli_freemem (xli, val);
return tmp;
@ -496,28 +522,39 @@ static qse_xli_root_list_t* make_root (qse_xli_t* xli)
return tmp;
}
static void unsafe_free_val (qse_xli_root_list_t* root, qse_xli_val_t* val)
{
if (val->type == QSE_XLI_LIST)
{
free_list (root, (qse_xli_list_t*)val);
}
else if (val->type == QSE_XLI_STR)
{
qse_xli_str_t* cur, * next;
cur = ((qse_xli_str_t*)val)->next;
while (cur)
{
next = cur->next;
QSE_MMGR_FREE (root->mmgr, cur);
cur = next;
}
}
QSE_MMGR_FREE (root->mmgr, val);
}
void qse_xli_freeval (qse_xli_t* xli, qse_xli_val_t* val)
{
unsafe_free_val (xli->root, val);
}
static void free_val (qse_xli_root_list_t* root, qse_xli_val_t* val)
{
if ((qse_xli_nil_t*)val != &root->xnil)
{
if (val->type == QSE_XLI_LIST)
{
free_list (root, (qse_xli_list_t*)val);
}
else if (val->type == QSE_XLI_STR)
{
qse_xli_str_t* cur, * next;
cur = ((qse_xli_str_t*)val)->next;
while (cur)
{
next = cur->next;
QSE_MMGR_FREE (root->mmgr, cur);
cur = next;
}
}
QSE_MMGR_FREE (root->mmgr, val);
unsafe_free_val (root, val);
}
}
@ -579,7 +616,7 @@ qse_xli_list_t* qse_xli_yieldroot (qse_xli_t* xli)
{
qse_xli_root_list_t* tmp, * tmp2;
tmp = make_root (xli);
tmp = make_root(xli);
if (!tmp) return QSE_NULL;
tmp2 = xli->root;
@ -732,7 +769,7 @@ const qse_char_t* get_next_fqpn_segment (qse_xli_t* xli, const qse_char_t* fqpn,
* so if your alias contains these characters (in a quoted string),
* you can't reference it using a dotted key name. */
seg->idxtype = FQPN_SEG_IDX_ALIAS;
seg->idx.alias.ptr = ptr;
seg->idx.alias.ptr = (qse_char_t*)ptr;
while (*ptr != QSE_T('}') && *ptr != QSE_T('\0')) ptr++;
seg->idx.alias.len = ptr - seg->idx.alias.ptr;
@ -1010,7 +1047,7 @@ int qse_xli_definepair (qse_xli_t* xli, const qse_char_t* fqpn, const qse_xli_sc
return -1;
}
if (qse_rbt_upsert (xli->schema, fqpn, qse_strlen(fqpn), scm, QSE_SIZEOF(*scm)) == QSE_NULL)
if (qse_rbt_upsert (xli->schema, (void*)fqpn, qse_strlen(fqpn), (void*)scm, QSE_SIZEOF(*scm)) == QSE_NULL)
{
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
return -1;
@ -1171,8 +1208,6 @@ noent:
return QSE_NULL;
#endif
}
#endif
void* qse_getxlipairxtn (qse_xli_pair_t* pair)

View File

@ -36,8 +36,8 @@ enum qse_xli_tok_type_t
{
QSE_XLI_TOK_EOF,
QSE_XLI_TOK_XINCLUDE,
QSE_XLI_TOK_SEMICOLON,
QSE_XLI_TOK_COLON,
QSE_XLI_TOK_SEMICOLON,
QSE_XLI_TOK_LBRACE,
QSE_XLI_TOK_RBRACE,
QSE_XLI_TOK_LBRACK,
@ -103,7 +103,7 @@ struct qse_xli_t
qse_xli_ecb_t* ecb;
qse_xli_root_list_t* root;
qse_xli_list_link_t* parlink; /* link that points to the list being read currently */
qse_xli_list_link_t* parlink; /* internal use only - link that points to the list being read currently */
qse_str_t* dotted_curkey;
qse_rbt_t* schema;
@ -138,12 +138,11 @@ int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr, qse_size_t rootxtnsize);
void qse_xli_fini (qse_xli_t* xli);
const qse_char_t* qse_xli_dflerrstr (
const qse_xli_t* xli, qse_xli_errnum_t errnum);
const qse_xli_t* xli, qse_xli_errnum_t errnum);
void qse_xli_clearrionames (qse_xli_t* xli);
void qse_xli_clearwionames (qse_xli_t* xli);
int qse_xli_getchar (qse_xli_t* xli);
int qse_xli_openrstream (qse_xli_t* xli, qse_xli_io_arg_t* arg);
int qse_xli_closeactiverstream (qse_xli_t* xli);
@ -155,6 +154,12 @@ int qse_xli_flushwstream (qse_xli_t* xli, qse_xli_io_arg_t* arg);
qse_xli_list_link_t* qse_xli_makelistlink (qse_xli_t* xli, qse_xli_list_t* parlist);
void qse_xli_freelistlink (qse_xli_t* xli, qse_xli_list_link_t* link);
qse_xli_str_t* qse_xli_makestrval (qse_xli_t* xli, const qse_cstr_t* value, const qse_char_t* strtag);
qse_xli_list_t* qse_xli_makelistval (qse_xli_t* xli);
qse_xli_pair_t* qse_xli_makepairval (qse_xli_t* xli);
void qse_xli_freeval (qse_xli_t* xli, qse_xli_val_t* val);
#if defined(__cplusplus)
}
#endif