Implemented "global" variables in substitution files.
Rewrote the YACC grammar, with help from Benjamin Franksen in formally defining the substitution file format in EBNF. This version also changes the way in which variables are added to the sub_collect string; previously it appended a ',' after every entry, and removed it off the end before calling dbLoadRecords(), but now we put the ',' at the beginning of each entry, and just offer dbLoadRecords() the string starting at the second character (not that this really matters, macLib will quite happily ignore either a leading or a trailing comma in the variable definition string). We now warn if there are substitution values for which we have no name, or if the file uses the deprecated syntax which permitted a bareword token in front of the variable substitution or pattern definition braces.
This commit is contained in:
@@ -1,137 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
* National Laboratory.
|
||||
* Copyright (c) 2002 The Regents of the University of California, as
|
||||
* 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.
|
||||
\*************************************************************************/
|
||||
<HTML>
|
||||
<BODY>
|
||||
<PRE>
|
||||
<!-- Manpage converted by man2html 3.0.1 -->
|
||||
|
||||
</PRE>
|
||||
<H2>NAME</H2><PRE>
|
||||
dbLoadRecords, dbLoadTemplate - load ascii database records
|
||||
into an IOC
|
||||
|
||||
|
||||
</PRE>
|
||||
<H2>SYNOPSIS</H2><PRE>
|
||||
dbLoadRecords(char* db_file, char* substitutions)
|
||||
|
||||
dbLoadTemplate(char* template_file)
|
||||
|
||||
|
||||
</PRE>
|
||||
<H2>DESCRIPTION</H2><PRE>
|
||||
These routines are available from IOC core on the vxWorks
|
||||
command line. Both provide a way to load ascii ".db" files
|
||||
(usually created by <B>gdct(1)</B> ) into the IOC. The ".db" files
|
||||
contain ascii versions of record instances and are described
|
||||
in more detail in <B>dbfile(5)</B>. In addition to loading the
|
||||
".db" ascii files into the IOC, both routines provide a
|
||||
method of performing variable substitution on record names
|
||||
and field values.
|
||||
|
||||
dbLoadRecords() reads the ".db" file <I>db</I>_<I>file</I> performing sub-
|
||||
stitutions specified in string <I>substitutions</I>. The substitu-
|
||||
tion must be a string specified as follows:
|
||||
|
||||
"var1=sub1,var2=sub3,..."
|
||||
|
||||
Variables are specified in the ".db" file as
|
||||
$(variable_name). If the substitution string
|
||||
"a=1,b=2,c=\"this is a test\"" were used, any variables
|
||||
$(a), $(b), or $(c) would be substituted with the appropri-
|
||||
ate data. See the EXAMPLES section for more details.
|
||||
|
||||
dbLoadTemplate() will read a <I>template</I>_<I>file</I>. The
|
||||
<I>template</I>_<I>file</I> resides in the your IOC boot directory and
|
||||
contains rules about loading ".db" files and performing sub-
|
||||
stitutions. The template_file must be in the form used by
|
||||
an IOC and is described in <B>templatefile(5)</B>. The EXAMPLES
|
||||
section descibes how it can be used.
|
||||
|
||||
|
||||
</PRE>
|
||||
<H2>EXAMPLES</H2><PRE>
|
||||
The next two examples of dbLoadRecords() and dbLoadTem-
|
||||
plate() will use the following ".db" file named <I>test</I>.<I>db</I> :
|
||||
|
||||
database(test)
|
||||
{
|
||||
record(ai,"$(pre)testrec1")
|
||||
record(ai,"$(pre)testrec2")
|
||||
record(stringout,"$(pre)testrec3")
|
||||
{
|
||||
field(VAL,"$(STRING)")
|
||||
field(SCAN,"$(SCAN)")
|
||||
}
|
||||
}
|
||||
Running dbLoadRecords ("test.db","pre=TEST,STRING=\"this is
|
||||
a test\",SCAN=Passive") will produce the following records
|
||||
in the IOC's database:
|
||||
|
||||
TESTtestrec1
|
||||
TESTtestrec2
|
||||
TESTtestrec3
|
||||
|
||||
The third record will have VAL set to "this is a test" and
|
||||
SCAN set to "Passive".
|
||||
|
||||
Running dbLoadTemplate ("test.template") with test.template
|
||||
containing:
|
||||
file test.db
|
||||
{
|
||||
{pre=TEST1, STRING = "this is a test two", SCAN="1 Second" }
|
||||
{pre=TEST2, STRING = "this is a test one", SCAN=Passive }
|
||||
{pre=TEST3, STRING = "this is a test three", SCAN=Passive }
|
||||
}
|
||||
will produce a total of nine records in the IOC's database:
|
||||
TEST1testrec1
|
||||
TEST1testrec2
|
||||
TEST1testrec3 - (VAL="this is a test two", SCAN="1 Second")
|
||||
TEST2testrec1
|
||||
TEST2testrec2
|
||||
TEST2testrec3 - (VAL="this is a test one", SCAN="Passive")
|
||||
TEST3testrec1
|
||||
TEST3testrec2
|
||||
TEST3testrec3 - (VAL="this is a test three", SCAN="Passive")
|
||||
|
||||
|
||||
</PRE>
|
||||
<H2>NOTES</H2><PRE>
|
||||
The binary file <I>default</I>.<I>dctsdr</I> must be loaded prior to run-
|
||||
ning either of these routines. This file contains the rules
|
||||
on how to construct records and change field values.
|
||||
|
||||
After the default.dctsdr file is loaded, these routines can
|
||||
be run as many times as desired until iocInit is run.
|
||||
|
||||
|
||||
</PRE>
|
||||
<H2>SEE ALSO</H2><PRE>
|
||||
<B>gdct(1)</B>, <B>templatefile(5)</B>, <B>dbfile(5)</B>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</PRE>
|
||||
<HR>
|
||||
<ADDRESS>
|
||||
Man(1) output converted with
|
||||
<a href="http://www.oac.uci.edu/indiv/ehood/man2html.html">man2html</a>
|
||||
</ADDRESS>
|
||||
</BODY>
|
||||
</HTML>
|
||||
+171
-125
@@ -27,15 +27,15 @@ static int yyerror(char* str);
|
||||
#define VAR_MAX_VAR_STRING 5000
|
||||
#define VAR_MAX_VARS 100
|
||||
|
||||
static char *sub_collect = NULL;
|
||||
static char *gbl_collect;
|
||||
static char *sub_collect;
|
||||
static char *sub_locals;
|
||||
static char** vars = NULL;
|
||||
static char* db_file_name = NULL;
|
||||
static int var_count, sub_count;
|
||||
|
||||
%}
|
||||
|
||||
%start template
|
||||
%start substitution_file
|
||||
|
||||
%token <Str> WORD QUOTE
|
||||
%token DBFILE
|
||||
@@ -55,67 +55,83 @@ static int var_count, sub_count;
|
||||
|
||||
%%
|
||||
|
||||
template: templs
|
||||
| subst
|
||||
substitution_file: global_or_template
|
||||
| substitution_file global_or_template
|
||||
;
|
||||
|
||||
templs: templs templ
|
||||
| templ
|
||||
global_or_template: global_definitions
|
||||
| template_substitutions
|
||||
;
|
||||
|
||||
templ: templ_head O_BRACE subst C_BRACE
|
||||
| templ_head
|
||||
global_definitions: GLOBAL O_BRACE C_BRACE
|
||||
| GLOBAL O_BRACE variable_definitions C_BRACE
|
||||
{
|
||||
if (db_file_name)
|
||||
dbLoadRecords(db_file_name, NULL);
|
||||
else
|
||||
fprintf(stderr, "Error: no db file name given\n");
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "global_definitions: %s\n", sub_collect+1);
|
||||
#endif
|
||||
sub_locals += strlen(sub_locals);
|
||||
}
|
||||
;
|
||||
|
||||
templ_head: DBFILE WORD
|
||||
template_substitutions: template_filename O_BRACE C_BRACE
|
||||
{
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "template_substitutions: %s unused\n", db_file_name);
|
||||
#endif
|
||||
dbmfFree(db_file_name);
|
||||
db_file_name = NULL;
|
||||
}
|
||||
| template_filename O_BRACE substitutions C_BRACE
|
||||
{
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "template_substitutions: %s finished\n", db_file_name);
|
||||
#endif
|
||||
dbmfFree(db_file_name);
|
||||
db_file_name = NULL;
|
||||
}
|
||||
;
|
||||
|
||||
template_filename: DBFILE WORD
|
||||
{
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "template_filename: %s\n", $2);
|
||||
#endif
|
||||
var_count = 0;
|
||||
if (db_file_name)
|
||||
dbmfFree(db_file_name);
|
||||
db_file_name = dbmfMalloc(strlen($2)+1);
|
||||
strcpy(db_file_name, $2);
|
||||
dbmfFree($2);
|
||||
}
|
||||
| DBFILE QUOTE
|
||||
{
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "template_filename: \"%s\"\n", $2);
|
||||
#endif
|
||||
var_count = 0;
|
||||
if (db_file_name)
|
||||
dbmfFree(db_file_name);
|
||||
db_file_name = dbmfMalloc(strlen($2)+1);
|
||||
strcpy(db_file_name, $2);
|
||||
dbmfFree($2);
|
||||
}
|
||||
;
|
||||
|
||||
subst: PATTERN pattern subs
|
||||
| PATTERN pattern
|
||||
| var_subs
|
||||
substitutions: pattern_substitutions
|
||||
| variable_substitutions
|
||||
;
|
||||
|
||||
pattern: O_BRACE vars C_BRACE
|
||||
{
|
||||
#ifdef ERROR_STUFF
|
||||
int i;
|
||||
for (i = 0; i < var_count; i++)
|
||||
fprintf(stderr, "variable = (%s)\n", vars[i]);
|
||||
fprintf(stderr, "var_count = %d\n", var_count);
|
||||
#endif
|
||||
}
|
||||
;
|
||||
|
||||
vars: vars var
|
||||
| vars COMMA var
|
||||
| var
|
||||
;
|
||||
|
||||
var: WORD
|
||||
pattern_substitutions: PATTERN O_BRACE C_BRACE
|
||||
| PATTERN O_BRACE pattern_names C_BRACE
|
||||
| PATTERN O_BRACE pattern_names C_BRACE pattern_definitions
|
||||
;
|
||||
|
||||
pattern_names: pattern_name
|
||||
| pattern_names COMMA
|
||||
| pattern_names pattern_name
|
||||
;
|
||||
|
||||
pattern_name: WORD
|
||||
{
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "pattern_name: [%d] = %s\n", var_count, $1);
|
||||
#endif
|
||||
vars[var_count] = dbmfMalloc(strlen($1)+1);
|
||||
strcpy(vars[var_count], $1);
|
||||
var_count++;
|
||||
@@ -123,123 +139,153 @@ var: WORD
|
||||
}
|
||||
;
|
||||
|
||||
subs: subs sub
|
||||
| sub
|
||||
pattern_definitions: pattern_definition
|
||||
| pattern_definitions pattern_definition
|
||||
;
|
||||
|
||||
sub: WORD O_BRACE vals C_BRACE
|
||||
pattern_definition: O_BRACE C_BRACE
|
||||
{
|
||||
gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect);
|
||||
#endif
|
||||
if (db_file_name)
|
||||
dbLoadRecords(db_file_name, sub_collect);
|
||||
else
|
||||
fprintf(stderr, "Error: no db file name given\n");
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "pattern_definition: pattern_values empty\n");
|
||||
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
|
||||
#endif
|
||||
dbLoadRecords(db_file_name, sub_collect+1);
|
||||
}
|
||||
| O_BRACE pattern_values C_BRACE
|
||||
{
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "pattern_definition:\n");
|
||||
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
|
||||
#endif
|
||||
dbLoadRecords(db_file_name, sub_collect+1);
|
||||
*sub_locals = '\0';
|
||||
sub_count = 0;
|
||||
}
|
||||
| WORD O_BRACE pattern_values C_BRACE
|
||||
{ /* DEPRECATED SYNTAX */
|
||||
fprintf(stderr,
|
||||
"dbLoadTemplate: Substitution file uses deprecated syntax.\n"
|
||||
" the string '%s' on line %d that comes just before the\n"
|
||||
" '{' character is extraneous and should be removed.\n",
|
||||
$1, line_num);
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "pattern_definition:\n");
|
||||
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
|
||||
#endif
|
||||
dbLoadRecords(db_file_name, sub_collect+1);
|
||||
dbmfFree($1);
|
||||
*gbl_collect = '\0';
|
||||
sub_count = 0;
|
||||
}
|
||||
| O_BRACE vals C_BRACE
|
||||
{
|
||||
gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect);
|
||||
#endif
|
||||
if (db_file_name)
|
||||
dbLoadRecords(db_file_name, sub_collect);
|
||||
else
|
||||
fprintf(stderr, "Error: no db file name given\n");
|
||||
*gbl_collect = '\0';
|
||||
*sub_locals = '\0';
|
||||
sub_count = 0;
|
||||
}
|
||||
;
|
||||
|
||||
vals: vals val
|
||||
| vals COMMA val
|
||||
| val
|
||||
pattern_values: pattern_value
|
||||
| pattern_values COMMA
|
||||
| pattern_values pattern_value
|
||||
;
|
||||
|
||||
val: QUOTE
|
||||
pattern_value: QUOTE
|
||||
{
|
||||
if (sub_count <= var_count) {
|
||||
strcat(gbl_collect, vars[sub_count]);
|
||||
strcat(gbl_collect, "=\"");
|
||||
strcat(gbl_collect, $1);
|
||||
strcat(gbl_collect, "\",");
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "pattern_value: [%d] = \"%s\"\n", sub_count, $1);
|
||||
#endif
|
||||
if (sub_count < var_count) {
|
||||
strcat(sub_locals, ",");
|
||||
strcat(sub_locals, vars[sub_count]);
|
||||
strcat(sub_locals, "=\"");
|
||||
strcat(sub_locals, $1);
|
||||
strcat(sub_locals, "\"");
|
||||
sub_count++;
|
||||
} else {
|
||||
fprintf(stderr, "dbLoadTemplate: Too many values given, line %d.\n",
|
||||
line_num);
|
||||
}
|
||||
dbmfFree($1);
|
||||
}
|
||||
| WORD
|
||||
{
|
||||
if (sub_count <= var_count) {
|
||||
strcat(gbl_collect, vars[sub_count]);
|
||||
strcat(gbl_collect, "=");
|
||||
strcat(gbl_collect, $1);
|
||||
strcat(gbl_collect, ",");
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "pattern_value: [%d] = %s\n", sub_count, $1);
|
||||
#endif
|
||||
if (sub_count < var_count) {
|
||||
strcat(sub_locals, ",");
|
||||
strcat(sub_locals, vars[sub_count]);
|
||||
strcat(sub_locals, "=");
|
||||
strcat(sub_locals, $1);
|
||||
sub_count++;
|
||||
} else {
|
||||
fprintf(stderr, "dbLoadTemplate: Too many values given, line %d.\n",
|
||||
line_num);
|
||||
}
|
||||
dbmfFree($1);
|
||||
}
|
||||
;
|
||||
|
||||
var_subs: var_subs var_sub
|
||||
| var_sub
|
||||
variable_substitutions: variable_substitution
|
||||
| variable_substitutions variable_substitution
|
||||
;
|
||||
|
||||
var_sub: WORD O_BRACE sub_pats C_BRACE
|
||||
variable_substitution: O_BRACE C_BRACE
|
||||
{
|
||||
gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect);
|
||||
#endif
|
||||
if (db_file_name)
|
||||
dbLoadRecords(db_file_name, sub_collect);
|
||||
else
|
||||
fprintf(stderr, "Error: no db file name given\n");
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "variable_substitution: variable_definitions empty\n");
|
||||
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
|
||||
#endif
|
||||
dbLoadRecords(db_file_name, sub_collect+1);
|
||||
}
|
||||
| O_BRACE variable_definitions C_BRACE
|
||||
{
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "variable_substitution:\n");
|
||||
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
|
||||
#endif
|
||||
dbLoadRecords(db_file_name, sub_collect+1);
|
||||
*sub_locals = '\0';
|
||||
}
|
||||
| WORD O_BRACE variable_definitions C_BRACE
|
||||
{ /* DEPRECATED SYNTAX */
|
||||
fprintf(stderr,
|
||||
"dbLoadTemplate: Substitution file uses deprecated syntax.\n"
|
||||
" the string '%s' on line %d that comes just before the\n"
|
||||
" '{' character is extraneous and should be removed.\n",
|
||||
$1, line_num);
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "variable_substitution:\n");
|
||||
fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
|
||||
#endif
|
||||
dbLoadRecords(db_file_name, sub_collect+1);
|
||||
dbmfFree($1);
|
||||
*gbl_collect = '\0';
|
||||
sub_count = 0;
|
||||
}
|
||||
| O_BRACE sub_pats C_BRACE
|
||||
{
|
||||
gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect);
|
||||
#endif
|
||||
if (db_file_name)
|
||||
dbLoadRecords(db_file_name, sub_collect);
|
||||
else
|
||||
fprintf(stderr, "Error: no db file name given\n");
|
||||
*gbl_collect = '\0';
|
||||
sub_count = 0;
|
||||
*sub_locals = '\0';
|
||||
}
|
||||
;
|
||||
|
||||
sub_pats: sub_pats sub_pat
|
||||
| sub_pats COMMA sub_pat
|
||||
| sub_pat
|
||||
variable_definitions: variable_definition
|
||||
| variable_definitions COMMA
|
||||
| variable_definitions variable_definition
|
||||
;
|
||||
|
||||
sub_pat: WORD EQUALS WORD
|
||||
variable_definition: WORD EQUALS WORD
|
||||
{
|
||||
strcat(gbl_collect, $1);
|
||||
strcat(gbl_collect, "=");
|
||||
strcat(gbl_collect, $3);
|
||||
strcat(gbl_collect, ",");
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "variable_definition: %s = %s\n", $1, $3);
|
||||
#endif
|
||||
strcat(sub_locals, ",");
|
||||
strcat(sub_locals, $1);
|
||||
strcat(sub_locals, "=");
|
||||
strcat(sub_locals, $3);
|
||||
dbmfFree($1); dbmfFree($3);
|
||||
sub_count++;
|
||||
}
|
||||
| WORD EQUALS QUOTE
|
||||
{
|
||||
strcat(gbl_collect, $1);
|
||||
strcat(gbl_collect, "=\"");
|
||||
strcat(gbl_collect, $3);
|
||||
strcat(gbl_collect, "\",");
|
||||
#ifdef ERROR_STUFF
|
||||
fprintf(stderr, "variable_definition: %s = \"%s\"\n", $1, $3);
|
||||
#endif
|
||||
strcat(sub_locals, ",");
|
||||
strcat(sub_locals, $1);
|
||||
strcat(sub_locals, "=\"");
|
||||
strcat(sub_locals, $3);
|
||||
strcat(sub_locals, "\"");
|
||||
dbmfFree($1); dbmfFree($3);
|
||||
sub_count++;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -262,7 +308,7 @@ static int is_not_inited = 1;
|
||||
int epicsShareAPI dbLoadTemplate(const char *sub_file, const char *cmd_collect)
|
||||
{
|
||||
FILE *fp;
|
||||
int ind;
|
||||
int i;
|
||||
|
||||
line_num = 1;
|
||||
|
||||
@@ -286,14 +332,14 @@ int epicsShareAPI dbLoadTemplate(const char *sub_file, const char *cmd_collect)
|
||||
fprintf(stderr, "dbLoadTemplate: Out of memory!\n");
|
||||
return -1;
|
||||
}
|
||||
strcpy(sub_collect, ",");
|
||||
|
||||
if (cmd_collect && *cmd_collect) {
|
||||
strcpy(sub_collect, cmd_collect);
|
||||
strcat(sub_collect, ",");
|
||||
gbl_collect = sub_collect + strlen(sub_collect);
|
||||
strcat(sub_collect, cmd_collect);
|
||||
sub_locals = sub_collect + strlen(sub_collect);
|
||||
} else {
|
||||
gbl_collect = sub_collect;
|
||||
*gbl_collect = '\0';
|
||||
sub_locals = sub_collect;
|
||||
*sub_locals = '\0';
|
||||
}
|
||||
var_count = 0;
|
||||
sub_count = 0;
|
||||
@@ -307,8 +353,8 @@ int epicsShareAPI dbLoadTemplate(const char *sub_file, const char *cmd_collect)
|
||||
|
||||
yyparse();
|
||||
|
||||
for (ind = 0; ind < var_count; ind++) {
|
||||
dbmfFree(vars[ind]);
|
||||
for (i = 0; i < var_count; i++) {
|
||||
dbmfFree(vars[i]);
|
||||
}
|
||||
free(vars);
|
||||
free(sub_collect);
|
||||
|
||||
Reference in New Issue
Block a user