started adding simple xli validation

This commit is contained in:
hyung-hwan 2013-07-11 16:55:08 +00:00
parent 2bccba995c
commit 67c47e906d
8 changed files with 332 additions and 161 deletions

View File

@ -846,8 +846,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg)
for (i = 0; i < QSE_COUNTOF(loc_xcfg_items); i++)
{
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, loc_xcfg_items[i].x);
if (!pair) pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, loc_xcfg_items[i].y);
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, loc_xcfg_items[i].x);
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, loc_xcfg_items[i].y);
if (pair && pair->val->type == QSE_XLI_STR)
{
cfg->xcfg[i] = qse_httpd_strntombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len);
@ -860,8 +860,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg)
}
}
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, QSE_T("index"));
if (!pair) pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.index"));
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, QSE_T("index"));
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.index"));
if (pair && pair->val->type == QSE_XLI_STR)
{
qse_char_t* duptmp;
@ -886,8 +886,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg)
cfg->index.count = count;
}
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, QSE_T("cgi"));
if (!pair) pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.cgi"));
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, QSE_T("cgi"));
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.cgi"));
if (pair && pair->val->type == QSE_XLI_LIST)
{
/* TODO: more sanity check... this can be done with xli schema... if supported */
@ -963,8 +963,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg)
}
}
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, QSE_T("auth-rule"));
if (!pair) pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.auth-rule"));
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, QSE_T("auth-rule"));
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.auth-rule"));
if (pair && pair->val->type == QSE_XLI_LIST)
{
qse_xli_list_t* auth_rule_list = (qse_xli_list_t*)pair->val;
@ -1015,8 +1015,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg)
}
}
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, QSE_T("mime"));
if (!pair) pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.mime"));
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, QSE_T("mime"));
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.mime"));
if (pair && pair->val->type == QSE_XLI_LIST)
{
qse_xli_list_t* mimelist = (qse_xli_list_t*)pair->val;
@ -1072,8 +1072,8 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_list_t* list, loccfg_t* cfg)
for (i = 0; i < 2; i++)
{
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, loc_acc_items[i].x);
if (!pair) pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, loc_acc_items[i].y);
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, loc_acc_items[i].x);
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, loc_acc_items[i].y);
if (pair && pair->val->type == QSE_XLI_LIST)
{
qse_xli_list_t* acclist = (qse_xli_list_t*)pair->val;
@ -1208,8 +1208,8 @@ static int load_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server, q
{
qse_xli_pair_t* pair;
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, scfg_items[i].x);
if (!pair) pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, scfg_items[i].y);
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, scfg_items[i].x);
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, scfg_items[i].y);
if (pair && pair->val->type == QSE_XLI_STR)
{
server_xtn->scfg[i] = qse_httpd_strntombsdup (httpd, ((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len);
@ -1223,7 +1223,7 @@ static int load_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server, q
}
/* load host/location specific configuration */
host_count = qse_xli_getnumpairsbyalias (httpd_xtn->xli, list, QSE_T("host"));
host_count = qse_xli_getnumpairsbyname (httpd_xtn->xli, list, QSE_T("host"));
if (host_count <= 0) return 0; /* nothing to load */
QSE_ASSERT (server_xtn->cfgtab == QSE_NULL);
@ -1246,12 +1246,12 @@ static int load_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server, q
qse_char_t buf[32];
qse_sprintf (buf, QSE_COUNTOF(buf), QSE_T("host[%d]"), i);
host = qse_xli_findpairbyalias (httpd_xtn->xli, list, buf);
host = qse_xli_findpairbyname (httpd_xtn->xli, list, buf);
if (!host) break;
if (host->val->type == QSE_XLI_LIST && host->alias)
{
loc_count = qse_xli_getnumpairsbyalias (httpd_xtn->xli, (qse_xli_list_t*)host->val, QSE_T("location"));
loc_count = qse_xli_getnumpairsbyname (httpd_xtn->xli, (qse_xli_list_t*)host->val, QSE_T("location"));
if (((hostcfg = qse_httpd_callocmem (httpd, QSE_SIZEOF(*hostcfg))) == QSE_NULL) ||
((hostcfg->hostname = qse_httpd_strtombsdup (httpd, (host->alias[0] == QSE_T('\0')? QSE_T("*"):host->alias))) == QSE_NULL)) goto oops;
@ -1263,7 +1263,7 @@ static int load_server_config (qse_httpd_t* httpd, qse_httpd_server_t* server, q
j--;
qse_sprintf (buf, QSE_COUNTOF(buf), QSE_T("location[%d]"), j);
loc = qse_xli_findpairbyalias (httpd_xtn->xli, (qse_xli_list_t*)host->val, buf);
loc = qse_xli_findpairbyname (httpd_xtn->xli, (qse_xli_list_t*)host->val, buf);
if (!loc) break;
if (loc->val->type == QSE_XLI_LIST && loc->alias)
@ -1335,7 +1335,7 @@ static qse_httpd_server_t* attach_server (qse_httpd_t* httpd, int num, qse_xli_l
httpd_xtn = qse_httpd_getxtnstd (httpd);
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, QSE_T("bind"));
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, QSE_T("bind"));
if (pair == QSE_NULL || pair->val->type != QSE_XLI_STR)
{
/* TOOD: logging */
@ -1351,8 +1351,8 @@ static qse_httpd_server_t* attach_server (qse_httpd_t* httpd, int num, qse_xli_l
return QSE_NULL;
}
pair = qse_xli_findpairbyalias (httpd_xtn->xli, list, QSE_T("ssl"));
if (!pair) pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.ssl"));
pair = qse_xli_findpairbyname (httpd_xtn->xli, list, QSE_T("ssl"));
if (!pair) pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, QSE_T("server-default.ssl"));
if (pair && pair->val->type == QSE_XLI_STR &&
qse_strxcmp (((qse_xli_str_t*)pair->val)->ptr, ((qse_xli_str_t*)pair->val)->len, QSE_T("yes")) == 0) dope.flags |= QSE_HTTPD_SERVER_SECURE;
@ -1440,7 +1440,7 @@ static void set_limit (qse_httpd_t* httpd, const qse_char_t* name, int what)
httpd_xtn = (httpd_xtn_t*)qse_httpd_getxtnstd (httpd);
pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, name);
pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, name);
if (pair && pair->val->type == QSE_XLI_STR)
{
#if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
@ -1479,7 +1479,7 @@ static int load_config (qse_httpd_t* httpd)
if (open_config_file (httpd) <= -1) goto oops;
pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, QSE_T("name"));
pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, QSE_T("name"));
if (pair && pair->val->type == QSE_XLI_STR)
{
qse_mchar_t* tmp;
@ -1499,7 +1499,7 @@ static int load_config (qse_httpd_t* httpd)
{
qse_char_t buf[32];
qse_sprintf (buf, QSE_COUNTOF(buf), QSE_T("server[%d]"), i);
pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, buf);
pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, buf);
if (pair == QSE_NULL) break;
if (pair->val->type != QSE_XLI_LIST)
@ -1529,7 +1529,7 @@ static int load_config (qse_httpd_t* httpd)
}
/* load the global default */
pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, QSE_T("server-default"));
pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, QSE_T("server-default"));
if (pair && pair->val->type == QSE_XLI_LIST)
{
if (load_loccfg (httpd, (qse_xli_list_t*)pair->val, &httpd_xtn->dflcfg) <= -1)
@ -1563,7 +1563,7 @@ static void reconf_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
{
qse_char_t buf[32];
qse_sprintf (buf, QSE_COUNTOF(buf), QSE_T("server[%d]"), server_xtn->num);
pair = qse_xli_findpairbyalias (httpd_xtn->xli, QSE_NULL, buf);
pair = qse_xli_findpairbyname (httpd_xtn->xli, QSE_NULL, buf);
if (pair && pair->val->type == QSE_XLI_LIST)
{

View File

@ -130,6 +130,7 @@ static void print_usage (QSE_FILE* out, int argc, qse_char_t* argv[])
qse_fprintf (out, QSE_T(" --version show version\n"));
qse_fprintf (out, QSE_T(" -i file specify an input file\n"));
qse_fprintf (out, QSE_T(" -o file specify an 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"));
qse_fprintf (out, QSE_T(" -t keep comment text\n"));
@ -159,9 +160,9 @@ static int handle_args (int argc, qse_char_t* argv[])
static qse_opt_t opt =
{
#if defined(QSE_BUILD_DEBUG)
QSE_T("hi:o:aftm:X:"),
QSE_T("hi:o:uaftvm:X:"),
#else
QSE_T("hi:o:aftm:"),
QSE_T("hi:o:uaftvm:"),
#endif
lng
};
@ -203,6 +204,10 @@ static int handle_args (int argc, qse_char_t* argv[])
g_output_file = opt.arg;
break;
case QSE_T('u'):
g_trait |= QSE_XLI_KEYNODUP;
break;
case QSE_T('a'):
g_trait |= QSE_XLI_KEYALIAS;
break;
@ -215,6 +220,10 @@ static int handle_args (int argc, qse_char_t* argv[])
g_trait |= QSE_XLI_KEEPTEXT;
break;
case QSE_T('v'):
g_trait |= QSE_XLI_VALIDATE;
break;
case QSE_T('m'):
g_memlimit = qse_strtoulong (opt.arg);
break;
@ -352,6 +361,12 @@ static int xli_main (int argc, qse_char_t* argv[])
in.u.file.path = g_input_file;
in.u.file.cmgr = g_infile_cmgr;
{
qse_xli_scm_t scm;
scm.flags = QSE_XLI_SCM_VAL_LIST | QSE_XLI_SCM_KEY_NODUP;
qse_xli_setschema (xli, QSE_T("a.b"), &scm);
}
if (qse_xli_readstd (xli, &in) <= -1)
{
const qse_xli_loc_t* errloc;
@ -384,7 +399,7 @@ static int xli_main (int argc, qse_char_t* argv[])
if (g_lookup_key)
{
qse_xli_pair_t* pair;
pair = qse_xli_findpairbyalias (xli, QSE_NULL, g_lookup_key);
pair = qse_xli_findpairbyname (xli, QSE_NULL, g_lookup_key);
if (pair == QSE_NULL)
{
qse_fprintf (QSE_STDERR,

View File

@ -49,7 +49,10 @@ enum qse_xli_errnum_t
QSE_XLI_EINCLSTR,/**< '@include' not followed by a string */
QSE_XLI_ELXCHR, /**< invalid character '${0} */
QSE_XLI_EXKWNR, /**< @word '${0}' not recognized */
QSE_XLI_EXKWEM /**< @ not followed by a valid word */
QSE_XLI_EXKWEM, /**< @ not followed by a valid word */
QSE_XLI_EILKEY, /**< illegal key '${0}' */
QSE_XLI_EILVAL, /**< illegal value for '${0}' */
QSE_XLI_ESTRSEG /**< too many string segments for '${0}' */
};
typedef enum qse_xli_errnum_t qse_xli_errnum_t;
@ -78,6 +81,8 @@ enum qse_xli_trait_t
QSE_XLI_KEEPTEXT = (1 << 3), /**< keep comment text */
QSE_XLI_KEEPFILE = (1 << 4), /**< keep inclusion file info */
QSE_XLI_VALIDATE = (1 << 5)
};
typedef enum qse_xli_trait_t qse_xli_trait_t;
@ -287,11 +292,30 @@ typedef qse_ssize_t (*qse_xli_io_impl_t) (
qse_size_t count
);
enum qse_xli_scm_flag_t
{
QSE_XLI_SCM_REQUIRED = (1 << 0),
QSE_XLI_SCM_VAL_NIL = (1 << 1),
QSE_XLI_SCM_VAL_STR = (1 << 2),
QSE_XLI_SCM_VAL_LIST = (1 << 3),
QSE_XLI_SCM_KEY_NODUP = (1 << 4),
QSE_XLI_SCM_KEY_ALIAS = (1 << 5)
};
struct qse_xli_scm_t
{
int flags;
int str_minseg;
int str_maxseg;
};
typedef struct qse_xli_scm_t qse_xli_scm_t;
#if defined(__cplusplus)
extern "C" {
#endif
QSE_EXPORT qse_xli_t* qse_xli_open (
qse_mmgr_t* mmgr,
qse_size_t xtnsize
@ -518,20 +542,16 @@ QSE_EXPORT qse_xli_eof_t* qse_xli_inserteof (
qse_xli_atom_t* peer
);
QSE_EXPORT qse_xli_list_t* qse_xli_getroot (
qse_xli_t* xli
);
QSE_EXPORT qse_xli_pair_t* qse_xli_findpairbyalias (
QSE_EXPORT qse_xli_pair_t* qse_xli_findpairbyname (
qse_xli_t* xli,
const qse_xli_list_t* list,
const qse_char_t* alias
const qse_char_t* dotted_name
);
QSE_EXPORT qse_size_t qse_xli_getnumpairsbyalias (
QSE_EXPORT qse_size_t qse_xli_getnumpairsbyname (
qse_xli_t* xli,
const qse_xli_list_t* list,
const qse_char_t* alias
const qse_char_t* dotted_name
);
/**
@ -558,10 +578,28 @@ qse_char_t* qse_xli_dupflatstr (
qse_size_t* nsegs
);
QSE_EXPORT qse_xli_list_t* qse_xli_getroot (
qse_xli_t* xli
);
QSE_EXPORT void qse_xli_clearroot (
qse_xli_t* xli
);
QSE_EXPORT void qse_xli_clearschema (
qse_xli_t* xli
);
QSE_EXPORT void qse_xli_clear (
qse_xli_t* xli
);
QSE_EXPORT int qse_xli_setschema (
qse_xli_t* xli,
const qse_char_t* dotted_name,
const qse_xli_scm_t* scm
);
QSE_EXPORT int qse_xli_read (
qse_xli_t* xli,
qse_xli_io_impl_t io

View File

@ -156,6 +156,7 @@ int qse_gettime (qse_ntime_t* t)
struct timeval tv;
int n;
/* TODO: consider using clock_gettime() if it's avaialble.. -lrt may be needed */
n = QSE_GETTIMEOFDAY (&tv, QSE_NULL);
if (n == -1) return -1;
@ -227,13 +228,12 @@ int qse_settime (const qse_ntime_t* t)
tv.tv_usec = QSE_NSEC_TO_USEC(t->nsec);
/*
#if defined CLOCK_REALTIME && HAVE_CLOCK_SETTIME
#if defined(CLOCK_REALTIME) && defined(HAVE_CLOCK_SETTIME)
{
int r = clock_settime (CLOCK_REALTIME, ts);
if (r == 0 || errno == EPERM)
return r;
if (r == 0 || errno == EPERM) return r;
}
#elif HAVE_STIME
#elif defined(HAVE_STIME)
return stime (&ts->tv_sec);
#else
*/

View File

@ -48,7 +48,10 @@ const qse_char_t* qse_xli_dflerrstr (
QSE_T("'@include' not followed by a string"),
QSE_T("invalid character '${0}'"),
QSE_T("'${0}' not recognized"),
QSE_T("@ not followed by a valid word")
QSE_T("@ not followed by a valid word"),
QSE_T("illegal key '${0}'"),
QSE_T("illegal value for '${0}'"),
QSE_T("too many string segments for '${0}'")
};
return (errnum >= 0 && errnum < QSE_COUNTOF(errstr))?

View File

@ -594,10 +594,17 @@ static int get_token (qse_xli_t* xli)
static int read_pair (qse_xli_t* xli)
{
qse_char_t* key = QSE_NULL;
qse_char_t* name = QSE_NULL;
qse_xstr_t key;
qse_xli_loc_t kloc;
qse_char_t* name;
qse_xli_pair_t* pair;
qse_xli_list_t* parlist;
qse_size_t dotted_curkey_len;
qse_xli_scm_t* scm = QSE_NULL;
key.ptr = QSE_NULL;
name = QSE_NULL;
dotted_curkey_len = (qse_size_t)-1;
parlist = xli->parlink->list;
@ -606,6 +613,7 @@ static int read_pair (qse_xli_t* xli)
qse_xli_atom_t* atom;
/* find any key conflicts in the current scope */
/* TODO: optimization. no sequential search */
atom = parlist->tail;
while (atom)
{
@ -620,18 +628,47 @@ static int read_pair (qse_xli_t* xli)
}
}
key = qse_strdup (QSE_STR_PTR(xli->tok.name), xli->mmgr);
if (key == QSE_NULL)
kloc = xli->tok.loc;
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);
goto oops;
}
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)
{
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
goto oops;
}
if (xli->opt.trait & QSE_XLI_VALIDATE)
{
qse_rbt_pair_t* pair;
pair = qse_rbt_search (xli->schema, QSE_STR_PTR(xli->dotted_curkey), QSE_STR_LEN(xli->dotted_curkey));
if (pair == QSE_NULL)
{
qse_xli_seterror (xli, QSE_XLI_EILKEY, (const qse_cstr_t*)&key, &kloc);
goto oops;
}
scm = (qse_xli_scm_t*)QSE_RBT_VPTR(pair);
if (scm->flags & QSE_XLI_SCM_KEY_NODUP)
{
}
}
xli->tok_status |= TOK_STATUS_ENABLE_NSTR;
if (get_token (xli) <= -1) goto oops;
if (xli->opt.trait & QSE_XLI_KEYALIAS)
if (xli->opt.trait & QSE_XLI_KEYALIAS)
{
/* the name part must be unique for the same key(s) */
if (MATCH (xli, TOK_IDENT) || MATCH (xli, TOK_DQSTR) || MATCH (xli, TOK_SQSTR) || MATCH(xli, TOK_NSTR))
@ -643,7 +680,7 @@ static int read_pair (qse_xli_t* xli)
{
if (atom->type == QSE_XLI_PAIR &&
((qse_xli_pair_t*)atom)->alias &&
qse_strcmp (((qse_xli_pair_t*)atom)->key, key) == 0 &&
qse_strcmp (((qse_xli_pair_t*)atom)->key, key.ptr) == 0 &&
qse_strcmp (((qse_xli_pair_t*)atom)->alias, QSE_STR_PTR(xli->tok.name)) == 0)
{
qse_xli_seterror (xli, QSE_XLI_EEXIST, QSE_STR_CSTR(xli->tok.name), &xli->tok.loc);
@ -670,11 +707,20 @@ static int read_pair (qse_xli_t* xli)
if (MATCH (xli, TOK_SQSTR) || MATCH (xli, TOK_DQSTR) || MATCH(xli, TOK_NSTR) || MATCH (xli, TOK_IDENT))
{
qse_xli_str_t* curstrseg;
qse_size_t segcount = 0;
if (scm && !(scm->flags & QSE_XLI_SCM_VAL_STR))
{
/* check the value type */
qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc);
goto oops;
}
/* add a new pair with the initial string segment */
pair = qse_xli_insertpairwithstr (xli, parlist, QSE_NULL, key, name, QSE_STR_CSTR(xli->tok.name));
pair = qse_xli_insertpairwithstr (xli, parlist, QSE_NULL, key.ptr, name, QSE_STR_CSTR(xli->tok.name));
if (pair == QSE_NULL) goto oops;
segcount++;
curstrseg = (qse_xli_str_t*)pair->val;
if (get_token (xli) <= -1) goto oops;
@ -691,11 +737,11 @@ static int read_pair (qse_xli_t* xli)
goto oops;
}
/* add an additional segment to the string */
curstrseg = qse_xli_addsegtostr (xli, curstrseg, QSE_STR_CSTR(xli->tok.name));
if (curstrseg == QSE_NULL) goto oops;
segcount++;
if (get_token (xli) <= -1) goto oops; /* skip the value */
}
while (MATCH (xli, TOK_COMMA));
@ -708,6 +754,13 @@ static int read_pair (qse_xli_t* xli)
goto oops;
}
if (scm && (segcount < scm->str_minseg || segcount > scm->str_maxseg))
{
/* too many string segments for the key */
qse_xli_seterror (xli, QSE_XLI_ESTRSEG, (const qse_cstr_t*)&key, &kloc);
goto oops;
}
if (get_token (xli) <= -1) goto oops;
}
else
@ -716,13 +769,23 @@ static int read_pair (qse_xli_t* xli)
goto oops;
}
/* TODO: check against schema */
}
else if (MATCH (xli, TOK_LBRACE))
{
if (scm && !(scm->flags & QSE_XLI_SCM_VAL_LIST))
{
/* check the value type */
qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc);
goto oops;
}
xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR;
/* insert a pair with an empty list */
pair = qse_xli_insertpairwithemptylist (xli, parlist, QSE_NULL, key, name);
pair = qse_xli_insertpairwithemptylist (xli, parlist, QSE_NULL, key.ptr, name);
if (pair == QSE_NULL) goto oops;
if (read_list (xli, (qse_xli_list_t*)pair->val) <= -1) goto oops;
@ -741,17 +804,28 @@ static int read_pair (qse_xli_t* xli)
/* skip the semicolon */
if (get_token (xli) <= -1) goto oops;
}
/* TODO: check against schema */
}
else if (MATCH (xli, TOK_SEMICOLON))
{
if (scm && !(scm->flags & QSE_XLI_SCM_VAL_NIL))
{
/* check the value type */
qse_xli_seterror (xli, QSE_XLI_EILVAL, (const qse_cstr_t*)&key, &kloc);
goto oops;
}
xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR;
/* no value has been specified for the pair */
pair = qse_xli_insertpair (xli, parlist, QSE_NULL, key, name, (qse_xli_val_t*)&xli->xnil);
pair = qse_xli_insertpair (xli, parlist, QSE_NULL, key.ptr, name, (qse_xli_val_t*)&xli->xnil);
if (pair == QSE_NULL) goto oops;
/* skip the semicolon */
if (get_token (xli) <= -1) goto oops;
/* TODO: check against schema */
}
else
{
@ -760,13 +834,16 @@ static int read_pair (qse_xli_t* xli)
}
QSE_MMGR_FREE (xli->mmgr, name);
QSE_MMGR_FREE (xli->mmgr, key);
QSE_MMGR_FREE (xli->mmgr, key.ptr);
qse_str_setlen (xli->dotted_curkey, dotted_curkey_len);
return 0;
oops:
xli->tok_status &= ~TOK_STATUS_ENABLE_NSTR;
if (name) QSE_MMGR_FREE (xli->mmgr, name);
if (key) QSE_MMGR_FREE (xli->mmgr, key);
if (key.ptr) QSE_MMGR_FREE (xli->mmgr, key.ptr);
if (dotted_curkey_len != (qse_size_t)-1)
qse_str_setlen (xli->dotted_curkey, dotted_curkey_len);
return -1;
}
@ -894,6 +971,8 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io)
qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL);
qse_xli_clearrionames (xli);
QSE_ASSERT (QSE_STR_LEN(xli->dotted_curkey) == 0);
n = xli->rio.impl (xli, QSE_XLI_IO_OPEN, xli->rio.inp, QSE_NULL, 0);
if (n <= -1)
{
@ -915,6 +994,7 @@ int qse_xli_read (qse_xli_t* xli, qse_xli_io_impl_t io)
QSE_ASSERT (xli->rio.inp == &xli->rio.top);
close_current_stream (xli);
qse_str_clear (xli->tok.name);
return 0;
oops:
@ -935,5 +1015,6 @@ oops:
}
close_current_stream (xli);
qse_str_clear (xli->tok.name);
return -1;
}

