Merged simple-filter-conf branch

This commit is contained in:
Andrew Johnson
2014-10-01 18:11:28 -05:00
6 changed files with 348 additions and 83 deletions

View File

@@ -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;
}

View File

@@ -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}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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
};

View File

@@ -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
};