Merge lp:~epics-core/epics-base/msi-join into lp:~epics-core/epics-base/3.15

Proposed by Andrew Johnson
Status: Merged
Merged at revision: 12293
Proposed branch: lp:~epics-core/epics-base/msi-join
Merge into: lp:~epics-core/epics-base/3.15
Diff against target: 2715 lines (+2044/-425) (has conflicts)
30 files modified
configure/CONFIG_BASE (+1/-1)
src/ioc/dbtemplate/Makefile (+34/-0)
src/ioc/dbtemplate/dbLoadTemplate.h (+3/-7)
src/ioc/dbtemplate/dbLoadTemplate.html (+0/-137)
src/ioc/dbtemplate/dbLoadTemplate.y (+304/-248)
src/ioc/dbtemplate/dbLoadTemplate_lex.l (+28/-27)
src/ioc/dbtemplate/dbtoolsIocRegister.c (+8/-5)
src/ioc/dbtemplate/msi.c (+841/-0)
src/ioc/dbtemplate/msi.html (+438/-0)
src/ioc/dbtemplate/test/Makefile (+21/-0)
src/ioc/dbtemplate/test/dbltExpand.c (+100/-0)
src/ioc/dbtemplate/test/msi.plt (+48/-0)
src/ioc/dbtemplate/test/t1-include.txt (+5/-0)
src/ioc/dbtemplate/test/t1-result.txt (+21/-0)
src/ioc/dbtemplate/test/t1-template.txt (+14/-0)
src/ioc/dbtemplate/test/t2-result.txt (+6/-0)
src/ioc/dbtemplate/test/t2-substitution.txt (+11/-0)
src/ioc/dbtemplate/test/t2-template.txt (+1/-0)
src/ioc/dbtemplate/test/t3-result.txt (+28/-0)
src/ioc/dbtemplate/test/t3-substitution.txt (+37/-0)
src/ioc/dbtemplate/test/t3-template.txt (+1/-0)
src/ioc/dbtemplate/test/t4-result.txt (+6/-0)
src/ioc/dbtemplate/test/t4-substitution.txt (+11/-0)
src/ioc/dbtemplate/test/t5-result.txt (+20/-0)
src/ioc/dbtemplate/test/t5-substitute.txt (+9/-0)
src/ioc/dbtemplate/test/t5-template.txt (+5/-0)
src/ioc/dbtemplate/test/t6-result.txt (+20/-0)
src/ioc/dbtemplate/test/t6-substitute.txt (+13/-0)
src/ioc/dbtemplate/test/t6-template.txt (+5/-0)
src/ioc/dbtemplate/test/template (+5/-0)
Text conflict in src/ioc/dbtemplate/Makefile
To merge this branch: bzr merge lp:~epics-core/epics-base/msi-join
Reviewer Review Type Date Requested Status
EPICS Core Developers Pending
Review via email: mp+108420@code.launchpad.net

Description of the change

This branch brings an updated version of the msi tool (and its HTML documentation) into Base. Additions to both msi and dbLoadRecords support defining global macros in substition files, and a flag for msi that changes substitution macros from local (the new default) to global scope (the original behavior).

Since msi only uses the macro substitution code from Base, this branch also builds a simple test program called dbltExpand which calls the dbLoadTemplate substitution file parser to help prove that the parser modifications made to both msi and dbLoadTemplate are compatible.

I also added a series of automated tests of msi into the build.

To post a comment you must log in.
Revision history for this message
Andrew Johnson (anj) wrote :

