From d825f873594b1500bea61510b18d53ab57b05536 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 27 Apr 2017 12:06:54 -0500 Subject: [PATCH 01/14] Check for empty PV names in Perl catools --- src/cap5/caget.pl | 9 ++++++--- src/cap5/cainfo.pl | 7 +++++-- src/cap5/camonitor.pl | 9 ++++++--- src/cap5/caput.pl | 6 ++++-- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/cap5/caget.pl b/src/cap5/caget.pl index a3fcbfe85..9d3df35b4 100644 --- a/src/cap5/caget.pl +++ b/src/cap5/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/cap5/cainfo.pl b/src/cap5/cainfo.pl index 2c08bcfe6..ee6b6d0a2 100644 --- a/src/cap5/cainfo.pl +++ b/src/cap5/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/cap5/camonitor.pl b/src/cap5/camonitor.pl index 2a933abbe..d49c85d45 100644 --- a/src/cap5/camonitor.pl +++ b/src/cap5/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/cap5/caput.pl b/src/cap5/caput.pl index 69cd4b638..468c3ad7a 100644 --- a/src/cap5/caput.pl +++ b/src/cap5/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); From a2ab17a7824a77450c07422854974607fe81e44a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 27 Apr 2017 16:45:22 -0400 Subject: [PATCH 02/14] libCom: STATIC_ASSERT use c++11 static_assert when possible --- src/libCom/osi/epicsAssert.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libCom/osi/epicsAssert.h b/src/libCom/osi/epicsAssert.h index e90ec9a7b..1889d642a 100644 --- a/src/libCom/osi/epicsAssert.h +++ b/src/libCom/osi/epicsAssert.h @@ -43,12 +43,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 ] - +#endif #ifdef __cplusplus } From 57cbe61709d3f45882b6eb55f48057321e2195c9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 27 Apr 2017 16:53:40 -0400 Subject: [PATCH 03/14] libCom/test: errlog test more verbose --- src/libCom/test/epicsErrlogTest.c | 34 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/libCom/test/epicsErrlogTest.c b/src/libCom/test/epicsErrlogTest.c index b93bee967..3f241af95 100644 --- a/src/libCom/test/epicsErrlogTest.c +++ b/src/libCom/test/epicsErrlogTest.c @@ -75,6 +75,12 @@ typedef struct { int jam; } clientPvt; +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) { @@ -146,7 +152,7 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", pvt.expect); errlogFlush(); - testOk1(pvt.count == 1); + testEqInt(pvt.count, 1); errlogAddListener(&logClient, &pvt2); @@ -156,8 +162,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, but the second remains */ errlogRemoveListener(&logClient); @@ -168,8 +174,8 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", pvt2.expect); errlogFlush(); - testOk1(pvt.count == 2); - testOk1(pvt2.count == 2); + testEqInt(pvt.count, 2); + testEqInt(pvt2.count, 2); /* Remove the second listener */ errlogRemoveListener(&logClient); @@ -177,8 +183,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); @@ -191,7 +197,7 @@ MAIN(epicsErrlogTest) errlogPrintfNoConsole("%s", longmsg); errlogFlush(); - testOk1(pvt.count == 3); + testEqInt(pvt.count, 3); pvt.expect = NULL; @@ -204,12 +210,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); @@ -262,7 +268,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; @@ -270,7 +276,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 */ @@ -278,13 +284,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 */ errlogRemoveListener(&logClient); From 0bf789db4cc59fcb3973ad82c20e936a3f61cdb0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 28 Apr 2017 14:56:18 -0500 Subject: [PATCH 04/14] Fix indentation warning from GCC --- src/rec/subRecord.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rec/subRecord.c b/src/rec/subRecord.c index 22742e6fe..441755ed8 100644 --- a/src/rec/subRecord.c +++ b/src/rec/subRecord.c @@ -170,9 +170,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; } From dcac64d50f97c4d55a2cc023a4b5300f9e088be3 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 18:01:39 -0400 Subject: [PATCH 05/14] ioc/dbStatic: whitespace --- src/dbStatic/dbStaticLib.c | 196 ++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index 2235bac2f..f36a4606b 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -599,128 +599,128 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase) 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); + 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); } 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); - 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); + 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; } gphFreeMem(pdbbase->pgpHash); dbPvdFreeMem(pdbbase); From 1ffce72a38dd2ece259f782dbea8fcfb74cabb5a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 18:02:05 -0400 Subject: [PATCH 06/14] ioc/dbStatic: plug leak in dbFreeBase() --- src/dbStatic/dbStaticLib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index f36a4606b..545f8906d 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -651,6 +651,7 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase) ellDelete(&pdbRecordType->attributeList,&pAttribute->node); free((void *)pAttribute->name); free((void *)pAttribute->pdbFldDes); + free(pAttribute); pAttribute = pAttributeNext; } pdbRecordTypeNext = (dbRecordType *)ellNext(&pdbRecordType->node); From 27cd9fd0514557822f55a658c74efdd5b6fb2e4e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 17:52:58 -0400 Subject: [PATCH 07/14] ioc/dbStatic: dbFreeBase() don't double free alias'd records dbFreeBase() has been broken since alias() was introduced. Traversal of recList in the function assumed that dbDeleteRecord() remove only the current dbRecordNode. However, dbDeleteRecord() called dbDeleteAliases() which removes alias dbRecordNode s. If this happens (as it often does) to be the node immediately after the real node, dbFreeBase() will then iterate using a ellDelete()d node. --- src/dbStatic/dbStaticLib.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index 545f8906d..a2ff7fc61 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -578,8 +578,6 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase) dbRecordType *pdbRecordType; dbRecordType *pdbRecordTypeNext; dbFldDes * pdbFldDes; - dbRecordNode *pdbRecordNode; - dbRecordNode *pdbRecordNodeNext; dbRecordAttribute *pAttribute; dbRecordAttribute *pAttributeNext; devSup *pdevSup; @@ -594,19 +592,21 @@ void epicsShareAPI dbFreeBase(dbBase *pdbbase) brkTable *pbrkTableNext; 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; + 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); } - pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node); + assert(status==S_dbLib_recNotFound); + status = dbNextRecordType(&dbentry); } dbFinishEntry(&dbentry); pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); From 38be82a1548e96ec3a70400090ce8e105bc6c5f4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 18:22:57 -0400 Subject: [PATCH 08/14] missing include --- src/dbStatic/dbStaticLib.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dbStatic/dbStaticLib.c b/src/dbStatic/dbStaticLib.c index a2ff7fc61..c601a4733 100644 --- a/src/dbStatic/dbStaticLib.c +++ b/src/dbStatic/dbStaticLib.c @@ -18,6 +18,7 @@ #define DBFLDTYPES_GBLSOURCE #define GUIGROUPS_GBLSOURCE #define SPECIAL_GBLSOURCE +#include "epicsAssert.h" #include "dbDefs.h" #include "epicsPrint.h" #include "errlog.h" From daad3c699506f979e03eca9eec5c38941f477260 Mon Sep 17 00:00:00 2001 From: Keenan Lang Date: Mon, 10 Oct 2016 11:29:22 -0500 Subject: [PATCH 09/14] Added functions to allow access to what functions and variables the ioc shell has registered. --- src/libCom/iocsh/iocsh.cpp | 60 +++++++++++++++++++++----------------- src/libCom/iocsh/iocsh.h | 17 ++++++++++- 2 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp index 21253bbc9..77094a43b 100644 --- a/src/libCom/iocsh/iocsh.cpp +++ b/src/libCom/iocsh/iocsh.cpp @@ -4,7 +4,7 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* iocsh.cpp */ /* Author: Marty Kraimer Date: 27APR2000 */ @@ -41,17 +41,8 @@ epicsShareDef struct dbBase **iocshPpdbbase; /* * File-local information */ -struct iocshCommand { - iocshFuncDef const *pFuncDef; - iocshCallFunc func; - struct iocshCommand *next; -}; static struct iocshCommand *iocshCommandHead; static char iocshCmdID[] = "iocshCmd"; -struct iocshVariable { - iocshVarDef const *pVarDef; - struct iocshVariable *next; -}; static struct iocshVariable *iocshVariableHead; static char iocshVarID[] = "iocshVar"; extern "C" { static void varCallFunc(const iocshArgBuf *); } @@ -146,6 +137,15 @@ void epicsShareAPI iocshRegister (const iocshFuncDef *piocshFuncDef, iocshTableUnlock (); } + +/* + * Retrieves a previously registered function with the given name. + */ +struct iocshCommand * epicsShareAPI iocshFind(const char *name) +{ + return (iocshCommand *) registryFind(iocshCmdID, name); +} + /* * Register the "var" command and any variable(s) */ @@ -204,10 +204,18 @@ void epicsShareAPI iocshRegisterVariable (const iocshVarDef *piocshVarDef) iocshTableUnlock (); } +/* + * Retrieves a previously registered variable with the given name. + */ +struct iocshVariable * epicsShareAPI iocshFindVariable(const char *name) +{ + return (iocshVariable *) registryFind(iocshVarID, name); +} + /* * Free storage created by iocshRegister/iocshRegisterVariable */ -void epicsShareAPI iocshFree(void) +void epicsShareAPI iocshFree(void) { struct iocshCommand *pc; struct iocshVariable *pv; @@ -507,7 +515,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) static const char * pairs[] = {"", "environ", NULL, NULL}; MAC_HANDLE *handle; char ** defines = NULL; - + iocshInit(); /* @@ -551,37 +559,37 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) fprintf(epicsGetStderr(), "Out of memory!\n"); return -1; } - + /* * Parse macro definitions, this check occurs before creating the * macro handle to simplify cleanup. */ - + if (macros) { if (macParseDefns(NULL, macros, &defines) < 0) { free(redirects); return -1; } } - + /* * Check for existing macro context or construct a new one. */ handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); - + if (handle == NULL) { if (macCreateHandle(&handle, pairs)) { errlogMessage("iocsh: macCreateHandle failed."); free(redirects); return -1; } - + epicsThreadPrivateSet(iocshMacroHandleId, (void *) handle); } - + macPushScope(handle); macInstallMacros(handle, defines); - + /* * Read commands till EOF or exit */ @@ -853,7 +861,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) stopRedirect(filename, lineno, redirects); } macPopScope(handle); - + if (handle->level == 0) { macDeleteHandle(handle); epicsThreadPrivateSet(iocshMacroHandleId, NULL); @@ -909,11 +917,11 @@ iocshRun(const char *cmd, const char *macros) * Needed to work around the necessary limitations of macLib and * environment variables. In every other case of macro expansion * it is the expected outcome that defined macros override any - * environment variables. + * environment variables. * - * iocshLoad/Run turn this on its head as it is very likely that - * an epicsEnvSet command may be run within the context of their - * calls. Thus, it would be expected that the new value would be + * iocshLoad/Run turn this on its head as it is very likely that + * an epicsEnvSet command may be run within the context of their + * calls. Thus, it would be expected that the new value would be * returned in any future macro expansion. * * To do so, the epicsEnvSet command needs to be able to access @@ -924,10 +932,10 @@ void epicsShareAPI iocshEnvClear(const char *name) { MAC_HANDLE *handle; - + if (iocshMacroHandleId) { handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); - + if (handle != NULL) { macPutValue(handle, name, NULL); } diff --git a/src/libCom/iocsh/iocsh.h b/src/libCom/iocsh/iocsh.h index e31756479..915cdf413 100644 --- a/src/libCom/iocsh/iocsh.h +++ b/src/libCom/iocsh/iocsh.h @@ -5,7 +5,7 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* iocsh.h ioc: call registered function*/ /* Author: Marty Kraimer Date: 27APR2000 */ @@ -59,10 +59,25 @@ typedef struct iocshFuncDef { typedef void (*iocshCallFunc)(const iocshArgBuf *argBuf); +struct iocshCommand { + iocshFuncDef const *pFuncDef; + iocshCallFunc func; + struct iocshCommand *next; +}; + +struct iocshVariable { + iocshVarDef const *pVarDef; + struct iocshVariable *next; +}; + epicsShareFunc void epicsShareAPI iocshRegister( const iocshFuncDef *piocshFuncDef, iocshCallFunc func); epicsShareFunc void epicsShareAPI iocshRegisterVariable ( const iocshVarDef *piocshVarDef); +epicsShareFunc struct iocshCommand* epicsShareAPI iocshFind( + const char* name); +epicsShareFunc struct iocshVariable* epicsShareAPI iocshFindVariable( + const char* name); /* iocshFree frees storage used by iocshRegister*/ /* This should only be called when iocsh is no longer needed*/ From 3986e431352dbb564b3374fc73584383d0fa8a6a Mon Sep 17 00:00:00 2001 From: Keenan Lang Date: Mon, 10 Oct 2016 11:55:03 -0500 Subject: [PATCH 10/14] whitespace --- src/libCom/iocsh/iocsh.cpp | 32 ++++++++++++++++---------------- src/libCom/iocsh/iocsh.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp index 77094a43b..485aecfd7 100644 --- a/src/libCom/iocsh/iocsh.cpp +++ b/src/libCom/iocsh/iocsh.cpp @@ -4,7 +4,7 @@ * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. * EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* iocsh.cpp */ /* Author: Marty Kraimer Date: 27APR2000 */ @@ -215,7 +215,7 @@ struct iocshVariable * epicsShareAPI iocshFindVariable(const char *name) /* * Free storage created by iocshRegister/iocshRegisterVariable */ -void epicsShareAPI iocshFree(void) +void epicsShareAPI iocshFree(void) { struct iocshCommand *pc; struct iocshVariable *pv; @@ -515,7 +515,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) static const char * pairs[] = {"", "environ", NULL, NULL}; MAC_HANDLE *handle; char ** defines = NULL; - + iocshInit(); /* @@ -559,7 +559,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) fprintf(epicsGetStderr(), "Out of memory!\n"); return -1; } - + /* * Parse macro definitions, this check occurs before creating the * macro handle to simplify cleanup. @@ -571,25 +571,25 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) return -1; } } - + /* * Check for existing macro context or construct a new one. */ handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); - + if (handle == NULL) { if (macCreateHandle(&handle, pairs)) { errlogMessage("iocsh: macCreateHandle failed."); free(redirects); return -1; } - + epicsThreadPrivateSet(iocshMacroHandleId, (void *) handle); } - + macPushScope(handle); macInstallMacros(handle, defines); - + /* * Read commands till EOF or exit */ @@ -861,7 +861,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) stopRedirect(filename, lineno, redirects); } macPopScope(handle); - + if (handle->level == 0) { macDeleteHandle(handle); epicsThreadPrivateSet(iocshMacroHandleId, NULL); @@ -917,11 +917,11 @@ iocshRun(const char *cmd, const char *macros) * Needed to work around the necessary limitations of macLib and * environment variables. In every other case of macro expansion * it is the expected outcome that defined macros override any - * environment variables. + * environment variables. * - * iocshLoad/Run turn this on its head as it is very likely that - * an epicsEnvSet command may be run within the context of their - * calls. Thus, it would be expected that the new value would be + * iocshLoad/Run turn this on its head as it is very likely that + * an epicsEnvSet command may be run within the context of their + * calls. Thus, it would be expected that the new value would be * returned in any future macro expansion. * * To do so, the epicsEnvSet command needs to be able to access @@ -932,10 +932,10 @@ void epicsShareAPI iocshEnvClear(const char *name) { MAC_HANDLE *handle; - + if (iocshMacroHandleId) { handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); - + if (handle != NULL) { macPutValue(handle, name, NULL); } diff --git a/src/libCom/iocsh/iocsh.h b/src/libCom/iocsh/iocsh.h index 915cdf413..9884967e2 100644 --- a/src/libCom/iocsh/iocsh.h +++ b/src/libCom/iocsh/iocsh.h @@ -5,7 +5,7 @@ * Operator of Los Alamos National Laboratory. * EPICS BASE Versions 3.13.7 * and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* in file LICENSE that is included with this distribution. \*************************************************************************/ /* iocsh.h ioc: call registered function*/ /* Author: Marty Kraimer Date: 27APR2000 */ From 45ed461665e8521793c601005f28f5c5e73ad575 Mon Sep 17 00:00:00 2001 From: Keenan Lang Date: Mon, 10 Oct 2016 12:19:35 -0500 Subject: [PATCH 11/14] more whitespace --- src/libCom/iocsh/iocsh.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp index 485aecfd7..4e8fb03e1 100644 --- a/src/libCom/iocsh/iocsh.cpp +++ b/src/libCom/iocsh/iocsh.cpp @@ -564,7 +564,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Parse macro definitions, this check occurs before creating the * macro handle to simplify cleanup. */ - + if (macros) { if (macParseDefns(NULL, macros, &defines) < 0) { free(redirects); @@ -935,7 +935,7 @@ iocshEnvClear(const char *name) if (iocshMacroHandleId) { handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); - + if (handle != NULL) { macPutValue(handle, name, NULL); } From 15cb72acbcd7c7832d8ef0c310d774d042493d6a Mon Sep 17 00:00:00 2001 From: Keenan Lang Date: Mon, 10 Oct 2016 15:22:51 -0500 Subject: [PATCH 12/14] Changed function outputs to remove pointer to next function. --- src/libCom/iocsh/iocsh.cpp | 18 ++++++++++++++---- src/libCom/iocsh/iocsh.h | 14 ++++---------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp index 4e8fb03e1..a2eaad883 100644 --- a/src/libCom/iocsh/iocsh.cpp +++ b/src/libCom/iocsh/iocsh.cpp @@ -41,8 +41,17 @@ epicsShareDef struct dbBase **iocshPpdbbase; /* * File-local information */ +struct iocshCommand { + iocshFuncDef const *pFuncDef; + iocshCallFunc func; + struct iocshCommand *next; +}; static struct iocshCommand *iocshCommandHead; static char iocshCmdID[] = "iocshCmd"; +struct iocshVariable { + iocshVarDef const *pVarDef; + struct iocshVariable *next; +}; static struct iocshVariable *iocshVariableHead; static char iocshVarID[] = "iocshVar"; extern "C" { static void varCallFunc(const iocshArgBuf *); } @@ -141,9 +150,9 @@ void epicsShareAPI iocshRegister (const iocshFuncDef *piocshFuncDef, /* * Retrieves a previously registered function with the given name. */ -struct iocshCommand * epicsShareAPI iocshFind(const char *name) +const iocshCmdDef * epicsShareAPI iocshFind(const char *name) { - return (iocshCommand *) registryFind(iocshCmdID, name); + return (iocshCmdDef *) registryFind(iocshCmdID, name); } /* @@ -207,9 +216,10 @@ void epicsShareAPI iocshRegisterVariable (const iocshVarDef *piocshVarDef) /* * Retrieves a previously registered variable with the given name. */ -struct iocshVariable * epicsShareAPI iocshFindVariable(const char *name) +const iocshVarDef * epicsShareAPI iocshFindVariable(const char *name) { - return (iocshVariable *) registryFind(iocshVarID, name); + struct iocshVariable *temp = (iocshVariable *) registryFind(iocshVarID, name); + return temp->pVarDef; } /* diff --git a/src/libCom/iocsh/iocsh.h b/src/libCom/iocsh/iocsh.h index 9884967e2..769863082 100644 --- a/src/libCom/iocsh/iocsh.h +++ b/src/libCom/iocsh/iocsh.h @@ -59,24 +59,18 @@ typedef struct iocshFuncDef { typedef void (*iocshCallFunc)(const iocshArgBuf *argBuf); -struct iocshCommand { +typedef struct iocshCmdDef { iocshFuncDef const *pFuncDef; iocshCallFunc func; - struct iocshCommand *next; -}; - -struct iocshVariable { - iocshVarDef const *pVarDef; - struct iocshVariable *next; -}; +}iocshCmdDef; epicsShareFunc void epicsShareAPI iocshRegister( const iocshFuncDef *piocshFuncDef, iocshCallFunc func); epicsShareFunc void epicsShareAPI iocshRegisterVariable ( const iocshVarDef *piocshVarDef); -epicsShareFunc struct iocshCommand* epicsShareAPI iocshFind( +epicsShareFunc const iocshCmdDef * epicsShareAPI iocshFind( const char* name); -epicsShareFunc struct iocshVariable* epicsShareAPI iocshFindVariable( +epicsShareFunc const iocshVarDef * epicsShareAPI iocshFindVariable( const char* name); /* iocshFree frees storage used by iocshRegister*/ From 67e12bca9f820872e5294a6b51d1e508afa4ca7c Mon Sep 17 00:00:00 2001 From: Keenan Lang Date: Thu, 13 Oct 2016 09:47:12 -0500 Subject: [PATCH 13/14] Added patch --- src/libCom/iocsh/iocsh.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp index a2eaad883..db462133f 100644 --- a/src/libCom/iocsh/iocsh.cpp +++ b/src/libCom/iocsh/iocsh.cpp @@ -42,8 +42,7 @@ epicsShareDef struct dbBase **iocshPpdbbase; * File-local information */ struct iocshCommand { - iocshFuncDef const *pFuncDef; - iocshCallFunc func; + iocshCmdDef def; struct iocshCommand *next; }; static struct iocshCommand *iocshCommandHead; @@ -115,10 +114,10 @@ void epicsShareAPI iocshRegister (const iocshFuncDef *piocshFuncDef, iocshTableLock (); for (l = NULL, p = iocshCommandHead ; p != NULL ; l = p, p = p->next) { - i = strcmp (piocshFuncDef->name, p->pFuncDef->name); + i = strcmp (piocshFuncDef->name, p->def.pFuncDef->name); if (i == 0) { - p->pFuncDef = piocshFuncDef; - p->func = func; + p->def.pFuncDef = piocshFuncDef; + p->def.func = func; iocshTableUnlock (); return; } @@ -141,8 +140,8 @@ void epicsShareAPI iocshRegister (const iocshFuncDef *piocshFuncDef, n->next = l->next; l->next = n; } - n->pFuncDef = piocshFuncDef; - n->func = func; + n->def.pFuncDef = piocshFuncDef; + n->def.func = func; iocshTableUnlock (); } @@ -449,7 +448,7 @@ static void helpCallFunc(const iocshArgBuf *args) "Type 'help ' to see the arguments of .\n"); iocshTableLock (); for (pcmd = iocshCommandHead ; pcmd != NULL ; pcmd = pcmd->next) { - piocshFuncDef = pcmd->pFuncDef; + piocshFuncDef = pcmd->def.pFuncDef; l = strlen (piocshFuncDef->name); if ((l + col) >= 79) { fputc('\n', epicsGetStdout()); @@ -475,7 +474,7 @@ static void helpCallFunc(const iocshArgBuf *args) else { for (int iarg = 1 ; iarg < argc ; iarg++) { for (pcmd = iocshCommandHead ; pcmd != NULL ; pcmd = pcmd->next) { - piocshFuncDef = pcmd->pFuncDef; + piocshFuncDef = pcmd->def.pFuncDef; if (epicsStrGlobMatch(piocshFuncDef->name, argv[iarg]) != 0) { fputs(piocshFuncDef->name, epicsGetStdout()); for (int a = 0 ; a < piocshFuncDef->nargs ; a++) { @@ -826,11 +825,11 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) /* * Process arguments and call function */ - struct iocshFuncDef const *piocshFuncDef = found->pFuncDef; + struct iocshFuncDef const *piocshFuncDef = found->def.pFuncDef; for (int iarg = 0 ; ; ) { if (iarg == piocshFuncDef->nargs) { startRedirect(filename, lineno, redirects); - (*found->func)(argBuf); + (*found->def.func)(argBuf); break; } if (iarg >= argBufCapacity) { From 9d7c4434ad11b28983a3124c051c7fdeea4192bc Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 May 2017 18:15:07 -0400 Subject: [PATCH 14/14] rename iocshFind -> iocshFindCommand --- src/libCom/iocsh/iocsh.cpp | 2 +- src/libCom/iocsh/iocsh.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp index db462133f..ef646158e 100644 --- a/src/libCom/iocsh/iocsh.cpp +++ b/src/libCom/iocsh/iocsh.cpp @@ -149,7 +149,7 @@ void epicsShareAPI iocshRegister (const iocshFuncDef *piocshFuncDef, /* * Retrieves a previously registered function with the given name. */ -const iocshCmdDef * epicsShareAPI iocshFind(const char *name) +const iocshCmdDef * epicsShareAPI iocshFindCommand(const char *name) { return (iocshCmdDef *) registryFind(iocshCmdID, name); } diff --git a/src/libCom/iocsh/iocsh.h b/src/libCom/iocsh/iocsh.h index 769863082..3ef3d952b 100644 --- a/src/libCom/iocsh/iocsh.h +++ b/src/libCom/iocsh/iocsh.h @@ -68,7 +68,7 @@ epicsShareFunc void epicsShareAPI iocshRegister( const iocshFuncDef *piocshFuncDef, iocshCallFunc func); epicsShareFunc void epicsShareAPI iocshRegisterVariable ( const iocshVarDef *piocshVarDef); -epicsShareFunc const iocshCmdDef * epicsShareAPI iocshFind( +epicsShareFunc const iocshCmdDef * epicsShareAPI iocshFindCommand( const char* name); epicsShareFunc const iocshVarDef * epicsShareAPI iocshFindVariable( const char* name);