View File

@ -56,26 +56,35 @@ int qse_xli_init (qse_xli_t* xli, qse_mmgr_t* mmgr)
xli->mmgr = mmgr;
xli->errstr = qse_xli_dflerrstr;
xli->dotted_curkey = qse_str_open (mmgr, 0, 128);
if (xli->dotted_curkey == QSE_NULL) goto oops;
xli->tok.name = qse_str_open (mmgr, 0, 128);
if (xli->tok.name == QSE_NULL) goto oops;
xli->schema = qse_rbt_open (mmgr, 0, QSE_SIZEOF(qse_char_t), 1);
if (xli->schema == QSE_NULL) goto oops;
xli->root.type = QSE_XLI_LIST;
xli->xnil.type = QSE_XLI_NIL;
return 0;
oops:
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
if (xli->schema) qse_rbt_close (xli->schema);
if (xli->tok.name) qse_str_close (xli->tok.name);
if (xli->dotted_curkey) qse_str_close (xli->dotted_curkey);
return -1;
}
void qse_xli_fini (qse_xli_t* xli)
{
qse_xli_clear (xli);
qse_str_close (xli->tok.name);
qse_xli_clearrionames (xli);
qse_xli_clearwionames (xli);
qse_rbt_close (xli->schema);
qse_str_close (xli->tok.name);
qse_str_close (xli->dotted_curkey);
}
qse_mmgr_t* qse_xli_getmmgr (qse_xli_t* xli)
@ -156,13 +165,6 @@ void qse_xli_freemem (qse_xli_t* xli, void* ptr)
}
/* ------------------------------------------------------ */
qse_xli_list_t* qse_xli_getroot (qse_xli_t* xli)
{
return &xli->root;
}
/* ------------------------------------------------------ */
static void insert_atom (
qse_xli_t* xli, qse_xli_list_t* parent,
qse_xli_atom_t* peer, qse_xli_atom_t* atom)
@ -375,9 +377,31 @@ static void free_list (qse_xli_t* xli, qse_xli_list_t* list)
void qse_xli_clear (qse_xli_t* xli)
{
free_list (xli, &xli->root);
qse_rbt_clear (xli->schema);
qse_xli_seterrnum (xli, QSE_XLI_ENOERR, QSE_NULL);
qse_xli_clearrionames (xli);
qse_xli_clearwionames (xli);
}
static qse_size_t count_pair_byalias (
qse_xli_list_t* qse_xli_getroot (qse_xli_t* xli)
{
return &xli->root;
}
void qse_xli_clearroot (qse_xli_t* xli)
{
free_list (xli, &xli->root);
}
void qse_xli_clearschema (qse_xli_t* xli)
{
qse_rbt_clear (xli->schema);
}
/* ------------------------------------------------------ */
static qse_size_t count_pairs_by_key_and_alias (
qse_xli_t* xli, const qse_xli_list_t* list,
const qse_cstr_t* key, const qse_cstr_t* alias)
{
@ -404,7 +428,7 @@ static qse_size_t count_pair_byalias (
return count;
}
static qse_xli_pair_t* find_pair_byalias (
static qse_xli_pair_t* find_pair_by_key_and_alias (
qse_xli_t* xli, const qse_xli_list_t* list,
const qse_cstr_t* key, const qse_cstr_t* alias)
{
@ -430,7 +454,7 @@ static qse_xli_pair_t* find_pair_byalias (
return QSE_NULL;
}
static qse_xli_pair_t* find_pair_byindex (
static qse_xli_pair_t* find_pair_by_key_and_index (
qse_xli_t* xli, const qse_xli_list_t* list,
const qse_cstr_t* key, qse_size_t index)
{
@ -457,7 +481,7 @@ static qse_xli_pair_t* find_pair_byindex (
return QSE_NULL;
}
qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* alias)
qse_xli_pair_t* qse_xli_findpairbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* dotted_name)
{
const qse_char_t* ptr;
const qse_xli_list_t* curlist;
@ -466,11 +490,11 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l
curlist = list? list: &xli->root;
ptr = alias;
ptr = dotted_name;
while (1)
{
seg.ptr = ptr;
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++;
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[') && *ptr != QSE_T('{')) ptr++;
if (ptr == seg.ptr) goto inval;
seg.len = ptr - seg.ptr;
@ -479,14 +503,14 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l
/* check the type of curlist. this check is needed
* because of the unconditional switching at the bottom of the
* this loop. this implementation strategy has been chosen
* to provide the segment alias easily. */
* to provide the segment name easily. */
goto noent;
}
if (*ptr == QSE_T('['))
{
/* index is specified */
ptr++;
ptr++; /* skip [ */
if (QSE_ISDIGIT(*ptr))
{
@ -501,50 +525,13 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l
if (*ptr != QSE_T(']')) goto inval;
pair = find_pair_byindex (xli, curlist, &seg, index);
pair = find_pair_by_key_and_index (xli, curlist, &seg, index);
if (pair == QSE_NULL)
{
seg.len += count + 2; /* adjustment for error message */
goto noent;
}
}
else if (QSE_ISALPHA(*ptr))
{
/* word index */
qse_cstr_t idx;
idx.ptr = ptr;
do ptr++; while (QSE_ISALNUM(*ptr) || *ptr == QSE_T('_') || *ptr == QSE_T('-'));
idx.len = ptr - idx.ptr;
if (*ptr != QSE_T(']')) goto inval;
pair = find_pair_byalias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 2; /* adjustment for error message */
goto noent;
}
}
else if (*ptr == QSE_T('\'') || *ptr == QSE_T('\"'))
{
qse_cstr_t idx;
qse_char_t cc = *ptr++;
idx.ptr = ptr;
do ptr++; while (*ptr != cc && *ptr != QSE_T('\0'));
idx.len = ptr - idx.ptr;
if (*ptr != cc) goto inval;
if (*++ptr != QSE_T(']')) goto inval;
pair = find_pair_byalias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 4; /* adjustment for error message */
goto noent;
}
}
else goto inval;
ptr++; /* skip ] */
@ -552,9 +539,37 @@ qse_xli_pair_t* qse_xli_findpairbyalias (qse_xli_t* xli, const qse_xli_list_t* l
if (*ptr == QSE_T('\0')) break; /* no more segments */
else if (*ptr != QSE_T('.')) goto inval;
}
else if (*ptr == QSE_T('{'))
{
/* word index - alias */
qse_cstr_t idx;
ptr++; /* skip { */
/* no escaping is supported for the alias inside {}.
* so if your alias contains these characters (in a quoted string),
* you can't reference it using a dotted key name. */
idx.ptr = ptr;
while (*ptr != QSE_T('}') && *ptr != QSE_T('\0')) ptr++;
idx.len = ptr - idx.ptr;
if (*ptr != QSE_T('}') || idx.len == 0) goto inval;
pair = find_pair_by_key_and_alias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 2; /* adjustment for error message */
goto noent;
}
ptr++; /* skip } */
if (*ptr == QSE_T('\0')) break; /* no more segments */
else if (*ptr != QSE_T('.')) goto inval;
}
else
{
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL);
if (pair == QSE_NULL) goto noent;
if (*ptr == QSE_T('\0')) break; /* no more segments */
@ -581,7 +596,7 @@ noent:
return QSE_NULL;
}
qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* alias)
qse_size_t qse_xli_getnumpairsbyname (qse_xli_t* xli, const qse_xli_list_t* list, const qse_char_t* dotted_name)
{
const qse_char_t* ptr;
const qse_xli_list_t* curlist;
@ -590,11 +605,11 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
curlist = list? list: &xli->root;
ptr = alias;
ptr = dotted_name;
while (1)
{
seg.ptr = ptr;
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[')) ptr++;
while (*ptr != QSE_T('\0') && *ptr != QSE_T('.') && *ptr != QSE_T('[') && *ptr != QSE_T('{')) ptr++;
if (ptr == seg.ptr) goto inval;
seg.len = ptr - seg.ptr;
@ -603,14 +618,14 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
/* check the type of curlist. this check is needed
* because of the unconditional switching at the bottom of the
* this loop. this implementation strategy has been chosen
* to provide the segment alias easily. */
* to provide the segment name easily. */
goto noent;
}
if (*ptr == QSE_T('['))
{
/* index is specified */
ptr++;
ptr++; /* skip [ */
if (QSE_ISDIGIT(*ptr))
{
@ -625,50 +640,13 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
if (*ptr != QSE_T(']')) goto inval;
pair = find_pair_byindex (xli, curlist, &seg, index);
pair = find_pair_by_key_and_index (xli, curlist, &seg, index);
if (pair == QSE_NULL)
{
seg.len += count + 2; /* adjustment for error message */
goto noent;
}
}
else if (QSE_ISALPHA(*ptr))
{
/* word index */
qse_cstr_t idx;
idx.ptr = ptr;
do ptr++; while (QSE_ISALNUM(*ptr) || *ptr == QSE_T('_') || *ptr == QSE_T('-'));
idx.len = ptr - idx.ptr;
if (*ptr != QSE_T(']')) goto inval;
pair = find_pair_byalias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 2; /* adjustment for error message */
goto noent;
}
}
else if (*ptr == QSE_T('\'') || *ptr == QSE_T('\"'))
{
qse_cstr_t idx;
qse_char_t cc = *ptr++;
idx.ptr = ptr;
do ptr++; while (*ptr != cc && *ptr != QSE_T('\0'));
idx.len = ptr - idx.ptr;
if (*ptr != cc) goto inval;
if (*++ptr != QSE_T(']')) goto inval;
pair = find_pair_byalias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 4; /* adjustment for error message */
goto noent;
}
}
else goto inval;
ptr++; /* skip ] */
@ -680,18 +658,47 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
}
else if (*ptr != QSE_T('.')) goto inval;
}
else if (*ptr == QSE_T('{'))
{
/* word index - alias */
qse_cstr_t idx;
ptr++; /* skip { */
idx.ptr = ptr;
while (*ptr != QSE_T('}') && *ptr != QSE_T('\0')) ptr++;
idx.len = ptr - idx.ptr;
if (*ptr != QSE_T('}') || idx.len == 0) goto inval;
pair = find_pair_by_key_and_alias (xli, curlist, &seg, &idx);
if (pair == QSE_NULL)
{
seg.len += idx.len + 2; /* adjustment for error message */
goto noent;
}
ptr++; /* skip } */
if (*ptr == QSE_T('\0'))
{
/* no more segments */
return 1;
}
else if (*ptr != QSE_T('.')) goto inval;
}
else
{
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL);
if (pair == QSE_NULL) goto noent;
if (*ptr == QSE_T('\0'))
{
return count_pair_byalias (xli, curlist, &seg, QSE_NULL);
return count_pairs_by_key_and_alias (xli, curlist, &seg, QSE_NULL);
}
else
{
pair = find_pair_byalias (xli, curlist, &seg, QSE_NULL);
pair = find_pair_by_key_and_alias (xli, curlist, &seg, QSE_NULL);
if (pair == QSE_NULL) goto noent;
}
}
@ -702,7 +709,7 @@ qse_size_t qse_xli_getnumpairsbyalias (qse_xli_t* xli, const qse_xli_list_t* lis
/* switch to the value regardless of its type.
* check if it is a list in the beginning of the loop
* just after having gotten the next segment alias */
* just after having gotten the next segment name */
curlist = (qse_xli_list_t*)pair->val;
}
@ -760,3 +767,25 @@ qse_char_t* qse_xli_dupflatstr (qse_xli_t* xli, qse_xli_str_t* str, qse_size_t*
return tmp;
}
int qse_xli_setschema (qse_xli_t* xli, const qse_char_t* dotted_name, const qse_xli_scm_t* scm)
{
int tmp;
tmp = scm->flags & (QSE_XLI_SCM_VAL_LIST | QSE_XLI_SCM_VAL_STR | QSE_XLI_SCM_VAL_NIL);
if (tmp != QSE_XLI_SCM_VAL_LIST && tmp != QSE_XLI_SCM_VAL_STR && tmp != QSE_XLI_SCM_VAL_NIL)
{
/* VAL_LIST, VAL_STR, VAL_NIL can't co-exist */
qse_xli_seterrnum (xli, QSE_XLI_EINVAL, QSE_NULL);
return -1;
}
if (qse_rbt_upsert (xli->schema, dotted_name, qse_strlen(dotted_name), scm, QSE_SIZEOF(scm)) == QSE_NULL)
{
qse_xli_seterrnum (xli, QSE_XLI_ENOMEM, QSE_NULL);
return -1;
}
return 0;
}

View File

@ -23,6 +23,7 @@
#include <qse/xli/xli.h>
#include <qse/cmn/str.h>
#include <qse/cmn/rbt.h>
#include "../cmn/mem.h"
typedef struct qse_xli_tok_t qse_xli_tok_t;
@ -60,7 +61,11 @@ struct qse_xli_t
qse_xli_nil_t xnil;
qse_xli_list_t root;
qse_xli_list_link_t* parlink;
qse_xli_list_link_t* parlink; /* link that points to the list being read currently */
qse_str_t* dotted_curkey;
qse_rbt_t* schema;
qse_xli_tok_t tok;
int tok_status;