Fix dbConstLink to handle a long-string array properly

Added a new parser dbLSConvertJSON for long-string arrays.
New test checks that only the first string element is used.
This commit is contained in:
Andrew Johnson
2017-04-24 17:09:01 -05:00
parent 311ad57e93
commit da94b7a2e4
5 changed files with 99 additions and 23 deletions

View File

@@ -73,26 +73,11 @@ static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
epicsUInt32 *plen)
{
const char *pstr = plink->value.constantStr;
size_t len;
if (!pstr)
return S_db_badField;
if (!size)
return 0;
len = strlen(pstr);
/* FIXME This handles the common case, but not the general one... */
if (pstr[0] == '[' && pstr[1] == '"' &&
pstr[len-2] == '"' && pstr[len-1] == ']') {
pstr += 2;
len -= 4;
}
if (len+1 > size) len = size-1;
memcpy(pbuffer, pstr, len);
pbuffer[len] = 0;
*plen = len+1;
return 0;
return dbLSConvertJSON(pstr, pbuffer, size, plen);
}
static long dbConstLoadArray(struct link *plink, short dbrType, void *pbuffer,

View File

@@ -17,6 +17,7 @@
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbConvertFast.h"
#include "dbConvertJSON.h"
typedef long (*FASTCONVERT)();
@@ -49,6 +50,10 @@ static int dbcj_integer(void *ctx, long num) {
return 1;
}
static int dblsj_integer(void *ctx, long num) {
return 0; /* Illegal */
}
static int dbcj_double(void *ctx, double num) {
parseContext *parser = (parseContext *) ctx;
FASTCONVERT conv = dbFastPutConvertRoutine[DBF_DOUBLE][parser->dbrType];
@@ -61,6 +66,10 @@ static int dbcj_double(void *ctx, double num) {
return 1;
}
static int dblsj_double(void *ctx, double num) {
return 0; /* Illegal */
}
static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
parseContext *parser = (parseContext *) ctx;
char *pdest = parser->pdest;
@@ -69,7 +78,7 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
* metadata about the field than we have available at the moment.
*/
if (parser->dbrType != DBF_STRING) {
errlogPrintf("dbPutConvertJSON: String provided, numeric value(s) expected\n");
errlogPrintf("dbConvertJSON: String provided, numeric value(s) expected\n");
return 0; /* Illegal */
}
@@ -84,8 +93,28 @@ static int dbcj_string(void *ctx, const unsigned char *val, unsigned int len) {
return 1;
}
static int dblsj_string(void *ctx, const unsigned char *val, unsigned int len) {
parseContext *parser = (parseContext *) ctx;
char *pdest = parser->pdest;
if (parser->dbrType != DBF_STRING) {
errlogPrintf("dbConvertJSON: dblsj_string dbrType error\n");
return 0; /* Illegal */
}
if (parser->elems > 0) {
if (len > parser->dbrSize - 1)
len = parser->dbrSize - 1;
strncpy(pdest, (const char *) val, len);
pdest[len] = 0;
parser->pdest = pdest + len;
parser->elems = 0;
}
return 1;
}
static int dbcj_start_map(void *ctx) {
errlogPrintf("dbPutConvertJSON: Map type not supported\n");
errlogPrintf("dbConvertJSON: Map type not supported\n");
return 0; /* Illegal */
}
@@ -101,7 +130,7 @@ static int dbcj_start_array(void *ctx) {
parseContext *parser = (parseContext *) ctx;
if (++parser->depth > 1)
errlogPrintf("dbPutConvertJSON: Embedded arrays not supported\n");
errlogPrintf("dbConvertJSON: Embedded arrays not supported\n");
return (parser->depth == 1);
}
@@ -157,7 +186,7 @@ long dbPutConvertJSON(const char *json, short dbrType,
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, (unsigned int) jlen);
fprintf(stderr, "dbPutConvertJSON: %s\n", err);
fprintf(stderr, "dbConvertJSON: %s\n", err);
yajl_free_error(yh, err);
}
/* fall through */
@@ -170,3 +199,59 @@ long dbPutConvertJSON(const char *json, short dbrType,
}
static yajl_callbacks dblsj_callbacks = {
dbcj_null, dbcj_boolean, dblsj_integer, dblsj_double, NULL, dblsj_string,
dbcj_start_map, dbcj_map_key, dbcj_end_map,
dbcj_start_array, dbcj_end_array
};
long dbLSConvertJSON(const char *json, char *pdest, epicsUInt32 size,
epicsUInt32 *plen)
{
parseContext context, *parser = &context;
yajl_alloc_funcs dbcj_alloc;
yajl_handle yh;
yajl_status ys;
size_t jlen = strlen(json);
long status;
if (!size) {
*plen = 0;
return 0;
}
parser->depth = 0;
parser->dbrType = DBF_STRING;
parser->dbrSize = size;
parser->pdest = pdest;
parser->elems = 1;
yajl_set_default_alloc_funcs(&dbcj_alloc);
yh = yajl_alloc(&dblsj_callbacks, &dbcj_config, &dbcj_alloc, parser);
if (!yh)
return S_db_noMemory;
ys = yajl_parse(yh, (const unsigned char *) json, (unsigned int) jlen);
if (ys == yajl_status_insufficient_data)
ys = yajl_parse_complete(yh);
switch (ys) {
case yajl_status_ok:
*plen = (char *) parser->pdest - pdest + 1;
status = 0;
break;
case yajl_status_error: {
unsigned char *err = yajl_get_error(yh, 1,
(const unsigned char *) json, (unsigned int) jlen);
fprintf(stderr, "dbLoadLS_JSON: %s\n", err);
yajl_free_error(yh, err);
}
/* fall through */
default:
status = S_db_badField;
}
yajl_free(yh);
return status;
}

View File

@@ -18,7 +18,8 @@ extern "C" {
/* This name should probably be changed to inclue "array" */
epicsShareFunc long dbPutConvertJSON(const char *json, short dbrType,
void *pdest, long *psize);
epicsShareFunc long dbLSConvertJSON(const char *json, char *pdest,
epicsUInt32 size, epicsUInt32 *plen);
#ifdef __cplusplus
}
#endif

View File

@@ -53,6 +53,8 @@ static void testLongStringInit()
testdbGetFieldEqual("longstr3.VAL", DBR_STRING, "!--------------------------------------");
}
testdbGetFieldEqual("longstr4.VAL", DBR_STRING, "One");
testIocShutdownOk();
testdbCleanup();
@@ -149,7 +151,7 @@ static void testPrintfInit()
MAIN(linkInitTest)
{
testPlan(30);
testPlan(31);
testLongStringInit();
testCalcInit();
testPrintfInit();

View File

@@ -1,4 +1,3 @@
record(lsi, "longstr1") {
field(SIZV, "100")
field(INP, ["!----------------------------------------------!"])
@@ -14,6 +13,10 @@ record(lsi, "longstr3") {
field(INP, {const: "!----------------------------------------------!"})
}
record(stringin, "longstr4") {
field(INP, ["One","Two","Three","Four"])
}
record(ai, "emptylink" ) {
field(INP, {calc: {expr:"0"}})
}