Fix scalar link initialization from hex constants

Partially fixes LP: #1699445
Includes regression tests, with TODO for arrays which are still broken
and need a full JSON5 parser to fix.
This commit is contained in:
Andrew Johnson
2017-06-22 18:45:10 -05:00
3 changed files with 177 additions and 16 deletions
+105 -3
View File
@@ -16,18 +16,121 @@
#include <string.h>
#include "dbDefs.h"
#include "epicsStdlib.h"
#define epicsExportSharedSymbols
#include "dbAccessDefs.h"
#include "dbAddr.h"
#include "dbCommon.h"
#include "dbConstLink.h"
#include "dbConvertFast.h"
#include "dbConvertJSON.h"
#include "dbFldTypes.h"
#include "dbLink.h"
#include "link.h"
/**************************** Convert functions ****************************/
/* The difference between these and dbFastConvert is that constants
* may contain hex numbers, whereas database conversions can't.
*/
/* Copy to STRING */
static long cvt_st_st(const char *from, void *pfield, const dbAddr *paddr)
{
char *to = pfield;
size_t size;
if (paddr && paddr->field_size < MAX_STRING_SIZE) {
size = paddr->field_size - 1;
} else {
size = MAX_STRING_SIZE - 1;
}
strncpy(to, from, size);
to[size] = 0;
return 0;
}
/* Most integer conversions are identical */
#define cvt_st_int(TYPE) static long \
cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
epics##TYPE *to = pfield; \
char *end; \
\
if (*from == 0) { \
*to = 0; \
return 0; \
} \
return epicsParse##TYPE(from, to, 0, &end); \
}
/* Instanciate for CHAR, UCHAR, SHORT, USHORT and LONG */
cvt_st_int(Int8)
cvt_st_int(UInt8)
cvt_st_int(Int16)
cvt_st_int(UInt16)
cvt_st_int(Int32)
/* Conversion for ULONG is different... */
static long cvt_st_UInt32(const char *from, void *pfield, const dbAddr *paddr)
{
epicsUInt32 *to = pfield;
char *end;
long status;
if (*from == 0) {
*to = 0;
return 0;
}
status = epicsParseUInt32(from, to, 0, &end);
if (status == S_stdlib_noConversion ||
(!status && (*end == '.' || *end == 'e' || *end == 'E'))) {
/*
* Convert via double so numbers like 1.0e3 convert properly.
* db_access pretends ULONG fields are DOUBLE.
*/
double dval;
status = epicsParseFloat64(from, &dval, &end);
if (!status &&
dval >=0 &&
dval <= ULONG_MAX)
*to = dval;
}
return status;
}
/* Instanciate for INT64 and UINT64 */
cvt_st_int(Int64)
cvt_st_int(UInt64)
/* Float conversions are identical */
#define cvt_st_float(TYPE) static long \
cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
epics##TYPE *to = pfield; \
char *end; \
\
if (*from == 0) { \
*to = 0; \
return 0; \
} \
return epicsParse##TYPE(from, to, &end); \
}
/* Instanciate for FLOAT32 and FLOAT64 */
cvt_st_float(Float32)
cvt_st_float(Float64)
static long (*convert[DBF_DOUBLE+1])(const char *, void *, const dbAddr *) = {
cvt_st_st,
cvt_st_Int8, cvt_st_UInt8,
cvt_st_Int16, cvt_st_UInt16,
cvt_st_Int32, cvt_st_UInt32,
cvt_st_Int64, cvt_st_UInt64,
cvt_st_Float32, cvt_st_Float64
};
/***************************** Constant Links *****************************/
/* Forward definition */
@@ -65,8 +168,7 @@ static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer)
return dbPutConvertJSON(pstr, dbrType, pbuffer, &nReq);
}
return dbFastPutConvertRoutine[DBR_STRING][dbrType]
(pstr, pbuffer, NULL);
return convert[dbrType](pstr, pbuffer, NULL);
}
static long dbConstLoadLS(struct link *plink, char *pbuffer, epicsUInt32 size,
+28
View File
@@ -0,0 +1,28 @@
record(ai, "ai1") {
field(INP, 0x10)
}
record(longin, "li1") {
field(INP, 0x10)
}
record(mbbiDirect, "mi1") {
field(INP, 0x10)
field(NOBT, 8)
}
record(aSub, "as1") {
field(INPA, 0x10)
field(FTA, "CHAR")
field(INPB, 0x10)
field(FTB, "UCHAR")
field(INPC, 0x10)
field(FTC, "SHORT")
field(INPD, 0x10)
field(FTD, "USHORT")
field(INPE, 0x10)
field(FTE, "LONG")
field(INPF, 0x10)
field(FTF, "ULONG")
field(INPG, 0x10)
field(FTG, "FLOAT")
field(INPH, 0x10)
field(FTH, "DOUBLE")
}
+44 -13
View File
@@ -13,11 +13,24 @@
#include <waveformRecord.h>
/*
* Test the some identified regressions
* Tests for specific regressions
*/
void regressTest_registerRecordDeviceDriver(struct dbBase *);
static
void startRegressTestIoc(const char *dbfile)
{
testdbPrepare();
testdbReadDatabase("regressTest.dbd", NULL, NULL);
regressTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase(dbfile, NULL, NULL);
eltc(0);
testIocInitOk();
eltc(1);
}
/*
* https://bugs.launchpad.net/epics-base/+bug/1577108
*/
@@ -28,21 +41,11 @@ void testArrayLength1(void)
calcoutRecord *precco;
double *pbuf;
testdbPrepare();
testdbReadDatabase("regressTest.dbd", NULL, NULL);
regressTest_registerRecordDeviceDriver(pdbbase);
testdbReadDatabase("regressArray1.db", NULL, NULL);
startRegressTestIoc("regressArray1.db");
precwf = (waveformRecord*)testdbRecordPtr("wf");
precco = (calcoutRecord*)testdbRecordPtr("co");
eltc(0);
testIocInitOk();
eltc(1);
dbScanLock((dbCommon*)precwf);
pbuf = (double*)precwf->bptr;
dbScanUnlock((dbCommon*)precwf);
@@ -65,9 +68,37 @@ void testArrayLength1(void)
testdbCleanup();
}
/*
* https://bugs.launchpad.net/epics-base/+bug/1699445
*/
static
void testHexConstantLinks(void)
{
startRegressTestIoc("regressHex.db");
testdbGetFieldEqual("ai1", DBR_LONG, 0x10);
testdbGetFieldEqual("li1", DBR_LONG, 0x10);
testdbGetFieldEqual("mi1", DBR_LONG, 0x10);
testTodoBegin("Needs JSON5 for hex arrays");
testdbGetFieldEqual("as1.A", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.B", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.C", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.D", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.E", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.F", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.G", DBR_LONG, 0x10);
testdbGetFieldEqual("as1.H", DBR_LONG, 0x10);
testTodoEnd();
testIocShutdownOk();
testdbCleanup();
}
MAIN(regressTest)
{
testPlan(5);
testPlan(16);
testArrayLength1();
testHexConstantLinks();
return testDone();
}