Merge branch '7.0' into PSI-7.0
This commit is contained in:
@@ -16,7 +16,7 @@ USR_CPPFLAGS += -DUSE_TYPED_RSET -DUSE_TYPED_DSET
|
||||
# Shared library ABI version.
|
||||
SHRLIB_VERSION = $(EPICS_DATABASE_MAJOR_VERSION).$(EPICS_DATABASE_MINOR_VERSION).$(EPICS_DATABASE_MAINTENANCE_VERSION)
|
||||
|
||||
API_HEADER = dbCoreAPI.h
|
||||
# dbCoreAPI.h generated earlier during libcom/
|
||||
dbCore_API = dbCore
|
||||
|
||||
LIBRARY_IOC += dbCore
|
||||
|
||||
@@ -20,7 +20,7 @@ BPT_DBD += bptTypeJdegF.dbd
|
||||
BPT_DBD += bptTypeKdegC.dbd
|
||||
BPT_DBD += bptTypeKdegF.dbd
|
||||
|
||||
ifneq (inc,$(strip $(MAKECMDGOALS)))
|
||||
ifneq ($(filter-out inc,$(strip $(MAKECMDGOALS))),)
|
||||
DBD += $(BPT_DBD)
|
||||
endif
|
||||
|
||||
@@ -28,5 +28,5 @@ PROD_HOST += makeBpt
|
||||
|
||||
makeBpt_SRCS = makeBpt
|
||||
|
||||
DOCS += menuConvert.md
|
||||
HTMLS += menuConvert.html
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ DBDINC += menuScan
|
||||
DBDINC += dbCommon
|
||||
|
||||
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
|
||||
|
||||
DOCS += $(patsubst %.dbd.pod,%.md,$(dbMenusPod))
|
||||
DOCS += dbCommonRecord.md
|
||||
DOCS += dbCommonInput.md
|
||||
DOCS += dbCommonOutput.md
|
||||
|
||||
HTMLS += $(patsubst %.dbd.pod,%.html,$(dbMenusPod))
|
||||
HTMLS += dbCommonRecord.html
|
||||
HTMLS += dbCommonInput.html
|
||||
|
||||
@@ -62,8 +62,28 @@ DBCORE_API void post_event(int event);
|
||||
DBCORE_API void scanAdd(struct dbCommon *);
|
||||
DBCORE_API void scanDelete(struct dbCommon *);
|
||||
DBCORE_API double scanPeriod(int scan);
|
||||
DBCORE_API int scanOnce(struct dbCommon *);
|
||||
DBCORE_API int scanOnceCallback(struct dbCommon *, once_complete cb, void *usr);
|
||||
/** Shorthand for scanOnceCallback(prec, NULL, NULL)
|
||||
*/
|
||||
DBCORE_API int scanOnce(struct dbCommon *prec);
|
||||
/** @brief scanOnce Request immediate record processing from another thread.
|
||||
*
|
||||
* Queue a request for record processing from the dedicated "Once" thread.
|
||||
* Request may fail if Once queue overflows. See scanOnceSetQueueSize()
|
||||
*
|
||||
* @param prec Record to process
|
||||
* @param cb Function called after target record dbProcess()
|
||||
* Does not wait for async record completion.
|
||||
* @param usr Argumentfor cb
|
||||
* @return Zero on success. Non-zero if the request could not be queued.
|
||||
*/
|
||||
DBCORE_API int scanOnceCallback(struct dbCommon *prec, once_complete cb, void *usr);
|
||||
/** @brief Set Once queue size
|
||||
*
|
||||
* Must be called prior to iocInit()
|
||||
*
|
||||
* @param size New size. May be smaller
|
||||
* @return Zero on success
|
||||
*/
|
||||
DBCORE_API int scanOnceSetQueueSize(int size);
|
||||
DBCORE_API int scanOnceQueueStatus(const int reset, scanOnceQueueStats *result);
|
||||
DBCORE_API void scanOnceQueueShow(const int reset);
|
||||
@@ -77,9 +97,39 @@ DBCORE_API int scanpel(const char *event_name);
|
||||
/*print io_event list*/
|
||||
DBCORE_API int scanpiol(void);
|
||||
|
||||
/** @brief Initialize "I/O Intr" source
|
||||
* @param ppios Pointer to scan list to be initialized
|
||||
*
|
||||
* Afterwards this IOSCANPVT may be assigned during a get_ioint_info() callback.
|
||||
* See typed_dset::get_ioint_info()
|
||||
*
|
||||
* @note There is currently no way to free this allocation.
|
||||
*/
|
||||
DBCORE_API void scanIoInit(IOSCANPVT *ppios);
|
||||
/** @brief Request processing of all associated records from callback threads
|
||||
* @param pios The scan list
|
||||
* @pre pios must be initialized by scanIoInit()
|
||||
* @return
|
||||
*/
|
||||
DBCORE_API unsigned int scanIoRequest(IOSCANPVT pios);
|
||||
/** @brief Process all records on the scan list for the specificed priority.
|
||||
*
|
||||
* Also executes the callback set by scanIoSetComplete()
|
||||
*
|
||||
* @param pios The scan list
|
||||
* @param prio one of priorityLow through priorityHigh (defined in callback.h).
|
||||
* A value between 0 and NUM_CALLBACK_PRIORITIES-1 .
|
||||
* @return Zero if the scan list was empty or 1<<prio
|
||||
* @since 3.16.0.1
|
||||
*/
|
||||
DBCORE_API unsigned int scanIoImmediate(IOSCANPVT pios, int prio);
|
||||
/** @brief Set scan list completion callback
|
||||
*
|
||||
* Replace the callback which will be invoked after record processing begins.
|
||||
* Asynchronous record processing may be ongoing.
|
||||
*
|
||||
* @since 3.15.0.2
|
||||
*/
|
||||
DBCORE_API void scanIoSetComplete(IOSCANPVT, io_scan_complete, void *usr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -17,7 +17,8 @@ C<MAYBE> or C<NO WAY> would not be accepted as choices for the field.
|
||||
Also, the choices C<yes>, C<No>, and C<Yes> are not valid choices since they
|
||||
don't match the case of C<NO> or C<YES>.
|
||||
The integer values C<0> and C<1> may often be used instead however, they are
|
||||
used as an index into the choices so C<0> becomes C<NO> and C<1> becomes <YES>.
|
||||
used as an index into the choices so C<0> becomes C<NO> and C<1> becomes
|
||||
C<YES>.
|
||||
|
||||
=menu menuYesNo
|
||||
|
||||
|
||||
@@ -190,6 +190,7 @@ unsigned short recGblResetAlarms(void *precord)
|
||||
|
||||
if(strcmp(pdbc->namsg, pdbc->amsg)!=0) {
|
||||
strcpy(pdbc->amsg, pdbc->namsg);
|
||||
pdbc->namsg[0] = '\0';
|
||||
stat_mask = DBE_ALARM;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ SRC_DIRS += $(IOCDIR)/dbtemplate
|
||||
PROD_CMD += msi
|
||||
|
||||
msi_SRCS = msi.cpp
|
||||
HTMLS += msi.html
|
||||
DOCS += msi.md
|
||||
|
||||
INC += dbLoadTemplate.h
|
||||
INC += dbtoolsIocRegister.h
|
||||
|
||||
@@ -1,445 +0,0 @@
|
||||
<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>msi: Macro Substitution and Include Tool</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
|
||||
<p>msi is a general purpose macro substitution/include tool. It accepts as input
|
||||
an ascii template file. It looks for lines containing two reserved command
|
||||
names: <tt>include</tt> and <tt>substitute</tt>. It also looks for and performs
|
||||
substitutions on macros of the form $(var) and ${var}. It uses the macLib
|
||||
routines from EPICS Base to perform the substitutions, so it also accepts the
|
||||
default value and value definition syntax that macLib implements.</p>
|
||||
|
||||
<p>msi also allows substitutions to be specified via a separate substitution
|
||||
file. This substitution file allows the same format as the substitution files
|
||||
accepted by the EPICS IOC's dbLoadTemplate command.</p>
|
||||
|
||||
<h2>Command Syntax:</h2>
|
||||
|
||||
<pre>msi -V -g -D -o<i>outfile</i> -I<i>dir</i> -M<i>subs</i> -S<i>subfile</i> <i>template</i></pre>
|
||||
|
||||
<p>All parameters are optional. The -o, -I, -M, and -S switches may be
|
||||
separated from their associated value string by spaces if desired. Output will
|
||||
be written to stdout unless the -o option is given.</p>
|
||||
|
||||
<p>Switches have the following meanings:</p>
|
||||
|
||||
<dl>
|
||||
<dt><tt>-V</tt></dt>
|
||||
<dd>Verbose warnings; if this parameter is specified then any undefined or
|
||||
recursive macros discovered in the template will be considered an error and
|
||||
will be marked in the output file. An error message will be shown, and when
|
||||
msi terminates it will do so with an exit status of 2.</dd>
|
||||
|
||||
<dt><tt>-g</tt></dt>
|
||||
<dd>When this flag is given all macros defined in a substitution file will
|
||||
have global scope and thus their values will persist until a new value is
|
||||
given for this macro. This flag is provided for backwards compatibility as
|
||||
this was the behavior of previous versions of msi, but it does not follow
|
||||
common scoping rules and is discouraged.</dd>
|
||||
|
||||
<dt><tt>-D</tt></dt>
|
||||
<dd>Output dependency information suitable for including by a Makefile to
|
||||
stdout instead of performing the macro substitutions. The <tt>-o</tt> option
|
||||
must be given to specify the target name for the dependency rules. Other
|
||||
options should be given exactly as will be used in the macro substitution
|
||||
process.</dd>
|
||||
|
||||
<dt><tt>-o</tt> <i>file</i></dt>
|
||||
<dd>Output will be written to the specifed file rather than to the standard
|
||||
output.</dd>
|
||||
|
||||
<dt><tt>-I</tt> <i>dir</i></dt>
|
||||
<dd>This parameter, which may be repeated or contain a colon-separated (or
|
||||
semi-colon separated on Windows) list of directory paths, specifies a search
|
||||
path for include commands. For example:
|
||||
|
||||
<blockquote>
|
||||
<pre>msi -I /home/mrk/examples:. -I.. template</pre>
|
||||
</blockquote>
|
||||
|
||||
specifies that all named files should be searched for in the following
|
||||
locations in the order given:
|
||||
|
||||
<ol>
|
||||
<li><tt>/home/mrk/examples</tt></li>
|
||||
<li><tt>.</tt> (the current directory)</li>
|
||||
<li><tt>..</tt> (the parent of the current directory)</li>
|
||||
</ol>
|
||||
</dd>
|
||||
|
||||
<dt><tt>-M</tt> <i>substitutions</i></dt>
|
||||
<dd>This parameter specifies macro values for the template instance.
|
||||
Multiple macro values can be specified in one substitution parameter, or in
|
||||
multiple <tt>-M</tt> parameters. For example:
|
||||
|
||||
<blockquote>
|
||||
<pre>msi -M "a=aval,b=bval" -Mc=cval template</pre>
|
||||
</blockquote>
|
||||
|
||||
specifies that in the template file each occurrence of:
|
||||
|
||||
<dl>
|
||||
<dd><tt>$(a)</tt> or <tt>${a}</tt> is replaced by <tt>aval</tt></dd>
|
||||
<dd><tt>$(b)</tt> or <tt>${b}</tt> is replaced by <tt>bval</tt></dd>
|
||||
<dd><tt>$(c)</tt> or <tt>${c}</tt> is replaced by <tt>cval</tt></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
|
||||
<dt><tt>-S</tt> <i>subfile</i></dt>
|
||||
<dd>The substitution file. See below for format.</dd>
|
||||
|
||||
<dt><i>template</i></dt>
|
||||
<dd> The input file. If no file is specified then input is taken from
|
||||
stdin, i.e. msi can be used as a filter. See below for a description of
|
||||
commands that can be embedded in the template file.</dd>
|
||||
</dl>
|
||||
|
||||
<p>It is not possible to display usage by just typing <tt>msi</tt> since
|
||||
executing the command with no arguments is a valid command. To show usage
|
||||
specify an illegal switch, e.g.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>msi -help</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2>Exit Status</h2>
|
||||
|
||||
<dl>
|
||||
<dt>0<dd>Success.
|
||||
<dt>1<dd>Can't open/create file, or other I/O error.
|
||||
<dt>2<dd>Undefined macros encountered with the <tt>-V</tt> option specified.
|
||||
</dl>
|
||||
|
||||
<h2>Template File Format</h2>
|
||||
|
||||
<p>This file contains the text to be read and written to the output after macro
|
||||
substitution is performed. If no file is given then input is read from stdin.
|
||||
Variable instances to be substituted by macro values are expressed in the
|
||||
template using the syntax <tt>$(</tt><i>name</i><tt>)</tt> or
|
||||
<tt>${</tt><i>name</i><tt>}</tt>. The template can also provide default values
|
||||
to be used when a macro has not been given a value, using the syntax
|
||||
<tt>$(</tt><i>name</i><tt>=</tt><i>default</i><tt>)</tt> or
|
||||
<tt>${</tt><i>name</i><tt>=</tt><i>default</i><tt>}</tt>.</p>
|
||||
|
||||
<p>For example, using the command</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>msi -M name=Marty template</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>where the file template contains</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>My name is $(name)
|
||||
My age is $(age=none of your business)</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>results in this output:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>My name is Marty
|
||||
My age is none of your business</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Macro variables and their default values can be expressed in terms of other
|
||||
macros if necessary, to almost any level of complexity. Recursive definitions
|
||||
will generate warning messages on stderr and result in undefined output.</p>
|
||||
|
||||
<p>The template file is read and processed one line at a time, where the
|
||||
maximum length of a line before and/or after macro expansion is 1023 characters
|
||||
— longer input or output lines will cause msi to fail. Within the context
|
||||
of a single line, macro expansion does not occur when the variable instance
|
||||
appears inside a single-quoted string, or where the dollar sign <tt>$</tt> is
|
||||
preceded by a back-slash character <tt>\</tt>, but as with the standard Unix
|
||||
shells, variables inside double quoted strings are expanded properly.</p>
|
||||
|
||||
<p>However neither back-slash characters nor quotes of either variety are
|
||||
removed when generating the output file, so depending on what is being output
|
||||
the single quote behaviour may not be useful and may even be a hinderance. It
|
||||
cannot be disabled in the current version of msi.</p>
|
||||
|
||||
<h3>Template file commands</h3>
|
||||
|
||||
<p>In addition to the regular text and variable instances described above, the
|
||||
template file may also contain commands which allow the insertion of other
|
||||
template files and the ability to set macro values inside the template file
|
||||
itself. These commands are:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>include "file"
|
||||
substitute "var=value,var=value,..."</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Lines containing commands must be in one of these forms:</p>
|
||||
|
||||
<ul>
|
||||
<li><tt>include "</tt><i>filename</i><tt>"</tt></li>
|
||||
<li><tt>substitute "</tt><i>name1=value1, name2=value2, ...</i><tt>"</tt></li>
|
||||
</ul>
|
||||
|
||||
<p>White space is allowed before and after the command verb, and after the
|
||||
quoted string. If embedded quotes are needed, the backslash character
|
||||
<tt>\</tt> can be used as an escape character. For example</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>substitute "a=\"val\""</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>specifies that (unless <tt>a</tt> is subsequently redefined) wherever a
|
||||
<tt>$(a)</tt> macro appears in the template below this point, the text
|
||||
<tt>"val"</tt> (including the double quote characters) will appear in the
|
||||
output instead.</p>
|
||||
|
||||
<p>If a line does match either syntax above it is just passed to macLib for
|
||||
processing without any notification. Thus the input line:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>include "myfile" #include file</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>would just be passed to macLib, i.e. it would <em>not</em> be considered an
|
||||
include command.</p>
|
||||
|
||||
<p>As an example of these commands, let the Unix command be:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>msi template</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>and file includeFile contain:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>first name is ${first}
|
||||
family name is ${family}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>and template is</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>substitute "first=Marty,family=Kraimer"
|
||||
include "includeFile"
|
||||
substitute "first=Irma,family=Kraimer"
|
||||
include "includeFile"</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>then the following is written to the output.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Note that the IOC's <tt>dbLoadTemplate</tt> command does not support the
|
||||
<tt>substitute</tt> syntax in template files, although the <tt>include</tt>
|
||||
syntax is supported.</p>
|
||||
|
||||
<h2>Substitution File Format</h2>
|
||||
|
||||
<p>The optional substitution file has three formats: regular, pattern, and
|
||||
dbTemplate format. We will discuss each separately.</p>
|
||||
|
||||
<h3>Regular format</h3>
|
||||
|
||||
<blockquote>
|
||||
<pre>global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
|
||||
{var1=set1_val1, var2=set1_val2, ...}
|
||||
{var2=set2_val2, var1=set2_val1, ...}
|
||||
global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
|
||||
{var1=set3_val1, var2=set3_val2, ...}
|
||||
{var2=set4_val2, var1=set4_val1, ...}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>The template file is output with macro substitutions performed once for each
|
||||
set of braces containing macro replacement values.</p>
|
||||
|
||||
<h3>Pattern format</h3>
|
||||
|
||||
<blockquote>
|
||||
<pre>global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
|
||||
pattern {var1, var2, ...}
|
||||
{set1_val1, set1_val2, ...}
|
||||
{set2_val1, set2_val2, ...}
|
||||
pattern {var2, var1, ...}
|
||||
global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
|
||||
{set3_val2, set3_val1, ...}
|
||||
{set4_val2, set4_val2, ...}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>This produces the same result as the regular format example above.</p>
|
||||
|
||||
<h3>dbLoadTemplate Format</h3>
|
||||
|
||||
<p>This format is an extension of the format accepted by the EPICS IOC command
|
||||
<tt>dbLoadTemplate</tt>, and allows templates to be expanded on the host rather
|
||||
by using dbLoadTemplate at IOC boot time.</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
|
||||
file templatefile {
|
||||
<i>pattern format or regular format</i>
|
||||
}
|
||||
file "${WHERE}/template2" {
|
||||
<i>pattern format or regular format</i>
|
||||
}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>For the dbTemplate format, the template filename does not have to be given
|
||||
on the command line, and is usually specified in the substitutions file
|
||||
instead. If a template filename is given on the command line it will override
|
||||
the filenames listed in the substitutions files.</p>
|
||||
|
||||
<h3>Syntax for all formats</h3>
|
||||
|
||||
<p>A comment line may appear anywhere in a substitution file, and will be
|
||||
ignored. A comment line is any line beginning with the character <tt>#</tt>,
|
||||
which must be the very first character on the line.</p>
|
||||
|
||||
<p>Global definitions may supplement or override the macro values supplied on
|
||||
the command-line using the <tt>-M</tt> switch, and set default values that will
|
||||
survive for the remainder of the file unless another global definition of the
|
||||
same macro changes it.</p>
|
||||
|
||||
<p>For definitions within braces given in any of the file formats, a separator
|
||||
must be given between items. A separator is either a comma, or one or more of
|
||||
the standard white space characters (space, formfeed, newline, carriage return,
|
||||
tab or vertical tab).</p>
|
||||
|
||||
<p>Each item within braces can be an alphanumeric token, or a double-quoted
|
||||
string. A back-slash character <tt>\</tt> can be used to escape a quote
|
||||
character needed inside a quoted string. These three sets of substitutions are
|
||||
all equivalent:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>{a=aa b=bb c="\"cc\""}
|
||||
{b="bb",a=aa,c="\"cc\""}
|
||||
{
|
||||
c="\"cc\""
|
||||
b=bb
|
||||
a="aa"
|
||||
}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>Within a substitutions file, the file name may appear inside double quotation
|
||||
marks; these are required if the name contains certain characters or environment
|
||||
variable macros of the form ${ENV_VAR} or $(ENV_VAR), which will be expanded
|
||||
before the file is opened.</p>
|
||||
|
||||
<h3>Regular substitution example</h3>
|
||||
|
||||
<p>Let the command be:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>msi -S substitute template</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>The file <tt>template</tt> contains</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>first name is ${first}
|
||||
family name is ${family}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p> and the file <tt>substitute</tt> is</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>global {family=Kraimer}
|
||||
{first=Marty}
|
||||
{first=Irma}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>The following is the output produced:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>Pattern substitution example</h3>
|
||||
|
||||
<p>Let the command be:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>msi -S pattern template</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>The file <tt>pattern</tt> contains</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>pattern {first,last}
|
||||
{Marty,Kraimer}
|
||||
{Irma,Kraimer}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>and <tt>template</tt> is the same as the previous example:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>first name is ${first}
|
||||
family name is ${family}</pre>
|
||||
</blockquote>
|
||||
|
||||
<p>This is the output:</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer</pre>
|
||||
</blockquote>
|
||||
|
||||
<h3>dbTemplate example</h3>
|
||||
Let the command be
|
||||
|
||||
<blockquote>
|
||||
<pre>msi -S xxx.substitutions</pre>
|
||||
</blockquote>
|
||||
|
||||
<tt>xxx.substitutions</tt> is
|
||||
|
||||
<blockquote>
|
||||
<pre>file template {
|
||||
pattern {first,last}
|
||||
{Marty,Kraimer}
|
||||
{Irma,Kraimer}
|
||||
pattern {last,first}
|
||||
{Smith,Bill}
|
||||
{Smith,Mary}
|
||||
}
|
||||
file template {
|
||||
{first=Marty,last=Kraimer}
|
||||
{first=Irma,last=Kraimer}
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<tt>template</tt> is the same as in the previous example..
|
||||
|
||||
<p>The following is written to the output</p>
|
||||
|
||||
<blockquote>
|
||||
<pre>first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer
|
||||
first name is Bill
|
||||
last name is Smith
|
||||
first name is Mary
|
||||
last name is Smith
|
||||
first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer</pre>
|
||||
</blockquote>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,384 @@
|
||||
# msi: Macro Substitution and Include Tool
|
||||
|
||||
(msitool)=
|
||||
## Introduction
|
||||
|
||||
msi is a general purpose macro substitution/include tool.
|
||||
It accepts as input an ascii template file. It looks for lines containing two reserved
|
||||
command names: `include` and `substitute`. It also looks for and performs
|
||||
substitutions on macros of the form `$(var)` and `${var}`. It uses the
|
||||
macLib routines from EPICS Base to perform the substitutions, so it also
|
||||
accepts the default value and value definition syntax that macLib
|
||||
implements.
|
||||
|
||||
msi also allows substitutions to be specified via a separate
|
||||
substitution file. This substitution file allows the same format as the
|
||||
substitution files accepted by the EPICS IOC's dbLoadTemplate command.
|
||||
|
||||
|
||||
## Command Syntax
|
||||
|
||||
`msi -V -g -o outfile -I dir -M subs -S subfile template`
|
||||
|
||||
All parameters are optional. The -o, -I, -M, and -S switches may be
|
||||
separated from their associated value string by spaces if desired.
|
||||
Output will be written to stdout unless the -o option is given.
|
||||
|
||||
Switches have the following meanings:
|
||||
|
||||
- **-V**
|
||||
|
||||
Verbose warnings; if this parameter is specified then any undefined
|
||||
macro discovered in the template file which does not have an
|
||||
associated default value is considered an error. An error message is
|
||||
generated, and when msi terminates it will do so with an exit status
|
||||
of 2.
|
||||
- **-g**
|
||||
|
||||
When this flag is given all macros defined in a substitution file
|
||||
will have global scope and thus their values will persist until a
|
||||
new value is given for this macro. This flag is provided for
|
||||
backwards compatibility as this was the behavior of previous
|
||||
versions of msi, but it does not follow common scoping rules and is
|
||||
discouraged.
|
||||
- **-o _file_**
|
||||
|
||||
Output will be written to the specifed file rather than to the
|
||||
standard output.
|
||||
- **-I _dir_**
|
||||
|
||||
This parameter, which may be repeated or contain a colon-separated
|
||||
(or semi-colon separated on Windows) list of directory paths,
|
||||
specifies a search path for include commands. For example:
|
||||
|
||||
msi -I /home/mrk/examples:. -I.. template
|
||||
|
||||
specifies that all named files should be searched for in the following locations,
|
||||
in the order given:
|
||||
|
||||
1. /home/mrk/examples
|
||||
2. . (the current directory)
|
||||
3. .. (the parent of the current directory)
|
||||
|
||||
- **-M _substitutions_**
|
||||
|
||||
This parameter specifies macro values for the template instance.
|
||||
Multiple macro values can be specified in one substitution
|
||||
parameter, or in multiple -M parameters. For example:
|
||||
|
||||
msi -M "a=aval,b=bval" -Mc=cval template
|
||||
|
||||
specifies that in the template file each occurrence of:
|
||||
|
||||
- `$(a)` or `${a}` is replaced by _aval_
|
||||
- `$(b)` or `${b}` is replaced by _bval_
|
||||
- `$(c)` or `${c}` is replaced by _cval_
|
||||
|
||||
- **-S _subfile_**
|
||||
|
||||
The substitution file. See below for format.
|
||||
- **_template_**
|
||||
|
||||
The input file. If no file is specified then input is taken from
|
||||
stdin, i.e. msi can be used as a filter. See below for a description
|
||||
of commands that can be embedded in the template file.
|
||||
|
||||
It is not possible to display usage by just typing msi since executing
|
||||
the command with no arguments is a valid command. To show usage specify
|
||||
an illegal switch, e.g.
|
||||
|
||||
msi -help
|
||||
|
||||
|
||||
## Exit Status
|
||||
|
||||
- **0**
|
||||
Success.
|
||||
- **1**
|
||||
Can't open/create file, or other I/O error.
|
||||
- **2**
|
||||
Undefined macros encountered with the -V option specified.
|
||||
|
||||
|
||||
## Template File Format
|
||||
|
||||
This file contains the text to be read and written to the output after
|
||||
macro substitution is performed. If no file is given then input is read
|
||||
from stdin. Variable instances to be substituted by macro values are
|
||||
expressed in the template using the syntax \$(_name_) or \${_name_}. The
|
||||
template can also provide default values to be used when a macro has not
|
||||
been given a value, using the syntax \$(_name_=_default_) or \${_name_=_default_}.
|
||||
|
||||
For example, using the command
|
||||
|
||||
msi -M name=Marty template
|
||||
|
||||
where the file template contains
|
||||
|
||||
My name is $(name)
|
||||
My age is $(age=none of your business)
|
||||
|
||||
results in this output:
|
||||
|
||||
My name is Marty
|
||||
My age is none of your business
|
||||
|
||||
Macro variables and their default values can be expressed in terms of
|
||||
other macros if necessary, to almost any level of complexity. Recursive
|
||||
definitions will generate warning messages on stderr and result in
|
||||
undefined output.
|
||||
|
||||
The template file is read and processed one line at a time, where the
|
||||
maximum length of a line before and/or after macro expansion is 1023
|
||||
characters; longer input or output lines will cause msi to fail. Within
|
||||
the context of a single line, macro expansion does not occur when the
|
||||
variable instance appears inside a single-quoted string, or where the
|
||||
dollar sign $ is preceded by a back-slash character \, but as with the
|
||||
standard Unix shells, variables inside double quoted strings are
|
||||
expanded properly.
|
||||
|
||||
However neither back-slash characters nor quotes of either variety are
|
||||
removed when generating the output file, so depending on what is being
|
||||
output the single quote behaviour may not be useful and may even be a
|
||||
hinderance. It cannot be disabled in the current version of msi.
|
||||
|
||||
|
||||
### Template file commands
|
||||
|
||||
In addition to the regular text and variable instances described above,
|
||||
the template file may also contain commands which allow the insertion of
|
||||
other template files and the ability to set macro values inside the
|
||||
template file itself. These commands are:
|
||||
|
||||
include "file"
|
||||
substitute "var=value,var=value,..."
|
||||
|
||||
Lines containing commands must be in one of these forms:
|
||||
|
||||
- include "_filename_"
|
||||
|
||||
- substitute "_name1=value1, name2=value2, ..._"
|
||||
|
||||
White space is allowed before and after the command verb, and after the
|
||||
quoted string. If embedded quotes are needed, the backslash character \
|
||||
can be used as an escape character. For example
|
||||
|
||||
substitute "a=\"val\""
|
||||
|
||||
specifies that (unless a is subsequently redefined) wherever a $(a)
|
||||
macro appears in the template below this point, the text
|
||||
"val" (including the double quote characters) will appear in the output
|
||||
instead.
|
||||
|
||||
If a line does match either syntax above it is just passed to macLib for
|
||||
processing without any notification. Thus the input line:
|
||||
|
||||
include "myfile" #include file
|
||||
|
||||
would just be passed to macLib, i.e. it would _not_ be considered an
|
||||
include command.
|
||||
|
||||
As an example of these commands, let the Unix command be:
|
||||
|
||||
msi template
|
||||
|
||||
and file includeFile contain:
|
||||
|
||||
first name is ${first}
|
||||
family name is ${family}
|
||||
|
||||
and template is
|
||||
|
||||
substitute "first=Marty,family=Kraimer"
|
||||
include "includeFile"
|
||||
substitute "first=Irma,family=Kraimer"
|
||||
include "includeFile"
|
||||
|
||||
then the following is written to the output.
|
||||
|
||||
first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer
|
||||
|
||||
Note that the IOC's dbLoadTemplate command does not support the
|
||||
substitute syntax in template files, although the include syntax is
|
||||
supported.
|
||||
|
||||
|
||||
## Substitution File Format
|
||||
|
||||
The optional substitution file has three formats: regular, pattern, and
|
||||
dbTemplate format. We will discuss each separately.
|
||||
|
||||
|
||||
### Regular format
|
||||
|
||||
global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
|
||||
{var1=set1_val1, var2=set1_val2, ...}
|
||||
{var2=set2_val2, var1=set2_val1, ...}
|
||||
global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
|
||||
{var1=set3_val1, var2=set3_val2, ...}
|
||||
{var2=set4_val2, var1=set4_val1, ...}
|
||||
|
||||
The template file is output with macro substitutions performed once for
|
||||
each set of braces containing macro replacement values.
|
||||
|
||||
|
||||
### Pattern format
|
||||
|
||||
global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
|
||||
pattern {var1, var2, ...}
|
||||
{set1_val1, set1_val2, ...}
|
||||
{set2_val1, set2_val2, ...}
|
||||
pattern {var2, var1, ...}
|
||||
global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
|
||||
{set3_val2, set3_val1, ...}
|
||||
{set4_val2, set4_val2, ...}
|
||||
|
||||
This produces the same result as the regular format example above.
|
||||
|
||||
|
||||
### dbLoadTemplate Format
|
||||
|
||||
This format is an extension of the format accepted by the EPICS IOC
|
||||
command dbLoadTemplate, and allows templates to be expanded on the host
|
||||
rather by using dbLoadTemplate at IOC boot time.
|
||||
|
||||
global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
|
||||
file templatefile {
|
||||
/pattern format or regular format/
|
||||
}
|
||||
file "${WHERE}/template2" {
|
||||
/pattern format or regular format/
|
||||
}
|
||||
|
||||
For the dbTemplate format, the template filename does not have to be
|
||||
given on the command line, and is usually specified in the substitutions
|
||||
file instead. If a template filename is given on the command line it
|
||||
will override the filenames listed in the substitutions files.
|
||||
|
||||
|
||||
### Syntax for all formats
|
||||
|
||||
A comment line may appear anywhere in a substitution file, and will be
|
||||
ignored. A comment line is any line beginning with the character #,
|
||||
which must be the very first character on the line.
|
||||
|
||||
Global definitions may supplement or override the macro values supplied
|
||||
on the command-line using the -M switch, and set default values that
|
||||
will survive for the remainder of the file unless another global
|
||||
definition of the same macro changes it.
|
||||
|
||||
For definitions within braces given in any of the file formats, a
|
||||
separator must be given between items. A separator is either a comma, or
|
||||
one or more of the standard white space characters (space, formfeed,
|
||||
newline, carriage return, tab or vertical tab).
|
||||
|
||||
Each item within braces can be an alphanumeric token, or a double-quoted
|
||||
string. A back-slash character \ can be used to escape a quote character
|
||||
needed inside a quoted string. These three sets of substitutions are all
|
||||
equivalent:
|
||||
|
||||
{a=aa b=bb c="\"cc\""}
|
||||
{b="bb",a=aa,c="\"cc\""}
|
||||
{
|
||||
c="\"cc\""
|
||||
b=bb
|
||||
a="aa"
|
||||
}
|
||||
|
||||
Within a substitutions file, the file name may appear inside double
|
||||
quotation marks; these are required if the name contains certain
|
||||
characters or environment variable macros of the form `${ENV_VAR}` or
|
||||
`$(ENV_VAR)`, which will be expanded before the file is opened.
|
||||
|
||||
|
||||
### Regular substitution example
|
||||
|
||||
Let the command be:
|
||||
|
||||
msi -S substitute template
|
||||
|
||||
The file template contains
|
||||
|
||||
first name is ${first}
|
||||
family name is ${family}
|
||||
|
||||
and the file `substitute` is
|
||||
|
||||
global {family=Kraimer}
|
||||
{first=Marty}
|
||||
{first=Irma}
|
||||
|
||||
The following is the output produced:
|
||||
|
||||
first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer
|
||||
|
||||
|
||||
### Pattern substitution example
|
||||
|
||||
Let the command be:
|
||||
|
||||
msi -S pattern template
|
||||
|
||||
The file pattern contains
|
||||
|
||||
pattern {first,last}
|
||||
{Marty,Kraimer}
|
||||
{Irma,Kraimer}
|
||||
|
||||
and template is the same as the previous example:
|
||||
|
||||
first name is ${first}
|
||||
family name is ${family}
|
||||
|
||||
This is the output:
|
||||
|
||||
first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer
|
||||
|
||||
|
||||
### dbTemplate example
|
||||
|
||||
Let the command be
|
||||
|
||||
msi -S xxx.substitutions
|
||||
|
||||
`xxx.substitutions` is
|
||||
|
||||
file template {
|
||||
pattern {first,last}
|
||||
{Marty,Kraimer}
|
||||
{Irma,Kraimer}
|
||||
pattern {last,first}
|
||||
{Smith,Bill}
|
||||
{Smith,Mary}
|
||||
}
|
||||
file template {
|
||||
{first=Marty,last=Kraimer}
|
||||
{first=Irma,last=Kraimer}
|
||||
}
|
||||
|
||||
`template` is the same as in the previous example.
|
||||
|
||||
The following is written to the output
|
||||
|
||||
first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer
|
||||
first name is Bill
|
||||
last name is Smith
|
||||
first name is Mary
|
||||
last name is Smith
|
||||
first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# IOC Component Reference
|
||||
|
||||
This document provides reference information about the record types,
|
||||
menus, link types and channel filters included with EPICS Base.
|
||||
|
||||
## Introduction and IOC Concepts
|
||||
|
||||
- [Introduction to EPICS](https://docs.epics-controls.org/en/latest/getting-started/EPICS_Intro.html)
|
||||
- [Process Database Concepts](https://docs.epics-controls.org/en/latest/process-database/EPICS_Process_Database_Concepts.html)
|
||||
|
||||
## Record Type Definitions
|
||||
|
||||
These sections describe common aspects of the record types:
|
||||
|
||||
```{toctree}
|
||||
:titlesonly:
|
||||
|
||||
dbCommonRecord
|
||||
dbCommonInput
|
||||
dbCommonOutput
|
||||
```
|
||||
|
||||
These are the record types supplied with EPICS Base:
|
||||
|
||||
```{toctree}
|
||||
:titlesonly:
|
||||
|
||||
aaiRecord
|
||||
aaoRecord
|
||||
aiRecord
|
||||
aoRecord
|
||||
aSubRecord
|
||||
biRecord
|
||||
boRecord
|
||||
calcoutRecord
|
||||
calcRecord
|
||||
compressRecord
|
||||
dfanoutRecord
|
||||
eventRecord
|
||||
fanoutRecord
|
||||
histogramRecord
|
||||
int64inRecord
|
||||
int64outRecord
|
||||
longinRecord
|
||||
longoutRecord
|
||||
lsiRecord
|
||||
lsoRecord
|
||||
mbbiDirectRecord
|
||||
mbbiRecord
|
||||
mbboDirectRecord
|
||||
mbboRecord
|
||||
permissiveRecord
|
||||
printfRecord
|
||||
selRecord
|
||||
seqRecord
|
||||
stateRecord
|
||||
stringinRecord
|
||||
stringoutRecord
|
||||
subArrayRecord
|
||||
subRecord
|
||||
waveformRecord
|
||||
```
|
||||
|
||||
## Menu Definitions
|
||||
|
||||
Menu field choices are documented with the record type that defines them, or
|
||||
here for the global menus that are used by multiple record types:
|
||||
|
||||
```{toctree}
|
||||
:titlesonly:
|
||||
|
||||
menuAlarmSevr
|
||||
menuAlarmStat
|
||||
menuConvert
|
||||
menuFtype
|
||||
menuIvoa
|
||||
menuOmsl
|
||||
menuPini
|
||||
menuPost
|
||||
menuPriority
|
||||
menuScan
|
||||
menuSimm
|
||||
menuYesNo
|
||||
```
|
||||
|
||||
## Other Components
|
||||
|
||||
EPICS Base also comes with extensible sets of server Channel Filters and IOC
|
||||
Database Link types, which are documented here:
|
||||
|
||||
```{toctree}
|
||||
:titlesonly:
|
||||
|
||||
filters
|
||||
links
|
||||
```
|
||||
@@ -0,0 +1,170 @@
|
||||
=head1 EPICS Component Reference Manual
|
||||
|
||||
This document provides reference information about the record types,
|
||||
menus, link types and channel filters included with EPICS Base.
|
||||
|
||||
Many details about the record and menu definitions are derived automatically
|
||||
from the source code at build time.
|
||||
|
||||
|
||||
=head2 Introduction and IOC Concepts
|
||||
|
||||
These links point to an external website where introductory and overview
|
||||
documentation is now being published.
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Introduction to EPICS|https://docs.epics-controls.org/en/latest/guides/EPICS_Intro.html>
|
||||
|
||||
=item * L<Process Database Concepts|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Record Type Definitions
|
||||
|
||||
These sections describe common aspects of the record types:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Fields Common to All Record Types|dbCommonRecord>
|
||||
|
||||
=item * L<Fields Common to Input Record Types|dbCommonInput>
|
||||
|
||||
=item * L<Fields Common to Output Record Types|dbCommonOutput>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
These are the record types supplied with EPICS Base:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Analog Array Input Record (aai)|aaiRecord>
|
||||
|
||||
=item * L<Analog Array Output Record (aao)|aaoRecord>
|
||||
|
||||
=item * L<Analog Input Record (ai)|aiRecord>
|
||||
|
||||
=item * L<Analog Output Record (ao)|aoRecord>
|
||||
|
||||
=item * L<Array Subroutine Record (aSub)|aSubRecord>
|
||||
|
||||
=item * L<Binary Input Record (bi)|biRecord>
|
||||
|
||||
=item * L<Binary Output Record (bo)|boRecord>
|
||||
|
||||
=item * L<Calculation Output Record (calcout)|calcoutRecord>
|
||||
|
||||
=item * L<Calculation Record (calc)|calcRecord>
|
||||
|
||||
=item * L<Compression Record (compress)|compressRecord>
|
||||
|
||||
=item * L<Data Fanout Record (dfanout)|dfanoutRecord>
|
||||
|
||||
=item * L<Event Record (event)|eventRecord>
|
||||
|
||||
=item * L<Fanout Record (fanout)|fanoutRecord>
|
||||
|
||||
=item * L<Histogram Record (histogram)|histogramRecord>
|
||||
|
||||
=item * L<64-bit Integer Input Record (int64in)|int64inRecord>
|
||||
|
||||
=item * L<64-bit Integer Output Record (int64out)|int64outRecord>
|
||||
|
||||
=item * L<Long Input Record (longin)|longinRecord>
|
||||
|
||||
=item * L<Long Output Record (longout)|longoutRecord>
|
||||
|
||||
=item * L<Long String Input Record (lsi)|lsiRecord>
|
||||
|
||||
=item * L<Long String Output Record (lso)|lsoRecord>
|
||||
|
||||
=item * L<Multi-Bit Binary Input Direct Record (mbbiDirect)|mbbiDirectRecord>
|
||||
|
||||
=item * L<Multi-Bit Binary Input Record (mbbi)|mbbiRecord>
|
||||
|
||||
=item * L<Multi-Bit Binary Output Direct Record (mbboDirect)|mbboDirectRecord>
|
||||
|
||||
=item * L<Multi-Bit Binary Output Record (mbbo)|mbboRecord>
|
||||
|
||||
=item * L<Permissive Record (permissive)|permissiveRecord>
|
||||
|
||||
=item * L<Printf Record (printf)|printfRecord>
|
||||
|
||||
=item * L<Select Record (sel)|selRecord>
|
||||
|
||||
=item * L<Sequence Record (seq)|seqRecord>
|
||||
|
||||
=item * L<State Record (state)|stateRecord>
|
||||
|
||||
=item * L<String Input Record (stringin)|stringinRecord>
|
||||
|
||||
=item * L<String Output Record (stringout)|stringoutRecord>
|
||||
|
||||
=item * L<Sub-Array Record (subArray)|subArrayRecord>
|
||||
|
||||
=item * L<Subroutine Record (sub)|subRecord>
|
||||
|
||||
=item * L<Waveform Record (waveform)|waveformRecord>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Menu Definitions
|
||||
|
||||
Menu field choices are documented with the record type that defines them, or
|
||||
here for the global menus that are used by multiple record types:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Alarm Severity Menu|menuAlarmSevr>
|
||||
|
||||
=item * L<Alarm Status Menu|menuAlarmStat>
|
||||
|
||||
=item * L<Analog Conversions Menu|menuConvert>
|
||||
|
||||
=item * L<Field Type Menu|menuFtype>
|
||||
|
||||
=item * L<Invalid Value Output Action Menu|menuIvoa>
|
||||
|
||||
=item * L<Output Mode Select Menu|menuOmsl>
|
||||
|
||||
=item * L<Process at iocInit Menu|menuPini>
|
||||
|
||||
=item * L<Post Monitors Menu|menuPost>
|
||||
|
||||
=item * L<Priority Menu|menuPriority>
|
||||
|
||||
=item * L<Scan Menu|menuScan>
|
||||
|
||||
=item * L<Simulation Mode Menu|menuSimm>
|
||||
|
||||
=item * L<YesE<sol>No Menu|menuYesNo>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Other Components
|
||||
|
||||
EPICS Base also comes with extensible sets of server Channel Filters and IOC
|
||||
Database Link types, which are documented here:
|
||||
|
||||
=over
|
||||
|
||||
=item * L<Channel Filters|filters>
|
||||
|
||||
=item * L<IOC Database Link Types|links>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Corrections and Updates
|
||||
|
||||
Corrections to these documents can be submitted as patch files to the EPICS
|
||||
core developers, or as GitHub pull requests to the 7.0 branch of Base.
|
||||
These document sources can be found under C<modules/database/src> tree, mostly
|
||||
in the C<std/rec> and C<ioc/db> directories in files with extension C<.dbd.pod>.
|
||||
The documentation source format is a combination of the EPICS DBD file format
|
||||
with an extended version of Perl's POD (plain old documentation); run
|
||||
C<perldoc pod> for details of POD.
|
||||
@@ -30,6 +30,9 @@ include $(STDDIR)/filters/Makefile
|
||||
include $(STDDIR)/link/Makefile
|
||||
include $(STDDIR)/softIoc/Makefile
|
||||
|
||||
DOCS += ComponentReference.md
|
||||
HTMLS += ComponentReference.html
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
include $(STDDIR)/rec/RULES
|
||||
|
||||
@@ -18,5 +18,5 @@ dbRecStd_SRCS += sync.c
|
||||
dbRecStd_SRCS += decimate.c
|
||||
dbRecStd_SRCS += utag.c
|
||||
|
||||
DOCS += filters.md
|
||||
HTMLS += filters.html
|
||||
|
||||
|
||||
@@ -16,4 +16,5 @@ dbRecStd_SRCS += lnkCalc.c
|
||||
dbRecStd_SRCS += lnkState.c
|
||||
dbRecStd_SRCS += lnkDebug.c
|
||||
|
||||
DOCS += links.md
|
||||
HTMLS += links.html
|
||||
|
||||
@@ -54,8 +54,13 @@ stdRecords_DBD = $(patsubst %,%.dbd,$(stdRecords))
|
||||
|
||||
dbRecStd_SRCS += $(patsubst %,%.c,$(stdRecords))
|
||||
|
||||
DOCS += $(patsubst %.dbd.pod,%.md,$(notdir $(wildcard ../rec/*Record.dbd.pod)))
|
||||
HTMLS += $(patsubst %.dbd.pod,%.html,$(notdir $(wildcard ../rec/*Record.dbd.pod)))
|
||||
|
||||
vpath %.png $(SRC_DIRS)
|
||||
|
||||
DOCS += image/compress-1.png
|
||||
DOCS += image/compress-2.png
|
||||
|
||||
HTMLS += image/compress-1.png
|
||||
HTMLS += image/compress-2.png
|
||||
|
||||
@@ -34,6 +34,7 @@ PERL_SCRIPTS += dbdToRecordtypeH.pl
|
||||
PERL_SCRIPTS += dbdExpand.pl
|
||||
PERL_SCRIPTS += dbExpand.pl
|
||||
PERL_SCRIPTS += dbdToHtml.pl
|
||||
PERL_SCRIPTS += dbdToMD.pl
|
||||
PERL_SCRIPTS += registerRecordDeviceDriver.pl
|
||||
|
||||
HTMLS += dbdToHtml.html
|
||||
|
||||
@@ -0,0 +1,307 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
#*************************************************************************
|
||||
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
|
||||
# National Laboratory.
|
||||
# SPDX-License-Identifier: EPICS
|
||||
# EPICS BASE is distributed subject to a Software License Agreement found
|
||||
# in file LICENSE that is included with this distribution.
|
||||
#*************************************************************************
|
||||
|
||||
use strict;
|
||||
|
||||
|
||||
use FindBin qw($Bin);
|
||||
use lib ("$Bin/../../lib/perl");
|
||||
|
||||
use DBD;
|
||||
use DBD::Parser;
|
||||
use EPICS::Getopts;
|
||||
use EPICS::macLib;
|
||||
use EPICS::PodMD;
|
||||
use EPICS::Readfile;
|
||||
|
||||
use Pod::Usage;
|
||||
|
||||
=head1 NAME
|
||||
|
||||
dbdToMD.pl - Convert DBD file with POD to Markdown
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<dbdToMD.pl> [B<-h>] [B<-D>] [B<-I> dir] [B<-o> file] file.dbd.pod
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Generates MArkdown documentation from a B<.dbd.pod> file.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
B<dbdToMD.pl> understands the following options:
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<-h>
|
||||
|
||||
Help, display usage information.
|
||||
|
||||
=item B<-H>
|
||||
|
||||
Conversion help, display information about converting reference documentation
|
||||
from the EPICS Wiki into a B<.dbd.pod> file for use with this tool.
|
||||
|
||||
=item B<-I>
|
||||
|
||||
Path to look for include files.
|
||||
|
||||
=item B<-o> file
|
||||
|
||||
Name of the output file to be created.
|
||||
|
||||
=back
|
||||
|
||||
If no output filename is set, the file created will be named after the input
|
||||
file, removing any directory components in the path and replacing any
|
||||
B<.dbd.pod> file extension with B<.md>.
|
||||
|
||||
=cut
|
||||
|
||||
our ($opt_h, $opt_H, @opt_I, $opt_o);
|
||||
|
||||
my $tool = 'dbdToMD.pl';
|
||||
|
||||
getopts('hHI@o:') or
|
||||
pod2usage(2);
|
||||
pod2usage(-verbose => 2) if $opt_H;
|
||||
pod2usage(1) if $opt_h;
|
||||
pod2usage("$tool: No input file given.\n") if @ARGV != 1;
|
||||
|
||||
my $dbd = DBD->new();
|
||||
|
||||
my $infile = shift @ARGV;
|
||||
$infile =~ m/\.dbd.pod$/ or
|
||||
pod2usage("$tool: Input file '$infile' must have '.dbd.pod' extension.\n");
|
||||
|
||||
ParseDBD($dbd, Readfile($infile, 0, \@opt_I));
|
||||
|
||||
if (!$opt_o) {
|
||||
($opt_o = $infile) =~ s/\.dbd\.pod$/.md/;
|
||||
$opt_o =~ s/^.*\///;
|
||||
$opt_o =~ s/dbCommonRecord/dbCommon/;
|
||||
}
|
||||
|
||||
(my $title = $opt_o) =~ s/\.md$//;
|
||||
|
||||
open my $out, '>', $opt_o or
|
||||
die "Can't create $opt_o: $!\n";
|
||||
|
||||
$SIG{__DIE__} = sub {
|
||||
die @_ if $^S; # Ignore eval deaths
|
||||
close $out;
|
||||
unlink $opt_o;
|
||||
};
|
||||
|
||||
sub make_fragment {
|
||||
my $fragment = $_[1];
|
||||
$fragment =~ s/\W+/-/g;
|
||||
$fragment = lc($fragment);
|
||||
$_[1] = $fragment;
|
||||
}
|
||||
|
||||
my $podRst = EPICS::PodMD->new(
|
||||
perldoc_url_prefix => '',
|
||||
perldoc_fragment_format => make_fragment,
|
||||
markdown_fragment_format => make_fragment,
|
||||
);
|
||||
|
||||
# Parse the Pod text from the root DBD object
|
||||
my $pod = join "\n",
|
||||
map {
|
||||
# Handle a 'recordtype' Pod directive
|
||||
if (m/^ =recordtype \s+ (\w+) /x) {
|
||||
my $rn = $1;
|
||||
my $rtyp = $dbd->recordtype($rn);
|
||||
die "Unknown recordtype '$rn' in $infile POD directive\n"
|
||||
unless $rtyp;
|
||||
rtypeToMD($rtyp, $dbd);
|
||||
}
|
||||
# Handle a 'menu' Pod directive
|
||||
elsif (m/^ =menu \s+ (\w+) /x) {
|
||||
my $mn = $1;
|
||||
my $menu = $dbd->menu($mn);
|
||||
die "Unknown menu '$mn' in $infile POD directive\n"
|
||||
unless $menu;
|
||||
menuToMD($menu);
|
||||
}
|
||||
elsif (m/^ =title \s+ (.*)/x) {
|
||||
$title = $1;
|
||||
"=head1 $title";
|
||||
}
|
||||
else {
|
||||
$_;
|
||||
}
|
||||
} $dbd->pod;
|
||||
|
||||
$podRst->output_fh($out);
|
||||
$podRst->parse_string_document($pod);
|
||||
close $out;
|
||||
|
||||
sub menuToMD {
|
||||
my ($menu) = @_;
|
||||
my $index = 0;
|
||||
return "| Index | Identifier | Choice String |",
|
||||
"| ----- | ---------- | ------------- |",
|
||||
map({choiceTableRow($_, $index++)} $menu->choices);
|
||||
}
|
||||
|
||||
sub choiceTableRow {
|
||||
my ($ch, $index) = @_;
|
||||
my ($id, $name) = @{$ch};
|
||||
return "| $index | $id | $name |";
|
||||
}
|
||||
|
||||
sub rtypeToMD {
|
||||
my ($rtyp, $dbd) = @_;
|
||||
return map {
|
||||
# Handle a 'fields' Pod directive
|
||||
if (m/^ =fields \s+ (\w+ (?:\s* , \s* \w+ )* )/x) {
|
||||
my @names = split /\s*,\s*/, $1;
|
||||
# Look up the named fields
|
||||
my @fields = map {
|
||||
my $field = $rtyp->field($_);
|
||||
die "Unknown field name '$_' in $infile POD\n"
|
||||
unless $field;
|
||||
$field;
|
||||
} @names;
|
||||
# Generate Pod for the table
|
||||
"| Field | Summary | Type | DCT | Default | Read | Write | CA PP |",
|
||||
"| ----- | ------- | ---- | --- | ------- | ---- | ----- | ----- |",
|
||||
map({fieldTableRow($_, $dbd)} @fields);
|
||||
}
|
||||
# Handle a 'menu' Pod directive
|
||||
elsif (m/^ =menu \s+ (\w+) /x) {
|
||||
my $mn = $1;
|
||||
my $menu = $dbd->menu($mn);
|
||||
die "Unknown menu '$mn' in $infile POD directive\n"
|
||||
unless $menu;
|
||||
menuToMD($menu);
|
||||
}
|
||||
else {
|
||||
# Raw text line
|
||||
$_;
|
||||
}
|
||||
} $rtyp->pod;
|
||||
}
|
||||
|
||||
sub fieldTableRow {
|
||||
my ($fld, $dbd) = @_;
|
||||
my @md;
|
||||
push @md, $fld->name, $fld->attribute('prompt');
|
||||
|
||||
my $type = $fld->public_type;
|
||||
if ($type eq 'STRING') {
|
||||
$type .= ' [' . $fld->attribute('size') . ']';
|
||||
} elsif ($type eq 'MENU') {
|
||||
my $mn = $fld->attribute('menu');
|
||||
my $menu = $dbd->menu($mn);
|
||||
my $mnl = lc($mn);
|
||||
my $url = $menu ? "/menu-$mnl" : "${mn}.md";
|
||||
#just pass a L directive for the parser
|
||||
$type .= " L<$mn|$url>";
|
||||
}
|
||||
push @md, $type;
|
||||
|
||||
push @md, $fld->attribute('promptgroup') ? 'Yes' : 'No';
|
||||
push @md, $fld->attribute('initial') || ' ';
|
||||
push @md, $fld->readable;
|
||||
push @md, $fld->writable;
|
||||
push @md, $fld->attribute('pp') eq 'TRUE' ? 'Yes' : 'No';
|
||||
return '| ' . join(' | ', @md) . ' |';
|
||||
}
|
||||
|
||||
# Native type presented to dbAccess users
|
||||
sub DBD::Recfield::public_type {
|
||||
my $fld = shift;
|
||||
m/^ =type \s+ (.+) /x && return $1 for $fld->comments;
|
||||
my $type = $fld->dbf_type;
|
||||
$type =~ s/^DBF_//;
|
||||
return $type;
|
||||
}
|
||||
|
||||
# Check if this field is readable
|
||||
sub DBD::Recfield::readable {
|
||||
my $fld = shift;
|
||||
m/^ =read \s+ (?i) (Yes|No) /x && return $1 for $fld->comments;
|
||||
return 'Probably'
|
||||
if $fld->attribute('special') eq "SPC_DBADDR";
|
||||
return $fld->dbf_type eq 'DBF_NOACCESS' ? 'No' : 'Yes';
|
||||
}
|
||||
|
||||
# Check if this field is writable
|
||||
sub DBD::Recfield::writable {
|
||||
my $fld = shift;
|
||||
m/^ =write \s+ (?i) (Yes|No) /x && return $1 for $fld->comments;
|
||||
my $special = $fld->attribute('special');
|
||||
return 'No'
|
||||
if $special eq "SPC_NOMOD";
|
||||
return 'Maybe'
|
||||
if $special eq "SPC_DBADDR";
|
||||
return $fld->dbf_type eq "DBF_NOACCESS" ? 'No' : 'Yes';
|
||||
}
|
||||
|
||||
=pod
|
||||
|
||||
=head1 Converting Wiki Record Reference to POD
|
||||
|
||||
If you open the src/std/rec/aiRecord.dbd.pod file in your favourite plain text
|
||||
editor you'll see what input was required to generate the aiRecord.html file.
|
||||
The text markup language we're using is a standard called POD (Plain Old
|
||||
Documentation) which is used by Perl developers, but you don't need to know Perl
|
||||
at all to be able to use it.
|
||||
|
||||
When we add POD markup to a record type, we rename its *Record.dbd file to
|
||||
.dbd.pod in the src/std/rec directory; no other changes are needed for the build
|
||||
system to find it by its new name. The POD content is effectively just a new
|
||||
kind of comment that appears in .dbd.pod files, which the formatter knows how to
|
||||
convert into Markdown. The build also generates a plain *Record.dbd file from this
|
||||
same input file by stripping out all of the POD markup.
|
||||
|
||||
Documentation for Perl's POD markup standard can be found online at
|
||||
L<https://perldoc.perl.org/perlpod.html> or you may be able to type 'perldoc
|
||||
perlpod' into a Linux command-line to see the same text. We added a few POD
|
||||
keywords of our own to handle the table generation, and I'll cover those briefly
|
||||
below.
|
||||
|
||||
POD text can appear almost anywhere in a dbd.pod file. It always starts with a
|
||||
line "=[keyword] [additional text...]" where [keyword] is "title", "head1"
|
||||
through "head4" etc.. The POD text ends with a line "=cut". There must be a
|
||||
blank line above every POD line, and in many cases below it as well.
|
||||
|
||||
The POD keywords we have added are "title", "recordtype", "menu", "fields",
|
||||
"type", "read" and "write". The last 3 are less common but are used in some of
|
||||
the other record types such as the waveform and aSub records.
|
||||
|
||||
The most interesting of our new keywords is "fields", which takes a list of
|
||||
record field names on the same line after the keyword and generates an Markdown
|
||||
Table describing those fields based on the field description found in the DBD
|
||||
parts. In the ai documentation the first such table covers the DTYP and INP
|
||||
fields.
|
||||
|
||||
Note that the "=fields" line must appear inside the DBD's declaration of the
|
||||
record type, i.e. after the line
|
||||
|
||||
recordtype(ai) {
|
||||
|
||||
The "type", "read" and "write" POD keywords are used inside an individual record
|
||||
field declaration and provide information for the "Type", "Read" and "Write"
|
||||
columns of the field's table output for fields where this information is
|
||||
normally supplied by the record support code. Usage examples for these keywords
|
||||
can be found in the aai and aSub record types.
|
||||
|
||||
If you look at the L<aoRecord.dbd.pod> file you'll see that the POD there starts
|
||||
by documenting a record-specific menu definition. The "menu" keyword generates a
|
||||
table that lists all the choices found in the named menu. Any MENU fields in the
|
||||
field tables that refer to a locally-defined menu will generate a link to a
|
||||
document section which must be titled "Menu [menuName]".
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user