For some reason Launchpad is not showing all of the revisions that this merge will incorporate; the full set of commits on this branch goes back to revno 12104 inclusive. The diff below is also a bit confused by the 3.15 source tree reorganization, but if you ignore the embedded conflict markers it does seem to show all of the changes.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure/CONFIG_BASE'
2--- configure/CONFIG_BASE 2012-04-04 17:30:27 +0000
3+++ configure/CONFIG_BASE 2012-06-01 20:39:23 +0000
4@@ -109,7 +109,7 @@
5 endif
6
7 ifndef MSI
8-MSI = msi
9+MSI = $(EPICS_BASE_HOST_BIN)/msi
10 endif
11
12
13
14=== modified file 'src/ioc/dbtemplate/Makefile'
15--- src/ioc/dbtemplate/Makefile 2011-09-15 19:05:05 +0000
16+++ src/ioc/dbtemplate/Makefile 2012-06-01 20:39:23 +0000
17@@ -14,9 +14,43 @@
18 INC += dbLoadTemplate.h
19 INC += dbtoolsIocRegister.h
20
21+<<<<<<< TREE
22 dbCore_SRCS += dbLoadTemplate.c
23 dbCore_SRCS += dbtoolsIocRegister.c
24
25 HTMLS += dbtemplate/dbLoadTemplate.html
26
27 CLEANS += dbLoadTemplate_lex.c dbLoadTemplate.c
28+=======
29+LIBRARY_IOC = dbtoolsIoc
30+
31+LIB_SRCS += dbLoadTemplate.c
32+LIB_SRCS += dbtoolsIocRegister.c
33+dbtoolsIoc_LIBS = dbIoc dbStaticIoc Com
34+dbtoolsIoc_RCS = dbtoolsIoc.rc
35+HTMLS += dbLoadTemplate.html
36+
37+PROD_HOST = msi
38+
39+msi_SRCS = msi.c
40+msi_LIBS += Com
41+HTMLS = msi.html
42+
43+# For R3.13 compatibility only
44+ifeq ($(strip $(COMPAT_313)),YES)
45+OBJLIB_vxWorks=dbtoolsIoc
46+OBJLIB_SRCS = $(LIB_SRCS)
47+endif
48+
49+include $(TOP)/configure/RULES
50+
51+#
52+# These lex sources are included in some C sources,
53+# so they have to be created in time:
54+#
55+dbLoadTemplate.c: dbLoadTemplate_lex.c ../dbLoadTemplate.h
56+
57+clean::
58+ @$(RM) dbLoadTemplate_lex.c dbLoadTemplate.c
59+
60+>>>>>>> MERGE-SOURCE
61
62=== modified file 'src/ioc/dbtemplate/dbLoadTemplate.h'
63--- src/ioc/dbtemplate/dbLoadTemplate.h 2002-07-12 21:35:43 +0000
64+++ src/ioc/dbtemplate/dbLoadTemplate.h 2012-06-01 20:39:23 +0000
65@@ -3,8 +3,7 @@
66 * National Laboratory.
67 * Copyright (c) 2002 The Regents of the University of California, as
68 * Operator of Los Alamos National Laboratory.
69-* EPICS BASE Versions 3.13.7
70-* and higher are distributed subject to a Software License Agreement found
71+* EPICS BASE is distributed subject to a Software License Agreement found
72 * in file LICENSE that is included with this distribution.
73 \*************************************************************************/
74 /* dbLoadTemplate.h */
75@@ -13,10 +12,7 @@
76 #define INCdbLoadTemplateh
77
78 #include "shareLib.h"
79-epicsShareFunc int epicsShareAPI dbLoadTemplate(char* sub_file);
80+epicsShareFunc int epicsShareAPI dbLoadTemplate(
81+ const char *sub_file, const char *cmd_collect);
82
83 #endif /*INCdbLoadTemplateh*/
84-
85-
86-
87-
88
89=== removed file 'src/ioc/dbtemplate/dbLoadTemplate.html'
90--- src/ioc/dbtemplate/dbLoadTemplate.html 2002-07-12 21:35:43 +0000
91+++ src/ioc/dbtemplate/dbLoadTemplate.html 1970-01-01 00:00:00 +0000
92@@ -1,137 +0,0 @@
93-/*************************************************************************\
94-* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
95-* National Laboratory.
96-* Copyright (c) 2002 The Regents of the University of California, as
97-* Operator of Los Alamos National Laboratory.
98-* EPICS BASE Versions 3.13.7
99-* and higher are distributed subject to a Software License Agreement found
100-* in file LICENSE that is included with this distribution.
101-\*************************************************************************/
102-<HTML>
103-<BODY>
104-<PRE>
105-<!-- Manpage converted by man2html 3.0.1 -->
106-
107-</PRE>
108-<H2>NAME</H2><PRE>
109- dbLoadRecords, dbLoadTemplate - load ascii database records
110- into an IOC
111-
112-
113-</PRE>
114-<H2>SYNOPSIS</H2><PRE>
115- dbLoadRecords(char* db_file, char* substitutions)
116-
117- dbLoadTemplate(char* template_file)
118-
119-
120-</PRE>
121-<H2>DESCRIPTION</H2><PRE>
122- These routines are available from IOC core on the vxWorks
123- command line. Both provide a way to load ascii ".db" files
124- (usually created by <B>gdct(1)</B> ) into the IOC. The ".db" files
125- contain ascii versions of record instances and are described
126- in more detail in <B>dbfile(5)</B>. In addition to loading the
127- ".db" ascii files into the IOC, both routines provide a
128- method of performing variable substitution on record names
129- and field values.
130-
131- dbLoadRecords() reads the ".db" file <I>db</I>_<I>file</I> performing sub-
132- stitutions specified in string <I>substitutions</I>. The substitu-
133- tion must be a string specified as follows:
134-
135- "var1=sub1,var2=sub3,..."
136-
137- Variables are specified in the ".db" file as
138- $(variable_name). If the substitution string
139- "a=1,b=2,c=\"this is a test\"" were used, any variables
140- $(a), $(b), or $(c) would be substituted with the appropri-
141- ate data. See the EXAMPLES section for more details.
142-
143- dbLoadTemplate() will read a <I>template</I>_<I>file</I>. The
144- <I>template</I>_<I>file</I> resides in the your IOC boot directory and
145- contains rules about loading ".db" files and performing sub-
146- stitutions. The template_file must be in the form used by
147- an IOC and is described in <B>templatefile(5)</B>. The EXAMPLES
148- section descibes how it can be used.
149-
150-
151-</PRE>
152-<H2>EXAMPLES</H2><PRE>
153- The next two examples of dbLoadRecords() and dbLoadTem-
154- plate() will use the following ".db" file named <I>test</I>.<I>db</I> :
155-
156- database(test)
157- {
158- record(ai,"$(pre)testrec1")
159- record(ai,"$(pre)testrec2")
160- record(stringout,"$(pre)testrec3")
161- {
162- field(VAL,"$(STRING)")
163- field(SCAN,"$(SCAN)")
164- }
165- }
166- Running dbLoadRecords ("test.db","pre=TEST,STRING=\"this is
167- a test\",SCAN=Passive") will produce the following records
168- in the IOC's database:
169-
170- TESTtestrec1
171- TESTtestrec2
172- TESTtestrec3
173-
174- The third record will have VAL set to "this is a test" and
175- SCAN set to "Passive".
176-
177- Running dbLoadTemplate ("test.template") with test.template
178- containing:
179- file test.db
180- {
181- {pre=TEST1, STRING = "this is a test two", SCAN="1 Second" }
182- {pre=TEST2, STRING = "this is a test one", SCAN=Passive }
183- {pre=TEST3, STRING = "this is a test three", SCAN=Passive }
184- }
185- will produce a total of nine records in the IOC's database:
186- TEST1testrec1
187- TEST1testrec2
188- TEST1testrec3 - (VAL="this is a test two", SCAN="1 Second")
189- TEST2testrec1
190- TEST2testrec2
191- TEST2testrec3 - (VAL="this is a test one", SCAN="Passive")
192- TEST3testrec1
193- TEST3testrec2
194- TEST3testrec3 - (VAL="this is a test three", SCAN="Passive")
195-
196-
197-</PRE>
198-<H2>NOTES</H2><PRE>
199- The binary file <I>default</I>.<I>dctsdr</I> must be loaded prior to run-
200- ning either of these routines. This file contains the rules
201- on how to construct records and change field values.
202-
203- After the default.dctsdr file is loaded, these routines can
204- be run as many times as desired until iocInit is run.
205-
206-
207-</PRE>
208-<H2>SEE ALSO</H2><PRE>
209- <B>gdct(1)</B>, <B>templatefile(5)</B>, <B>dbfile(5)</B>
210-
211-
212-
213-
214-
215-
216-
217-
218-
219-
220-
221-
222-</PRE>
223-<HR>
224-<ADDRESS>
225-Man(1) output converted with
226-<a href="http://www.oac.uci.edu/indiv/ehood/man2html.html">man2html</a>
227-</ADDRESS>
228-</BODY>
229-</HTML>
230
231=== modified file 'src/ioc/dbtemplate/dbLoadTemplate.y'
232--- src/ioc/dbtemplate/dbLoadTemplate.y 2009-05-05 15:19:00 +0000
233+++ src/ioc/dbtemplate/dbLoadTemplate.y 2012-06-01 20:39:23 +0000
234@@ -22,30 +22,32 @@
235 #include "dbLoadTemplate.h"
236
237 static int line_num;
238-static int yyerror();
239+static int yyerror(char* str);
240
241 #define VAR_MAX_VAR_STRING 5000
242 #define VAR_MAX_VARS 100
243
244-static char *sub_collect = NULL;
245+static char *sub_collect;
246+static char *sub_locals;
247 static char** vars = NULL;
248 static char* db_file_name = NULL;
249-static int var_count,sub_count;
250+static int var_count, sub_count;
251
252 %}
253
254-%start template
255+%start substitution_file
256
257 %token <Str> WORD QUOTE
258 %token DBFILE
259 %token PATTERN
260+%token GLOBAL
261 %token EQUALS COMMA
262 %left O_PAREN C_PAREN
263 %left O_BRACE C_BRACE
264
265 %union
266 {
267- int Int;
268+ int Int;
269 char Char;
270 char *Str;
271 double Real;
272@@ -53,192 +55,242 @@
273
274 %%
275
276-template: templs
277- | subst
278- ;
279-
280-templs: templs templ
281- | templ
282- ;
283-
284-templ: templ_head O_BRACE subst C_BRACE
285- | templ_head
286- {
287- if(db_file_name)
288- dbLoadRecords(db_file_name,NULL);
289- else
290- fprintf(stderr,"Error: no db file name given\n");
291- }
292- ;
293-
294-templ_head: DBFILE WORD
295- {
296- var_count=0;
297- if(db_file_name) dbmfFree(db_file_name);
298- db_file_name = dbmfMalloc(strlen($2)+1);
299- strcpy(db_file_name,$2);
300- dbmfFree($2);
301- }
302- | DBFILE QUOTE
303- {
304- var_count=0;
305- if(db_file_name) dbmfFree(db_file_name);
306- db_file_name = dbmfMalloc(strlen($2)+1);
307- strcpy(db_file_name,$2);
308- dbmfFree($2);
309- }
310- ;
311-
312-subst: PATTERN pattern subs
313- | PATTERN pattern
314- | var_subs
315- ;
316-
317-pattern: O_BRACE vars C_BRACE
318- {
319-#ifdef ERROR_STUFF
320- int i;
321- for(i=0;i<var_count;i++) fprintf(stderr,"variable=(%s)\n",vars[i]);
322- fprintf(stderr,"var_count=%d\n",var_count);
323-#endif
324- }
325- ;
326-
327-vars: vars var
328- | vars COMMA var
329- | var
330- ;
331-
332-var: WORD
333- {
334- vars[var_count] = dbmfMalloc(strlen($1)+1);
335- strcpy(vars[var_count],$1);
336- var_count++;
337- dbmfFree($1);
338- }
339- ;
340-
341-subs: subs sub
342- | sub
343- ;
344-
345-sub: WORD O_BRACE vals C_BRACE
346- {
347- sub_collect[strlen(sub_collect)-1]='\0';
348-#ifdef ERROR_STUFF
349- fprintf(stderr,"dbLoadRecords(%s)\n",sub_collect);
350-#endif
351- if(db_file_name)
352- dbLoadRecords(db_file_name,sub_collect);
353- else
354- fprintf(stderr,"Error: no db file name given\n");
355- dbmfFree($1);
356- sub_collect[0]='\0';
357- sub_count=0;
358- }
359- | O_BRACE vals C_BRACE
360- {
361- sub_collect[strlen(sub_collect)-1]='\0';
362-#ifdef ERROR_STUFF
363- fprintf(stderr,"dbLoadRecords(%s)\n",sub_collect);
364-#endif
365- if(db_file_name)
366- dbLoadRecords(db_file_name,sub_collect);
367- else
368- fprintf(stderr,"Error: no db file name given\n");
369- sub_collect[0]='\0';
370- sub_count=0;
371- }
372- ;
373-
374-vals: vals val
375- | vals COMMA val
376- | val
377- ;
378-
379-val: QUOTE
380- {
381- if(sub_count<=var_count)
382- {
383- strcat(sub_collect,vars[sub_count]);
384- strcat(sub_collect,"=\"");
385- strcat(sub_collect,$1);
386- strcat(sub_collect,"\",");
387- sub_count++;
388- }
389- dbmfFree($1);
390- }
391- | WORD
392- {
393- if(sub_count<=var_count)
394- {
395- strcat(sub_collect,vars[sub_count]);
396- strcat(sub_collect,"=");
397- strcat(sub_collect,$1);
398- strcat(sub_collect,",");
399- sub_count++;
400- }
401- dbmfFree($1);
402- }
403- ;
404-
405-var_subs: var_subs var_sub
406- | var_sub
407- ;
408-
409-var_sub: WORD O_BRACE sub_pats C_BRACE
410- {
411- sub_collect[strlen(sub_collect)-1]='\0';
412-#ifdef ERROR_STUFF
413- fprintf(stderr,"dbLoadRecords(%s)\n",sub_collect);
414-#endif
415- if(db_file_name)
416- dbLoadRecords(db_file_name,sub_collect);
417- else
418- fprintf(stderr,"Error: no db file name given\n");
419- dbmfFree($1);
420- sub_collect[0]='\0';
421- sub_count=0;
422- }
423- | O_BRACE sub_pats C_BRACE
424- {
425- sub_collect[strlen(sub_collect)-1]='\0';
426-#ifdef ERROR_STUFF
427- fprintf(stderr,"dbLoadRecords(%s)\n",sub_collect);
428-#endif
429- if(db_file_name)
430- dbLoadRecords(db_file_name,sub_collect);
431- else
432- fprintf(stderr,"Error: no db file name given\n");
433- sub_collect[0]='\0';
434- sub_count=0;
435- }
436- ;
437-
438-sub_pats: sub_pats sub_pat
439- | sub_pats COMMA sub_pat
440- | sub_pat
441- ;
442-
443-sub_pat: WORD EQUALS WORD
444- {
445- strcat(sub_collect,$1);
446- strcat(sub_collect,"=");
447- strcat(sub_collect,$3);
448- strcat(sub_collect,",");
449- dbmfFree($1); dbmfFree($3);
450- sub_count++;
451- }
452- | WORD EQUALS QUOTE
453- {
454- strcat(sub_collect,$1);
455- strcat(sub_collect,"=\"");
456- strcat(sub_collect,$3);
457- strcat(sub_collect,"\",");
458- dbmfFree($1); dbmfFree($3);
459- sub_count++;
460- }
461- ;
462+substitution_file: global_or_template
463+ | substitution_file global_or_template
464+ ;
465+
466+global_or_template: global_definitions
467+ | template_substitutions
468+ ;
469+
470+global_definitions: GLOBAL O_BRACE C_BRACE
471+ | GLOBAL O_BRACE variable_definitions C_BRACE
472+ {
473+ #ifdef ERROR_STUFF
474+ fprintf(stderr, "global_definitions: %s\n", sub_collect+1);
475+ #endif
476+ sub_locals += strlen(sub_locals);
477+ }
478+ ;
479+
480+template_substitutions: template_filename O_BRACE C_BRACE
481+ {
482+ #ifdef ERROR_STUFF
483+ fprintf(stderr, "template_substitutions: %s unused\n", db_file_name);
484+ #endif
485+ dbmfFree(db_file_name);
486+ db_file_name = NULL;
487+ }
488+ | template_filename O_BRACE substitutions C_BRACE
489+ {
490+ #ifdef ERROR_STUFF
491+ fprintf(stderr, "template_substitutions: %s finished\n", db_file_name);
492+ #endif
493+ dbmfFree(db_file_name);
494+ db_file_name = NULL;
495+ }
496+ ;
497+
498+template_filename: DBFILE WORD
499+ {
500+ #ifdef ERROR_STUFF
501+ fprintf(stderr, "template_filename: %s\n", $2);
502+ #endif
503+ var_count = 0;
504+ db_file_name = dbmfMalloc(strlen($2)+1);
505+ strcpy(db_file_name, $2);
506+ dbmfFree($2);
507+ }
508+ | DBFILE QUOTE
509+ {
510+ #ifdef ERROR_STUFF
511+ fprintf(stderr, "template_filename: \"%s\"\n", $2);
512+ #endif
513+ var_count = 0;
514+ db_file_name = dbmfMalloc(strlen($2)+1);
515+ strcpy(db_file_name, $2);
516+ dbmfFree($2);
517+ }
518+ ;
519+
520+substitutions: pattern_substitutions
521+ | variable_substitutions
522+ ;
523+
524+pattern_substitutions: PATTERN O_BRACE C_BRACE
525+ | PATTERN O_BRACE C_BRACE pattern_definitions
526+ | PATTERN O_BRACE pattern_names C_BRACE
527+ | PATTERN O_BRACE pattern_names C_BRACE pattern_definitions
528+ ;
529+
530+pattern_names: pattern_name
531+ | pattern_names COMMA
532+ | pattern_names pattern_name
533+ ;
534+
535+pattern_name: WORD
536+ {
537+ #ifdef ERROR_STUFF
538+ fprintf(stderr, "pattern_name: [%d] = %s\n", var_count, $1);
539+ #endif
540+ vars[var_count] = dbmfMalloc(strlen($1)+1);
541+ strcpy(vars[var_count], $1);
542+ var_count++;
543+ dbmfFree($1);
544+ }
545+ ;
546+
547+pattern_definitions: pattern_definition
548+ | pattern_definitions pattern_definition
549+ ;
550+
551+pattern_definition: global_definitions
552+ | O_BRACE C_BRACE
553+ {
554+ #ifdef ERROR_STUFF
555+ fprintf(stderr, "pattern_definition: pattern_values empty\n");
556+ fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
557+ #endif
558+ dbLoadRecords(db_file_name, sub_collect+1);
559+ }
560+ | O_BRACE pattern_values C_BRACE
561+ {
562+ #ifdef ERROR_STUFF
563+ fprintf(stderr, "pattern_definition:\n");
564+ fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
565+ #endif
566+ dbLoadRecords(db_file_name, sub_collect+1);
567+ *sub_locals = '\0';
568+ sub_count = 0;
569+ }
570+ | WORD O_BRACE pattern_values C_BRACE
571+ { /* DEPRECATED SYNTAX */
572+ fprintf(stderr,
573+ "dbLoadTemplate: Substitution file uses deprecated syntax.\n"
574+ " the string '%s' on line %d that comes just before the\n"
575+ " '{' character is extraneous and should be removed.\n",
576+ $1, line_num);
577+ #ifdef ERROR_STUFF
578+ fprintf(stderr, "pattern_definition:\n");
579+ fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
580+ #endif
581+ dbLoadRecords(db_file_name, sub_collect+1);
582+ dbmfFree($1);
583+ *sub_locals = '\0';
584+ sub_count = 0;
585+ }
586+ ;
587+
588+pattern_values: pattern_value
589+ | pattern_values COMMA
590+ | pattern_values pattern_value
591+ ;
592+
593+pattern_value: QUOTE
594+ {
595+ #ifdef ERROR_STUFF
596+ fprintf(stderr, "pattern_value: [%d] = \"%s\"\n", sub_count, $1);
597+ #endif
598+ if (sub_count < var_count) {
599+ strcat(sub_locals, ",");
600+ strcat(sub_locals, vars[sub_count]);
601+ strcat(sub_locals, "=\"");
602+ strcat(sub_locals, $1);
603+ strcat(sub_locals, "\"");
604+ sub_count++;
605+ } else {
606+ fprintf(stderr, "dbLoadTemplate: Too many values given, line %d.\n",
607+ line_num);
608+ }
609+ dbmfFree($1);
610+ }
611+ | WORD
612+ {
613+ #ifdef ERROR_STUFF
614+ fprintf(stderr, "pattern_value: [%d] = %s\n", sub_count, $1);
615+ #endif
616+ if (sub_count < var_count) {
617+ strcat(sub_locals, ",");
618+ strcat(sub_locals, vars[sub_count]);
619+ strcat(sub_locals, "=");
620+ strcat(sub_locals, $1);
621+ sub_count++;
622+ } else {
623+ fprintf(stderr, "dbLoadTemplate: Too many values given, line %d.\n",
624+ line_num);
625+ }
626+ dbmfFree($1);
627+ }
628+ ;
629+
630+variable_substitutions: variable_substitution
631+ | variable_substitutions variable_substitution
632+ ;
633+
634+variable_substitution: global_definitions
635+ | O_BRACE C_BRACE
636+ {
637+ #ifdef ERROR_STUFF
638+ fprintf(stderr, "variable_substitution: variable_definitions empty\n");
639+ fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
640+ #endif
641+ dbLoadRecords(db_file_name, sub_collect+1);
642+ }
643+ | O_BRACE variable_definitions C_BRACE
644+ {
645+ #ifdef ERROR_STUFF
646+ fprintf(stderr, "variable_substitution:\n");
647+ fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
648+ #endif
649+ dbLoadRecords(db_file_name, sub_collect+1);
650+ *sub_locals = '\0';
651+ }
652+ | WORD O_BRACE variable_definitions C_BRACE
653+ { /* DEPRECATED SYNTAX */
654+ fprintf(stderr,
655+ "dbLoadTemplate: Substitution file uses deprecated syntax.\n"
656+ " the string '%s' on line %d that comes just before the\n"
657+ " '{' character is extraneous and should be removed.\n",
658+ $1, line_num);
659+ #ifdef ERROR_STUFF
660+ fprintf(stderr, "variable_substitution:\n");
661+ fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1);
662+ #endif
663+ dbLoadRecords(db_file_name, sub_collect+1);
664+ dbmfFree($1);
665+ *sub_locals = '\0';
666+ }
667+ ;
668+
669+variable_definitions: variable_definition
670+ | variable_definitions COMMA
671+ | variable_definitions variable_definition
672+ ;
673+
674+variable_definition: WORD EQUALS WORD
675+ {
676+ #ifdef ERROR_STUFF
677+ fprintf(stderr, "variable_definition: %s = %s\n", $1, $3);
678+ #endif
679+ strcat(sub_locals, ",");
680+ strcat(sub_locals, $1);
681+ strcat(sub_locals, "=");
682+ strcat(sub_locals, $3);
683+ dbmfFree($1); dbmfFree($3);
684+ }
685+ | WORD EQUALS QUOTE
686+ {
687+ #ifdef ERROR_STUFF
688+ fprintf(stderr, "variable_definition: %s = \"%s\"\n", $1, $3);
689+ #endif
690+ strcat(sub_locals, ",");
691+ strcat(sub_locals, $1);
692+ strcat(sub_locals, "=\"");
693+ strcat(sub_locals, $3);
694+ strcat(sub_locals, "\"");
695+ dbmfFree($1); dbmfFree($3);
696+ }
697+ ;
698
699 %%
700
701@@ -247,69 +299,73 @@
702 static int yyerror(char* str)
703 {
704 if (str)
705- fprintf(stderr, "Substitution file error: %s\n", str);
706+ fprintf(stderr, "Substitution file error: %s\n", str);
707 else
708- fprintf(stderr, "Substitution file error.\n");
709+ fprintf(stderr, "Substitution file error.\n");
710 fprintf(stderr, "line %d: '%s'\n", line_num, yytext);
711 return 0;
712 }
713
714 static int is_not_inited = 1;
715
716-int epicsShareAPI dbLoadTemplate(char* sub_file)
717+int epicsShareAPI dbLoadTemplate(const char *sub_file, const char *cmd_collect)
718 {
719- FILE *fp;
720- int ind;
721-
722- line_num=1;
723-
724- if( !sub_file || !*sub_file)
725- {
726- fprintf(stderr,"must specify variable substitution file\n");
727- return -1;
728- }
729-
730- if( !(fp=fopen(sub_file,"r")) )
731- {
732- fprintf(stderr,"dbLoadTemplate: error opening sub file %s\n",sub_file);
733- return -1;
734- }
735-
736- vars = (char**)malloc(VAR_MAX_VARS * sizeof(char*));
737- sub_collect = malloc(VAR_MAX_VAR_STRING);
738- if (!vars || !sub_collect)
739- {
740- free(vars);
741- free(sub_collect);
742- fclose(fp);
743- fprintf(stderr, "dbLoadTemplate: Out of memory!\n");
744- return -1;
745- }
746-
747- sub_collect[0]='\0';
748- var_count=0;
749- sub_count=0;
750-
751- if(is_not_inited)
752- {
753- yyin=fp;
754- is_not_inited=0;
755- }
756- else
757- {
758- yyrestart(fp);
759- }
760-
761- yyparse();
762- for(ind=0;ind<var_count;ind++) dbmfFree(vars[ind]);
763- free(vars);
764- free(sub_collect);
765- vars = NULL;
766- fclose(fp);
767- if(db_file_name){
768- dbmfFree((void *)db_file_name);
769- db_file_name = NULL;
770- }
771- return 0;
772+ FILE *fp;
773+ int i;
774+
775+ line_num = 1;
776+
777+ if (!sub_file || !*sub_file) {
778+ fprintf(stderr, "must specify variable substitution file\n");
779+ return -1;
780+ }
781+
782+ fp = fopen(sub_file, "r");
783+ if (!fp) {
784+ fprintf(stderr, "dbLoadTemplate: error opening sub file %s\n", sub_file);
785+ return -1;
786+ }
787+
788+ vars = (char**)malloc(VAR_MAX_VARS * sizeof(char*));
789+ sub_collect = malloc(VAR_MAX_VAR_STRING);
790+ if (!vars || !sub_collect) {
791+ free(vars);
792+ free(sub_collect);
793+ fclose(fp);
794+ fprintf(stderr, "dbLoadTemplate: Out of memory!\n");
795+ return -1;
796+ }
797+ strcpy(sub_collect, ",");
798+
799+ if (cmd_collect && *cmd_collect) {
800+ strcat(sub_collect, cmd_collect);
801+ sub_locals = sub_collect + strlen(sub_collect);
802+ } else {
803+ sub_locals = sub_collect;
804+ *sub_locals = '\0';
805+ }
806+ var_count = 0;
807+ sub_count = 0;
808+
809+ if (is_not_inited) {
810+ yyin = fp;
811+ is_not_inited = 0;
812+ } else {
813+ yyrestart(fp);
814+ }
815+
816+ yyparse();
817+
818+ for (i = 0; i < var_count; i++) {
819+ dbmfFree(vars[i]);
820+ }
821+ free(vars);
822+ free(sub_collect);
823+ vars = NULL;
824+ fclose(fp);
825+ if (db_file_name) {
826+ dbmfFree(db_file_name);
827+ db_file_name = NULL;
828+ }
829+ return 0;
830 }
831-
832
833=== modified file 'src/ioc/dbtemplate/dbLoadTemplate_lex.l'
834--- src/ioc/dbtemplate/dbLoadTemplate_lex.l 2006-11-17 22:18:35 +0000
835+++ src/ioc/dbtemplate/dbLoadTemplate_lex.l 2012-06-01 20:39:23 +0000
836@@ -18,39 +18,40 @@
837
838 %%
839
840-"pattern" { return(PATTERN); }
841-"file" { return(DBFILE); }
842+"pattern" { return(PATTERN); }
843+"file" { return(DBFILE); }
844+"global" { return(GLOBAL); }
845
846 {doublequote}({dstringchar}|{escape})*{doublequote} |
847 {singlequote}({sstringchar}|{escape})*{singlequote} {
848- yylval.Str = dbmfStrdup(yytext+1);
849- yylval.Str[strlen(yylval.Str)-1] = '\0';
850- return(QUOTE);
851- }
852+ yylval.Str = dbmfStrdup(yytext+1);
853+ yylval.Str[strlen(yylval.Str)-1] = '\0';
854+ return(QUOTE);
855+}
856
857 {bareword}+ {
858- yylval.Str = dbmfStrdup(yytext);
859- return(WORD);
860- }
861-
862-"=" { return(EQUALS); }
863-"," { return(COMMA); }
864-"{" { return(O_BRACE); }
865-"}" { return(C_BRACE); }
866-
867-{comment}.* ;
868-{whitespace} ;
869-{newline} { line_num++; }
870+ yylval.Str = dbmfStrdup(yytext);
871+ return(WORD);
872+}
873+
874+"=" { return(EQUALS); }
875+"," { return(COMMA); }
876+"{" { return(O_BRACE); }
877+"}" { return(C_BRACE); }
878+
879+{comment}.* ;
880+{whitespace} ;
881+{newline} { line_num++; }
882
883 . {
884- char message[40];
885-
886- sprintf(message,"invalid character '%c'", yytext[0]);
887- yyerror(message);
888-
889- /* Suppress compiler warning messages */
890- if (0) yyunput('c',NULL);
891- if (0) yy_switch_to_buffer(NULL);
892- }
893+ char message[40];
894+
895+ sprintf(message, "invalid character '%c'", yytext[0]);
896+ yyerror(message);
897+
898+ /* Suppress compiler warning messages */
899+ if (0) yyunput('c',NULL);
900+ if (0) yy_switch_to_buffer(NULL);
901+}
902
903 %%
904
905=== modified file 'src/ioc/dbtemplate/dbtoolsIocRegister.c'
906--- src/ioc/dbtemplate/dbtoolsIocRegister.c 2007-03-13 17:54:23 +0000
907+++ src/ioc/dbtemplate/dbtoolsIocRegister.c 2012-06-01 20:39:23 +0000
908@@ -13,17 +13,20 @@
909
910
911 /* dbLoadTemplate */
912-static const iocshArg dbLoadTemplateArg0 = { "file name",iocshArgString};
913-static const iocshArg * const dbLoadTemplateArgs[1] = {&dbLoadTemplateArg0};
914+static const iocshArg dbLoadTemplateArg0 = {"filename", iocshArgString};
915+static const iocshArg dbLoadTemplateArg1 = {"var=value", iocshArgString};
916+static const iocshArg * const dbLoadTemplateArgs[2] = {
917+ &dbLoadTemplateArg0, &dbLoadTemplateArg1
918+};
919 static const iocshFuncDef dbLoadTemplateFuncDef =
920- {"dbLoadTemplate",1,dbLoadTemplateArgs};
921+ {"dbLoadTemplate", 2, dbLoadTemplateArgs};
922 static void dbLoadTemplateCallFunc(const iocshArgBuf *args)
923 {
924- dbLoadTemplate(args[0].sval);
925+ dbLoadTemplate(args[0].sval, args[1].sval);
926 }
927
928
929 void epicsShareAPI dbtoolsIocRegister(void)
930 {
931- iocshRegister(&dbLoadTemplateFuncDef,dbLoadTemplateCallFunc);
932+ iocshRegister(&dbLoadTemplateFuncDef, dbLoadTemplateCallFunc);
933 }
934
935=== added file 'src/ioc/dbtemplate/msi.c'
936--- src/ioc/dbtemplate/msi.c 1970-01-01 00:00:00 +0000
937+++ src/ioc/dbtemplate/msi.c 2012-06-01 20:39:23 +0000
938@@ -0,0 +1,841 @@
939+/*************************************************************************\
940+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
941+* National Laboratory.
942+* Copyright (c) 2002 The Regents of the University of California, as
943+* Operator of Los Alamos National Laboratory.
944+* EPICS Base is distributed subject to a Software License Agreement found
945+* in the file LICENSE that is included with this distribution.
946+\*************************************************************************/
947+
948+/* msi - macro substitutions and include */
949+
950+#include <stdlib.h>
951+#include <stddef.h>
952+#include <stdio.h>
953+#include <string.h>
954+#include <ctype.h>
955+#include <errno.h>
956+
957+#include <dbDefs.h>
958+#include <macLib.h>
959+#include <ellLib.h>
960+#include <epicsString.h>
961+#include <osiFileName.h>
962+
963+#define MAX_BUFFER_SIZE 4096
964+
965+/* Module to read the template files */
966+typedef struct inputData inputData;
967+
968+static void inputConstruct(inputData **ppvt);
969+static void inputDestruct(inputData *pvt);
970+static void inputAddPath(inputData *pvt, char *pval);
971+static void inputBegin(inputData *pvt, char *fileName);
972+static char *inputNextLine(inputData *pvt);
973+static void inputNewIncludeFile(inputData *pvt, char *name);
974+static void inputErrPrint(inputData *pvt);
975+
976+/* Module to read the substitution file */
977+typedef struct subInfo subInfo;
978+
979+static void substituteOpen(subInfo **ppvt, char *substitutionName);
980+static void substituteDestruct(subInfo *pvt);
981+static int substituteGetNextSet(subInfo *pvt, char **filename);
982+static int substituteGetGlobalSet(subInfo *pvt);
983+static char *substituteGetReplacements(subInfo *pvt);
984+static char *substituteGetGlobalReplacements(subInfo *pvt);
985+
986+/* Forward references to local routines */
987+static void usageExit(void);
988+static void addMacroReplacements(MAC_HANDLE *macPvt, char *pval);
989+static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *templateName);
990+
991+/*Global variables */
992+static int dontWarnUndef = 1;
993+
994+
995
996+int main(int argc,char **argv)
997+{
998+ inputData *inputPvt;
999+ MAC_HANDLE *macPvt;
1000+ char *pval;
1001+ int narg;
1002+ char *substitutionName=0;
1003+ char *templateName=0;
1004+ int i;
1005+ int localScope = 1;
1006+
1007+ inputConstruct(&inputPvt);
1008+ macCreateHandle(&macPvt,0);
1009+ macSuppressWarning(macPvt,1);
1010+ while((argc>1) && (argv[1][0] == '-')) {
1011+ narg = (strlen(argv[1])==2) ? 2 : 1;
1012+ pval = (narg==1) ? (argv[1]+2) : argv[2];
1013+ if(strncmp(argv[1],"-I",2)==0) {
1014+ inputAddPath(inputPvt,pval);
1015+ } else if(strncmp(argv[1],"-o",2)==0) {
1016+ if(freopen(pval,"w",stdout)==NULL) {
1017+ fprintf(stderr,"msi: Can't open %s for writing: %s\n",
1018+ pval, strerror(errno));
1019+ exit(1);
1020+ }
1021+ } else if(strncmp(argv[1],"-M",2)==0) {
1022+ addMacroReplacements(macPvt,pval);
1023+ } else if(strncmp(argv[1],"-S",2)==0) {
1024+ substitutionName = epicsStrDup(pval);
1025+ } else if(strncmp(argv[1],"-V",2)==0) {
1026+ macSuppressWarning(macPvt,0);
1027+ dontWarnUndef = 0;
1028+ narg = 1; /* no argument for this option */
1029+ } else if(strncmp(argv[1],"-g",2)==0) {
1030+ localScope = 0;
1031+ narg = 1; /* no argument for this option */
1032+ } else {
1033+ usageExit();
1034+ }
1035+ argc -= narg;
1036+ for(i=1; i<argc; i++) argv[i] = argv[i + narg];
1037+ }
1038+ if(argc>2) {
1039+ fprintf(stderr,"msi: Too many arguments\n");
1040+ usageExit();
1041+ }
1042+ if(argc==2) {
1043+ templateName = epicsStrDup(argv[1]);
1044+ }
1045+ if(!substitutionName) {
1046+ makeSubstitutions(inputPvt,macPvt,templateName);
1047+ } else {
1048+ subInfo *substitutePvt;
1049+ char *filename = 0;
1050+ int isGlobal, isFile;
1051+
1052+ substituteOpen(&substitutePvt,substitutionName);
1053+ do {
1054+ if ((isGlobal = substituteGetGlobalSet(substitutePvt))) {
1055+ pval = substituteGetGlobalReplacements(substitutePvt);
1056+ if(pval) {
1057+ addMacroReplacements(macPvt,pval);
1058+ }
1059+ } else if ((isFile = substituteGetNextSet(substitutePvt,&filename))) {
1060+ if(templateName) filename = templateName;
1061+ if(!filename) {
1062+ fprintf(stderr,"msi: No template file\n");
1063+ usageExit();
1064+ }
1065+ while((pval = substituteGetReplacements(substitutePvt))){
1066+ if (localScope) macPushScope(macPvt);
1067+ addMacroReplacements(macPvt,pval);
1068+ makeSubstitutions(inputPvt,macPvt,filename);
1069+ if (localScope) macPopScope(macPvt);
1070+ }
1071+ }
1072+ } while (isGlobal || isFile);
1073+ substituteDestruct(substitutePvt);
1074+ }
1075+ macDeleteHandle(macPvt);
1076+ inputDestruct(inputPvt);
1077+ free(templateName);
1078+ free(substitutionName);
1079+ return 0;
1080+}
1081+
1082
1083+void usageExit(void)
1084+{
1085+ fprintf(stderr,"usage: msi [options] [template]\n");
1086+ fprintf(stderr,"stdin is used if neither template nor substitution file is given\n");
1087+ fprintf(stderr,"options:\n");
1088+ fprintf(stderr," -V Verbose warnings\n");
1089+ fprintf(stderr," -g All macros have global scope\n");
1090+ fprintf(stderr," -o<FILE> Save output to <FILE>\n");
1091+ fprintf(stderr," -I<DIR> Add <DIR> to include file search path\n");
1092+ fprintf(stderr," -M<SUBST> Add <SUBST> to (global) macro definitions\n");
1093+ fprintf(stderr," (<SUBST> takes the form VAR=VALUE,...)\n");
1094+ fprintf(stderr," -S<FILE> Expand the substitutions in FILE\n");
1095+ exit(1);
1096+}
1097+
1098+static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval)
1099+{
1100+ char **pairs;
1101+ long status;
1102+
1103+ status = macParseDefns(macPvt,pval,&pairs);
1104+ if(status==-1) {
1105+ fprintf(stderr,"msi: Error from macParseDefns\n");
1106+ usageExit();
1107+ }
1108+ if(status) {
1109+ status = macInstallMacros(macPvt,pairs);
1110+ if(!status) {
1111+ fprintf(stderr,"Error from macInstallMacros\n");
1112+ usageExit();
1113+ }
1114+ free(pairs);
1115+ }
1116+}
1117+
1118+typedef enum {cmdInclude,cmdSubstitute} cmdType;
1119+static const char *cmdNames[] = {"include","substitute"};
1120+
1121+static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *templateName)
1122+{
1123+ char *input;
1124+ static char buffer[MAX_BUFFER_SIZE];
1125+ int n;
1126+
1127+ inputBegin(inputPvt,templateName);
1128+ while((input = inputNextLine(inputPvt))) {
1129+ int expand=1;
1130+ char *p;
1131+ char *command = 0;
1132+
1133+ p = input;
1134+ /*skip whitespace at beginning of line*/
1135+ while(*p && (isspace(*p))) ++p;
1136+ /*Look for i or s */
1137+ if(*p && (*p=='i' || *p=='s')) command = p;
1138+ if(command) {
1139+ char *pstart;
1140+ char *pend;
1141+ char *copy;
1142+ int cmdind=-1;
1143+ int i;
1144+
1145+ for(i=0; i< NELEMENTS(cmdNames); i++) {
1146+ if(strstr(command,cmdNames[i])) {
1147+ cmdind = i;
1148+ }
1149+ }
1150+ if(cmdind<0) goto endif;
1151+ p = command + strlen(cmdNames[cmdind]);
1152+ /*skip whitespace after command*/
1153+ while(*p && (isspace(*p))) ++p;
1154+ /*Next character must be quote*/
1155+ if((*p==0) || (*p!='"')) goto endif;
1156+ pstart = ++p;
1157+ /*Look for end quote*/
1158+ while(*p && (*p!='"')) {
1159+ /*allow escape for imbeded quote*/
1160+ if((*p=='\\') && *(p+1)=='"') {
1161+ p += 2; continue;
1162+ } else {
1163+ if(*p=='"') break;
1164+ }
1165+ ++p;
1166+ }
1167+ pend = p;
1168+ if(*p==0) goto endif;
1169+ /*skip quote and any trailing blanks*/
1170+ while(*++p==' ') ;
1171+ if(*p != '\n' && *p !=0) goto endif;
1172+ copy = calloc(pend-pstart+1,sizeof(char));
1173+ strncpy(copy,pstart,pend-pstart);
1174+ switch(cmdind) {
1175+ case cmdInclude:
1176+ inputNewIncludeFile(inputPvt,copy);
1177+ break;
1178+ case cmdSubstitute:
1179+ addMacroReplacements(macPvt,copy);
1180+ break;
1181+ default:
1182+ fprintf(stderr,"msi: Logic error in makeSubstitutions\n");
1183+ inputErrPrint(inputPvt);
1184+ exit(1);
1185+ }
1186+ free(copy);
1187+ expand = 0;
1188+ }
1189+endif:
1190+ if (expand) {
1191+ n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1);
1192+ fputs(buffer,stdout);
1193+ if (!dontWarnUndef && n<0) {
1194+ fprintf(stderr,"msi: Warning, undefined macros present\n");
1195+ dontWarnUndef++;
1196+ }
1197+ }
1198+ }
1199+}
1200+
1201
1202+typedef struct inputFile{
1203+ ELLNODE node;
1204+ char *filename;
1205+ FILE *fp;
1206+ int lineNum;
1207+}inputFile;
1208+
1209+typedef struct pathNode {
1210+ ELLNODE node;
1211+ char *directory;
1212+} pathNode;
1213+
1214+struct inputData {
1215+ ELLLIST inputFileList;
1216+ ELLLIST pathList;
1217+ char inputBuffer[MAX_BUFFER_SIZE];
1218+};
1219+
1220+static void inputOpenFile(inputData *pinputData,char *filename);
1221+static void inputCloseFile(inputData *pinputData);
1222+static void inputCloseAllFiles(inputData *pinputData);
1223+
1224+static void inputConstruct(inputData **ppvt)
1225+{
1226+ inputData *pinputData;
1227+
1228+ pinputData = calloc(1,sizeof(inputData));
1229+ ellInit(&pinputData->inputFileList);
1230+ ellInit(&pinputData->pathList);
1231+ *ppvt = pinputData;
1232+}
1233+
1234+static void inputDestruct(inputData *pinputData)
1235+{
1236+ pathNode *ppathNode;
1237+
1238+ inputCloseAllFiles(pinputData);
1239+ while((ppathNode = (pathNode *)ellFirst(&pinputData->pathList))) {
1240+ ellDelete(&pinputData->pathList,&ppathNode->node);
1241+ free(ppathNode->directory);
1242+ free(ppathNode);
1243+ }
1244+ free(pinputData);
1245+}
1246+
1247
1248+static void inputAddPath(inputData *pinputData, char *path)
1249+{
1250+ ELLLIST *ppathList = &pinputData->pathList;
1251+ pathNode *ppathNode;
1252+ const char *pcolon;
1253+ const char *pdir;
1254+ int len;
1255+ int emptyName;
1256+ const char sep = *OSI_PATH_LIST_SEPARATOR;
1257+
1258+ pdir = path;
1259+ /*an empty name at beginning, middle, or end means current directory*/
1260+ while(pdir && *pdir) {
1261+ emptyName = ((*pdir == sep) ? 1 : 0);
1262+ if(emptyName) ++pdir;
1263+ ppathNode = (pathNode *)calloc(1,sizeof(pathNode));
1264+ ellAdd(ppathList,&ppathNode->node);
1265+ if(!emptyName) {
1266+ pcolon = strchr(pdir,sep);
1267+ len = (pcolon ? (pcolon - pdir) : strlen(pdir));
1268+ if(len>0) {
1269+ ppathNode->directory = (char *)calloc(len+1,sizeof(char));
1270+ strncpy(ppathNode->directory,pdir,len);
1271+ pdir = pcolon;
1272+ /*unless at end skip past first colon*/
1273+ if(pdir && *(pdir+1)!=0) ++pdir;
1274+ } else { /*must have been trailing : */
1275+ emptyName=1;
1276+ }
1277+ }
1278+ if(emptyName) {
1279+ ppathNode->directory = (char *)calloc(2,sizeof(char));
1280+ strcpy(ppathNode->directory,".");
1281+ }
1282+ }
1283+ return;
1284+}
1285+
1286
1287+static void inputBegin(inputData *pinputData, char *fileName)
1288+{
1289+ inputCloseAllFiles(pinputData);
1290+ inputOpenFile(pinputData,fileName);
1291+}
1292+
1293+static char *inputNextLine(inputData *pinputData)
1294+{
1295+ inputFile *pinputFile;
1296+ char *pline;
1297+
1298+ while((pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList))) {
1299+ pline = fgets(pinputData->inputBuffer,MAX_BUFFER_SIZE,pinputFile->fp);
1300+ if(pline) {
1301+ ++pinputFile->lineNum;
1302+ return(pline);
1303+ }
1304+ inputCloseFile(pinputData);
1305+ }
1306+ return(0);
1307+}
1308+
1309+static void inputNewIncludeFile(inputData *pinputData, char *name)
1310+{
1311+ inputOpenFile(pinputData,name);
1312+}
1313+
1314+static void inputErrPrint(inputData *pinputData)
1315+{
1316+ inputFile *pinputFile;
1317+
1318+ fprintf(stderr,"input: '%s' at ",pinputData->inputBuffer);
1319+ pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList);
1320+ while(pinputFile) {
1321+ fprintf(stderr,"line %d of ",pinputFile->lineNum);
1322+ if(pinputFile->filename) {
1323+ fprintf(stderr," file %s\n",pinputFile->filename);
1324+ } else {
1325+ fprintf(stderr,"stdin:\n");
1326+ }
1327+ pinputFile = (inputFile *)ellNext(&pinputFile->node);
1328+ if(pinputFile) {
1329+ fprintf(stderr," included from ");
1330+ } else {
1331+ fprintf(stderr,"\n");
1332+ }
1333+ }
1334+ fprintf(stderr,"\n");
1335+}
1336+
1337
1338+static void inputOpenFile(inputData *pinputData,char *filename)
1339+{
1340+ ELLLIST *ppathList = &pinputData->pathList;
1341+ pathNode *ppathNode = 0;
1342+ inputFile *pinputFile;
1343+ char *fullname = 0;
1344+ FILE *fp = 0;
1345+
1346+ if(!filename) {
1347+ fp = stdin;
1348+ } else if((ellCount(ppathList)==0) || strchr(filename,'/')){
1349+ fp = fopen(filename,"r");
1350+ } else {
1351+ ppathNode = (pathNode *)ellFirst(ppathList);
1352+ while(ppathNode) {
1353+ fullname = calloc(strlen(filename)+strlen(ppathNode->directory) +2,
1354+ sizeof(char));
1355+ strcpy(fullname,ppathNode->directory);
1356+ strcat(fullname,"/");
1357+ strcat(fullname,filename);
1358+ fp = fopen(fullname,"r");
1359+ if(fp) break;
1360+ free(fullname);
1361+ ppathNode = (pathNode *)ellNext(&ppathNode->node);
1362+ }
1363+ }
1364+ if(!fp) {
1365+ fprintf(stderr,"msi: Can't open file '%s'\n",filename);
1366+ inputErrPrint(pinputData);
1367+ exit(1);
1368+ }
1369+ pinputFile = calloc(1,sizeof(inputFile));
1370+ if(ppathNode) {
1371+ pinputFile->filename = fullname;
1372+ } else if(filename) {
1373+ pinputFile->filename = epicsStrDup(filename);
1374+ } else {
1375+ pinputFile->filename = epicsStrDup("stdin");
1376+ }
1377+ pinputFile->fp = fp;
1378+ ellInsert(&pinputData->inputFileList,0,&pinputFile->node);
1379+}
1380+
1381+static void inputCloseFile(inputData *pinputData)
1382+{
1383+ inputFile *pinputFile;
1384+
1385+ pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList);
1386+ if(!pinputFile) return;
1387+ ellDelete(&pinputData->inputFileList,&pinputFile->node);
1388+ if(fclose(pinputFile->fp))
1389+ fprintf(stderr,"msi: Can't close input file '%s'\n",pinputFile->filename);
1390+ free(pinputFile->filename);
1391+ free(pinputFile);
1392+}
1393+
1394+static void inputCloseAllFiles(inputData *pinputData)
1395+{
1396+ inputFile *pinputFile;
1397+
1398+ while((pinputFile=(inputFile *)ellFirst(&pinputData->inputFileList))){
1399+ inputCloseFile(pinputData);
1400+ }
1401+}
1402+
1403
1404+/*start of code that handles substitution file*/
1405+typedef enum {
1406+ tokenLBrace,tokenRBrace,tokenSeparater,tokenString,tokenEOF
1407+}tokenType;
1408+
1409+typedef struct subFile {
1410+ char *substitutionName;
1411+ FILE *fp;
1412+ int lineNum;
1413+ char inputBuffer[MAX_BUFFER_SIZE];
1414+ char *pnextChar;
1415+ tokenType token;
1416+ char string[MAX_BUFFER_SIZE];
1417+} subFile;
1418+
1419+typedef struct patternNode {
1420+ ELLNODE node;
1421+ char *var;
1422+} patternNode;
1423+
1424+struct subInfo {
1425+ subFile *psubFile;
1426+ int isFile;
1427+ char *filename;
1428+ int isPattern;
1429+ ELLLIST patternList;
1430+ size_t size;
1431+ size_t curLength;
1432+ char *macroReplacements;
1433+};
1434+
1435+static char *subGetNextLine(subFile *psubFile);
1436+static tokenType subGetNextToken(subFile *psubFile);
1437+static void subFileErrPrint(subFile *psubFile,char * message);
1438+static void freeSubFile(subInfo *psubInfo);
1439+static void freePattern(subInfo *psubInfo);
1440+static void catMacroReplacements(subInfo *psubInfo,const char *value);
1441+
1442+void freeSubFile(subInfo *psubInfo)
1443+{
1444+ subFile *psubFile = psubInfo->psubFile;
1445+ if(psubFile->fp) {
1446+ if(fclose(psubFile->fp))
1447+ fprintf(stderr,"msi: Can't close substitution file\n");
1448+ }
1449+ free(psubFile);
1450+ free(psubInfo->filename);
1451+ psubInfo->psubFile = 0;
1452+}
1453+
1454+void freePattern(subInfo *psubInfo)
1455+{
1456+ patternNode *ppatternNode;
1457+ while((ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList))) {
1458+ ellDelete(&psubInfo->patternList,&ppatternNode->node);
1459+ free(ppatternNode->var);
1460+ free(ppatternNode);
1461+ }
1462+ psubInfo->isPattern = 0;
1463+}
1464+
1465
1466+static void substituteDestruct(subInfo *psubInfo)
1467+{
1468+ freeSubFile(psubInfo);
1469+ freePattern(psubInfo);
1470+ free(psubInfo);
1471+ return;
1472+}
1473+
1474+static void substituteOpen(subInfo **ppvt,char *substitutionName)
1475+{
1476+ subInfo *psubInfo;
1477+ subFile *psubFile;
1478+ FILE *fp;
1479+
1480+ psubInfo = calloc(1,sizeof(subInfo));
1481+ *ppvt = psubInfo;
1482+ psubFile = calloc(1,sizeof(subFile));
1483+ psubInfo->psubFile = psubFile;
1484+ ellInit(&psubInfo->patternList);
1485+ fp = fopen(substitutionName,"r");
1486+ if(!fp) {
1487+ fprintf(stderr,"msi: Can't open file '%s'\n",substitutionName);
1488+ exit(1);
1489+ }
1490+ psubFile->substitutionName = substitutionName;
1491+ psubFile->fp = fp;
1492+ psubFile->lineNum = 1;
1493+ psubFile->inputBuffer[0] = 0;
1494+ psubFile->pnextChar = &psubFile->inputBuffer[0];
1495+ subGetNextToken(psubFile);
1496+ return;
1497+}
1498+
1499+static int substituteGetGlobalSet(subInfo *psubInfo)
1500+{
1501+ subFile *psubFile = psubInfo->psubFile;
1502+
1503+ while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
1504+ if(psubFile->token==tokenString && strcmp(psubFile->string,"global")==0) {
1505+ subGetNextToken(psubFile);
1506+ return(1);
1507+ }
1508+ return(0);
1509+}
1510+
1511+static int substituteGetNextSet(subInfo *psubInfo,char **filename)
1512+{
1513+ subFile *psubFile = psubInfo->psubFile;
1514+ patternNode *ppatternNode;
1515+
1516+ *filename = 0;
1517+ while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
1518+ if(psubFile->token==tokenEOF) return(0);
1519+ if(psubFile->token==tokenString && strcmp(psubFile->string,"file")==0) {
1520+ psubInfo->isFile = 1;
1521+ if(subGetNextToken(psubFile)!=tokenString) {
1522+ subFileErrPrint(psubFile,"Parse error, expecting filename");
1523+ exit(1);
1524+ }
1525+ freePattern(psubInfo);
1526+ free(psubInfo->filename);
1527+ if(psubFile->string[0]=='"'&&psubFile->string[strlen(psubFile->string)-1]=='"') {
1528+ psubFile->string[strlen(psubFile->string)-1]='\0';
1529+ psubInfo->filename = macEnvExpand(psubFile->string+1);
1530+ }
1531+ else {
1532+ psubInfo->filename = macEnvExpand(psubFile->string);
1533+ }
1534+ while(subGetNextToken(psubFile)==tokenSeparater);
1535+ if(psubFile->token!=tokenLBrace) {
1536+ subFileErrPrint(psubFile,"Parse error, expecting {");
1537+ exit(1);
1538+ }
1539+ subGetNextToken(psubFile);
1540+ }
1541+ *filename = psubInfo->filename;
1542+ while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
1543+ if(psubFile->token==tokenLBrace) return(1);
1544+ if(psubFile->token==tokenRBrace) return(1);
1545+ if(psubFile->token!=tokenString
1546+ || strcmp(psubFile->string,"pattern")!=0) {
1547+ subFileErrPrint(psubFile,"Parse error, expecting pattern");
1548+ exit(1);
1549+ }
1550+ freePattern(psubInfo);
1551+ psubInfo->isPattern = 1;
1552+ while(subGetNextToken(psubFile)==tokenSeparater);
1553+ if(psubFile->token!=tokenLBrace) {
1554+ subFileErrPrint(psubFile,"Parse error, expecting {");
1555+ exit(1);
1556+ }
1557+ while(1) {
1558+ while(subGetNextToken(psubFile)==tokenSeparater);
1559+ if(psubFile->token!=tokenString) break;
1560+ ppatternNode = calloc(1,sizeof(patternNode));
1561+ ellAdd(&psubInfo->patternList,&ppatternNode->node);
1562+ ppatternNode->var = epicsStrDup(psubFile->string);
1563+ }
1564+ if(psubFile->token!=tokenRBrace) {
1565+ subFileErrPrint(psubFile,"Parse error, expecting }");
1566+ exit(1);
1567+ }
1568+ subGetNextToken(psubFile);
1569+ return(1);
1570+}
1571+
1572
1573+static char *substituteGetGlobalReplacements(subInfo *psubInfo)
1574+{
1575+ subFile *psubFile = psubInfo->psubFile;
1576+
1577+ if(psubInfo->macroReplacements) psubInfo->macroReplacements[0] = 0;
1578+ psubInfo->curLength = 0;
1579+ while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
1580+ if(psubFile->token==tokenRBrace && psubInfo->isFile) {
1581+ psubInfo->isFile = 0;
1582+ free(psubInfo->filename);
1583+ psubInfo->filename = 0;
1584+ freePattern(psubInfo);
1585+ subGetNextToken(psubFile);
1586+ return(0);
1587+ }
1588+ if(psubFile->token==tokenEOF) return(0);
1589+ if(psubFile->token!=tokenLBrace) return(0);
1590+ while(1) {
1591+ switch(subGetNextToken(psubFile)) {
1592+ case tokenRBrace:
1593+ subGetNextToken(psubFile);
1594+ if (!psubInfo->macroReplacements) {
1595+ catMacroReplacements(psubInfo,"");
1596+ }
1597+ return(psubInfo->macroReplacements);
1598+ case tokenSeparater:
1599+ catMacroReplacements(psubInfo,",");
1600+ break;
1601+ case tokenString:
1602+ catMacroReplacements(psubInfo,psubFile->string);
1603+ break;
1604+ default:
1605+ subFileErrPrint(psubFile,"Parse error, illegal token");
1606+ exit(1);
1607+ }
1608+ }
1609+}
1610+
1611+static char *substituteGetReplacements(subInfo *psubInfo)
1612+{
1613+ subFile *psubFile = psubInfo->psubFile;
1614+ patternNode *ppatternNode;
1615+
1616+ if(psubInfo->macroReplacements) psubInfo->macroReplacements[0] = 0;
1617+ psubInfo->curLength = 0;
1618+ while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
1619+ if(psubFile->token==tokenRBrace && psubInfo->isFile) {
1620+ psubInfo->isFile = 0;
1621+ free(psubInfo->filename);
1622+ psubInfo->filename = 0;
1623+ freePattern(psubInfo);
1624+ subGetNextToken(psubFile);
1625+ return(0);
1626+ }
1627+ if(psubFile->token==tokenEOF) return(0);
1628+ if(psubFile->token!=tokenLBrace) return(0);
1629+ if(psubInfo->isPattern) {
1630+ int gotFirstPattern = 0;
1631+
1632+ while(subGetNextToken(psubFile)==tokenSeparater);
1633+ ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList);
1634+ while(1) {
1635+ if(psubFile->token==tokenRBrace) {
1636+ subGetNextToken(psubFile);
1637+ return(psubInfo->macroReplacements);
1638+ }
1639+ if(psubFile->token!=tokenString) {
1640+ subFileErrPrint(psubFile,"Parse error, illegal token");
1641+ exit(-1);
1642+ }
1643+ if(gotFirstPattern) catMacroReplacements(psubInfo,",");
1644+ gotFirstPattern = 1;
1645+ if(ppatternNode) {
1646+ catMacroReplacements(psubInfo,ppatternNode->var);
1647+ catMacroReplacements(psubInfo,"=");
1648+ catMacroReplacements(psubInfo,psubFile->string);
1649+ ppatternNode = (patternNode *)ellNext(&ppatternNode->node);
1650+ } else {
1651+ subFileErrPrint(psubFile,"Warning, too many values given");
1652+ }
1653+ while(subGetNextToken(psubFile)==tokenSeparater);
1654+ }
1655+ } else while(1) {
1656+ switch(subGetNextToken(psubFile)) {
1657+ case tokenRBrace:
1658+ subGetNextToken(psubFile);
1659+ if (!psubInfo->macroReplacements) {
1660+ catMacroReplacements(psubInfo,"");
1661+ }
1662+ return(psubInfo->macroReplacements);
1663+ case tokenSeparater:
1664+ catMacroReplacements(psubInfo,",");
1665+ break;
1666+ case tokenString:
1667+ catMacroReplacements(psubInfo,psubFile->string);
1668+ break;
1669+ default:
1670+ subFileErrPrint(psubFile,"Parse error, illegal token");
1671+ exit(1);
1672+ }
1673+ }
1674+}
1675+
1676
1677+static char *subGetNextLine(subFile *psubFile)
1678+{
1679+ char *pline;
1680+
1681+ do {
1682+ pline = fgets(psubFile->inputBuffer,MAX_BUFFER_SIZE,psubFile->fp);
1683+ ++psubFile->lineNum;
1684+ } while(pline && psubFile->inputBuffer[0]=='#');
1685+ if(!pline) {
1686+ psubFile->token = tokenEOF;
1687+ psubFile->inputBuffer[0] = 0;
1688+ psubFile->pnextChar = 0;
1689+ return(0);
1690+ }
1691+ psubFile->pnextChar = &psubFile->inputBuffer[0];
1692+ return(&psubFile->inputBuffer[0]);
1693+}
1694+
1695+static void subFileErrPrint(subFile *psubFile,char * message)
1696+{
1697+ fprintf(stderr,"msi: %s\n",message);
1698+ fprintf(stderr," in substitution file '%s' at line %d:\n %s",
1699+ psubFile->substitutionName,
1700+ psubFile->lineNum,psubFile->inputBuffer);
1701+}
1702+
1703+
1704
1705+static tokenType subGetNextToken(subFile *psubFile)
1706+{
1707+ char *p;
1708+ char *pto;
1709+
1710+ p = psubFile->pnextChar;
1711+ if(!p) { psubFile->token = tokenEOF; return(tokenEOF);}
1712+ if(*p==0 || *p=='\n' || *p=='#') {
1713+ p = subGetNextLine(psubFile);
1714+ if(!p) { psubFile->token = tokenEOF; return(tokenEOF);}
1715+ else { psubFile->token = tokenSeparater; return(tokenSeparater);}
1716+ }
1717+ while(isspace(*p)) p++;
1718+ if(*p=='{') {
1719+ psubFile->token = tokenLBrace;
1720+ psubFile->pnextChar = ++p;
1721+ return(tokenLBrace);
1722+ }
1723+ if(*p=='}') {
1724+ psubFile->token = tokenRBrace;
1725+ psubFile->pnextChar = ++p;
1726+ return(tokenRBrace);
1727+ }
1728+ if(*p==0 || isspace(*p) || *p==',') {
1729+ while(isspace(*p) || *p==',') p++;
1730+ psubFile->token = tokenSeparater;
1731+ psubFile->pnextChar = p;
1732+ return(tokenSeparater);
1733+ }
1734+ /*now handle quoted strings*/
1735+ if(*p=='"') {
1736+ pto = &psubFile->string[0];
1737+ *pto++ = *p++;
1738+ while(*p!='"') {
1739+ if(*p==0 || *p=='\n') {
1740+ subFileErrPrint(psubFile,"Strings must be on single line\n");
1741+ exit(1);
1742+ }
1743+ /*allow escape for imbeded quote*/
1744+ if((*p=='\\') && *(p+1)=='"') {
1745+ *pto++ = *p++;
1746+ *pto++ = *p++;
1747+ continue;
1748+ }
1749+ *pto++ = *p++;
1750+ }
1751+ *pto++ = *p++;
1752+ psubFile->pnextChar = p;
1753+ *pto = 0;
1754+ psubFile->token = tokenString;
1755+ return(tokenString);
1756+ }
1757+ /*Now take anything up to next non String token and not space*/
1758+ pto = &psubFile->string[0];
1759+ while(!isspace(*p) && (strspn(p,"\",{}")==0)) *pto++ = *p++;
1760+ *pto = 0;
1761+ psubFile->pnextChar = p;
1762+ psubFile->token = tokenString;
1763+ return(tokenString);
1764+}
1765+
1766+static void catMacroReplacements(subInfo *psubInfo,const char *value)
1767+{
1768+ size_t len = strlen(value);
1769+
1770+ if(psubInfo->size <= (psubInfo->curLength + len)) {
1771+ size_t newsize = psubInfo->size + MAX_BUFFER_SIZE;
1772+ char *newbuf;
1773+
1774+ if(newsize <= psubInfo->curLength + len)
1775+ newsize = psubInfo->curLength + len + 1;
1776+ newbuf = calloc(1,newsize);
1777+ if(!newbuf) {
1778+ fprintf(stderr,"calloc failed for size %Zu\n",newsize);
1779+ exit(1);
1780+ }
1781+ if(psubInfo->macroReplacements) {
1782+ memcpy(newbuf,psubInfo->macroReplacements,psubInfo->curLength);
1783+ free(psubInfo->macroReplacements);
1784+ }
1785+ psubInfo->size = newsize;
1786+ psubInfo->macroReplacements = newbuf;
1787+ }
1788+ strcat(psubInfo->macroReplacements,value);
1789+ psubInfo->curLength += len;
1790+}
1791
1792=== added file 'src/ioc/dbtemplate/msi.html'
1793--- src/ioc/dbtemplate/msi.html 1970-01-01 00:00:00 +0000
1794+++ src/ioc/dbtemplate/msi.html 2012-06-01 20:39:23 +0000
1795@@ -0,0 +1,438 @@
1796+<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en">
1797+<html>
1798+<head>
1799+ <title></title>
1800+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
1801+</head>
1802+
1803+<body>
1804+
1805+<h1>msi: Macro Substitution and Include Tool</h1>
1806+
1807+<h2>Introduction</h2>
1808+
1809+<p>msi is a general purpose macro substitution/include tool. It accepts as input
1810+an ascii template file. It looks for lines containing two reserved command
1811+names: <tt>include</tt> and <tt>substitute</tt>. It also looks for and performs
1812+substitutions on macros of the form $(var) and ${var}. It uses the macLib
1813+routines from EPICS Base to perform the substitutions, so it also accepts the
1814+default value and value definition syntax that macLib implements.</p>
1815+
1816+<p>msi also allows substitutions to be specified via a separate substitution
1817+file. This substitution file allows the same format as the substitution files
1818+accepted by the EPICS IOC's dbLoadTemplate command.</p>
1819+
1820+<h2>Command Syntax:</h2>
1821+
1822+<pre>msi -V -g -o<i>outfile</i> -I<i>dir</i> -M<i>subs</i> -S<i>subfile</i> <i>template</i></pre>
1823+
1824+<p>All parameters are optional. The -o, -I, -M, and -S switches may be
1825+separated from their associated value string by spaces if desired. Output will
1826+be written to stdout unless the -o option is given.</p>
1827+
1828+<p>Switches have the following meanings:</p>
1829+
1830+<dl>
1831+ <dt><tt>-V</tt></dt>
1832+ <dd>Verbose warnings; if this parameter is specified then any undefined
1833+ macro discovered in the template file which does not have an associated
1834+ default value is considered an error. An error message is generated, and
1835+ when msi terminates it will do so with an exit status of 2.</dd>
1836+
1837+ <dt><tt>-g</tt></dt>
1838+ <dd>When this flag is given all macros defined in a substitution file will
1839+ have global scope and thus their values will persist until a new value is
1840+ given for this macro. This flag is provided for backwards compatibility as
1841+ this was the behavior of previous versions of msi, but it does not follow
1842+ common scoping rules and is discouraged.</dd>
1843+
1844+ <dt><tt>-o</tt> <i>file</i></dt>
1845+ <dd>Output will be written to the specifed file rather than to the standard
1846+ output.</dd>
1847+
1848+ <dt><tt>-I</tt> <i>dir</i></dt>
1849+ <dd>This parameter, which may be repeated or contain a colon-separated (or
1850+ semi-colon separated on Windows) list of directory paths, specifies a search
1851+ path for include commands. For example:
1852+
1853+ <blockquote>
1854+ <pre>msi -I /home/mrk/examples:. -I.. template</pre>
1855+ </blockquote>
1856+
1857+ specifies that all named files should be searched for in the following
1858+ locations in the order given:
1859+
1860+ <ol>
1861+ <li><tt>/home/mrk/examples</tt></li>
1862+ <li><tt>.</tt> (the current directory)</li>
1863+ <li><tt>..</tt> (the parent of the current directory)</li>
1864+ </ol>
1865+ </dd>
1866+
1867+ <dt><tt>-M</tt> <i>substitutions</i></dt>
1868+ <dd>This parameter specifies macro values for the template instance.
1869+ Multiple macro values can be specified in one substitution parameter, or in
1870+ multiple <tt>-M</tt> parameters. For example:
1871+
1872+ <blockquote>
1873+ <pre>msi -M "a=aval,b=bval" -Mc=cval template</pre>
1874+ </blockquote>
1875+
1876+ specifies that in the template file each occurrence of:
1877+
1878+ <dl>
1879+ <dd><tt>$(a)</tt> or <tt>${a}</tt> is replaced by <tt>aval</tt></dd>
1880+ <dd><tt>$(b)</tt> or <tt>${b}</tt> is replaced by <tt>bval</tt></dd>
1881+ <dd><tt>$(c)</tt> or <tt>${c}</tt> is replaced by <tt>cval</tt></dd>
1882+ </dl>
1883+ </dd>
1884+
1885+ <dt><tt>-S</tt> <i>subfile</i></dt>
1886+ <dd>The substitution file. See below for format.</dd>
1887+
1888+ <dt><i>template</i></dt>
1889+ <dd> The input file. If no file is specified then input is taken from
1890+ stdin, i.e. msi can be used as a filter. See below for a description of
1891+ commands that can be embedded in the template file.</dd>
1892+</dl>
1893+
1894+<p>It is not possible to display usage by just typing <tt>msi</tt> since
1895+executing the command with no arguments is a valid command. To show usage
1896+specify an illegal switch, e.g.</p>
1897+
1898+<blockquote>
1899+<pre>msi -help</pre>
1900+</blockquote>
1901+
1902+<h2>Exit Status</h2>
1903+
1904+<dl>
1905+ <dt>0<dd>Success.
1906+ <dt>1<dd>Can't open/create file, or other I/O error.
1907+ <dt>2<dd>Undefined macros encountered with the <tt>-V</tt> option specified.
1908+</dl>
1909+
1910+<h2>Template File Format</h2>
1911+
1912+<p>This file contains the text to be read and written to the output after macro
1913+substitution is performed. If no file is given then input is read from stdin.
1914+Variable instances to be substituted by macro values are expressed in the
1915+template using the syntax <tt>$(</tt><i>name</i><tt>)</tt> or
1916+<tt>${</tt><i>name</i><tt>}</tt>. The template can also provide default values
1917+to be used when a macro has not been given a value, using the syntax
1918+<tt>$(</tt><i>name</i><tt>=</tt><i>default</i><tt>)</tt> or
1919+<tt>${</tt><i>name</i><tt>=</tt><i>default</i><tt>}</tt>.</p>
1920+
1921+<p>For example, using the command</p>
1922+
1923+<blockquote>
1924+<pre>msi -M name=Marty template</pre>
1925+</blockquote>
1926+
1927+<p>where the file template contains</p>
1928+
1929+<blockquote>
1930+<pre>My name is $(name)
1931+My age is $(age=none of your business)</pre>
1932+</blockquote>
1933+
1934+<p>results in this output:</p>
1935+
1936+<blockquote>
1937+<pre>My name is Marty
1938+My age is none of your business</pre>
1939+</blockquote>
1940+
1941+<p>Macro variables and their default values can be expressed in terms of other
1942+macros if necessary, to almost any level of complexity. Recursive definitions
1943+will generate warning messages on stderr and result in undefined output.</p>
1944+
1945+<p>The template file is read and processed one line at a time, where the
1946+maximum length of a line before and/or after macro expansion is 1023 characters
1947+&mdash; longer input or output lines will cause msi to fail. Within the context
1948+of a single line, macro expansion does not occur when the variable instance
1949+appears inside a single-quoted string, or where the dollar sign <tt>$</tt> is
1950+preceded by a back-slash character <tt>\</tt>, but as with the standard Unix
1951+shells, variables inside double quoted strings are expanded properly.</p>
1952+
1953+<p>However neither back-slash characters nor quotes of either variety are
1954+removed when generating the output file, so depending on what is being output
1955+the single quote behaviour may not be useful and may even be a hinderance. It
1956+cannot be disabled in the current version of msi.</p>
1957+
1958+<h3>Template file commands</h3>
1959+
1960+<p>In addition to the regular text and variable instances described above, the
1961+template file may also contain commands which allow the insertion of other
1962+template files and the ability to set macro values inside the template file
1963+itself. These commands are:</p>
1964+
1965+<blockquote>
1966+<pre>include "file"
1967+substitute "var=value,var=value,..."</pre>
1968+</blockquote>
1969+
1970+<p>Lines containing commands must be in one of these forms:</p>
1971+
1972+<ul>
1973+ <li><tt>include "</tt><i>filename</i><tt>"</tt></li>
1974+ <li><tt>substitute "</tt><i>name1=value1, name2=value2, ...</i><tt>"</tt></li>
1975+</ul>
1976+
1977+<p>White space is allowed before and after the command verb, and after the
1978+quoted string. If embedded quotes are needed, the backslash character
1979+<tt>\</tt> can be used as an escape character. For example</p>
1980+
1981+<blockquote>
1982+<pre>substitute "a=\"val\""</pre>
1983+</blockquote>
1984+
1985+<p>specifies that (unless <tt>a</tt> is subsequently redefined) wherever a
1986+<tt>$(a)</tt> macro appears in the template below this point, the text
1987+<tt>"val"</tt> (including the double quote characters) will appear in the
1988+output instead.</p>
1989+
1990+<p>If a line does match either syntax above it is just passed to macLib for
1991+processing without any notification. Thus the input line:</p>
1992+
1993+<blockquote>
1994+<pre>include "myfile" #include file</pre>
1995+</blockquote>
1996+
1997+<p>would just be passed to macLib, i.e. it would <em>not</em> be considered an
1998+include command.</p>
1999+
2000+<p>As an example of these commands, let the Unix command be:</p>
2001+
2002+<blockquote>
2003+<pre>msi template</pre>
2004+</blockquote>
2005+
2006+<p>and file includeFile contain:</p>
2007+
2008+<blockquote>
2009+<pre>first name is ${first}
2010+family name is ${family}</pre>
2011+</blockquote>
2012+
2013+<p>and template is</p>
2014+
2015+<blockquote>
2016+<pre>substitute "first=Marty,family=Kraimer"
2017+include "includeFile"
2018+substitute "first=Irma,family=Kraimer"
2019+include "includeFile"</pre>
2020+</blockquote>
2021+
2022+<p>then the following is written to the output.</p>
2023+
2024+<blockquote>
2025+<pre>first name is Marty
2026+family name is Kraimer
2027+first name is Irma
2028+family name is Kraimer</pre>
2029+</blockquote>
2030+
2031+<p>Note that the IOC's <tt>dbLoadTemplate</tt> command does not support the
2032+<tt>substitute</tt> syntax in template files, although the <tt>include</tt>
2033+syntax is supported.</p>
2034+
2035+<h2>Substitution File Format</h2>
2036+
2037+<p>The optional substitution file has three formats: regular, pattern, and
2038+dbTemplate format. We will discuss each separately.</p>
2039+
2040+<h3>Regular format</h3>
2041+
2042+<blockquote>
2043+<pre>global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
2044+{var1=set1_val1, var2=set1_val2, ...}
2045+{var2=set2_val2, var1=set2_val1, ...}
2046+global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
2047+{var1=set3_val1, var2=set3_val2, ...}
2048+{var2=set4_val2, var1=set4_val1, ...}</pre>
2049+</blockquote>
2050+
2051+<p>The template file is output with macro substitutions performed once for each
2052+set of braces containing macro replacement values.</p>
2053+
2054+<h3>Pattern format</h3>
2055+
2056+<blockquote>
2057+<pre>global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
2058+pattern {var1, var2, ...}
2059+{set1_val1, set1_val2, ...}
2060+{set2_val1, set2_val2, ...}
2061+pattern {var2, var1, ...}
2062+global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
2063+{set3_val2, set3_val1, ...}
2064+{set4_val2, set4_val2, ...}</pre>
2065+</blockquote>
2066+
2067+<p>This produces the same result as the regular format example above.</p>
2068+
2069+<h3>dbLoadTemplate Format</h3>
2070+
2071+<p>This format is an extension of the format accepted by the EPICS IOC command
2072+<tt>dbLoadTemplate</tt>, and allows templates to be expanded on the host rather
2073+by using dbLoadTemplate at IOC boot time.</p>
2074+
2075+<blockquote>
2076+<pre>global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
2077+file templatefile {
2078+ <i>pattern format or regular format</i>
2079+}
2080+file "${WHERE}/template2" {
2081+ <i>pattern format or regular format</i>
2082+}</pre>
2083+</blockquote>
2084+
2085+<p>For the dbTemplate format, the template filename does not have to be given
2086+on the command line, and is usually specified in the substitutions file
2087+instead. If a template filename is given on the command line it will override
2088+the filenames listed in the substitutions files.</p>
2089+
2090+<h3>Syntax for all formats</h3>
2091+
2092+<p>A comment line may appear anywhere in a substitution file, and will be
2093+ignored. A comment line is any line beginning with the character <tt>#</tt>,
2094+which must be the very first character on the line.</p>
2095+
2096+<p>Global definitions may supplement or override the macro values supplied on
2097+the command-line using the <tt>-M</tt> switch, and set default values that will
2098+survive for the remainder of the file unless another global definition of the
2099+same macro changes it.</p>
2100+
2101+<p>For definitions within braces given in any of the file formats, a separator
2102+must be given between items. A separator is either a comma, or one or more of
2103+the standard white space characters (space, formfeed, newline, carriage return,
2104+tab or vertical tab).</p>
2105+
2106+<p>Each item within braces can be an alphanumeric token, or a double-quoted
2107+string. A back-slash character <tt>\</tt> can be used to escape a quote
2108+character needed inside a quoted string. These three sets of substitutions are
2109+all equivalent:</p>
2110+
2111+<blockquote>
2112+<pre>{a=aa b=bb c="\"cc\""}
2113+{b="bb",a=aa,c="\"cc\""}
2114+{
2115+ c="\"cc\""
2116+ b=bb
2117+ a="aa"
2118+}</pre>
2119+</blockquote>
2120+
2121+<p>Within a substitutions file, the file name may appear inside double quotation
2122+marks; these are required if the name contains certain characters or environment
2123+variable macros of the form ${ENV_VAR} or $(ENV_VAR), which will be expanded
2124+before the file is opened.</p>
2125+
2126+<h3>Regular substitution example</h3>
2127+
2128+<p>Let the command be:</p>
2129+
2130+<blockquote>
2131+<pre>msi -S substitute template</pre>
2132+</blockquote>
2133+
2134+<p>The file <tt>template</tt> contains</p>
2135+
2136+<blockquote>
2137+<pre>first name is ${first}
2138+family name is ${family}</pre>
2139+</blockquote>
2140+
2141+<p> and the file <tt>substitute</tt> is</p>
2142+
2143+<blockquote>
2144+<pre>global {family=Kraimer}
2145+{first=Marty}
2146+{first=Irma}</pre>
2147+</blockquote>
2148+
2149+<p>The following is the output produced:</p>
2150+
2151+<blockquote>
2152+<pre>first name is Marty
2153+family name is Kraimer
2154+first name is Irma
2155+family name is Kraimer</pre>
2156+</blockquote>
2157+
2158+<h3>Pattern substitution example</h3>
2159+
2160+<p>Let the command be:</p>
2161+
2162+<blockquote>
2163+<pre>msi -S pattern template</pre>
2164+</blockquote>
2165+
2166+<p>The file <tt>pattern</tt> contains</p>
2167+
2168+<blockquote>
2169+<pre>pattern {first,last}
2170+{Marty,Kraimer}
2171+{Irma,Kraimer}</pre>
2172+</blockquote>
2173+
2174+<p>and <tt>template</tt> is the same as the previous example:</p>
2175+
2176+<blockquote>
2177+<pre>first name is ${first}
2178+family name is ${family}</pre>
2179+</blockquote>
2180+
2181+<p>This is the output:</p>
2182+
2183+<blockquote>
2184+<pre>first name is Marty
2185+family name is Kraimer
2186+first name is Irma
2187+family name is Kraimer</pre>
2188+</blockquote>
2189+
2190+<h3>dbTemplate example</h3>
2191+Let the command be
2192+
2193+<blockquote>
2194+<pre>msi -S xxx.substitutions</pre>
2195+</blockquote>
2196+
2197+<tt>xxx.substitutions</tt> is
2198+
2199+<blockquote>
2200+<pre>file template {
2201+pattern {first,last}
2202+{Marty,Kraimer}
2203+{Irma,Kraimer}
2204+pattern {last,first}
2205+{Smith,Bill}
2206+{Smith,Mary}
2207+}
2208+file template {
2209+{first=Marty,last=Kraimer}
2210+{first=Irma,last=Kraimer}
2211+}</pre>
2212+</blockquote>
2213+<tt>template</tt> is the same as in the previous example..
2214+
2215+<p>The following is written to the output</p>
2216+
2217+<blockquote>
2218+<pre>first name is Marty
2219+family name is Kraimer
2220+first name is Irma
2221+family name is Kraimer
2222+first name is Bill
2223+last name is Smith
2224+first name is Mary
2225+last name is Smith
2226+first name is Marty
2227+family name is Kraimer
2228+first name is Irma
2229+family name is Kraimer</pre>
2230+</blockquote>
2231+
2232+</body>
2233+</html>
2234
2235=== added directory 'src/ioc/dbtemplate/test'
2236=== added file 'src/ioc/dbtemplate/test/Makefile'
2237--- src/ioc/dbtemplate/test/Makefile 1970-01-01 00:00:00 +0000
2238+++ src/ioc/dbtemplate/test/Makefile 2012-06-01 20:39:23 +0000
2239@@ -0,0 +1,21 @@
2240+#*************************************************************************
2241+# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
2242+# National Laboratory.
2243+# EPICS BASE is distributed subject to a Software License Agreement found
2244+# in the file LICENSE that is included with this distribution.
2245+#*************************************************************************
2246+TOP=../../..
2247+
2248+include $(TOP)/configure/CONFIG
2249+
2250+TESTPROD_HOST_DEFAULT = dbltExpand
2251+TESTPROD_HOST_WIN32 = -nil-
2252+dbltExpand_SRCS += dbltExpand.c
2253+dbltExpand_LIBS += dbtoolsIoc dbStaticHost Com
2254+
2255+TESTS += msi
2256+
2257+TESTSCRIPTS_HOST += $(TESTS:%=%.t)
2258+
2259+include $(TOP)/configure/RULES
2260+
2261
2262=== added file 'src/ioc/dbtemplate/test/dbltExpand.c'
2263--- src/ioc/dbtemplate/test/dbltExpand.c 1970-01-01 00:00:00 +0000
2264+++ src/ioc/dbtemplate/test/dbltExpand.c 2012-06-01 20:39:23 +0000
2265@@ -0,0 +1,100 @@
2266+/*************************************************************************\
2267+* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne
2268+* National Laboratory.
2269+* EPICS Base is distributed subject to a Software License Agreement found
2270+* in the file LICENSE that is included with this distribution.
2271+\*************************************************************************/
2272+
2273+/* This is a simple version of msi for testing the dbLoadTemplate() code.
2274+ *
2275+ * It calls dbLoadTemplate() to parse the substitution file, but replaces
2276+ * dbLoadRecords() with its own version that reads the template file,
2277+ * expands any macros in the text and prints the result to stdout.
2278+ *
2279+ * This technique won't work on Windows, dbLoadRecords() has to be
2280+ * epicsShare... decorated and loaded from a shared library.
2281+ */
2282+
2283+#include <stdio.h>
2284+#include <stdlib.h>
2285+#include <string.h>
2286+#include <errno.h>
2287+
2288+#include "macLib.h"
2289+#include "dbLoadTemplate.h"
2290+
2291+
2292+#define BUFFER_SIZE 0x10000
2293+
2294+static char *input_buffer, *output_buffer;
2295+
2296+int dbLoadRecords(const char *file, const char *macros)
2297+{
2298+ MAC_HANDLE *macHandle = NULL;
2299+ char **macPairs;
2300+ FILE *fp;
2301+ size_t input_len;
2302+
2303+ if (macCreateHandle(&macHandle, NULL)) {
2304+ fprintf(stderr, "macCreateHandle failed\n");
2305+ exit(1);
2306+ }
2307+
2308+ macSuppressWarning(macHandle, 1);
2309+ macParseDefns(macHandle, macros, &macPairs);
2310+ if (!macPairs) {
2311+ macDeleteHandle(macHandle);
2312+ macHandle = NULL;
2313+ } else {
2314+ macInstallMacros(macHandle, macPairs);
2315+ free(macPairs);
2316+ }
2317+
2318+ fp = fopen(file, "r");
2319+ if (!fp) {
2320+ fprintf(stderr, "fopen('%s') failed: %s\n", file, strerror(errno));
2321+ exit(1);
2322+ }
2323+
2324+ input_len = fread(input_buffer, 1, BUFFER_SIZE, fp);
2325+ if (!feof(fp)) {
2326+ fprintf(stderr, "input file > 64K!\n");
2327+ fclose(fp);
2328+ exit(1);
2329+ }
2330+ input_buffer[input_len] = 0;
2331+
2332+ if (fclose(fp)) {
2333+ fprintf(stderr, "fclose('%s') failed: %s\n", file, strerror(errno));
2334+ exit(1);
2335+ }
2336+
2337+ macExpandString(macHandle, input_buffer, output_buffer, BUFFER_SIZE-1);
2338+ printf(output_buffer);
2339+
2340+ if (macHandle) macDeleteHandle(macHandle);
2341+
2342+ return 0;
2343+}
2344+
2345+int main(int argc, char **argv)
2346+{
2347+ input_buffer = malloc(BUFFER_SIZE);
2348+ output_buffer = malloc(BUFFER_SIZE);
2349+
2350+ if (!input_buffer || !output_buffer) {
2351+ fprintf(stderr, "malloc(%d) failed\n", BUFFER_SIZE);
2352+ exit(1);
2353+ }
2354+
2355+ if (argc != 2) {
2356+ fprintf(stderr, "Usage: %s file.sub\n", argv[0]);
2357+ exit(1);
2358+ }
2359+
2360+ dbLoadTemplate(argv[1], NULL);
2361+
2362+ free(output_buffer);
2363+ free(input_buffer);
2364+ return 0;
2365+}
2366
2367=== added file 'src/ioc/dbtemplate/test/msi.plt'
2368--- src/ioc/dbtemplate/test/msi.plt 1970-01-01 00:00:00 +0000
2369+++ src/ioc/dbtemplate/test/msi.plt 2012-06-01 20:39:23 +0000
2370@@ -0,0 +1,48 @@
2371+#!/usr/bin/perl
2372+#*************************************************************************
2373+# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
2374+# National Laboratory.
2375+# EPICS BASE is distributed subject to a Software License Agreement found
2376+# in file LICENSE that is included with this distribution.
2377+#*************************************************************************
2378+
2379+# Script to run tests on the msi program
2380+
2381+use FindBin qw($Bin); # To find the msi executable
2382+
2383+use strict;
2384+use Test;
2385+
2386+BEGIN {plan tests => 7}
2387+
2388+ok(msi('-I .. ../t1-template.txt'), slurp('../t1-result.txt'));
2389+ok(msi('-I.. -S ../t2-substitution.txt'), slurp('../t2-result.txt'));
2390+ok(msi('-I. -I.. -S ../t3-substitution.txt'), slurp('../t3-result.txt'));
2391+ok(msi('-g -I.. -S ../t4-substitution.txt'), slurp('../t4-result.txt'));
2392+ok(msi('-S ../t5-substitute.txt ../t5-template.txt'), slurp('../t5-result.txt'));
2393+ok(msi('-S ../t6-substitute.txt ../t6-template.txt'), slurp('../t6-result.txt'));
2394+
2395+# Check -o works
2396+my $out = 't7-output.txt';
2397+unlink $out;
2398+msi("-I.. -o $out ../t1-template.txt");
2399+ok(slurp($out), slurp('../t1-result.txt'));
2400+
2401+
2402+# Support routines
2403+
2404+sub slurp {
2405+ my ($file) = @_;
2406+ open my $in, '<', $file
2407+ or die "Can't open file $file: $!\n";
2408+ my $contents = do { local $/; <$in> };
2409+ return $contents;
2410+}
2411+
2412+sub msi {
2413+ my ($args) = @_;
2414+ my $arch = $ENV{EPICS_HOST_ARCH};
2415+ my $exe = ($^O eq 'MSWin32') || ($^O eq 'cygwin') ? '.exe' : '';
2416+ my $msi = "$Bin/../../O.$arch/msi$exe";
2417+ return `$msi $args`;
2418+}
2419
2420=== added file 'src/ioc/dbtemplate/test/t1-include.txt'
2421--- src/ioc/dbtemplate/test/t1-include.txt 1970-01-01 00:00:00 +0000
2422+++ src/ioc/dbtemplate/test/t1-include.txt 2012-06-01 20:39:23 +0000
2423@@ -0,0 +1,5 @@
2424+This is t1-include.txt $(include-file-again=)
2425+ a = $(a=default value used when a is undefined)
2426+ b = $(b=default value used when b is undefined)
2427+substitute "include-file-again=again"
2428+End of t1-include.txt
2429
2430=== added file 'src/ioc/dbtemplate/test/t1-result.txt'
2431--- src/ioc/dbtemplate/test/t1-result.txt 1970-01-01 00:00:00 +0000
2432+++ src/ioc/dbtemplate/test/t1-result.txt 2012-06-01 20:39:23 +0000
2433@@ -0,0 +1,21 @@
2434+This is t1-template.txt
2435+
2436+With $(a,undefined) & $(b,undefined):
2437+This is t1-include.txt
2438+ a = default value used when a is undefined
2439+ b = default value used when b is undefined
2440+End of t1-include.txt
2441+
2442+On defining a=aaa & b=bbb:
2443+This is t1-include.txt again
2444+ a = aaa
2445+ b = bbb
2446+End of t1-include.txt
2447+
2448+On setting a="aa":
2449+This is t1-include.txt again
2450+ a = "aa"
2451+ b = bbb
2452+End of t1-include.txt
2453+
2454+End of t1-template.txt
2455
2456=== added file 'src/ioc/dbtemplate/test/t1-template.txt'
2457--- src/ioc/dbtemplate/test/t1-template.txt 1970-01-01 00:00:00 +0000
2458+++ src/ioc/dbtemplate/test/t1-template.txt 2012-06-01 20:39:23 +0000
2459@@ -0,0 +1,14 @@
2460+This is t1-template.txt
2461+
2462+With $(a) & ${b}:
2463+include "t1-include.txt"
2464+
2465+substitute "a=aaa,b=bbb"
2466+On defining a=$(a) & b=${b}:
2467+include "t1-include.txt"
2468+
2469+substitute "a=\"aa\""
2470+On setting a=$(a):
2471+include "t1-include.txt"
2472+
2473+End of t1-template.txt
2474
2475=== added file 'src/ioc/dbtemplate/test/t2-result.txt'
2476--- src/ioc/dbtemplate/test/t2-result.txt 1970-01-01 00:00:00 +0000
2477+++ src/ioc/dbtemplate/test/t2-result.txt 2012-06-01 20:39:23 +0000
2478@@ -0,0 +1,6 @@
2479+a = va1-a b = def-b c = def-c d = $(d,undefined)
2480+a = va2-a b = va2-b c = def-c d = $(d,undefined)
2481+a = va3-a b = va3-b c = va3-c d = $(d,undefined)
2482+a = va4-a b = va4-b c = def-c d = $(d,undefined)
2483+a = va5-a b = def-b c = def-c d = $(d,undefined)
2484+a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined)
2485
2486=== added file 'src/ioc/dbtemplate/test/t2-substitution.txt'
2487--- src/ioc/dbtemplate/test/t2-substitution.txt 1970-01-01 00:00:00 +0000
2488+++ src/ioc/dbtemplate/test/t2-substitution.txt 2012-06-01 20:39:23 +0000
2489@@ -0,0 +1,11 @@
2490+file t2-template.txt {
2491+ {a=va1-a}
2492+ {a=va2-a, b=va2-b}
2493+ {a=va3-a, b=va3-b, c=va3-c}
2494+ {a=va4-a, b=va4-b}
2495+ {a=va5-a}
2496+}
2497+file t2-template.txt {
2498+ pattern {a, b, c}
2499+ {pt3-a, pt3-b, pt3-c}
2500+}
2501
2502=== added file 'src/ioc/dbtemplate/test/t2-template.txt'
2503--- src/ioc/dbtemplate/test/t2-template.txt 1970-01-01 00:00:00 +0000
2504+++ src/ioc/dbtemplate/test/t2-template.txt 2012-06-01 20:39:23 +0000
2505@@ -0,0 +1,1 @@
2506+a = $(a=def-a) b = $(b=def-b) c = $(c=def-c) d = $(d,undef)
2507
2508=== added file 'src/ioc/dbtemplate/test/t3-result.txt'
2509--- src/ioc/dbtemplate/test/t3-result.txt 1970-01-01 00:00:00 +0000
2510+++ src/ioc/dbtemplate/test/t3-result.txt 2012-06-01 20:39:23 +0000
2511@@ -0,0 +1,28 @@
2512+a = gb1-a b = gb1-b c = def-c d = $(d,undefined)
2513+a = va1-a b = gb1-b c = def-c d = $(d,undefined)
2514+a = va2-a b = va2-b c = def-c d = $(d,undefined)
2515+a = va3-a b = va3-b c = va3-c d = $(d,undefined)
2516+a = va4-a b = va4-b c = def-c d = $(d,undefined)
2517+a = va5-a b = gb1-b c = def-c d = $(d,undefined)
2518+a = gb1-a b = gb1-b c = def-c d = $(d,undefined)
2519+a = gb2-a b = gb2-b c = def-c d = $(d,undefined)
2520+a = va1-a b = gb2-b c = def-c d = $(d,undefined)
2521+a = va2-a b = va2-b c = def-c d = $(d,undefined)
2522+a = va3-a b = va3-b c = va3-c d = $(d,undefined)
2523+a = va4-a b = va4-b c = def-c d = $(d,undefined)
2524+a = va5-a b = gb2-b c = def-c d = $(d,undefined)
2525+a = gb2-a b = gb2-b c = def-c d = $(d,undefined)
2526+a = gb3-a b = gb3-b c = def-c d = $(d,undefined)
2527+a = pt1-a b = gb3-b c = def-c d = $(d,undefined)
2528+a = pt2-a b = pt2-b c = def-c d = $(d,undefined)
2529+a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined)
2530+a = pt4-a b = pt4-b c = def-c d = $(d,undefined)
2531+a = pt5-a b = gb3-b c = def-c d = $(d,undefined)
2532+a = gb3-a b = gb3-b c = def-c d = $(d,undefined)
2533+a = gb4-a b = gb4-b c = def-c d = $(d,undefined)
2534+a = pt1-a b = gb4-b c = def-c d = $(d,undefined)
2535+a = pt2-a b = pt2-b c = def-c d = $(d,undefined)
2536+a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined)
2537+a = pt4-a b = pt4-b c = def-c d = $(d,undefined)
2538+a = pt5-a b = gb4-b c = def-c d = $(d,undefined)
2539+a = gb4-a b = gb4-b c = def-c d = $(d,undefined)
2540
2541=== added file 'src/ioc/dbtemplate/test/t3-substitution.txt'
2542--- src/ioc/dbtemplate/test/t3-substitution.txt 1970-01-01 00:00:00 +0000
2543+++ src/ioc/dbtemplate/test/t3-substitution.txt 2012-06-01 20:39:23 +0000
2544@@ -0,0 +1,37 @@
2545+global {a=gb1-a, b=gb1-b}
2546+file t3-template.txt {
2547+ {}
2548+ {a=va1-a}
2549+ {a=va2-a, b=va2-b}
2550+ {a=va3-a, b=va3-b, c=va3-c}
2551+ {a=va4-a, b=va4-b}
2552+ {a=va5-a}
2553+ {}
2554+ global {a=gb2-a, b=gb2-b}
2555+ {}
2556+ {a=va1-a}
2557+ {a=va2-a, b=va2-b}
2558+ {a=va3-a, b=va3-b, c=va3-c}
2559+ {a=va4-a, b=va4-b}
2560+ {a=va5-a}
2561+ {}
2562+}
2563+global {b=gb3-b, a=gb3-a}
2564+file t3-template.txt {
2565+ pattern {a, b, c}
2566+ {}
2567+ {pt1-a}
2568+ {pt2-a, pt2-b}
2569+ {pt3-a, pt3-b, pt3-c}
2570+ {pt4-a, pt4-b}
2571+ {pt5-a}
2572+ {}
2573+ global {b=gb4-b, a=gb4-a}
2574+ {}
2575+ {pt1-a}
2576+ {pt2-a, pt2-b}
2577+ {pt3-a, pt3-b, pt3-c}
2578+ {pt4-a, pt4-b}
2579+ {pt5-a}
2580+ {}
2581+}
2582
2583=== added file 'src/ioc/dbtemplate/test/t3-template.txt'
2584--- src/ioc/dbtemplate/test/t3-template.txt 1970-01-01 00:00:00 +0000
2585+++ src/ioc/dbtemplate/test/t3-template.txt 2012-06-01 20:39:23 +0000
2586@@ -0,0 +1,1 @@
2587+a = $(a=def-a) b = $(b=def-b) c = $(c=def-c) d = $(d,undef)
2588
2589=== added file 'src/ioc/dbtemplate/test/t4-result.txt'
2590--- src/ioc/dbtemplate/test/t4-result.txt 1970-01-01 00:00:00 +0000
2591+++ src/ioc/dbtemplate/test/t4-result.txt 2012-06-01 20:39:23 +0000
2592@@ -0,0 +1,6 @@
2593+a = va1-a b = def-b c = def-c d = $(d,undefined)
2594+a = va2-a b = va2-b c = def-c d = $(d,undefined)
2595+a = va3-a b = va3-b c = va3-c d = $(d,undefined)
2596+a = va4-a b = va4-b c = va3-c d = $(d,undefined)
2597+a = va5-a b = va4-b c = va3-c d = $(d,undefined)
2598+a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined)
2599
2600=== added file 'src/ioc/dbtemplate/test/t4-substitution.txt'
2601--- src/ioc/dbtemplate/test/t4-substitution.txt 1970-01-01 00:00:00 +0000
2602+++ src/ioc/dbtemplate/test/t4-substitution.txt 2012-06-01 20:39:23 +0000
2603@@ -0,0 +1,11 @@
2604+file t2-template.txt {
2605+ {a=va1-a}
2606+ {a=va2-a, b=va2-b}
2607+ {a=va3-a, b=va3-b, c=va3-c}
2608+ {a=va4-a, b=va4-b}
2609+ {a=va5-a}
2610+}
2611+file t2-template.txt {
2612+ pattern {a, b, c}
2613+ {pt3-a, pt3-b, pt3-c}
2614+}
2615
2616=== added file 'src/ioc/dbtemplate/test/t5-result.txt'
2617--- src/ioc/dbtemplate/test/t5-result.txt 1970-01-01 00:00:00 +0000
2618+++ src/ioc/dbtemplate/test/t5-result.txt 2012-06-01 20:39:23 +0000
2619@@ -0,0 +1,20 @@
2620+# comment line
2621+a = 111
2622+b = 222
2623+c = xx
2624+d = $(d,undefined)
2625+# comment line
2626+a = aaa
2627+b = bbb
2628+c = ccc
2629+d = $(d,undefined)
2630+# comment line
2631+a = AA
2632+b = BB
2633+c = xx
2634+d = $(d,undefined)
2635+# comment line
2636+a = aaa
2637+b = bbb
2638+c = yy
2639+d = $(d,undefined)
2640
2641=== added file 'src/ioc/dbtemplate/test/t5-substitute.txt'
2642--- src/ioc/dbtemplate/test/t5-substitute.txt 1970-01-01 00:00:00 +0000
2643+++ src/ioc/dbtemplate/test/t5-substitute.txt 2012-06-01 20:39:23 +0000
2644@@ -0,0 +1,9 @@
2645+global {c=xx}
2646+{a=111,b="222"}
2647+{ a = aaa , b=bbb , c = ccc}
2648+{a=AA,b='BB'}
2649+global { c = yy }
2650+{
2651+ a= aaa
2652+ b= bbb
2653+}
2654
2655=== added file 'src/ioc/dbtemplate/test/t5-template.txt'
2656--- src/ioc/dbtemplate/test/t5-template.txt 1970-01-01 00:00:00 +0000
2657+++ src/ioc/dbtemplate/test/t5-template.txt 2012-06-01 20:39:23 +0000
2658@@ -0,0 +1,5 @@
2659+# comment line
2660+a = $(a)
2661+b = $(b)
2662+c = $(c)
2663+d = $(d)
2664
2665=== added file 'src/ioc/dbtemplate/test/t6-result.txt'
2666--- src/ioc/dbtemplate/test/t6-result.txt 1970-01-01 00:00:00 +0000
2667+++ src/ioc/dbtemplate/test/t6-result.txt 2012-06-01 20:39:23 +0000
2668@@ -0,0 +1,20 @@
2669+# comment line
2670+a = 111
2671+b = 222
2672+c = xx
2673+d = $(d,undefined)
2674+# comment line
2675+a = aaa
2676+b = bbb
2677+c = ccc
2678+d = $(d,undefined)
2679+# comment line
2680+a = AA
2681+b = BB
2682+c = xx
2683+d = $(d,undefined)
2684+# comment line
2685+a = aaa
2686+b = bbb
2687+c = yy
2688+d = $(d,undefined)
2689
2690=== added file 'src/ioc/dbtemplate/test/t6-substitute.txt'
2691--- src/ioc/dbtemplate/test/t6-substitute.txt 1970-01-01 00:00:00 +0000
2692+++ src/ioc/dbtemplate/test/t6-substitute.txt 2012-06-01 20:39:23 +0000
2693@@ -0,0 +1,13 @@
2694+global {c=xx}
2695+pattern {b,a}
2696+{"222",111}
2697+pattern {a b c}
2698+{ aaa , bbb , ccc}
2699+pattern { a , b }
2700+{AA,'BB'}
2701+global { c = yy }
2702+pattern { a , b }
2703+{
2704+ aaa
2705+ bbb
2706+}
2707
2708=== added file 'src/ioc/dbtemplate/test/t6-template.txt'
2709--- src/ioc/dbtemplate/test/t6-template.txt 1970-01-01 00:00:00 +0000
2710+++ src/ioc/dbtemplate/test/t6-template.txt 2012-06-01 20:39:23 +0000
2711@@ -0,0 +1,5 @@
2712+# comment line
2713+a = $(a)
2714+b = $(b)
2715+c = $(c)
2716+d = $(d)
2717
2718=== added file 'src/ioc/dbtemplate/test/template'
2719--- src/ioc/dbtemplate/test/template 1970-01-01 00:00:00 +0000
2720+++ src/ioc/dbtemplate/test/template 2012-06-01 20:39:23 +0000
2721@@ -0,0 +1,5 @@
2722+# comment line
2723+a = $(a)
2724+b = $(b)
2725+c = $(c)
2726+d = $(d)

Subscribers

People subscribed via source and target branches

to all changes: