From e2464c857268f1346a54d86fc17f2c01f50ac0a0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 24 Aug 2010 19:01:19 -0500 Subject: [PATCH] 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. --- src/dbtools/dbLoadTemplate.html | 137 --------------- src/dbtools/dbLoadTemplate.y | 296 ++++++++++++++++++-------------- 2 files changed, 171 insertions(+), 262 deletions(-) delete mode 100644 src/dbtools/dbLoadTemplate.html diff --git a/src/dbtools/dbLoadTemplate.html b/src/dbtools/dbLoadTemplate.html deleted file mode 100644 index 4943b8c6f..000000000 --- a/src/dbtools/dbLoadTemplate.html +++ /dev/null @@ -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. -\*************************************************************************/ - - -
-
-
-
-

NAME

-     dbLoadRecords, dbLoadTemplate - load ascii database  records
-     into an IOC
-
-
-
-

SYNOPSIS

-     dbLoadRecords(char* db_file, char* substitutions)
-
-     dbLoadTemplate(char* template_file)
-
-
-
-

DESCRIPTION

-     These routines are available from IOC core  on  the  vxWorks
-     command  line.  Both provide a way to load ascii ".db" files
-     (usually created by gdct(1) ) into the IOC. The ".db"  files
-     contain ascii versions of record instances and are described
-     in more detail in dbfile(5).  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 db_file performing sub-
-     stitutions  specified in string substitutions. 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    template_file.    The
-     template_file  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  templatefile(5).   The  EXAMPLES
-     section descibes how it can be used.
-
-
-
-

EXAMPLES

-     The next two  examples  of  dbLoadRecords()  and  dbLoadTem-
-     plate() will use the following ".db" file named test.db :
-
-     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")
-
-
-
-

NOTES

-     The binary file default.dctsdr 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.
-
-
-
-

SEE ALSO

-     gdct(1), templatefile(5), dbfile(5)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Man(1) output converted with -man2html -
- - diff --git a/src/dbtools/dbLoadTemplate.y b/src/dbtools/dbLoadTemplate.y index a9d8d2eb8..1364e1978 100644 --- a/src/dbtools/dbLoadTemplate.y +++ b/src/dbtools/dbLoadTemplate.y @@ -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 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);