Merged simple-filter-conf branch
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* für Materialien und Energie GmbH.
|
||||
* Copyright (c) 2014 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
* Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
/* Based on the linkoptions utility by Michael Davidsaver (BNL) */
|
||||
@@ -84,19 +85,19 @@ store_integer_value(const chfPluginArgDef *opt, char *user, epicsInt32 val)
|
||||
|
||||
switch (opt->optType) {
|
||||
case chfPluginArgInt32:
|
||||
ival = (epicsInt32 *) ((char *)user + opt->offset);
|
||||
ival = (epicsInt32 *) ((char *)user + opt->dataOffset);
|
||||
*ival = val;
|
||||
break;
|
||||
case chfPluginArgBoolean:
|
||||
sval = user + opt->offset;
|
||||
sval = user + opt->dataOffset;
|
||||
*sval = !!val;
|
||||
break;
|
||||
case chfPluginArgDouble:
|
||||
dval = (double*) (user + opt->offset);
|
||||
dval = (double*) (user + opt->dataOffset);
|
||||
*dval = val;
|
||||
break;
|
||||
case chfPluginArgString:
|
||||
sval = user + opt->offset;
|
||||
sval = user + opt->dataOffset;
|
||||
ret = sprintf(buff, "%ld", (long)val);
|
||||
if (ret < 0 || (unsigned) ret > opt->size - 1) {
|
||||
return -1;
|
||||
@@ -105,7 +106,7 @@ store_integer_value(const chfPluginArgDef *opt, char *user, epicsInt32 val)
|
||||
sval[opt->size-1]='\0';
|
||||
break;
|
||||
case chfPluginArgEnum:
|
||||
eval = (int*) (user + opt->offset);
|
||||
eval = (int*) (user + opt->dataOffset);
|
||||
for (emap = opt->enums; emap && emap->name; emap++) {
|
||||
if (val == emap->value) {
|
||||
*eval = val;
|
||||
@@ -143,19 +144,19 @@ static int store_boolean_value(const chfPluginArgDef *opt, char *user, int val)
|
||||
|
||||
switch (opt->optType) {
|
||||
case chfPluginArgInt32:
|
||||
ival = (epicsInt32 *) (user + opt->offset);
|
||||
ival = (epicsInt32 *) (user + opt->dataOffset);
|
||||
*ival = val;
|
||||
break;
|
||||
case chfPluginArgBoolean:
|
||||
sval = user + opt->offset;
|
||||
sval = user + opt->dataOffset;
|
||||
*sval = val;
|
||||
break;
|
||||
case chfPluginArgDouble:
|
||||
dval = (double*) (user + opt->offset);
|
||||
dval = (double*) (user + opt->dataOffset);
|
||||
*dval = !!val;
|
||||
break;
|
||||
case chfPluginArgString:
|
||||
sval = user + opt->offset;
|
||||
sval = user + opt->dataOffset;
|
||||
if ((unsigned) (val ? 4 : 5) > opt->size - 1) {
|
||||
return -1;
|
||||
}
|
||||
@@ -196,24 +197,24 @@ store_double_value(const chfPluginArgDef *opt, void *vuser, double val)
|
||||
if (val < INT_MIN || val > INT_MAX) {
|
||||
return -1;
|
||||
}
|
||||
ival = (epicsInt32 *) (user + opt->offset);
|
||||
ival = (epicsInt32 *) (user + opt->dataOffset);
|
||||
*ival = (epicsInt32) val;
|
||||
break;
|
||||
case chfPluginArgBoolean:
|
||||
sval = user + opt->offset;
|
||||
sval = user + opt->dataOffset;
|
||||
*sval = !!val;
|
||||
break;
|
||||
case chfPluginArgDouble:
|
||||
dval = (double*) (user + opt->offset);
|
||||
dval = (double*) (user + opt->dataOffset);
|
||||
*dval = val;
|
||||
break;
|
||||
case chfPluginArgString:
|
||||
sval = user + opt->offset;
|
||||
sval = user + opt->dataOffset;
|
||||
if (opt->size <= 8) { /* Play it safe: 3 exp + 2 sign + 'e' + '.' */
|
||||
return -1;
|
||||
}
|
||||
i = epicsSnprintf(sval, opt->size, "%.*g", (int) opt->size - 7, val);
|
||||
if (i >= opt->size) {
|
||||
if (i < 0 || (unsigned) i >= opt->size) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -252,11 +253,11 @@ store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
|
||||
|
||||
switch (opt->optType) {
|
||||
case chfPluginArgInt32:
|
||||
ival = (epicsInt32 *) (user + opt->offset);
|
||||
ival = (epicsInt32 *) (user + opt->dataOffset);
|
||||
return epicsParseInt32(val, ival, 0, &end);
|
||||
|
||||
case chfPluginArgBoolean:
|
||||
sval = user + opt->offset;
|
||||
sval = user + opt->dataOffset;
|
||||
if (epicsStrnCaseCmp(val, "true", len) == 0) {
|
||||
*sval = 1;
|
||||
} else if (epicsStrnCaseCmp(val, "false", len) == 0) {
|
||||
@@ -270,17 +271,17 @@ store_string_value(const chfPluginArgDef *opt, char *user, const char *val,
|
||||
}
|
||||
break;
|
||||
case chfPluginArgDouble:
|
||||
dval = (double*) (user + opt->offset);
|
||||
dval = (double*) (user + opt->dataOffset);
|
||||
return epicsParseDouble(val, dval, &end);
|
||||
|
||||
case chfPluginArgString:
|
||||
i = opt->size-1 < len ? opt->size-1 : len;
|
||||
sval = user + opt->offset;
|
||||
i = opt->size-1 < len ? opt->size-1 : (int) len;
|
||||
sval = user + opt->dataOffset;
|
||||
strncpy(sval, val, i);
|
||||
sval[i] = '\0';
|
||||
break;
|
||||
case chfPluginArgEnum:
|
||||
eval = (int*) (user + opt->offset);
|
||||
eval = (int*) (user + opt->dataOffset);
|
||||
for (emap = opt->enums; emap && emap->name; emap++) {
|
||||
if (strncmp(emap->name, val, len) == 0) {
|
||||
*eval = emap->value;
|
||||
@@ -333,8 +334,10 @@ static parse_result parse_start(chFilter *filter)
|
||||
|
||||
/* Call the plugin to allocate its structure, it returns NULL on error */
|
||||
if (p->pif->allocPvt) {
|
||||
if ((f->puser = p->pif->allocPvt()) == NULL)
|
||||
if ((f->puser = p->pif->allocPvt()) == NULL) {
|
||||
errlogPrintf("chfConfigParseStart: plugin pvt alloc failed\n");
|
||||
goto errplugin;
|
||||
}
|
||||
}
|
||||
|
||||
filter->puser = (void*) f;
|
||||
@@ -455,11 +458,13 @@ parse_map_key(chFilter *filter, const char *key, size_t stringLen)
|
||||
{
|
||||
const chfPluginArgDef *cur;
|
||||
const chfPluginArgDef *opts = ((chfPlugin*)filter->plug->puser)->opts;
|
||||
chfFilter *f = (chfFilter*)filter->puser;
|
||||
chfFilter *f = (chfFilter*)filter->puser;
|
||||
int *tag;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
f->nextParam = -1;
|
||||
for(cur = opts, i = 0; cur && cur->name; cur++, i++) {
|
||||
for (cur = opts, i = 0; cur && cur->name; cur++, i++) {
|
||||
if (strncmp(key, cur->name, stringLen) == 0) {
|
||||
f->nextParam = i;
|
||||
break;
|
||||
@@ -469,7 +474,19 @@ parse_map_key(chFilter *filter, const char *key, size_t stringLen)
|
||||
return parse_stop;
|
||||
}
|
||||
|
||||
if (opts[i].tagged) {
|
||||
tag = (int*) ((char*) f->puser + opts[i].tagOffset);
|
||||
*tag = opts[i].choice;
|
||||
}
|
||||
|
||||
f->found[i/32] |= 1<<(i%32);
|
||||
/* Mark tag and all other options pointing to the same data as found */
|
||||
for (cur = opts, j = 0; cur && cur->name; cur++, j++) {
|
||||
if ((opts[i].tagged && cur->dataOffset == opts[i].tagOffset)
|
||||
|| cur->dataOffset == opts[i].dataOffset)
|
||||
f->found[j/32] |= 1<<(j%32);
|
||||
}
|
||||
|
||||
return parse_continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* für Materialien und Energie GmbH.
|
||||
* Copyright (c) 2014 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
* Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
/* Based on the linkoptions utility by Michael Davidsaver (BNL) */
|
||||
@@ -44,10 +45,11 @@ struct db_field_log;
|
||||
*
|
||||
* typedef struct myStruct {
|
||||
* ... other stuff
|
||||
* char mode;
|
||||
* epicsInt32 ival;
|
||||
* double dval;
|
||||
* double dval;
|
||||
* epicsInt32 ival2;
|
||||
* int enumval;
|
||||
* int enumval;
|
||||
* char strval[20];
|
||||
* char boolval;
|
||||
* } myStruct;
|
||||
@@ -57,18 +59,22 @@ struct db_field_log;
|
||||
*
|
||||
* static const
|
||||
* chfPluginDef myStructDef[] = {
|
||||
* chfInt32 (myStruct, ival, "Integer" , 0, 0),
|
||||
* chfInt32 (myStruct, ival2, "Second" , 1, 0),
|
||||
* chfDouble(myStruct, dval, "Double" , 1, 0),
|
||||
* chfString(myStruct, strval , "String" , 1, 0),
|
||||
* chfEnum (myStruct, enumval, "Color" , 1, 0, colorEnum),
|
||||
* chfBoolean(myStruct, boolval, "Bool" , 1, 0),
|
||||
* chfTagInt32(myStruct, ival, "Integer" , ival2, 3, 0, 0),
|
||||
* chfInt32 (myStruct, ival2, "Second" , 1, 0),
|
||||
* chfDouble (myStruct, dval, "Double" , 1, 0),
|
||||
* chfString (myStruct, strval , "String" , 1, 0),
|
||||
* chfEnum (myStruct, enumval, "Color" , 1, 0, colorEnum),
|
||||
* chfBoolean (myStruct, boolval, "Bool" , 1, 0),
|
||||
* chfPluginEnd
|
||||
* };
|
||||
*
|
||||
* Note: The 4th argument specifies the parameter to be required (1) or optional (0),
|
||||
* the 5th whether converting to the required type is allowed (1), or
|
||||
* type mismatches are an error (0).
|
||||
* Note: The "Tag" version has two additional arguments. the 4th arg specifies the tag
|
||||
* field (integer type) inside the structure to be set, the 5th arg specifies the
|
||||
* value to set the tag field to. Arguments 6 and 7 specify "required" and
|
||||
* "conversion" as described above.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -231,25 +237,57 @@ typedef struct chfPluginArgDef {
|
||||
chfPluginArg optType;
|
||||
unsigned int required:1;
|
||||
unsigned int convert:1;
|
||||
epicsUInt32 offset;
|
||||
epicsUInt32 size;
|
||||
unsigned int tagged:1;
|
||||
epicsUInt32 tagOffset;
|
||||
epicsUInt32 choice;
|
||||
epicsUInt32 dataOffset;
|
||||
epicsUInt32 size;
|
||||
const chfPluginEnumType *enums;
|
||||
} chfPluginArgDef;
|
||||
|
||||
/* Simple arguments */
|
||||
|
||||
#define chfInt32(Struct, Member, Name, Req, Conv) \
|
||||
{Name, chfPluginArgInt32, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
{Name, chfPluginArgInt32, Req, Conv, 0, 0, 0, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
|
||||
#define chfBoolean(Struct, Member, Name, Req, Conv) \
|
||||
{Name, chfPluginArgBoolean, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
{Name, chfPluginArgBoolean, Req, Conv, 0, 0, 0, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
|
||||
#define chfDouble(Struct, Member, Name, Req, Conv) \
|
||||
{Name, chfPluginArgDouble, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
{Name, chfPluginArgDouble, Req, Conv, 0, 0, 0, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
|
||||
#define chfString(Struct, Member, Name, Req, Conv) \
|
||||
{Name, chfPluginArgString, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
{Name, chfPluginArgString, Req, Conv, 0, 0, 0, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
|
||||
#define chfEnum(Struct, Member, Name, Req, Conv, Enums) \
|
||||
{Name, chfPluginArgEnum, Req, Conv, OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
|
||||
{Name, chfPluginArgEnum, Req, Conv, 0, 0, 0, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
|
||||
|
||||
/* Tagged arguments */
|
||||
|
||||
#define chfTagInt32(Struct, Member, Name, Tag, Choice, Req, Conv) \
|
||||
{Name, chfPluginArgInt32, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
|
||||
#define chfTagBoolean(Struct, Member, Name, Tag, Choice, Req, Conv) \
|
||||
{Name, chfPluginArgBoolean, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
|
||||
#define chfTagDouble(Struct, Member, Name, Tag, Choice, Req, Conv) \
|
||||
{Name, chfPluginArgDouble, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
|
||||
#define chfTagString(Struct, Member, Name, Tag, Choice, Req, Conv) \
|
||||
{Name, chfPluginArgString, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), NULL}
|
||||
|
||||
#define chfTagEnum(Struct, Member, Name, Tag, Choice, Req, Conv, Enums) \
|
||||
{Name, chfPluginArgEnum, Req, Conv, 1, OFFSET(Struct, Tag), Choice, \
|
||||
OFFSET(Struct, Member), sizeof( ((Struct*)0)->Member ), Enums}
|
||||
|
||||
#define chfPluginArgEnd {0}
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* für Materialien und Energie GmbH.
|
||||
* Copyright (c) 2014 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
* Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
@@ -59,6 +60,8 @@ typedef struct myStruct {
|
||||
int sent5;
|
||||
char str[20];
|
||||
int sent6;
|
||||
epicsUInt32 tval;
|
||||
int sent7;
|
||||
char c;
|
||||
char c1[2];
|
||||
int offpre;
|
||||
@@ -68,6 +71,29 @@ typedef struct myStruct {
|
||||
static const
|
||||
chfPluginEnumType colorEnum[] = { {"R", 1}, {"G", 2}, {"B", 4}, {NULL,0} };
|
||||
|
||||
static const
|
||||
chfPluginArgDef sloppyTaggedOpts[] = {
|
||||
chfInt32 (myStruct, tval, "t" , 0, 0),
|
||||
chfTagInt32 (myStruct, ival, "I" , tval, 1, 0, 0),
|
||||
chfTagBoolean(myStruct, flag, "F" , tval, 2, 0, 0),
|
||||
chfTagDouble (myStruct, dval, "D" , tval, 3, 0, 0),
|
||||
chfTagString (myStruct, str, "S" , tval, 4, 0, 0),
|
||||
chfTagEnum (myStruct, enumval, "C" , tval, 5, 0, 0, colorEnum),
|
||||
chfPluginArgEnd
|
||||
};
|
||||
|
||||
static const
|
||||
chfPluginArgDef strictTaggedOpts[] = {
|
||||
chfInt32 (myStruct, tval, "t" , 1, 0),
|
||||
chfBoolean (myStruct, flag, "f" , 1, 0),
|
||||
chfTagInt32 (myStruct, ival, "I" , tval, 1, 0, 0),
|
||||
chfTagBoolean(myStruct, flag, "F" , tval, 2, 0, 0),
|
||||
chfTagDouble (myStruct, dval, "D" , tval, 3, 1, 0),
|
||||
chfTagDouble (myStruct, dval, "D2", tval, 4, 1, 0),
|
||||
chfTagEnum (myStruct, enumval, "C" , tval, 5, 0, 0, colorEnum),
|
||||
chfPluginArgEnd
|
||||
};
|
||||
|
||||
static const
|
||||
chfPluginArgDef strictOpts[] = {
|
||||
chfInt32 (myStruct, ival, "i" , 1, 0),
|
||||
@@ -133,8 +159,9 @@ static void clearStruct(void *p) {
|
||||
if (!my) return;
|
||||
memset(my, 0, sizeof(myStruct));
|
||||
my->sent1 = my->sent2 = my->sent3 = my->sent4 =
|
||||
my->sent5 = my->sent6 = PATTERN;
|
||||
my->sent5 = my->sent6 = my->sent7 = PATTERN;
|
||||
my->ival = 12;
|
||||
my->tval = 99;
|
||||
my->flag = 1;
|
||||
my->dval = 1.234e5;
|
||||
strcpy(my->str, "hello");
|
||||
@@ -162,6 +189,15 @@ static void * allocPvt(void)
|
||||
return my;
|
||||
}
|
||||
|
||||
static void * allocPvtFail(void)
|
||||
{
|
||||
if (!puser1) {
|
||||
testOk(e1 & e_alloc, "allocPvt (1) called");
|
||||
c1 |= e_alloc;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void freePvt(void *user)
|
||||
{
|
||||
if (user == puser1) {
|
||||
@@ -446,8 +482,22 @@ static chfPluginIf postPif = {
|
||||
channel_close
|
||||
};
|
||||
|
||||
static chfPluginIf allocFailPif = {
|
||||
allocPvtFail,
|
||||
freePvt,
|
||||
|
||||
parse_error,
|
||||
parse_ok,
|
||||
|
||||
channel_open,
|
||||
channelRegisterPre,
|
||||
channelRegisterPost,
|
||||
channel_report,
|
||||
channel_close
|
||||
};
|
||||
|
||||
static int checkValues(myStruct *my,
|
||||
epicsUInt32 i, int f, double d, char *s1, char *s2, int c) {
|
||||
char t, epicsUInt32 i, int f, double d, char *s1, char *s2, int c) {
|
||||
int ret = 1;
|
||||
int s1fail, s2fail;
|
||||
int s2valid = (s2 && s2[0] != '\0');
|
||||
@@ -460,6 +510,8 @@ static int checkValues(myStruct *my,
|
||||
CHK(my->sent4, PATTERN, "%08x")
|
||||
CHK(my->sent5, PATTERN, "%08x")
|
||||
CHK(my->sent6, PATTERN, "%08x")
|
||||
CHK(my->sent7, PATTERN, "%08x")
|
||||
CHK(my->tval, t, "%08x")
|
||||
CHK(my->ival, i, "%08x")
|
||||
CHK(my->flag, f, "%02x")
|
||||
CHK(my->dval, d, "%f")
|
||||
@@ -492,7 +544,7 @@ MAIN(chfPluginTest)
|
||||
_set_output_format(_TWO_DIGIT_EXPONENT);
|
||||
#endif
|
||||
|
||||
testPlan(1351);
|
||||
testPlan(1433);
|
||||
|
||||
dbChannelInit();
|
||||
db_init_events();
|
||||
@@ -532,6 +584,10 @@ MAIN(chfPluginTest)
|
||||
eltc(1);
|
||||
|
||||
testHead("Register plugins");
|
||||
testOk(!chfPluginRegister("sloppy-tagged", &myPif, sloppyTaggedOpts),
|
||||
"register plugin sloppy-tagged");
|
||||
testOk(!chfPluginRegister("strict-tagged", &myPif, strictTaggedOpts),
|
||||
"register plugin strict-tagged");
|
||||
testOk(!chfPluginRegister("strict", &myPif, strictOpts),
|
||||
"register plugin strict");
|
||||
testOk(!chfPluginRegister("noconv", &myPif, noconvOpts),
|
||||
@@ -542,14 +598,155 @@ MAIN(chfPluginTest)
|
||||
"register plugin pre");
|
||||
testOk(!chfPluginRegister("post", &postPif, sloppyOpts),
|
||||
"register plugin post");
|
||||
testOk(!chfPluginRegister("alloc-fail", &allocFailPif, sloppyOpts),
|
||||
"register plugin alloc-fail");
|
||||
|
||||
/* Check failing allocation of plugin private structures */
|
||||
|
||||
testHead("Failing allocation of plugin private structures");
|
||||
/* tag i */
|
||||
e1 = e_alloc; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"alloc-fail\":{\"i\":1}}")),
|
||||
"create channel for alloc-fail: allocPvt returning NULL");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
|
||||
/* TAGGED parsing: shorthand for integer plus other parameter */
|
||||
|
||||
/* STRICT TAGGED parsing: mandatory, no conversions */
|
||||
|
||||
/* All perfect */
|
||||
testHead("STRICT TAGGED parsing: all ok");
|
||||
/* tag D (t and d) and f */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"strict-tagged\":{\"D\":1.2e15,\"f\":false}}")),
|
||||
"create channel for strict-tagged parsing: D (t and d) and f");
|
||||
testOk(checkValues(puser1, 3, 12, 0, 1.2e15, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_close | e_free; c1 = 0;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
/* tag D2 (t and d) and f */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"strict-tagged\":{\"D2\":1.2e15,\"f\":false}}")),
|
||||
"create channel for strict-tagged parsing: D2 (t and d) and f");
|
||||
testOk(checkValues(puser1, 4, 12, 0, 1.2e15, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_close | e_free; c1 = 0;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
/* tag F: (t and f), d missing) */
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict-tagged\":{\"F\":false}}")),
|
||||
"create channel for strict-tagged parsing: F (t and f), d missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
/* tag I: (t and i) and f, d missing) */
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict-tagged\":{\"I\":1,\"f\":false}}")),
|
||||
"create channel for strict-tagged parsing: I (t and i) and f, d missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
|
||||
/* SLOPPY TAGGED parsing: optional, all others have defaults */
|
||||
|
||||
testHead("SLOPPY TAGGED parsing: all ok");
|
||||
|
||||
/* tag i */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"I\":1}}")),
|
||||
"create channel for sloppy-tagged parsing: I");
|
||||
testOk(checkValues(puser1, 1, 1, 1, 1.234e5, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_close | e_free; c1 = 0;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
/* tag f */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"F\":false}}")),
|
||||
"create channel for sloppy-tagged parsing: F");
|
||||
testOk(checkValues(puser1, 2, 12, 0, 1.234e5, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_close | e_free; c1 = 0;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
/* tag d */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"D\":1.2e15}}")),
|
||||
"create channel for sloppy-tagged parsing: D");
|
||||
testOk(checkValues(puser1, 3, 12, 1, 1.2e15, "hello", 0, 4),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_close | e_free; c1 = 0;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
/* tag s */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"S\":\"bar\"}}")),
|
||||
"create channel for sloppy-tagged parsing: S");
|
||||
testOk(checkValues(puser1, 4, 12, 1, 1.234e5, "bar", 0, 4),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_close | e_free; c1 = 0;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
/* tag c */
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"sloppy-tagged\":{\"C\":\"R\"}}")),
|
||||
"create channel for sloppy-tagged parsing: C");
|
||||
testOk(checkValues(puser1, 5, 12, 1, 1.234e5, "hello", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_close | e_free; c1 = 0;
|
||||
if (pch) dbChannelDelete(pch);
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
|
||||
/* STRICT parsing: mandatory, no conversion */
|
||||
|
||||
/* All perfect */
|
||||
testHead("STRICT parsing: all ok");
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate("x.{\"strict\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")), "strict parsing: JSON correct");
|
||||
testOk(checkValues(puser1, 1, 0, 1.2e15, "bar", 0, 1),
|
||||
testOk(!!(pch = dbChannelCreate("x.{\"strict\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")),
|
||||
"create channel for strict parsing: JSON correct");
|
||||
testOk(checkValues(puser1, 99, 1, 0, 1.2e15, "bar", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
@@ -564,35 +761,35 @@ MAIN(chfPluginTest)
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\"}}")),
|
||||
"strict parsing: c missing");
|
||||
"create channel for strict parsing: c missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"f\":false,\"i\":1,\"d\":1.2e15,\"c\":\"R\"}}")),
|
||||
"strict parsing: s missing");
|
||||
"create channel for strict parsing: s missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"i\":1,\"c\":\"R\",\"f\":false,\"s\":\"bar\"}}")),
|
||||
"strict parsing: d missing");
|
||||
"create channel for strict parsing: d missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"d\":1.2e15,\"c\":\"R\",\"i\":1,\"s\":\"bar\"}}")),
|
||||
"strict parsing: f missing");
|
||||
"create channel for strict parsing: f missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0;
|
||||
testOk(!(pch = dbChannelCreate(
|
||||
"x.{\"strict\":{\"c\":\"R\",\"s\":\"bar\",\"f\":false,\"d\":1.2e15}}")),
|
||||
"strict parsing: i missing");
|
||||
"create channel for strict parsing: i missing");
|
||||
testOk(!puser1, "user part cleaned up");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
@@ -604,8 +801,8 @@ MAIN(chfPluginTest)
|
||||
e1 = e_alloc | e_ok; c1 = 0;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"s\":\"bar\"}}")),
|
||||
"noconv parsing: c missing");
|
||||
testOk(checkValues(puser1, 1, 0, 1.2e15, "bar", 0, 4),
|
||||
"create channel for noconv parsing: c missing");
|
||||
testOk(checkValues(puser1, 99, 1, 0, 1.2e15, "bar", 0, 4),
|
||||
"guards intact, values correct");
|
||||
if (!testOk(c1 == e1, "all expected calls happened"))
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
@@ -618,29 +815,29 @@ MAIN(chfPluginTest)
|
||||
e1 = e_any;
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"i\":1,\"f\":false,\"d\":1.2e15,\"c\":\"R\"}}")),
|
||||
"noconv parsing: s missing");
|
||||
testOk(checkValues(puser1, 1, 0, 1.2e15, "hello", 0, 1),
|
||||
"create channel for noconv parsing: s missing");
|
||||
testOk(checkValues(puser1, 99, 1, 0, 1.2e15, "hello", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"i\":1,\"f\":false,\"s\":\"bar\",\"c\":\"R\"}}")),
|
||||
"noconv parsing: d missing");
|
||||
testOk(checkValues(puser1, 1, 0, 1.234e5, "bar", 0, 1),
|
||||
"create channel for noconv parsing: d missing");
|
||||
testOk(checkValues(puser1, 99, 1, 0, 1.234e5, "bar", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"i\":1,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")),
|
||||
"noconv parsing: f missing");
|
||||
testOk(checkValues(puser1, 1, 1, 1.2e15, "bar", 0, 1),
|
||||
"create channel for noconv parsing: f missing");
|
||||
testOk(checkValues(puser1, 99, 1, 1, 1.2e15, "bar", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
testOk(!!(pch = dbChannelCreate(
|
||||
"x.{\"noconv\":{\"f\":false,\"d\":1.2e15,\"s\":\"bar\",\"c\":\"R\"}}")),
|
||||
"noconv parsing: i missing");
|
||||
testOk(checkValues(puser1, 12, 0, 1.2e15, "bar", 0, 1),
|
||||
"create channel for noconv parsing: i missing");
|
||||
testOk(checkValues(puser1, 99, 12, 0, 1.2e15, "bar", 0, 1),
|
||||
"guards intact, values correct");
|
||||
if (pch) dbChannelDelete(pch);
|
||||
|
||||
@@ -648,7 +845,7 @@ MAIN(chfPluginTest)
|
||||
#define WRONGTYPETEST(Var, Val, Typ) \
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0; \
|
||||
testOk(!(pch = dbChannelCreate("x.{\"noconv\":{\""#Var"\":"#Val"}}")), \
|
||||
"noconv parsing: wrong type "#Typ" for "#Var); \
|
||||
"create channel for noconv parsing: wrong type "#Typ" for "#Var); \
|
||||
testOk(!puser1, "user part cleaned up"); \
|
||||
if (!testOk(c1 == e1, "all expected calls happened")) \
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
@@ -677,8 +874,8 @@ MAIN(chfPluginTest)
|
||||
e1 = e_alloc | e_ok; c1 = 0; \
|
||||
testDiag("Calling dbChannelCreate x.{\"sloppy\":{\""#Var"\":"#Val"}}"); \
|
||||
testOk(!!(pch = dbChannelCreate("x.{\"sloppy\":{\""#Var"\":"#Val"}}")), \
|
||||
"sloppy parsing: "#Typ" (good) for "#Var); \
|
||||
testOk(checkValues(puser1, Ival, Fval, Dval, Sval1, Sval2, Cval), \
|
||||
"create channel for sloppy parsing: "#Typ" (good) for "#Var); \
|
||||
testOk(checkValues(puser1, 99, Ival, Fval, Dval, Sval1, Sval2, Cval), \
|
||||
"guards intact, values correct"); \
|
||||
if (!testOk(c1 == e1, "create channel: all expected calls happened")) \
|
||||
testDiag("expected %#x - called %#x", e1, c1); \
|
||||
@@ -692,7 +889,7 @@ MAIN(chfPluginTest)
|
||||
e1 = e_alloc | e_error | e_free; c1 = 0; \
|
||||
testDiag("Calling dbChannelCreate x.{\"sloppy\":{\""#Var"\":"#Val"}}"); \
|
||||
testOk(!(pch = dbChannelCreate("x.{\"sloppy\":{\""#Var"\":"#Val"}}")), \
|
||||
"sloppy parsing: "#Typ" (bad) for "#Var); \
|
||||
"create channel for sloppy parsing: "#Typ" (bad) for "#Var); \
|
||||
testOk(!puser1, "user part cleaned up"); \
|
||||
if (!testOk(c1 == e1, "create channel: all expected calls happened")) \
|
||||
testDiag("expected %#x - called %#x", e1, c1);
|
||||
|
||||
@@ -43,6 +43,8 @@ chfPluginArgDef opts[] = {
|
||||
static void * allocPvt(void)
|
||||
{
|
||||
myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);
|
||||
if (!my) return NULL;
|
||||
|
||||
my->incr = 1;
|
||||
my->end = -1;
|
||||
return (void *) my;
|
||||
@@ -120,12 +122,13 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
pfl->no_elements = nTarget;
|
||||
if (nTarget) {
|
||||
void *pdst = freeListCalloc(my->arrayFreeList);
|
||||
|
||||
pfl->u.r.dtor = freeArray;
|
||||
pfl->u.r.pvt = my->arrayFreeList;
|
||||
offset = (offset + start) % chan->addr.no_elements;
|
||||
dbExtractArrayFromRec(&chan->addr, pdst, nTarget, nSource, offset, my->incr);
|
||||
pfl->u.r.field = pdst;
|
||||
if (pdst) {
|
||||
pfl->u.r.dtor = freeArray;
|
||||
pfl->u.r.pvt = my->arrayFreeList;
|
||||
offset = (offset + start) % chan->addr.no_elements;
|
||||
dbExtractArrayFromRec(&chan->addr, pdst, nTarget, nSource, offset, my->incr);
|
||||
pfl->u.r.field = pdst;
|
||||
}
|
||||
}
|
||||
dbScanUnlock(prec);
|
||||
chan->addr.pfield = pfieldsave;
|
||||
@@ -141,6 +144,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
pfl->no_elements = nTarget;
|
||||
if (nTarget) { /* Copy the data out */
|
||||
pdst = freeListCalloc(my->arrayFreeList);
|
||||
if (!pdst) return pfl;
|
||||
offset = start;
|
||||
dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type, nTarget, nSource, offset, my->incr);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2010 Brookhaven National Laboratory.
|
||||
* Copyright (c) 2010 Helmholtz-Zentrum Berlin
|
||||
* fuer Materialien und Energie GmbH.
|
||||
* für Materialien und Energie GmbH.
|
||||
* Copyright (c) 2014 ITER Organization.
|
||||
* EPICS BASE is distributed subject to a Software License Agreement found
|
||||
* in file LICENSE that is included with this distribution.
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Author: Ralph Lange <Ralph.Lange@bessy.de>
|
||||
* Author: Ralph Lange <Ralph.Lange@gmx.de>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -34,8 +35,10 @@ chfPluginEnumType modeEnum[] = { {"abs", 0}, {"rel", 1}, {NULL,0} };
|
||||
|
||||
static const
|
||||
chfPluginArgDef opts[] = {
|
||||
chfDouble (myStruct, cval, "d", 0, 1),
|
||||
chfEnum (myStruct, mode, "m", 0, 1, modeEnum),
|
||||
chfDouble (myStruct, cval, "d", 0, 1),
|
||||
chfEnum (myStruct, mode, "m", 0, 1, modeEnum),
|
||||
chfTagDouble (myStruct, cval, "abs", mode, 0, 0, 1),
|
||||
chfTagDouble (myStruct, cval, "rel", mode, 1, 0, 1),
|
||||
chfPluginArgEnd
|
||||
};
|
||||
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
#define STATE_NAME_LENGTH 20
|
||||
|
||||
static const
|
||||
chfPluginEnumType modeEnum[] = { {"before", 0}, {"first", 1},
|
||||
{"last", 2}, {"after", 3},
|
||||
{"while", 4}, {"unless", 5},
|
||||
chfPluginEnumType modeEnum[] = { {"before", 0}, {"first", 1},
|
||||
{"last", 2}, {"after", 3},
|
||||
{"while", 4}, {"unless", 5},
|
||||
{NULL,0} };
|
||||
typedef enum syncMode {
|
||||
syncModeBefore=0,
|
||||
@@ -47,8 +47,14 @@ static void *myStructFreeList;
|
||||
|
||||
static const
|
||||
chfPluginArgDef opts[] = {
|
||||
chfEnum (myStruct, mode, "m", 1, 1, modeEnum),
|
||||
chfString (myStruct, state, "s", 1, 0),
|
||||
chfEnum (myStruct, mode, "m", 1, 1, modeEnum),
|
||||
chfString (myStruct, state, "s", 1, 0),
|
||||
chfTagString (myStruct, state, "before", mode, 0, 1, 0),
|
||||
chfTagString (myStruct, state, "first", mode, 1, 1, 0),
|
||||
chfTagString (myStruct, state, "last", mode, 2, 1, 0),
|
||||
chfTagString (myStruct, state, "after", mode, 3, 1, 0),
|
||||
chfTagString (myStruct, state, "while", mode, 4, 1, 0),
|
||||
chfTagString (myStruct, state, "unless", mode, 5, 1, 0),
|
||||
chfPluginArgEnd
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user