Various improvements:
* A filter's parse routines now return a parse_result (enum) * Return value from test filter parse routines is configurable * Either call parse_end() or parse_abort(), but never both.
This commit is contained in:
committed by
Michael Davidsaver
parent
eee5a28983
commit
4324ffd274
@@ -21,7 +21,6 @@
|
||||
#include "special.h"
|
||||
#include "yajl_parse.h"
|
||||
|
||||
|
||||
typedef struct parseContext {
|
||||
dbChannel *chan;
|
||||
chFilter *filter;
|
||||
@@ -34,31 +33,33 @@ typedef struct filterPlugin {
|
||||
const chFilterIf *fif;
|
||||
} filterPlugin;
|
||||
|
||||
#define CALLIF(rtn) !rtn ? parse_stop : rtn
|
||||
|
||||
#define CALLIF(rtn) rtn && rtn
|
||||
|
||||
static void chf_value(parseContext *parser, int result)
|
||||
static void chf_value(parseContext *parser, parse_result *presult)
|
||||
{
|
||||
chFilter *filter = parser->filter;
|
||||
|
||||
if (!result || parser->depth > 0) return;
|
||||
if (*presult == parse_stop || parser->depth > 0)
|
||||
return;
|
||||
|
||||
parser->filter = NULL;
|
||||
if (filter->fif->parse_end(filter)) {
|
||||
if (filter->fif->parse_end(filter) == parse_continue) {
|
||||
ellAdd(&parser->chan->filters, &filter->node);
|
||||
} else {
|
||||
free(filter); // FIXME: Use free-list
|
||||
*presult = parse_stop;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int chf_null(void * ctx)
|
||||
{
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
chFilter *filter = parser->filter;
|
||||
int result;
|
||||
parse_result result;
|
||||
|
||||
assert(filter);
|
||||
result = CALLIF(filter->fif->parse_null) (filter );
|
||||
chf_value(parser, result);
|
||||
result = CALLIF(filter->fif->parse_null)(filter );
|
||||
chf_value(parser, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -66,11 +67,11 @@ static int chf_boolean(void * ctx, int boolVal)
|
||||
{
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
chFilter *filter = parser->filter;
|
||||
int result;
|
||||
parse_result result;
|
||||
|
||||
assert(filter);
|
||||
result = CALLIF(filter->fif->parse_boolean) (filter , boolVal);
|
||||
chf_value(parser, result);
|
||||
result = CALLIF(filter->fif->parse_boolean)(filter , boolVal);
|
||||
chf_value(parser, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -78,11 +79,11 @@ static int chf_integer(void * ctx, long integerVal)
|
||||
{
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
chFilter *filter = parser->filter;
|
||||
int result;
|
||||
parse_result result;
|
||||
|
||||
assert(filter);
|
||||
result = CALLIF(filter->fif->parse_integer) (filter , integerVal);
|
||||
chf_value(parser, result);
|
||||
result = CALLIF(filter->fif->parse_integer)(filter , integerVal);
|
||||
chf_value(parser, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -90,11 +91,11 @@ static int chf_double(void * ctx, double doubleVal)
|
||||
{
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
chFilter *filter = parser->filter;
|
||||
int result;
|
||||
parse_result result;
|
||||
|
||||
assert(filter);
|
||||
result = CALLIF(filter->fif->parse_double) (filter , doubleVal);
|
||||
chf_value(parser, result);
|
||||
result = CALLIF(filter->fif->parse_double)(filter , doubleVal);
|
||||
chf_value(parser, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -103,11 +104,11 @@ static int chf_string(void * ctx, const unsigned char * stringVal,
|
||||
{
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
chFilter *filter = parser->filter;
|
||||
int result;
|
||||
parse_result result;
|
||||
|
||||
assert(filter);
|
||||
result = CALLIF(filter->fif->parse_string) (filter , (const char *) stringVal, stringLen);
|
||||
chf_value(parser, result);
|
||||
result = CALLIF(filter->fif->parse_string)(filter , (const char *) stringVal, stringLen);
|
||||
chf_value(parser, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -118,11 +119,11 @@ static int chf_start_map(void * ctx)
|
||||
|
||||
if (!filter) {
|
||||
assert(parser->depth == 0);
|
||||
return 1; /* Opening '{' */
|
||||
return parse_continue; /* Opening '{' */
|
||||
}
|
||||
|
||||
++parser->depth;
|
||||
return CALLIF(filter->fif->parse_start_map) (filter );
|
||||
return CALLIF(filter->fif->parse_start_map)(filter );
|
||||
}
|
||||
|
||||
static int chf_map_key(void * ctx, const unsigned char * key,
|
||||
@@ -131,10 +132,11 @@ static int chf_map_key(void * ctx, const unsigned char * key,
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
chFilter *filter = parser->filter;
|
||||
const chFilterIf *fif;
|
||||
int result;
|
||||
parse_result result;
|
||||
|
||||
if (filter) {
|
||||
return CALLIF(filter->fif->parse_map_key) (filter , (const char *) key, stringLen);
|
||||
assert(parser->depth > 0);
|
||||
return CALLIF(filter->fif->parse_map_key)(filter , (const char *) key, stringLen);
|
||||
}
|
||||
|
||||
assert(parser->depth == 0);
|
||||
@@ -144,6 +146,7 @@ static int chf_map_key(void * ctx, const unsigned char * key,
|
||||
return parse_stop;
|
||||
}
|
||||
|
||||
/* FIXME: Use a free-list */
|
||||
filter = (chFilter *) callocMustSucceed(1, sizeof(*filter), "Creating dbChannel filter");
|
||||
filter->chan = parser->chan;
|
||||
filter->fif = fif;
|
||||
@@ -153,7 +156,7 @@ static int chf_map_key(void * ctx, const unsigned char * key,
|
||||
if (result == parse_continue) {
|
||||
parser->filter = filter;
|
||||
} else {
|
||||
free(filter);
|
||||
free(filter); // FIXME: Use free-list
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -162,15 +165,19 @@ static int chf_end_map(void * ctx)
|
||||
{
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
chFilter *filter = parser->filter;
|
||||
parse_result result;
|
||||
|
||||
if (filter) {
|
||||
int result = CALLIF(filter->fif->parse_end_map) (filter );
|
||||
|
||||
if (--parser->depth == 0) chf_value(parser, result);
|
||||
return result;
|
||||
if (!filter) {
|
||||
assert(parser->depth == 0);
|
||||
return parse_continue; /* Final closing '}' */
|
||||
}
|
||||
assert(parser->depth == 0);
|
||||
return parse_continue; /* Final closing '}' */
|
||||
|
||||
assert(parser->depth > 0);
|
||||
result = CALLIF(filter->fif->parse_end_map)(filter );
|
||||
|
||||
--parser->depth;
|
||||
chf_value(parser, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int chf_start_array(void * ctx)
|
||||
@@ -180,18 +187,19 @@ static int chf_start_array(void * ctx)
|
||||
|
||||
assert(filter);
|
||||
++parser->depth;
|
||||
return CALLIF(filter->fif->parse_start_array) (filter );
|
||||
return CALLIF(filter->fif->parse_start_array)(filter );
|
||||
}
|
||||
|
||||
static int chf_end_array(void * ctx)
|
||||
{
|
||||
parseContext *parser = (parseContext *) ctx;
|
||||
chFilter *filter = parser->filter;
|
||||
int result;
|
||||
parse_result result;
|
||||
|
||||
assert(filter);
|
||||
result = CALLIF(filter->fif->parse_end_array) (filter );
|
||||
if (--parser->depth == 0) chf_value(parser, result);
|
||||
result = CALLIF(filter->fif->parse_end_array)(filter );
|
||||
--parser->depth;
|
||||
chf_value(parser, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -202,23 +210,23 @@ static const yajl_callbacks chf_callbacks =
|
||||
static const yajl_parser_config chf_config =
|
||||
{ 0, 1 }; /* allowComments = NO , checkUTF8 = YES */
|
||||
|
||||
|
||||
static long chf_parse(dbChannel *chan, const char *json)
|
||||
{
|
||||
parseContext parser =
|
||||
{ chan, NULL, 0};
|
||||
{ chan, NULL, 0 };
|
||||
yajl_handle yh = yajl_alloc(&chf_callbacks, &chf_config, NULL, &parser);
|
||||
size_t jlen = strlen(json);
|
||||
yajl_status ys;
|
||||
long status;
|
||||
|
||||
if (!yh) return S_db_noMemory;
|
||||
if (!yh)
|
||||
return S_db_noMemory;
|
||||
|
||||
ys = yajl_parse(yh, (const unsigned char *) json, jlen);
|
||||
if (ys == yajl_status_insufficient_data)
|
||||
ys = yajl_parse_complete(yh);
|
||||
|
||||
switch(ys) {
|
||||
switch (ys) {
|
||||
case yajl_status_ok:
|
||||
status = 0;
|
||||
break;
|
||||
@@ -244,24 +252,24 @@ static long chf_parse(dbChannel *chan, const char *json)
|
||||
}
|
||||
|
||||
/* Stolen from dbAccess.c: */
|
||||
static short mapDBFToDBR[DBF_NTYPES] = {
|
||||
/* DBF_STRING => */ DBR_STRING,
|
||||
/* DBF_CHAR => */ DBR_CHAR,
|
||||
/* DBF_UCHAR => */ DBR_UCHAR,
|
||||
/* DBF_SHORT => */ DBR_SHORT,
|
||||
/* DBF_USHORT => */ DBR_USHORT,
|
||||
/* DBF_LONG => */ DBR_LONG,
|
||||
/* DBF_ULONG => */ DBR_ULONG,
|
||||
/* DBF_FLOAT => */ DBR_FLOAT,
|
||||
/* DBF_DOUBLE => */ DBR_DOUBLE,
|
||||
/* DBF_ENUM, => */ DBR_ENUM,
|
||||
/* DBF_MENU, => */ DBR_ENUM,
|
||||
/* DBF_DEVICE => */ DBR_ENUM,
|
||||
/* DBF_INLINK => */ DBR_STRING,
|
||||
/* DBF_OUTLINK => */ DBR_STRING,
|
||||
/* DBF_FWDLINK => */ DBR_STRING,
|
||||
/* DBF_NOACCESS => */ DBR_NOACCESS
|
||||
};
|
||||
static short mapDBFToDBR[DBF_NTYPES] =
|
||||
{
|
||||
/* DBF_STRING => */DBR_STRING,
|
||||
/* DBF_CHAR => */DBR_CHAR,
|
||||
/* DBF_UCHAR => */DBR_UCHAR,
|
||||
/* DBF_SHORT => */DBR_SHORT,
|
||||
/* DBF_USHORT => */DBR_USHORT,
|
||||
/* DBF_LONG => */DBR_LONG,
|
||||
/* DBF_ULONG => */DBR_ULONG,
|
||||
/* DBF_FLOAT => */DBR_FLOAT,
|
||||
/* DBF_DOUBLE => */DBR_DOUBLE,
|
||||
/* DBF_ENUM, => */DBR_ENUM,
|
||||
/* DBF_MENU, => */DBR_ENUM,
|
||||
/* DBF_DEVICE => */DBR_ENUM,
|
||||
/* DBF_INLINK => */DBR_STRING,
|
||||
/* DBF_OUTLINK => */DBR_STRING,
|
||||
/* DBF_FWDLINK => */DBR_STRING,
|
||||
/* DBF_NOACCESS => */DBR_NOACCESS };
|
||||
|
||||
long dbChannelFind(dbChannel *chan, const char *pname)
|
||||
{
|
||||
@@ -288,25 +296,28 @@ long dbChannelFind(dbChannel *chan, const char *pname)
|
||||
|
||||
dbInitEntry(pdbbase, &dbEntry);
|
||||
status = dbFindRecordPart(&dbEntry, &pname);
|
||||
if (status) goto finish;
|
||||
if (status)
|
||||
goto finish;
|
||||
|
||||
if (*pname == '.') ++pname;
|
||||
if (*pname == '.')
|
||||
++pname;
|
||||
status = dbFindFieldPart(&dbEntry, &pname);
|
||||
if (status == S_dbLib_fieldNotFound)
|
||||
status = dbGetAttributePart(&dbEntry, &pname);
|
||||
if (status) goto finish;
|
||||
if (status)
|
||||
goto finish;
|
||||
|
||||
paddr = &chan->addr;
|
||||
paddr = &chan->addr;
|
||||
pflddes = dbEntry.pflddes;
|
||||
dbfType = pflddes->field_type;
|
||||
|
||||
paddr->precord = dbEntry.precnode->precord;
|
||||
paddr->pfield = dbEntry.pfield;
|
||||
paddr->pfldDes = pflddes;
|
||||
paddr->no_elements = 1;
|
||||
paddr->field_type = dbfType;
|
||||
paddr->field_size = pflddes->size;
|
||||
paddr->special = pflddes->special;
|
||||
paddr->precord = dbEntry.precnode->precord;
|
||||
paddr->pfield = dbEntry.pfield;
|
||||
paddr->pfldDes = pflddes;
|
||||
paddr->no_elements = 1;
|
||||
paddr->field_type = dbfType;
|
||||
paddr->field_size = pflddes->size;
|
||||
paddr->special = pflddes->special;
|
||||
paddr->dbr_field_type = mapDBFToDBR[dbfType];
|
||||
|
||||
/* Handle field modifiers */
|
||||
@@ -315,14 +326,14 @@ long dbChannelFind(dbChannel *chan, const char *pname)
|
||||
case '$':
|
||||
/* Some field types can be accessed as char arrays */
|
||||
if (dbfType == DBF_STRING) {
|
||||
paddr->no_elements = pflddes->size;
|
||||
paddr->field_type = DBF_CHAR;
|
||||
paddr->field_size = 1;
|
||||
paddr->no_elements = pflddes->size;
|
||||
paddr->field_type = DBF_CHAR;
|
||||
paddr->field_size = 1;
|
||||
paddr->dbr_field_type = DBR_CHAR;
|
||||
} else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) {
|
||||
/* Clients see a char array, but keep original dbfType */
|
||||
paddr->no_elements = PVNAME_STRINGSZ + 12;
|
||||
paddr->field_size = 1;
|
||||
paddr->no_elements = PVNAME_STRINGSZ + 12;
|
||||
paddr->field_size = 1;
|
||||
paddr->dbr_field_type = DBR_CHAR;
|
||||
} else {
|
||||
status = S_dbLib_fieldNotFound;
|
||||
@@ -339,8 +350,7 @@ long dbChannelFind(dbChannel *chan, const char *pname)
|
||||
pname++;
|
||||
}
|
||||
|
||||
finish:
|
||||
dbFinishEntry(&dbEntry);
|
||||
finish: dbFinishEntry(&dbEntry);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -350,7 +360,8 @@ long dbChannelOpen(dbChannel *chan)
|
||||
chFilter *filter;
|
||||
long status = 0;
|
||||
|
||||
if (chan->magic != DBCHANNEL_MAGIC) return S_db_notInit;
|
||||
if (chan->magic != DBCHANNEL_MAGIC)
|
||||
return S_db_notInit;
|
||||
|
||||
paddr = &chan->addr;
|
||||
if (paddr->special == SPC_DBADDR) {
|
||||
@@ -359,14 +370,16 @@ long dbChannelOpen(dbChannel *chan)
|
||||
/* Let record type modify the dbAddr */
|
||||
if (prset && prset->cvt_dbaddr) {
|
||||
status = prset->cvt_dbaddr(paddr);
|
||||
if (status) return status;
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
filter = (chFilter *) ellFirst(&chan->filters);
|
||||
while (filter) {
|
||||
status = filter->fif->channel_open(filter);
|
||||
if (status) break;
|
||||
if (status)
|
||||
break;
|
||||
filter = (chFilter *) ellNext(&filter->node);
|
||||
}
|
||||
return status;
|
||||
@@ -376,7 +389,8 @@ void dbChannelReport(dbChannel *chan, int level)
|
||||
{
|
||||
chFilter *filter;
|
||||
|
||||
if (chan->magic != DBCHANNEL_MAGIC) return;
|
||||
if (chan->magic != DBCHANNEL_MAGIC)
|
||||
return;
|
||||
|
||||
filter = (chFilter *) ellFirst(&chan->filters);
|
||||
while (filter) {
|
||||
@@ -389,7 +403,8 @@ long dbChannelClose(dbChannel *chan)
|
||||
{
|
||||
chFilter *filter;
|
||||
|
||||
if (chan->magic != DBCHANNEL_MAGIC) return S_db_notInit;
|
||||
if (chan->magic != DBCHANNEL_MAGIC)
|
||||
return S_db_notInit;
|
||||
|
||||
while ((filter = (chFilter *) ellGet(&chan->filters))) {
|
||||
filter->fif->channel_close(filter);
|
||||
@@ -412,16 +427,17 @@ void dbRegisterFilter(const char *name, const chFilterIf *fif)
|
||||
}
|
||||
|
||||
pgph = gphFind(pdbbase->pgpHash, name, &pdbbase->filterList);
|
||||
if (pgph) return;
|
||||
if (pgph)
|
||||
return;
|
||||
|
||||
pfilt = dbCalloc(1, sizeof(filterPlugin));
|
||||
pfilt->name = strdup(name);
|
||||
pfilt->fif = fif;
|
||||
pfilt->fif = fif;
|
||||
|
||||
ellAdd(&pdbbase->filterList, &pfilt->node);
|
||||
pgph = gphAdd(pdbbase->pgpHash, pfilt->name, &pdbbase->filterList);
|
||||
if (!pgph) {
|
||||
free((void *)pfilt->name);
|
||||
free((void *) pfilt->name);
|
||||
free(pfilt);
|
||||
printf("dbRegisterFilter: gphAdd failed\n");
|
||||
return;
|
||||
@@ -431,10 +447,12 @@ void dbRegisterFilter(const char *name, const chFilterIf *fif)
|
||||
|
||||
const chFilterIf * dbFindFilter(const char *name, size_t len)
|
||||
{
|
||||
GPHENTRY *pgph = gphFindParse(pdbbase->pgpHash, name, len, &pdbbase->filterList);
|
||||
GPHENTRY *pgph = gphFindParse(pdbbase->pgpHash, name, len,
|
||||
&pdbbase->filterList);
|
||||
filterPlugin *pfilt;
|
||||
|
||||
if (!pgph) return NULL;
|
||||
pfilt = (filterPlugin *)pgph->userPvt;
|
||||
if (!pgph)
|
||||
return NULL;
|
||||
pfilt = (filterPlugin *) pgph->userPvt;
|
||||
return pfilt->fif;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
#define S_db_notInit (M_dbAccess|21) /*dbChannel not initialized*/
|
||||
|
||||
|
||||
/* A dbChannel points to a record field, and can have multiple filters */
|
||||
typedef struct dbChannel {
|
||||
epicsUInt32 magic;
|
||||
@@ -34,31 +33,44 @@ typedef struct dbChannel {
|
||||
typedef struct chFilter chFilter;
|
||||
|
||||
/* Return values from chFilterIf->parse_* routines: */
|
||||
enum {parse_stop, parse_continue};
|
||||
typedef enum {
|
||||
parse_stop, parse_continue
|
||||
} parse_result;
|
||||
|
||||
/* These routines must be implemented by each filter plug-in */
|
||||
typedef struct chFilterIf {
|
||||
/* Parsing event handlers */
|
||||
int (* parse_start)(chFilter *filter);
|
||||
/* Parsing event handlers: */
|
||||
parse_result (* parse_start)(chFilter *filter);
|
||||
/* If parse_start() returns parse_continue for a filter, one of
|
||||
* parse_abort() or parse_end() will later be called for that same
|
||||
* filter.
|
||||
*/
|
||||
void (* parse_abort)(chFilter *filter);
|
||||
int (* parse_end)(chFilter *filter);
|
||||
/* If parse_abort() is called it should release any memory allocated
|
||||
* for this filter; no further parse_...() calls will be made;
|
||||
*/
|
||||
parse_result (* parse_end)(chFilter *filter);
|
||||
/* If parse_end() returns parse_stop it should have released any
|
||||
* memory allocated for this filter; no further parse_...() calls will
|
||||
* be made in this case.
|
||||
*/
|
||||
|
||||
int (* parse_null)(chFilter *filter);
|
||||
int (* parse_boolean)(chFilter *filter, int boolVal);
|
||||
int (* parse_integer)(chFilter *filter, long integerVal);
|
||||
int (* parse_double)(chFilter *filter, double doubleVal);
|
||||
int (* parse_string)(chFilter *filter, const char *stringVal,
|
||||
parse_result (* parse_null)(chFilter *filter);
|
||||
parse_result (* parse_boolean)(chFilter *filter, int boolVal);
|
||||
parse_result (* parse_integer)(chFilter *filter, long integerVal);
|
||||
parse_result (* parse_double)(chFilter *filter, double doubleVal);
|
||||
parse_result (* parse_string)(chFilter *filter, const char *stringVal,
|
||||
size_t stringLen); /* NB: stringVal is not zero-terminated: */
|
||||
|
||||
int (* parse_start_map)(chFilter *filter);
|
||||
int (* parse_map_key)(chFilter *filter, const char *key,
|
||||
size_t stringLen);
|
||||
int (* parse_end_map)(chFilter *filter);
|
||||
parse_result (* parse_start_map)(chFilter *filter);
|
||||
parse_result (* parse_map_key)(chFilter *filter, const char *key,
|
||||
size_t stringLen); /* NB: key is not zero-terminated: */
|
||||
parse_result (* parse_end_map)(chFilter *filter);
|
||||
|
||||
int (* parse_start_array)(chFilter *filter);
|
||||
int (* parse_end_array)(chFilter *filter);
|
||||
parse_result (* parse_start_array)(chFilter *filter);
|
||||
parse_result (* parse_end_array)(chFilter *filter);
|
||||
|
||||
/* Channel operations */
|
||||
/* Channel operations: */
|
||||
long (* channel_open)(chFilter *filter);
|
||||
void (* channel_report)(chFilter *filter, int level);
|
||||
/* FIXME: More routines here ... */
|
||||
|
||||
@@ -29,76 +29,84 @@
|
||||
#define e_report 0x00004000
|
||||
#define e_close 0x00008000
|
||||
|
||||
unsigned int e;
|
||||
#define r_any (e_start | e_abort | e_end | \
|
||||
e_null | e_boolean | e_integer | e_double | e_string | \
|
||||
e_start_map | e_map_key | e_end_map | e_start_array | e_end_array)
|
||||
#define r_scalar (e_start | e_abort | e_end | \
|
||||
e_null | e_boolean | e_integer | e_double | e_string)
|
||||
|
||||
int p_start(chFilter *filter)
|
||||
unsigned int e, r;
|
||||
#define p_ret(x) return r & x ? parse_continue : parse_stop
|
||||
|
||||
parse_result p_start(chFilter *filter)
|
||||
{
|
||||
testOk(e & e_start, "parse_start called");
|
||||
return parse_continue;
|
||||
p_ret(e_start);
|
||||
}
|
||||
|
||||
void p_abort(chFilter *filter)
|
||||
{
|
||||
testOk(e & e_abort, "parse_abort called");
|
||||
}
|
||||
int p_end(chFilter *filter)
|
||||
|
||||
parse_result p_end(chFilter *filter)
|
||||
{
|
||||
testOk(e & e_end, "parse_end called");
|
||||
return parse_continue;
|
||||
p_ret(e_end);
|
||||
}
|
||||
|
||||
int p_null(chFilter *filter)
|
||||
parse_result p_null(chFilter *filter)
|
||||
{
|
||||
testOk(e & e_null, "parse_null called");
|
||||
return parse_continue;
|
||||
p_ret(e_null);
|
||||
}
|
||||
int p_boolean(chFilter *filter, int boolVal)
|
||||
parse_result p_boolean(chFilter *filter, int boolVal)
|
||||
{
|
||||
testOk(e & e_boolean, "parse_boolean called, val = %d", boolVal);
|
||||
return parse_continue;
|
||||
p_ret(e_boolean);
|
||||
}
|
||||
int p_integer(chFilter *filter, long integerVal)
|
||||
parse_result p_integer(chFilter *filter, long integerVal)
|
||||
{
|
||||
testOk(e & e_integer, "parse_integer called, val = %ld", integerVal);
|
||||
return parse_continue;
|
||||
p_ret(e_integer);
|
||||
}
|
||||
int p_double(chFilter *filter, double doubleVal)
|
||||
parse_result p_double(chFilter *filter, double doubleVal)
|
||||
{
|
||||
testOk(e & e_double, "parse_double called, val = %g", doubleVal);
|
||||
return parse_continue;
|
||||
p_ret(e_double);
|
||||
}
|
||||
int p_string(chFilter *filter, const char *stringVal, size_t stringLen)
|
||||
parse_result p_string(chFilter *filter, const char *stringVal, size_t stringLen)
|
||||
{
|
||||
testOk(e & e_string, "parse_string called, val = '%.*s'", stringLen,
|
||||
stringVal);
|
||||
return parse_continue;
|
||||
p_ret(e_string);
|
||||
}
|
||||
|
||||
int p_start_map(chFilter *filter)
|
||||
parse_result p_start_map(chFilter *filter)
|
||||
{
|
||||
testOk(e & e_start_map, "parse_start_map called");
|
||||
return parse_continue;
|
||||
p_ret(e_start_map);
|
||||
}
|
||||
int p_map_key(chFilter *filter, const char *key, size_t stringLen)
|
||||
parse_result p_map_key(chFilter *filter, const char *key, size_t stringLen)
|
||||
{
|
||||
testOk(e & e_map_key, "parse_map_key called, key = '%.*s'", stringLen, key);
|
||||
return parse_continue;
|
||||
p_ret(e_map_key);
|
||||
}
|
||||
int p_end_map(chFilter *filter)
|
||||
parse_result p_end_map(chFilter *filter)
|
||||
{
|
||||
testOk(e & e_end_map, "parse_end_map called");
|
||||
return parse_continue;
|
||||
p_ret(e_end_map);
|
||||
}
|
||||
|
||||
int p_start_array(chFilter *filter)
|
||||
parse_result p_start_array(chFilter *filter)
|
||||
{
|
||||
testOk(e & e_start_array, "parse_start_array called");
|
||||
return parse_continue;
|
||||
p_ret(e_start_array);
|
||||
}
|
||||
int p_end_array(chFilter *filter)
|
||||
parse_result p_end_array(chFilter *filter)
|
||||
{
|
||||
testOk(e & e_end_array, "parse_end_array called");
|
||||
return parse_continue;
|
||||
p_ret(e_end_array);
|
||||
}
|
||||
|
||||
long c_open(chFilter *filter)
|
||||
@@ -115,39 +123,49 @@ void c_close(chFilter *filter)
|
||||
testOk(e & e_close, "channel_close called");
|
||||
}
|
||||
|
||||
chFilterIf anyIf =
|
||||
chFilterIf testIf =
|
||||
{ p_start, p_abort, p_end, p_null, p_boolean, p_integer, p_double,
|
||||
p_string, p_start_map, p_map_key, p_end_map, p_start_array, p_end_array,
|
||||
c_open, c_report, c_close };
|
||||
|
||||
chFilterIf scalarIf =
|
||||
{ p_start, p_abort, p_end, p_null, p_boolean, p_integer, p_double,
|
||||
p_string, NULL, NULL, NULL, NULL, NULL, c_open,
|
||||
c_report, c_close};
|
||||
|
||||
MAIN(dbChannelTest)
|
||||
{
|
||||
dbChannel ch;
|
||||
|
||||
testPlan(45);
|
||||
testPlan(59);
|
||||
|
||||
testOk1(!dbReadDatabase(&pdbbase, "dbChannelTest.dbx", ".:..", NULL));
|
||||
testOk(!!pdbbase, "pdbbase was set");
|
||||
|
||||
e = 0;
|
||||
r = e = 0;
|
||||
testOk1(!dbChannelFind(&ch, "x.NAME$"));
|
||||
testOk1(ch.addr.no_elements > 1);
|
||||
testOk1(ch.addr.no_elements> 1);
|
||||
|
||||
testOk1(!dbChannelFind(&ch, "x.{}"));
|
||||
|
||||
dbRegisterFilter("any", &anyIf);
|
||||
testOk1(dbChannelFind(&ch, "y"));
|
||||
testOk1(dbChannelFind(&ch, "x.{\"none\":null}"));
|
||||
|
||||
dbRegisterFilter("any", &testIf);
|
||||
|
||||
e = e_start;
|
||||
testOk1(dbChannelFind(&ch, "x.{\"any\":null}"));
|
||||
|
||||
r = e_start;
|
||||
e = e_start | e_null | e_abort;
|
||||
testOk1(dbChannelFind(&ch, "x.{\"any\":null}"));
|
||||
|
||||
r = e_start | e_null;
|
||||
e = e_start | e_null | e_end;
|
||||
testOk1(dbChannelFind(&ch, "x.{\"any\":null}"));
|
||||
|
||||
r = r_any;
|
||||
e = e_start | e_null | e_end;
|
||||
testOk1(!dbChannelFind(&ch, "x.{\"any\":null}"));
|
||||
e = e_close;
|
||||
testOk1(!dbChannelClose(&ch));
|
||||
|
||||
dbRegisterFilter("scalar", &scalarIf);
|
||||
dbRegisterFilter("scalar", &testIf);
|
||||
|
||||
e = e_start | e_null | e_end;
|
||||
testOk1(!dbChannelFind(&ch, "x.{\"scalar\":null}"));
|
||||
@@ -158,7 +176,8 @@ MAIN(dbChannelTest)
|
||||
e = e_close;
|
||||
testOk1(!dbChannelClose(&ch));
|
||||
|
||||
e = e_start | e_start_array | e_boolean | e_integer | e_end_array | e_end;
|
||||
e = e_start | e_start_array | e_boolean | e_integer | e_end_array
|
||||
| e_end;
|
||||
testOk1(!dbChannelFind(&ch, "x.{\"any\":[true,1]}"));
|
||||
e = e_close;
|
||||
testOk1(!dbChannelClose(&ch));
|
||||
@@ -167,12 +186,13 @@ MAIN(dbChannelTest)
|
||||
| e_end;
|
||||
testOk1(!dbChannelFind(&ch, "x.{\"any\":{\"a\":2.7183,\"b\":\"c\"}}"));
|
||||
|
||||
e = e_close | e_start | e_abort;
|
||||
r = r_scalar;
|
||||
e = e_close | e_start | e_start_array | e_abort;
|
||||
testOk1(dbChannelFind(&ch, "x.{\"scalar\":[null]}"));
|
||||
e = 0;
|
||||
testOk1(!dbChannelClose(&ch));
|
||||
|
||||
e = e_start | e_abort;
|
||||
e = e_start | e_start_map | e_abort;
|
||||
testOk1(dbChannelFind(&ch, "x.{\"scalar\":{}}"));
|
||||
e = 0;
|
||||
testOk1(!dbChannelClose(&ch));
|
||||
|
||||
Reference in New Issue
Block a user