From 6a592dc2c00c29c1127e44e45914addd5e97b63f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 8 May 2016 22:57:42 -0500 Subject: [PATCH] Support "link(name, lset)" syntax in DBD files Both Perl and dbStaticLib support included. Also added a new std/link directory for link types. Nothing looks up the registered link support tables yet. --- src/ioc/dbStatic/dbBase.h | 8 +++ src/ioc/dbStatic/dbLex.l | 1 + src/ioc/dbStatic/dbLexRoutines.c | 21 ++++++ src/ioc/dbStatic/dbStaticIocRegister.c | 9 +++ src/ioc/dbStatic/dbStaticLib.c | 36 ++++++++++ src/ioc/dbStatic/dbStaticLib.h | 5 ++ src/ioc/dbStatic/dbYacc.y | 10 ++- src/std/Makefile | 1 + src/std/link/Makefile | 17 +++++ src/std/link/links.dbd.pod | 92 ++++++++++++++++++++++++++ src/std/softIoc/RULES | 2 + src/std/softIoc/base.dbd | 3 + src/tools/DBD.pm | 6 ++ src/tools/DBD/Link.pm | 22 ++++++ src/tools/DBD/Output.pm | 9 +++ src/tools/DBD/Parser.pm | 6 ++ src/tools/Makefile | 1 + 17 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/std/link/Makefile create mode 100644 src/std/link/links.dbd.pod create mode 100644 src/tools/DBD/Link.pm diff --git a/src/ioc/dbStatic/dbBase.h b/src/ioc/dbStatic/dbBase.h index adf5f1d60..de543a1e7 100644 --- a/src/ioc/dbStatic/dbBase.h +++ b/src/ioc/dbStatic/dbBase.h @@ -44,6 +44,13 @@ typedef struct devSup { struct dsxt *pdsxt; /* Extended device support */ }devSup; +typedef struct linkSup { + ELLNODE node; + char *name; + char *lset_name; + struct lset *lset; +} linkSup; + typedef struct dbDeviceMenu { int nChoice; char **papChoice; @@ -162,6 +169,7 @@ typedef struct dbBase { ELLLIST menuList; ELLLIST recordTypeList; ELLLIST drvList; + ELLLIST linkList; ELLLIST registrarList; ELLLIST functionList; ELLLIST variableList; diff --git a/src/ioc/dbStatic/dbLex.l b/src/ioc/dbStatic/dbLex.l index 681cb1f24..37de82647 100644 --- a/src/ioc/dbStatic/dbLex.l +++ b/src/ioc/dbStatic/dbLex.l @@ -38,6 +38,7 @@ static int yyreset(void) "field" return(tokenFIELD); "device" return(tokenDEVICE); "driver" return(tokenDRIVER); +"link" return(tokenLINK); "breaktable" return(tokenBREAKTABLE); "record" return(tokenRECORD); "grecord" return(tokenGRECORD); diff --git a/src/ioc/dbStatic/dbLexRoutines.c b/src/ioc/dbStatic/dbLexRoutines.c index 2bbf272c1..6046c91a6 100644 --- a/src/ioc/dbStatic/dbLexRoutines.c +++ b/src/ioc/dbStatic/dbLexRoutines.c @@ -75,6 +75,7 @@ static void dbRecordtypeFieldItem(char *name,char *value); static void dbDevice(char *recordtype,char *linktype, char *dsetname,char *choicestring); static void dbDriver(char *name); +static void dbLinkType(char *name, char *lset_name); static void dbRegistrar(char *name); static void dbFunction(char *name); static void dbVariable(char *name, char *type); @@ -785,6 +786,26 @@ static void dbDriver(char *name) ellAdd(&pdbbase->drvList,&pdrvSup->node); } +static void dbLinkType(char *name, char *lset_name) +{ + linkSup *pLinkSup; + GPHENTRY *pgphentry; + + pgphentry = gphFind(pdbbase->pgpHash, name, &pdbbase->linkList); + if (pgphentry) { + return; + } + pLinkSup = dbCalloc(1,sizeof(linkSup)); + pLinkSup->name = epicsStrDup(name); + pLinkSup->lset_name = epicsStrDup(lset_name); + pgphentry = gphAdd(pdbbase->pgpHash, pLinkSup->name, &pdbbase->linkList); + if (!pgphentry) { + yyerrorAbort("gphAdd failed"); + } + pgphentry->userPvt = pLinkSup; + ellAdd(&pdbbase->linkList, &pLinkSup->node); +} + static void dbRegistrar(char *name) { dbText *ptext; diff --git a/src/ioc/dbStatic/dbStaticIocRegister.c b/src/ioc/dbStatic/dbStaticIocRegister.c index 18d346c70..65acc198d 100644 --- a/src/ioc/dbStatic/dbStaticIocRegister.c +++ b/src/ioc/dbStatic/dbStaticIocRegister.c @@ -86,6 +86,14 @@ static void dbDumpDriverCallFunc(const iocshArgBuf *args) dbDumpDriver(*iocshPpdbbase); } +/* dbDumpLink */ +static const iocshArg * const dbDumpLinkArgs[] = { &argPdbbase}; +static const iocshFuncDef dbDumpLinkFuncDef = {"dbDumpLink",1,dbDumpLinkArgs}; +static void dbDumpLinkCallFunc(const iocshArgBuf *args) +{ + dbDumpLink(*iocshPpdbbase); +} + /* dbDumpRegistrar */ static const iocshArg * const dbDumpRegistrarArgs[] = { &argPdbbase}; static const iocshFuncDef dbDumpRegistrarFuncDef = {"dbDumpRegistrar",1,dbDumpRegistrarArgs}; @@ -160,6 +168,7 @@ void dbStaticIocRegister(void) iocshRegister(&dbDumpFieldFuncDef, dbDumpFieldCallFunc); iocshRegister(&dbDumpDeviceFuncDef, dbDumpDeviceCallFunc); iocshRegister(&dbDumpDriverFuncDef, dbDumpDriverCallFunc); + iocshRegister(&dbDumpLinkFuncDef, dbDumpLinkCallFunc); iocshRegister(&dbDumpRegistrarFuncDef,dbDumpRegistrarCallFunc); iocshRegister(&dbDumpFunctionFuncDef, dbDumpFunctionCallFunc); iocshRegister(&dbDumpVariableFuncDef, dbDumpVariableCallFunc); diff --git a/src/ioc/dbStatic/dbStaticLib.c b/src/ioc/dbStatic/dbStaticLib.c index 6039266ed..c5774dec8 100644 --- a/src/ioc/dbStatic/dbStaticLib.c +++ b/src/ioc/dbStatic/dbStaticLib.c @@ -458,6 +458,7 @@ void dbFreeBase(dbBase *pdbbase) dbVariableDef *pvarNext; drvSup *pdrvSup; drvSup *pdrvSupNext; + linkSup *plinkSup; brkTable *pbrkTable; brkTable *pbrkTableNext; chFilterPlugin *pfilt; @@ -558,6 +559,11 @@ void dbFreeBase(dbBase *pdbbase) free((void *)pdrvSup); pdrvSup = pdrvSupNext; } + while ((plinkSup = (linkSup *) ellGet(&pdbbase->linkList))) { + free(plinkSup->lset_name); + free(plinkSup->name); + free(plinkSup); + } ptext = (dbText *)ellFirst(&pdbbase->registrarList); while(ptext) { ptextNext = (dbText *)ellNext(&ptext->node); @@ -1070,6 +1076,21 @@ long dbWriteDriverFP(DBBASE *pdbbase,FILE *fp) return(0); } +long dbWriteLinkFP(DBBASE *pdbbase, FILE *fp) +{ + linkSup *plinkSup; + + if (!pdbbase) { + fprintf(stderr, "pdbbase not specified\n"); + return -1; + } + for (plinkSup = (linkSup *) ellFirst(&pdbbase->linkList); + plinkSup; plinkSup = (linkSup *) ellNext(&plinkSup->node)) { + fprintf(fp, "link(%s,%s)\n", plinkSup->name, plinkSup->lset_name); + } + return 0; +} + long dbWriteRegistrarFP(DBBASE *pdbbase,FILE *fp) { dbText *ptext; @@ -3107,6 +3128,12 @@ char * dbGetRelatedField(DBENTRY *psave) return(rtnval); } +linkSup* dbFindLinkSup(dbBase *pdbbase, const char *name) { + GPHENTRY *pgph = gphFind(pdbbase->pgpHash,name,&pdbbase->linkList); + if (!pgph) return NULL; + return (linkSup *) pgph->userPvt; +} + int dbGetNLinks(DBENTRY *pdbentry) { dbRecordType *precordType = pdbentry->precordType; @@ -3460,6 +3487,15 @@ void dbDumpDriver(DBBASE *pdbbase) dbWriteDriverFP(pdbbase,stdout); } +void dbDumpLink(DBBASE *pdbbase) +{ + if(!pdbbase) { + fprintf(stderr,"pdbbase not specified\n"); + return; + } + dbWriteLinkFP(pdbbase,stdout); +} + void dbDumpRegistrar(DBBASE *pdbbase) { if(!pdbbase) { diff --git a/src/ioc/dbStatic/dbStaticLib.h b/src/ioc/dbStatic/dbStaticLib.h index 93f7f27d2..e01bec25d 100644 --- a/src/ioc/dbStatic/dbStaticLib.h +++ b/src/ioc/dbStatic/dbStaticLib.h @@ -99,6 +99,7 @@ epicsShareFunc long dbWriteDeviceFP(DBBASE *pdbbase, FILE *fp); epicsShareFunc long dbWriteDriver(DBBASE *pdbbase, const char *filename); epicsShareFunc long dbWriteDriverFP(DBBASE *pdbbase, FILE *fp); +epicsShareFunc long dbWriteLinkFP(DBBASE *pdbbase, FILE *fp); epicsShareFunc long dbWriteRegistrarFP(DBBASE *pdbbase, FILE *fp); epicsShareFunc long dbWriteFunctionFP(DBBASE *pdbbase, FILE *fp); epicsShareFunc long dbWriteVariableFP(DBBASE *pdbbase, FILE *fp); @@ -208,6 +209,9 @@ epicsShareFunc drvSup * dbFindDriver(dbBase *pdbbase, const char *name); epicsShareFunc char * dbGetRelatedField(DBENTRY *pdbentry); +epicsShareFunc linkSup * dbFindLinkSup(dbBase *pdbbase, + const char *name); + epicsShareFunc int dbGetNLinks(DBENTRY *pdbentry); epicsShareFunc long dbGetLinkField(DBENTRY *pdbentry, int index); epicsShareFunc int dbGetLinkType(DBENTRY *pdbentry); @@ -227,6 +231,7 @@ epicsShareFunc void dbDumpField(DBBASE *pdbbase, epicsShareFunc void dbDumpDevice(DBBASE *pdbbase, const char *recordTypeName); epicsShareFunc void dbDumpDriver(DBBASE *pdbbase); +epicsShareFunc void dbDumpLink(DBBASE *pdbbase); epicsShareFunc void dbDumpRegistrar(DBBASE *pdbbase); epicsShareFunc void dbDumpFunction(DBBASE *pdbbase); epicsShareFunc void dbDumpVariable(DBBASE *pdbbase); diff --git a/src/ioc/dbStatic/dbYacc.y b/src/ioc/dbStatic/dbYacc.y index 272f509c4..c5f64eef3 100644 --- a/src/ioc/dbStatic/dbYacc.y +++ b/src/ioc/dbStatic/dbYacc.y @@ -20,7 +20,7 @@ static int yyAbort = 0; %token tokenINCLUDE tokenPATH tokenADDPATH %token tokenALIAS tokenMENU tokenCHOICE tokenRECORDTYPE %token tokenFIELD tokenINFO tokenREGISTRAR -%token tokenDEVICE tokenDRIVER tokenBREAKTABLE +%token tokenDEVICE tokenDRIVER tokenLINK tokenBREAKTABLE %token tokenRECORD tokenGRECORD tokenVARIABLE tokenFUNCTION %token tokenSTRING tokenCDEFS @@ -46,6 +46,7 @@ database_item: include | tokenRECORDTYPE recordtype_head recordtype_body | device | driver + | link | registrar | function | variable @@ -162,6 +163,13 @@ driver: tokenDRIVER '(' tokenSTRING ')' dbDriver($3); dbmfFree($3); }; +link: tokenLINK '(' tokenSTRING ',' tokenSTRING ')' +{ + if(dbStaticDebug>2) printf("link %s %s\n",$3,$5); + dbLinkType($3,$5); + dbmfFree($3); dbmfFree($5); +}; + registrar: tokenREGISTRAR '(' tokenSTRING ')' { if(dbStaticDebug>2) printf("registrar %s\n",$3); diff --git a/src/std/Makefile b/src/std/Makefile index 2065f1f4e..dcfcb6a22 100644 --- a/src/std/Makefile +++ b/src/std/Makefile @@ -20,6 +20,7 @@ dbRecStd_RCS += dbRecStd.rc include $(STDDIR)/rec/Makefile include $(STDDIR)/dev/Makefile include $(STDDIR)/filters/Makefile +include $(STDDIR)/link/Makefile include $(STDDIR)/softIoc/Makefile include $(TOP)/configure/RULES diff --git a/src/std/link/Makefile b/src/std/link/Makefile new file mode 100644 index 000000000..d2e158475 --- /dev/null +++ b/src/std/link/Makefile @@ -0,0 +1,17 @@ +#************************************************************************* +# Copyright (c) 2016 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +# This is a Makefile fragment, see src/std/Makefile. + +SRC_DIRS += $(STDDIR)/link + +DBD += links.dbd + +# dbRecStd_SRCS += ... + +HTMLS += links.html + diff --git a/src/std/link/links.dbd.pod b/src/std/link/links.dbd.pod new file mode 100644 index 000000000..c4a5a45cd --- /dev/null +++ b/src/std/link/links.dbd.pod @@ -0,0 +1,92 @@ +=head1 Link Types + +Links are an extensible mechanism for adding new kinds of database link, +using JSON for link addresses. +The following link types are available in this release: + +=over + +=item * L + +=item * L + +=item * L + +=back + +=head2 Using Links + +... +must appear inside a pair of braces C< {} > expressed as a JSON +(L) object, which allows link +parameters to be defined as needed. + +Note that due to the required presence of the double-quote characters in the +JSON strings in a link field value string in a database file, it will usually +be necessary to escape all double-quote characters in the JSON object by +preceding them with a backslash C< \ > character. +Database configuration tools that support this link mechanism must be careful +to handle these escapes correctly on reading and writing string values from/to +a .db file. + +=head2 Filter Reference + +=cut + +link(const,lsetConst) + +=head3 Constant Link C<"const"> + +... + +=head4 Parameters + +... + +=head4 Example + + ... + +=cut + +link(db,lsetDatabase) + +=head3 Database Link C<"db"> + +... + +=head4 Parameters + +... + +=head4 Example + + ... + +=cut + +link(ca,lsetChannelAccess) + +=head3 Channel Access Link C<"ca"> + +... + +=head4 Parameters + +... + +=over + +=item ... + +... + +=back + +... + +=head4 Example + + ... + +=cut diff --git a/src/std/softIoc/RULES b/src/std/softIoc/RULES index cb540ad3c..fc1c6236e 100644 --- a/src/std/softIoc/RULES +++ b/src/std/softIoc/RULES @@ -9,8 +9,10 @@ softIoc.dbd$(DEP): $(COMMON_DIR)/stdRecords.dbd softIoc.dbd$(DEP): $(COMMON_DIR)/filters.dbd +softIoc.dbd$(DEP): $(COMMON_DIR)/links.dbd $(COMMON_DIR)/softIoc.dbd: $(COMMON_DIR)/stdRecords.dbd $(COMMON_DIR)/softIoc.dbd: $(COMMON_DIR)/filters.dbd +$(COMMON_DIR)/softIoc.dbd: $(COMMON_DIR)/links.dbd $(COMMON_DIR)/softIoc.dbd: $(STDDIR)/softIoc/Makefile softMain$(DEP): epicsInstallDir.h diff --git a/src/std/softIoc/base.dbd b/src/std/softIoc/base.dbd index 5c5632550..644d8bbaa 100644 --- a/src/std/softIoc/base.dbd +++ b/src/std/softIoc/base.dbd @@ -16,6 +16,9 @@ include "stdRecords.dbd" # Channel filters & plugins include "filters.dbd" +# Link types +include "links.dbd" + # Standard device support include "devSoft.dbd" diff --git a/src/tools/DBD.pm b/src/tools/DBD.pm index 3a2a85ee4..aabe26d26 100644 --- a/src/tools/DBD.pm +++ b/src/tools/DBD.pm @@ -6,6 +6,7 @@ use warnings; use DBD::Base; use DBD::Breaktable; use DBD::Driver; +use DBD::Link; use DBD::Menu; use DBD::Recordtype; use DBD::Recfield; @@ -21,6 +22,7 @@ sub new { my $this = { 'DBD::Breaktable' => {}, 'DBD::Driver' => {}, + 'DBD::Link' => {}, 'DBD::Function' => {}, 'DBD::Menu' => {}, 'DBD::Recordtype' => {}, @@ -80,6 +82,10 @@ sub drivers { return shift->{'DBD::Driver'}; } +sub links { + return shift->{'DBD::Link'}; +} + sub functions { return shift->{'DBD::Function'}; } diff --git a/src/tools/DBD/Link.pm b/src/tools/DBD/Link.pm new file mode 100644 index 000000000..ac1a14452 --- /dev/null +++ b/src/tools/DBD/Link.pm @@ -0,0 +1,22 @@ +package DBD::Link; +use DBD::Base; +@ISA = qw(DBD::Base); + +sub init { + my ($this, $name, $lset) = @_; + $this->SUPER::init($lset, "link support (lset)"); + $this->{KEY} = $name; + return $this; +} + +sub key { + return shift->{KEY}; +} + +sub equals { + my ($a, $b) = @_; + return $a->SUPER::equals($b) + && $a->{KEY} eq $b->{KEY}; +} + +1; diff --git a/src/tools/DBD/Output.pm b/src/tools/DBD/Output.pm index 6e9d67b3c..cfe5bb196 100644 --- a/src/tools/DBD/Output.pm +++ b/src/tools/DBD/Output.pm @@ -13,6 +13,7 @@ use DBD::Base; use DBD::Breaktable; use DBD::Device; use DBD::Driver; +use DBD::Link; use DBD::Menu; use DBD::Recordtype; use DBD::Recfield; @@ -26,6 +27,7 @@ sub OutputDBD { OutputMenus($out, $dbd->menus); OutputRecordtypes($out, $dbd->recordtypes); OutputDrivers($out, $dbd->drivers); + OutputLinks($out, $dbd->links); OutputRegistrars($out, $dbd->registrars); OutputFunctions($out, $dbd->functions); OutputVariables($out, $dbd->variables); @@ -78,6 +80,13 @@ sub OutputDrivers { foreach keys %{$drivers}; } +sub OutputLinks { + my ($out, $links) = @_; + while (my ($name, $link) = each %{$links}) { + printf $out "link(%s, %s)\n", $link->key, $name; + } +} + sub OutputRegistrars { my ($out, $registrars) = @_; printf $out "registrar(%s)\n", $_ diff --git a/src/tools/DBD/Parser.pm b/src/tools/DBD/Parser.pm index fa33bf26e..d36fca555 100644 --- a/src/tools/DBD/Parser.pm +++ b/src/tools/DBD/Parser.pm @@ -13,6 +13,7 @@ use DBD::Base; use DBD::Breaktable; use DBD::Device; use DBD::Driver; +use DBD::Link; use DBD::Menu; use DBD::Recordtype; use DBD::Recfield; @@ -37,6 +38,11 @@ sub ParseDBD { my ($driver_name) = unquote($1); $dbd->add(DBD::Driver->new($driver_name)); } + elsif (m/\G link \s* \( \s* $RXstr \s*, \s* $RXstr \s* \)/oxgc) { + print "Link $1, $2\n" if $debug; + my ($key, $lset) = unquote($1, $2); + $dbd->add(DBD::Link->new($key, $lset)); + } elsif (m/\G registrar \s* \( \s* $RXstr \s* \)/oxgc) { print "Registrar: $1\n" if $debug; my ($registrar_name) = unquote($1); diff --git a/src/tools/Makefile b/src/tools/Makefile index 99820d567..8f5aacbed 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -23,6 +23,7 @@ PERL_MODULES += DBD/Base.pm PERL_MODULES += DBD/Breaktable.pm PERL_MODULES += DBD/Device.pm PERL_MODULES += DBD/Driver.pm +PERL_MODULES += DBD/Link.pm PERL_MODULES += DBD/Function.pm PERL_MODULES += DBD/Menu.pm PERL_MODULES += DBD/Output.pm