diff --git a/src/ca/client/perl/caget.pl b/src/ca/client/perl/caget.pl index a3fcbfe85..9d3df35b4 100644 --- a/src/ca/client/perl/caget.pl +++ b/src/ca/client/perl/caget.pl @@ -20,13 +20,16 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1; HELP_MESSAGE() unless getopts('0:ac:d:e:f:F:g:hnsStw:'); HELP_MESSAGE() if $opt_h; -die "caget: -c option takes a positive number\n" +die "caget.pl: -c option takes a positive number\n" unless looks_like_number($opt_c) && $opt_c >= 0; -die "No pv name specified. ('caget -h' gives help.)\n" +die "No pv name specified. ('caget.pl -h' gives help.)\n" unless @ARGV; -my @chans = map { CA->new($_); } @ARGV; +my @chans = map { CA->new($_); } grep { $_ ne '' } @ARGV; + +die "caget.pl: Please provide at least one non-empty pv name\n" + unless @chans; eval { CA->pend_io($opt_w); }; if ($@) { diff --git a/src/ca/client/perl/cainfo.pl b/src/ca/client/perl/cainfo.pl index 2c08bcfe6..ee6b6d0a2 100644 --- a/src/ca/client/perl/cainfo.pl +++ b/src/ca/client/perl/cainfo.pl @@ -16,10 +16,13 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1; HELP_MESSAGE() unless getopts('hw:'); HELP_MESSAGE() if $opt_h; -die "No pv name specified. ('cainfo -h' gives help.)\n" +die "No pv name specified. ('cainfo.pl -h' gives help.)\n" unless @ARGV; -my @chans = map { CA->new($_); } @ARGV; +my @chans = map { CA->new($_); } grep { $_ ne '' } @ARGV; + +die "cainfo.pl: Please provide at least one non-empty pv name\n" + unless @chans; eval { CA->pend_io($opt_w); diff --git a/src/ca/client/perl/camonitor.pl b/src/ca/client/perl/camonitor.pl index 2a933abbe..d49c85d45 100644 --- a/src/ca/client/perl/camonitor.pl +++ b/src/ca/client/perl/camonitor.pl @@ -20,14 +20,17 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1; HELP_MESSAGE() unless getopts('0:c:e:f:F:g:hm:nsSw:'); HELP_MESSAGE() if $opt_h; -die "caget: -c option takes a positive number\n" +die "camonitor.pl: -c option takes a positive number\n" unless looks_like_number($opt_c) && $opt_c >= 0; -die "No pv name specified. ('camonitor -h' gives help.)\n" +die "No pv name specified. ('camonitor.pl -h' gives help.)\n" unless @ARGV; my %monitors; -my @chans = map { CA->new($_, \&conn_callback); } @ARGV; +my @chans = map { CA->new($_, \&conn_callback); } grep { $_ ne '' } @ARGV; + +die "camonitor.pl: Please provide at least one non-empty pv name\n" + unless @chans; my $fmt = ($opt_F eq ' ') ? "%-30s %s\n" : "%s$opt_F%s\n"; diff --git a/src/ca/client/perl/caput.pl b/src/ca/client/perl/caput.pl index 69cd4b638..468c3ad7a 100644 --- a/src/ca/client/perl/caput.pl +++ b/src/ca/client/perl/caput.pl @@ -17,11 +17,13 @@ $Getopt::Std::OUTPUT_HELP_VERSION = 1; HELP_MESSAGE() unless getopts('achlnsStw:'); HELP_MESSAGE() if $opt_h; -die "No pv name specified. ('caput -h' gives help.)\n" +die "No pv name specified. ('caput.pl -h' gives help.)\n" unless @ARGV; my $pv = shift; +die "caput.pl: Empty pv name given.\n" + unless $pv ne ''; -die "No value specified. ('caput -h' gives help.)\n" +die "No value specified. ('caput.pl -h' gives help.)\n" unless @ARGV; my $chan = CA->new($pv); diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 971063212..787599803 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -426,8 +426,6 @@ void dbFreeBase(dbBase *pdbbase) dbRecordType *pdbRecordType; dbRecordType *pdbRecordTypeNext; dbFldDes * pdbFldDes; - dbRecordNode *pdbRecordNode; - dbRecordNode *pdbRecordNodeNext; dbRecordAttribute *pAttribute; dbRecordAttribute *pAttributeNext; devSup *pdevSup; @@ -446,134 +444,136 @@ void dbFreeBase(dbBase *pdbbase) dbGuiGroup *pguiGroupNext; int i; DBENTRY dbentry; - + long status; dbInitEntry(pdbbase,&dbentry); - pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); - while(pdbRecordType) { - pdbRecordNode = (dbRecordNode *)ellFirst(&pdbRecordType->recList); - while(pdbRecordNode) { - pdbRecordNodeNext = (dbRecordNode *)ellNext(&pdbRecordNode->node); - if(!dbFindRecord(&dbentry,pdbRecordNode->recordname)) - dbDeleteRecord(&dbentry); - pdbRecordNode = pdbRecordNodeNext; - } - pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node); + status = dbFirstRecordType(&dbentry); + while(!status) { + /* dbDeleteRecord() will remove alias or real record node. + * For real record nodes, also removes the nodes of all aliases. + * This complicates safe traversal, so we re-start iteration + * from the first record after each call. + */ + while((status = dbFirstRecord(&dbentry))==0) { + dbDeleteRecord(&dbentry); + } + assert(status==S_dbLib_recNotFound); + status = dbNextRecordType(&dbentry); } dbFinishEntry(&dbentry); pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); while(pdbRecordType) { - for(i=0; ino_fields; i++) { - pdbFldDes = pdbRecordType->papFldDes[i]; - free((void *)pdbFldDes->prompt); - free((void *)pdbFldDes->name); - free((void *)pdbFldDes->extra); - free((void *)pdbFldDes->initial); - if(pdbFldDes->field_type==DBF_DEVICE && pdbFldDes->ftPvt) { - dbDeviceMenu *pdbDeviceMenu; + for(i=0; ino_fields; i++) { + pdbFldDes = pdbRecordType->papFldDes[i]; + free((void *)pdbFldDes->prompt); + free((void *)pdbFldDes->name); + free((void *)pdbFldDes->extra); + free((void *)pdbFldDes->initial); + if(pdbFldDes->field_type==DBF_DEVICE && pdbFldDes->ftPvt) { + dbDeviceMenu *pdbDeviceMenu; - pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; - free((void *)pdbDeviceMenu->papChoice); - free((void *)pdbDeviceMenu); - pdbFldDes->ftPvt=0; - } - free((void *)pdbFldDes); - } - pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); - while(pdevSup) { - pdevSupNext = (devSup *)ellNext(&pdevSup->node); - ellDelete(&pdbRecordType->devList,&pdevSup->node); - free((void *)pdevSup->name); - free((void *)pdevSup->choice); - free((void *)pdevSup); - pdevSup = pdevSupNext; - } - ptext = (dbText *)ellFirst(&pdbRecordType->cdefList); - while(ptext) { - ptextNext = (dbText *)ellNext(&ptext->node); - ellDelete(&pdbRecordType->cdefList,&ptext->node); - free((void *)ptext->text); - free((void *)ptext); - ptext = ptextNext; - } - pAttribute = - (dbRecordAttribute *)ellFirst(&pdbRecordType->attributeList); - while(pAttribute) { - pAttributeNext = (dbRecordAttribute *)ellNext(&pAttribute->node); - ellDelete(&pdbRecordType->attributeList,&pAttribute->node); - free((void *)pAttribute->name); - free((void *)pAttribute->pdbFldDes); - free(pAttribute); - pAttribute = pAttributeNext; - } - pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node); - gphDelete(pdbbase->pgpHash,pdbRecordType->name,&pdbbase->recordTypeList); - ellDelete(&pdbbase->recordTypeList,&pdbRecordType->node); - free((void *)pdbRecordType->name); - free((void *)pdbRecordType->link_ind); - free((void *)pdbRecordType->papsortFldName); - free((void *)pdbRecordType->sortFldInd); - free((void *)pdbRecordType->papFldDes); - free((void *)pdbRecordType); - pdbRecordType = pdbRecordTypeNext; + pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; + free((void *)pdbDeviceMenu->papChoice); + free((void *)pdbDeviceMenu); + pdbFldDes->ftPvt=0; + } + free((void *)pdbFldDes); + } + pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); + while(pdevSup) { + pdevSupNext = (devSup *)ellNext(&pdevSup->node); + ellDelete(&pdbRecordType->devList,&pdevSup->node); + free((void *)pdevSup->name); + free((void *)pdevSup->choice); + free((void *)pdevSup); + pdevSup = pdevSupNext; + } + ptext = (dbText *)ellFirst(&pdbRecordType->cdefList); + while(ptext) { + ptextNext = (dbText *)ellNext(&ptext->node); + ellDelete(&pdbRecordType->cdefList,&ptext->node); + free((void *)ptext->text); + free((void *)ptext); + ptext = ptextNext; + } + pAttribute = + (dbRecordAttribute *)ellFirst(&pdbRecordType->attributeList); + while(pAttribute) { + pAttributeNext = (dbRecordAttribute *)ellNext(&pAttribute->node); + ellDelete(&pdbRecordType->attributeList,&pAttribute->node); + free((void *)pAttribute->name); + free((void *)pAttribute->pdbFldDes); + free(pAttribute); + pAttribute = pAttributeNext; + } + pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node); + gphDelete(pdbbase->pgpHash,pdbRecordType->name,&pdbbase->recordTypeList); + ellDelete(&pdbbase->recordTypeList,&pdbRecordType->node); + free((void *)pdbRecordType->name); + free((void *)pdbRecordType->link_ind); + free((void *)pdbRecordType->papsortFldName); + free((void *)pdbRecordType->sortFldInd); + free((void *)pdbRecordType->papFldDes); + free((void *)pdbRecordType); + pdbRecordType = pdbRecordTypeNext; } pdbMenu = (dbMenu *)ellFirst(&pdbbase->menuList); while(pdbMenu) { - pdbMenuNext = (dbMenu *)ellNext(&pdbMenu->node); - gphDelete(pdbbase->pgpHash,pdbMenu->name,&pdbbase->menuList); - ellDelete(&pdbbase->menuList,&pdbMenu->node); - for(i=0; i< pdbMenu->nChoice; i++) { - free((void *)pdbMenu->papChoiceName[i]); - free((void *)pdbMenu->papChoiceValue[i]); - } - free((void *)pdbMenu->papChoiceName); - free((void *)pdbMenu->papChoiceValue); - free((void *)pdbMenu ->name); - free((void *)pdbMenu); - pdbMenu = pdbMenuNext; + pdbMenuNext = (dbMenu *)ellNext(&pdbMenu->node); + gphDelete(pdbbase->pgpHash,pdbMenu->name,&pdbbase->menuList); + ellDelete(&pdbbase->menuList,&pdbMenu->node); + for(i=0; i< pdbMenu->nChoice; i++) { + free((void *)pdbMenu->papChoiceName[i]); + free((void *)pdbMenu->papChoiceValue[i]); + } + free((void *)pdbMenu->papChoiceName); + free((void *)pdbMenu->papChoiceValue); + free((void *)pdbMenu ->name); + free((void *)pdbMenu); + pdbMenu = pdbMenuNext; } pdrvSup = (drvSup *)ellFirst(&pdbbase->drvList); while(pdrvSup) { - pdrvSupNext = (drvSup *)ellNext(&pdrvSup->node); - ellDelete(&pdbbase->drvList,&pdrvSup->node); - free((void *)pdrvSup->name); - free((void *)pdrvSup); - pdrvSup = pdrvSupNext; + pdrvSupNext = (drvSup *)ellNext(&pdrvSup->node); + ellDelete(&pdbbase->drvList,&pdrvSup->node); + free((void *)pdrvSup->name); + free((void *)pdrvSup); + pdrvSup = pdrvSupNext; } ptext = (dbText *)ellFirst(&pdbbase->registrarList); while(ptext) { - ptextNext = (dbText *)ellNext(&ptext->node); - ellDelete(&pdbbase->registrarList,&ptext->node); - free((void *)ptext->text); - free((void *)ptext); - ptext = ptextNext; + ptextNext = (dbText *)ellNext(&ptext->node); + ellDelete(&pdbbase->registrarList,&ptext->node); + free((void *)ptext->text); + free((void *)ptext); + ptext = ptextNext; } ptext = (dbText *)ellFirst(&pdbbase->functionList); while(ptext) { - ptextNext = (dbText *)ellNext(&ptext->node); - ellDelete(&pdbbase->functionList,&ptext->node); - free((void *)ptext->text); - free((void *)ptext); - ptext = ptextNext; + ptextNext = (dbText *)ellNext(&ptext->node); + ellDelete(&pdbbase->functionList,&ptext->node); + free((void *)ptext->text); + free((void *)ptext); + ptext = ptextNext; } pvar = (dbVariableDef *)ellFirst(&pdbbase->variableList); while(pvar) { - pvarNext = (dbVariableDef *)ellNext(&pvar->node); - ellDelete(&pdbbase->variableList,&pvar->node); - free((void *)pvar->name); + pvarNext = (dbVariableDef *)ellNext(&pvar->node); + ellDelete(&pdbbase->variableList,&pvar->node); + free((void *)pvar->name); free((void *)pvar->type); - free((void *)pvar); - pvar = pvarNext; + free((void *)pvar); + pvar = pvarNext; } pbrkTable = (brkTable *)ellFirst(&pdbbase->bptList); while(pbrkTable) { - pbrkTableNext = (brkTable *)ellNext(&pbrkTable->node); - gphDelete(pdbbase->pgpHash,pbrkTable->name,&pdbbase->bptList); - ellDelete(&pdbbase->bptList,&pbrkTable->node); - free(pbrkTable->name); - free((void *)pbrkTable->paBrkInt); - free((void *)pbrkTable); - pbrkTable = pbrkTableNext; + pbrkTableNext = (brkTable *)ellNext(&pbrkTable->node); + gphDelete(pdbbase->pgpHash,pbrkTable->name,&pdbbase->bptList); + ellDelete(&pdbbase->bptList,&pbrkTable->node); + free(pbrkTable->name); + free((void *)pbrkTable->paBrkInt); + free((void *)pbrkTable); + pbrkTable = pbrkTableNext; } pfilt = (chFilterPlugin *)ellFirst(&pdbbase->filterList); while(pfilt) { diff --git a/src/libCom/osi/epicsAssert.h b/src/libCom/osi/epicsAssert.h index 60dc130c8..6f83d3a82 100644 --- a/src/libCom/osi/epicsAssert.h +++ b/src/libCom/osi/epicsAssert.h @@ -44,12 +44,15 @@ epicsShareFunc void epicsAssert (const char *pFile, const unsigned line, /* Compile-time checks */ +#if __cplusplus>=201103L +#define STATIC_ASSERT(expr) static_assert(expr, #expr) +#else #define STATIC_JOIN(x, y) STATIC_JOIN2(x, y) #define STATIC_JOIN2(x, y) x ## y #define STATIC_ASSERT(expr) \ typedef int STATIC_JOIN(static_assert_failed_at_line_, __LINE__) \ [ (expr) ? 1 : -1 ] EPICS_UNUSED - +#endif #ifdef __cplusplus } diff --git a/src/libCom/test/epicsErrlogTest.c b/src/libCom/test/epicsErrlogTest.c index ff60d7084..28d88f6af 100644 --- a/src/libCom/test/epicsErrlogTest.c +++ b/src/libCom/test/epicsErrlogTest.c @@ -102,6 +102,12 @@ static const char prefixexpectedmsg[] = "A message without prefix" static char prefixmsgbuffer[1024]; +static +void testEqInt_(int lhs, int rhs, const char *LHS, const char *RHS) +{ + testOk(lhs==rhs, "%s (%d) == %s (%d)", LHS, lhs, RHS, rhs); +} +#define testEqInt(L, R) testEqInt_(L, R, #L, #R); static void logClient(void* raw, const char* msg) { @@ -194,7 +200,7 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", pvt.expect); errlogFlush(); - testOk1(pvt.count == 1); + testEqInt(pvt.count, 1); errlogAddListener(&logClient, &pvt2); @@ -204,8 +210,8 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", pvt.expect); errlogFlush(); - testOk1(pvt.count == 2); - testOk1(pvt2.count == 1); + testEqInt(pvt.count, 2); + testEqInt(pvt2.count, 1); /* Removes the first listener */ testOk(1 == errlogRemoveListeners(&logClient, &pvt), @@ -217,8 +223,8 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", pvt2.expect); errlogFlush(); - testOk1(pvt.count == 2); - testOk1(pvt2.count == 2); + testEqInt(pvt.count, 2); + testEqInt(pvt2.count, 2); /* Add the second listener again, then remove both instances */ errlogAddListener(&logClient, &pvt2); @@ -228,8 +234,8 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("Something different"); errlogFlush(); - testOk1(pvt.count == 2); - testOk1(pvt2.count == 2); + testEqInt(pvt.count, 2); + testEqInt(pvt2.count, 2); /* Re-add one listener */ errlogAddListener(&logClient, &pvt); @@ -242,7 +248,7 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", longmsg); errlogFlush(); - testOk1(pvt.count == 3); + testEqInt(pvt.count, 3); pvt.expect = NULL; @@ -255,12 +261,12 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", longmsg); epicsThreadSleep(0.1); - testOk1(pvt.count == 3); + testEqInt(pvt.count, 3); epicsEventSignal(pvt.jammer); errlogFlush(); - testOk1(pvt.count == 4); + testEqInt(pvt.count, 4); testDiag("Find buffer capacity (%u theoretical)",LOGBUFSIZE); @@ -313,7 +319,7 @@ MAIN(epicsErrlogTest) } epicsThreadSleep(0.1); /* should really be a second Event */ - testOk1(pvt.count == 0); + testEqInt(pvt.count, 0); /* Extract the first 2 messages, 2*(sizeof(msgNode) + 128) bytes */ pvt.jam = -2; @@ -321,7 +327,7 @@ MAIN(epicsErrlogTest) epicsThreadSleep(0.1); testDiag("Drained %u messages", pvt.count); - testOk1(pvt.count == 2); + testEqInt(pvt.count, 2); /* The buffer has space for 1 more message: sizeof(msgNode) + 256 bytes */ errlogPrintfNoConsole("%s", msg); /* Use up that space */ @@ -329,13 +335,13 @@ MAIN(epicsErrlogTest) testDiag("Overflow the buffer"); errlogPrintfNoConsole("%s", msg); - testOk1(pvt.count == 2); + testEqInt(pvt.count, 2); epicsEventSignal(pvt.jammer); /* Empty */ errlogFlush(); testDiag("Logged %u messages", pvt.count); - testOk1(pvt.count == N+1); + testEqInt(pvt.count, N+1); /* Clean up */ testOk(1 == errlogRemoveListeners(&logClient, &pvt), diff --git a/src/std/rec/subRecord.c b/src/std/rec/subRecord.c index 50a5049b9..9c5dc16fd 100644 --- a/src/std/rec/subRecord.c +++ b/src/std/rec/subRecord.c @@ -169,9 +169,10 @@ static long special(DBADDR *paddr, int after) subRecord *prec = (subRecord *)paddr->precord; if (!after) { - if (prec->snam[0] == 0 && prec->pact) + if (prec->snam[0] == 0 && prec->pact) { prec->pact = FALSE; prec->rpro = FALSE; + } return 0; }