I have long considered that a good way to register commands would be to
define them in a DBD file with some new syntax/keywords, and provide a
tool that generates the necessary code at build time as a .c or .cpp
file. I have never looked at implementing this, but Ben's script shows
the possibilities. If anyone is interested in tackling that approach I
would be happy to discuss what would need to be done.
- Andrew
On 4/29/19 9:12 AM, Michael Davidsaver via Tech-talk wrote:
> This reminds me. I added a boilerplate reduction helper
> in the pvAccessCPP module. This has now appeared in several
> epics 7.0 releases.
>
> Usage looks like:
>
>> #include <pv/iocshelper.h>
>> void startPVAServer(const char *names) ...
>> ...
>> void someRegistar() {
>> epics::iocshRegister<const char*, &startPVAServer>("startPVAServer", "provider names");
> Ugly, still somewhat repetitive ('const char*' appears twice),
> and currently only for functions with between 0 and 3 arguments
> due to the limitations of c++98.
>
> https://github.com/epics-base/pvAccessCPP/blob/master/src/ioc/pv/iocshelper.h
>
>
> On 4/26/19 8:44 AM, Benjamin Franksen via Tech-talk wrote:
>> I recently wrote this little perl script (attached) to automate the
>> writing of iocsh registration code using a trivial but (I think)
>> complete declarative specification "language" that is easy to compose on
>> the command line or in a Makefile. I am posting the code and an example
>> of what it does in the hope that it may turn out to be useful for others.
>>
>> Here is the help output (slightly re-formatted for this email):
>>
>> """
>>> gen_iocsh_reg.pl -h
>> Usage: gen_iocsh_reg.pl [REG=<registrar>] <command>=[<args>] ...
>> where
>> <registrar> is the name of a C function to register the commands (if
>> not specified you'll have to call iocshRegister yourself for each
>> command)
>> <command> is the name of a command (in C as well as in the shell)
>> <args> is a comma separated list of argument descriptions <arg>
>> <arg> describes an argument to the underlying C command and is either
>> * a constant literal value (for instance 0 or "a string"), or
>> * an iocsh argument description of the form <name>:<type> (for
>> instance card_number:Int) where <type> is one of {Int, Double,
>> String}.
>> Only arguments of the <name>:<type> sort are exposed as arguments to the
>> command in the shell.
>> """
>>
>> Here is a real-world example use case,. This is from a Makefile in one
>> of our projects:
>>
>> """
>> iocshExtra.c:
>> $(PERL) $(BII_SCRIPTS_BIN)/gen_iocsh_reg.pl REG=registerIocshExtra\
>> asDump=0,0,verbosity:Int \
>> bootShow= bootChange= \
>> gevShow= gevDelete=name:String
>> gevUpdate=name:String,value:String > $@
>> """
>>
>> From this it generates the following boilerplate code:
>>
>> """
>> /*
>> * IOC shell command registration
>> */
>>
>> #include "epicsExport.h"
>> #include "iocsh.h"
>>
>> static const iocshArg asDumpArg0 = { "verbosity", iocshArgInt };
>> static const iocshArg *const asDumpArgs[] = {
>> &asDumpArg0
>> };
>> static const iocshFuncDef asDumpDef = {"asDump", 1, asDumpArgs};
>> static void asDumpWrapper(const iocshArgBuf *args) {
>> asDump(0, 0, args[0].ival);
>> }
>>
>> static const iocshArg *const bootChangeArgs[] = {};
>> static const iocshFuncDef bootChangeDef = {"bootChange", 0, bootChangeArgs};
>> static void bootChangeWrapper(const iocshArgBuf *args) {
>> bootChange();
>> }
>>
>> static const iocshArg *const bootShowArgs[] = {};
>> static const iocshFuncDef bootShowDef = {"bootShow", 0, bootShowArgs};
>> static void bootShowWrapper(const iocshArgBuf *args) {
>> bootShow();
>> }
>>
>> static const iocshArg gevDeleteArg0 = { "name", iocshArgString };
>> static const iocshArg *const gevDeleteArgs[] = {
>> &gevDeleteArg0
>> };
>> static const iocshFuncDef gevDeleteDef = {"gevDelete", 1, gevDeleteArgs};
>> static void gevDeleteWrapper(const iocshArgBuf *args) {
>> gevDelete(args[0].sval);
>> }
>>
>> static const iocshArg *const gevShowArgs[] = {};
>> static const iocshFuncDef gevShowDef = {"gevShow", 0, gevShowArgs};
>> static void gevShowWrapper(const iocshArgBuf *args) {
>> gevShow();
>> }
>>
>> static const iocshArg gevUpdateArg0 = { "name", iocshArgString };
>> static const iocshArg gevUpdateArg1 = { "value", iocshArgString };
>> static const iocshArg *const gevUpdateArgs[] = {
>> &gevUpdateArg0,
>> &gevUpdateArg1
>> };
>> static const iocshFuncDef gevUpdateDef = {"gevUpdate", 2, gevUpdateArgs};
>> static void gevUpdateWrapper(const iocshArgBuf *args) {
>> gevUpdate(args[0].sval, args[1].sval);
>> }
>>
>> static void registerIocshExtra(void) {
>> static int firstTime = 1;
>> if (firstTime) {
>> firstTime = 0;
>> iocshRegister(&asDumpDef, asDumpWrapper);
>> iocshRegister(&bootChangeDef, bootChangeWrapper);
>> iocshRegister(&bootShowDef, bootShowWrapper);
>> iocshRegister(&gevDeleteDef, gevDeleteWrapper);
>> iocshRegister(&gevShowDef, gevShowWrapper);
>> iocshRegister(&gevUpdateDef, gevUpdateWrapper);
>> }
>> }
>> epicsExportRegistrar(registerIocshExtra);
>> """
>>
>> Cheers
>> Ben
>>
>
--
Complexity comes for free, Simplicity you have to work for.
- References:
- gen_iocsh_reg.pl Benjamin Franksen via Tech-talk
- Re: gen_iocsh_reg.pl Michael Davidsaver via Tech-talk
- Navigate by Date:
- Prev:
Re: Stopping IOC boot on failure to load database Johnson, Andrew N. via Tech-talk
- Next:
Re: Pmac Slits Davis, Mark via Tech-talk
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
<2019>
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
Re: gen_iocsh_reg.pl Michael Davidsaver via Tech-talk
- Next:
MasarService run error =?gb18030?b?MTIz?= via Tech-talk
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
<2019>
2020
2021
2022
2023
2024
|