provide support for dbTemplate expansion
This commit is contained in:
280
msi.c
280
msi.c
@@ -28,6 +28,7 @@ of this distribution.
|
||||
#define MAX_BUFFER_SIZE 1024
|
||||
|
||||
/*Forward references to local routines*/
|
||||
static void usageExit(void);
|
||||
static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval);
|
||||
static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName);
|
||||
|
||||
@@ -41,17 +42,10 @@ static void inputNewIncludeFile(void *inputPvt,char *name);
|
||||
static void inputErrPrint(void *inputPvt);
|
||||
|
||||
/*Routines that read the substitution file */
|
||||
static void substituteConstruct(void **substitutePvt);
|
||||
static void substituteDestruct(void *substitutePvt);
|
||||
static void substituteOpen(void *substitutePvt,char *substitutionName);
|
||||
static void substituteOpen(void **substitutePvt,char *substitutionName);
|
||||
static int substituteGetNextSet(void *substitutePvt,char **filename);
|
||||
static char *substituteGetReplacements(void *substitutePvt);
|
||||
#define USAGEEXIT \
|
||||
{\
|
||||
fprintf(stderr,"usage: msi -V -Ipath ... -Msub ... -Ssubfile template \n");\
|
||||
fprintf(stderr," Specifying path will replace the default '.'\n");\
|
||||
fprintf(stderr," stdin is used if template is not given\n");\
|
||||
exit(1);\
|
||||
}
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
@@ -80,48 +74,71 @@ int main(int argc,char **argv)
|
||||
macSuppressWarning(macPvt,FALSE);
|
||||
narg = 1; /* no argument for this option */
|
||||
} else {
|
||||
USAGEEXIT
|
||||
usageExit();
|
||||
}
|
||||
argc -= narg;
|
||||
for(i=1; i<argc; i++) argv[i] = argv[i + narg];
|
||||
}
|
||||
if(argc>2) {
|
||||
fprintf(stderr,"too many files\n");
|
||||
USAGEEXIT
|
||||
usageExit();
|
||||
}
|
||||
if(argc==2) {
|
||||
templateName = calloc(strlen(argv[1])+1,sizeof(char));
|
||||
strcpy(templateName,argv[1]);
|
||||
}
|
||||
if(argc==2) templateName = argv[1];
|
||||
if(!substitutionName) {
|
||||
makeSubstitutions(inputPvt,macPvt,templateName);
|
||||
} else {
|
||||
void *substitutePvt;
|
||||
char *filename = 0;
|
||||
|
||||
if(!templateName) {
|
||||
fprintf(stderr,"stdin not legal with substitution file\n");
|
||||
USAGEEXIT
|
||||
}
|
||||
substituteConstruct(&substitutePvt);
|
||||
substituteOpen(substitutePvt,substitutionName);
|
||||
while(pval = substituteGetReplacements(substitutePvt)){
|
||||
addMacroReplacements(macPvt,pval);
|
||||
makeSubstitutions(inputPvt,macPvt,templateName);
|
||||
}
|
||||
substituteOpen(&substitutePvt,substitutionName);
|
||||
while(substituteGetNextSet(substitutePvt,&filename)) {
|
||||
if(templateName) filename = templateName;
|
||||
if(!filename) {
|
||||
fprintf(stderr,"no template file\n");
|
||||
usageExit();
|
||||
}
|
||||
while(pval = substituteGetReplacements(substitutePvt)){
|
||||
addMacroReplacements(macPvt,pval);
|
||||
makeSubstitutions(inputPvt,macPvt,filename);
|
||||
}
|
||||
}
|
||||
substituteDestruct(substitutePvt);
|
||||
}
|
||||
inputDestruct(inputPvt);
|
||||
free((void *)templateName);
|
||||
free((void *)substitutionName);
|
||||
return(0);
|
||||
}
|
||||
|
||||
void usageExit(void)
|
||||
{
|
||||
fprintf(stderr,"usage: msi -V -Ipath ... -Msub ... -Ssubfile template\n");
|
||||
fprintf(stderr," Specifying path will replace the default '.'\n");
|
||||
fprintf(stderr," stdin is used if template is not given\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval)
|
||||
{
|
||||
char **pairs;
|
||||
long status;
|
||||
|
||||
status = macParseDefns(macPvt,pval,&pairs);
|
||||
if(!status) {
|
||||
fprintf(stderr,"Error macParseDefns error\n");
|
||||
usageExit();
|
||||
}
|
||||
status = macInstallMacros(macPvt,pairs);
|
||||
if(!status) {
|
||||
fprintf(stderr,"Error macInstallMacros error\n");
|
||||
usageExit();
|
||||
}
|
||||
free((void *)pairs);
|
||||
}
|
||||
|
||||
|
||||
#define cmdNumberOf 2
|
||||
typedef enum {cmdInclude,cmdSubstitute} cmdType;
|
||||
static char *cmdName[cmdNumberOf] = {"include","substitute"};
|
||||
@@ -172,8 +189,11 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName)
|
||||
}
|
||||
++p;
|
||||
}
|
||||
if(*p==0) goto endif;
|
||||
pend = p;
|
||||
if(*p==0) goto endif;
|
||||
/*skip quote and any trailing blanks*/
|
||||
while(*++p==' ') ;
|
||||
if(*p != '\n' && *p !=0) goto endif;
|
||||
copy = calloc(pend-pstart+1,sizeof(char));
|
||||
strncpy(copy,pstart,pend-pstart);
|
||||
switch(cmdind) {
|
||||
@@ -221,10 +241,10 @@ typedef struct inputData {
|
||||
char inputBuffer[MAX_BUFFER_SIZE];
|
||||
}inputData;
|
||||
|
||||
static char *inputOpenFile(inputData *pinputData,char *filename);
|
||||
static void inputOpenFile(inputData *pinputData,char *filename);
|
||||
static void inputCloseFile(inputData *pinputData);
|
||||
static void inputCloseAllFiles(inputData *pinputData);
|
||||
|
||||
|
||||
static void inputConstruct(void **ppvt)
|
||||
{
|
||||
inputData *pinputData;
|
||||
@@ -248,7 +268,7 @@ static void inputDestruct(void *pvt)
|
||||
}
|
||||
free(pvt);
|
||||
}
|
||||
|
||||
|
||||
static void inputAddPath(void *pvt, char *path)
|
||||
{
|
||||
inputData *pinputData = (inputData *)pvt;
|
||||
@@ -344,7 +364,7 @@ static void inputErrPrint(void *pvt)
|
||||
fprintf(stderr,"\n");
|
||||
}
|
||||
|
||||
static char *inputOpenFile(inputData *pinputData,char *filename)
|
||||
static void inputOpenFile(inputData *pinputData,char *filename)
|
||||
{
|
||||
ELLLIST *ppathList = &pinputData->pathList;
|
||||
pathNode *ppathNode = 0;
|
||||
@@ -372,7 +392,8 @@ static char *inputOpenFile(inputData *pinputData,char *filename)
|
||||
}
|
||||
if(!fp) {
|
||||
fprintf(stderr,"Could not open %s\n",filename);
|
||||
return(0);
|
||||
inputErrPrint((void *)pinputData);
|
||||
exit(1);
|
||||
}
|
||||
pinputFile = calloc(1,sizeof(inputFile));
|
||||
if(ppathNode) {
|
||||
@@ -388,9 +409,8 @@ static char *inputOpenFile(inputData *pinputData,char *filename)
|
||||
}
|
||||
pinputFile->fp = fp;
|
||||
ellInsert(&pinputData->inputFileList,0,&pinputFile->node);
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
static void inputCloseFile(inputData *pinputData)
|
||||
{
|
||||
inputFile *pinputFile;
|
||||
@@ -435,6 +455,8 @@ typedef struct patternNode {
|
||||
|
||||
typedef struct subInfo {
|
||||
subFile *psubFile;
|
||||
int isFile;
|
||||
char *filename;
|
||||
int isPattern;
|
||||
ELLLIST patternList;
|
||||
char macroReplacements[MAX_BUFFER_SIZE];
|
||||
@@ -443,61 +465,105 @@ typedef struct subInfo {
|
||||
static char *subGetNextLine(subFile *psubFile);
|
||||
static tokenType subGetNextToken(subFile *psubFile);
|
||||
static void subFileErrPrint(subFile *psubFile,char * message);
|
||||
|
||||
static void substituteConstruct(void **pvt)
|
||||
{
|
||||
subFile *psubFile;
|
||||
subInfo *psubInfo;
|
||||
static void freeSubFile(subInfo *psubInfo);
|
||||
static void freePattern(subInfo *psubInfo);
|
||||
|
||||
psubInfo = calloc(1,sizeof(subInfo));
|
||||
psubFile = calloc(1,sizeof(subFile));
|
||||
ellInit(&psubInfo->patternList);
|
||||
psubInfo->psubFile = psubFile;
|
||||
*pvt = psubInfo;
|
||||
return;
|
||||
void freeSubFile(subInfo *psubInfo)
|
||||
{
|
||||
subFile *psubFile = psubInfo->psubFile;
|
||||
if(psubFile->fp) {
|
||||
if(fclose(psubFile->fp))
|
||||
fprintf(stderr,"fclose failed on substitution file\n");
|
||||
}
|
||||
free((void *)psubFile);
|
||||
free((void *)psubInfo->filename);
|
||||
psubInfo->psubFile = 0;
|
||||
}
|
||||
|
||||
static void substituteDestruct(void *pvt)
|
||||
void freePattern(subInfo *psubInfo)
|
||||
{
|
||||
subInfo *psubInfo = (subInfo *)pvt;
|
||||
subFile *psubFile = psubInfo->psubFile;
|
||||
patternNode *ppatternNode;
|
||||
|
||||
if(fclose(psubFile->fp))
|
||||
fprintf(stderr,"fclose failed on substitution file\n");
|
||||
while(ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList)) {
|
||||
ellDelete(&psubInfo->patternList,&ppatternNode->node);
|
||||
free(ppatternNode->var);
|
||||
free(ppatternNode);
|
||||
}
|
||||
free((void *)psubFile);
|
||||
free((void *)psubInfo);
|
||||
return;
|
||||
psubInfo->isPattern = FALSE;
|
||||
}
|
||||
|
||||
static void substituteOpen(void *pvt,char *substitutionName)
|
||||
static void substituteDestruct(void *pvt)
|
||||
{
|
||||
subInfo *psubInfo = (subInfo *)pvt;
|
||||
subFile *psubFile = psubInfo->psubFile;
|
||||
|
||||
freePattern(psubInfo);
|
||||
freeSubFile(psubInfo);
|
||||
free((void *)psubInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
static void substituteOpen(void **ppvt,char *substitutionName)
|
||||
{
|
||||
subInfo *psubInfo;
|
||||
subFile *psubFile;
|
||||
FILE *fp;
|
||||
patternNode *ppatternNode;
|
||||
|
||||
psubInfo = calloc(1,sizeof(subInfo));
|
||||
*ppvt = (void *)psubInfo;
|
||||
psubFile = calloc(1,sizeof(subFile));
|
||||
psubInfo->psubFile = psubFile;
|
||||
ellInit(&psubInfo->patternList);
|
||||
fp = fopen(substitutionName,"r");
|
||||
if(!fp) {
|
||||
fprintf(stderr,"Could not open %s\n",substitutionName);
|
||||
exit(1);
|
||||
exit(1);
|
||||
}
|
||||
psubFile->substitutionName = substitutionName;
|
||||
psubFile->fp = fp;
|
||||
psubFile->lineNum = 0;
|
||||
psubFile->inputBuffer[0] = 0;
|
||||
psubFile->pnextChar = &psubFile->inputBuffer[0];
|
||||
while(subGetNextToken(psubFile)==tokenSeparater);
|
||||
subGetNextToken(psubFile);
|
||||
return;
|
||||
}
|
||||
|
||||
static int substituteGetNextSet(void *pvt,char **filename)
|
||||
{
|
||||
subInfo *psubInfo = (subInfo *)pvt;
|
||||
subFile *psubFile = psubInfo->psubFile;
|
||||
FILE *fp;
|
||||
patternNode *ppatternNode;
|
||||
|
||||
*filename = 0;
|
||||
while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
|
||||
if(psubFile->token==tokenEOF) return(FALSE);
|
||||
if(psubFile->token==tokenString && strcmp(psubFile->string,"file")==0) {
|
||||
psubInfo->isFile = TRUE;
|
||||
if(subGetNextToken(psubFile)!=tokenString) {
|
||||
subFileErrPrint(psubFile,"Expecting filename");
|
||||
exit(1);
|
||||
}
|
||||
freePattern(psubInfo);
|
||||
free((void *)psubInfo->filename);
|
||||
psubInfo->filename = calloc(strlen(psubFile->string)+1,sizeof(char));
|
||||
strcpy(psubInfo->filename,psubFile->string);
|
||||
while(subGetNextToken(psubFile)==tokenSeparater);
|
||||
if(psubFile->token!=tokenLBrace) {
|
||||
subFileErrPrint(psubFile,"Expecting {");
|
||||
exit(1);
|
||||
}
|
||||
subGetNextToken(psubFile);
|
||||
}
|
||||
*filename = psubInfo->filename;
|
||||
while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
|
||||
if(psubFile->token==tokenLBrace) return(TRUE);
|
||||
if(psubFile->token!=tokenString
|
||||
|| strcmp(psubFile->string,"pattern")!=0) {
|
||||
psubInfo->isPattern = FALSE;
|
||||
return;
|
||||
subFileErrPrint(psubFile,"Expecting pattern");
|
||||
exit(1);
|
||||
}
|
||||
freePattern(psubInfo);
|
||||
psubInfo->isPattern = TRUE;
|
||||
while(subGetNextToken(psubFile)==tokenSeparater);
|
||||
if(psubFile->token!=tokenLBrace) {
|
||||
@@ -505,22 +571,19 @@ static void substituteOpen(void *pvt,char *substitutionName)
|
||||
exit(1);
|
||||
}
|
||||
while(TRUE) {
|
||||
subGetNextToken(psubFile);
|
||||
if(psubFile->token==tokenSeparater) continue;
|
||||
if(psubFile->token==tokenString) {
|
||||
ppatternNode = calloc(1,sizeof(patternNode));
|
||||
ellAdd(&psubInfo->patternList,&ppatternNode->node);
|
||||
ppatternNode->var = calloc(strlen(psubFile->string)+1,sizeof(char));
|
||||
strcpy(ppatternNode->var,psubFile->string);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
while(subGetNextToken(psubFile)==tokenSeparater);
|
||||
if(psubFile->token!=tokenString) break;
|
||||
ppatternNode = calloc(1,sizeof(patternNode));
|
||||
ellAdd(&psubInfo->patternList,&ppatternNode->node);
|
||||
ppatternNode->var = calloc(strlen(psubFile->string)+1,sizeof(char));
|
||||
strcpy(ppatternNode->var,psubFile->string);
|
||||
}
|
||||
if(psubFile->token!=tokenRBrace) {
|
||||
subFileErrPrint(psubFile,"Expecting }");
|
||||
exit(1);
|
||||
}
|
||||
return;
|
||||
subGetNextToken(psubFile);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
static char *substituteGetReplacements(void *pvt)
|
||||
@@ -532,45 +595,50 @@ static char *substituteGetReplacements(void *pvt)
|
||||
|
||||
pNext = &psubInfo->macroReplacements[0];
|
||||
psubInfo->macroReplacements[0] = 0;
|
||||
while(psubFile->token!=tokenLBrace) {
|
||||
if(psubFile->token==tokenEOF) return(0);
|
||||
subGetNextToken(psubFile);
|
||||
}
|
||||
if(psubFile->token!=tokenLBrace) {
|
||||
subFileErrPrint(psubFile,"Expecting {");
|
||||
exit(1);
|
||||
while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
|
||||
if(psubFile->token==tokenRBrace && psubInfo->isFile) {
|
||||
psubInfo->isFile = FALSE;
|
||||
free((void *)psubInfo->filename);
|
||||
psubInfo->filename = 0;
|
||||
freePattern(psubInfo);
|
||||
subGetNextToken(psubFile);
|
||||
return(0);
|
||||
}
|
||||
if(psubFile->token==tokenEOF) return(0);
|
||||
if(psubFile->token!=tokenLBrace) return(0);
|
||||
if(psubInfo->isPattern) {
|
||||
int gotFirstPattern = FALSE;
|
||||
|
||||
while(subGetNextToken(psubFile)==tokenSeparater);
|
||||
ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList);
|
||||
if(!ppatternNode) {
|
||||
subFileErrPrint(psubFile,"No patterns");
|
||||
exit(1);
|
||||
}
|
||||
while(TRUE) {
|
||||
switch(subGetNextToken(psubFile)) {
|
||||
case tokenSeparater: continue;
|
||||
case tokenRBrace: return(psubInfo->macroReplacements);
|
||||
case tokenString:
|
||||
if(gotFirstPattern) {
|
||||
strcat(psubInfo->macroReplacements,",");
|
||||
}
|
||||
gotFirstPattern = TRUE;
|
||||
strcat(psubInfo->macroReplacements,ppatternNode->var);
|
||||
strcat(psubInfo->macroReplacements,"=");
|
||||
strcat(psubInfo->macroReplacements,psubFile->string);
|
||||
break;
|
||||
default:
|
||||
subFileErrPrint(psubFile,"Illegal token");
|
||||
exit(1);
|
||||
}
|
||||
ppatternNode = (patternNode *)ellNext(&ppatternNode->node);
|
||||
|
||||
if(psubFile->token==tokenRBrace) {
|
||||
if(ppatternNode)
|
||||
subFileErrPrint(psubFile,"less values than patterns");
|
||||
subGetNextToken(psubFile);
|
||||
return(psubInfo->macroReplacements);
|
||||
}
|
||||
if(psubFile->token!=tokenString) {
|
||||
subFileErrPrint(psubFile,"Illegal token");
|
||||
exit(-1);
|
||||
}
|
||||
if(gotFirstPattern) strcat(psubInfo->macroReplacements,",");
|
||||
gotFirstPattern = TRUE;
|
||||
if(ppatternNode) {
|
||||
strcat(psubInfo->macroReplacements,ppatternNode->var);
|
||||
strcat(psubInfo->macroReplacements,"=");
|
||||
strcat(psubInfo->macroReplacements,psubFile->string);
|
||||
ppatternNode = (patternNode *)ellNext(&ppatternNode->node);
|
||||
} else {
|
||||
subFileErrPrint(psubFile,"more values than patterns");
|
||||
}
|
||||
while(subGetNextToken(psubFile)==tokenSeparater);
|
||||
}
|
||||
} else while(TRUE) {
|
||||
switch(subGetNextToken(psubFile)) {
|
||||
case tokenRBrace: return(psubInfo->macroReplacements);
|
||||
switch(subGetNextToken(psubFile)) {
|
||||
case tokenRBrace:
|
||||
subGetNextToken(psubFile);
|
||||
return(psubInfo->macroReplacements);
|
||||
case tokenSeparater:
|
||||
strcat(psubInfo->macroReplacements,",");
|
||||
break;
|
||||
@@ -589,6 +657,7 @@ static char *subGetNextLine(subFile *psubFile)
|
||||
char *pline;
|
||||
|
||||
pline = fgets(psubFile->inputBuffer,MAX_BUFFER_SIZE,psubFile->fp);
|
||||
++psubFile->lineNum;
|
||||
while(pline && psubFile->inputBuffer[0]=='#') {
|
||||
pline = fgets(psubFile->inputBuffer,MAX_BUFFER_SIZE,psubFile->fp);
|
||||
++psubFile->lineNum;
|
||||
@@ -600,7 +669,6 @@ static char *subGetNextLine(subFile *psubFile)
|
||||
return(0);
|
||||
}
|
||||
psubFile->pnextChar = &psubFile->inputBuffer[0];
|
||||
++psubFile->lineNum;
|
||||
return(&psubFile->inputBuffer[0]);
|
||||
}
|
||||
|
||||
@@ -619,11 +687,11 @@ static tokenType subGetNextToken(subFile *psubFile)
|
||||
char *pto;
|
||||
|
||||
p = psubFile->pnextChar;
|
||||
if(!p) return(tokenEOF);
|
||||
if(*p==0 || *p=='\n') {
|
||||
if(!p) { psubFile->token = tokenEOF; return(tokenEOF);}
|
||||
if(*p==0 || *p=='\n' || *p=='#') {
|
||||
p = subGetNextLine(psubFile);
|
||||
if(!p) return(tokenEOF);
|
||||
else return(tokenSeparater);
|
||||
if(!p) { psubFile->token = tokenEOF; return(tokenEOF);}
|
||||
else { psubFile->token = tokenSeparater; return(tokenSeparater);}
|
||||
}
|
||||
while(isspace(*p)) p++;
|
||||
if(*p=='{') {
|
||||
@@ -636,7 +704,7 @@ static tokenType subGetNextToken(subFile *psubFile)
|
||||
psubFile->pnextChar = ++p;
|
||||
return(tokenRBrace);
|
||||
}
|
||||
if(isspace(*p) || *p==',') {
|
||||
if(*p==0 || isspace(*p) || *p==',') {
|
||||
while(isspace(*p) || *p==',') p++;
|
||||
psubFile->token = tokenSeparater;
|
||||
psubFile->pnextChar = p;
|
||||
@@ -647,7 +715,7 @@ static tokenType subGetNextToken(subFile *psubFile)
|
||||
pto = &psubFile->string[0];
|
||||
*pto++ = *p++;
|
||||
while(*p!='"') {
|
||||
if(*p==0) {
|
||||
if(*p==0 || *p=='\n') {
|
||||
subFileErrPrint(psubFile,"Strings must be on single line\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -665,7 +733,7 @@ static tokenType subGetNextToken(subFile *psubFile)
|
||||
psubFile->token = tokenString;
|
||||
return(tokenString);
|
||||
}
|
||||
/*Now take anything up to next non String token*/
|
||||
/*Now take anything up to next non String token and not space*/
|
||||
pto = &psubFile->string[0];
|
||||
while(!isspace(*p) && (strspn(p,"\",{}")==0)) *pto++ = *p++;
|
||||
*pto = 0;
|
||||
|
||||
368
msi.html
368
msi.html
@@ -1,240 +1,292 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
|
||||
<META NAME="GENERATOR" CONTENT="Mozilla/4.04 [en] (X11; U; SunOS 5.5.1 sun4u) [Netscape]">
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.51 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<H1>
|
||||
msi: Macro Substitution and Include Tool</H1>
|
||||
<h1>
|
||||
msi: Macro Substitution and Include Tool</h1>
|
||||
Marty Kraimer
|
||||
<BR>Argonne National Laboratory - Advanced Photon Source
|
||||
<BR>Original: December 1997
|
||||
<H2>
|
||||
Introduction</H2>
|
||||
<br>Argonne National Laboratory - Advanced Photon Source
|
||||
<br>Original: April 26, 1999
|
||||
<h2>
|
||||
Introduction</h2>
|
||||
msi is a general purpose macro substitution/include tool. It accepts as
|
||||
input an ascii template file. It looks for lines containing two reserved
|
||||
command names: include and substitute. It also looks for and performs substitutions
|
||||
on macros of the form $(var) and ${var}. It uses the macLib, an epics base
|
||||
library created by William Lupton, to perform the substitutions.
|
||||
<p>msi also allows substitutions to be specified via a separate substitution
|
||||
file. This substitution file allows the same format as the substitution
|
||||
files accepted by dbLoadTemplate or subtool.
|
||||
<br>
|
||||
<h2>
|
||||
Command Syntax:</h2>
|
||||
|
||||
<P>msi also allows substitutions to be specified via a separate substitution
|
||||
file. This substitution file has the same format as the substitution file
|
||||
accepted by subtool, which is provided with epics base. Subtool,
|
||||
however, does not support include files.
|
||||
<BR>
|
||||
<H2>
|
||||
Command Syntax:</H2>
|
||||
|
||||
<PRE>msi -V -Idir -Msub -Ssubfile template</PRE>
|
||||
<pre>msi -V -Idir -Msub -Ssubfile template</pre>
|
||||
NOTE: All parameters are optional and a space is optional between
|
||||
-I, -M, and -S and the associated value. Output is written
|
||||
to stdout.
|
||||
<p>Where:
|
||||
<p><tt>-V</tt>
|
||||
<ul>If this parameter is specified then an undefined macro is considered
|
||||
an error. An error message is generated and the line containing the macro
|
||||
is not written to stdout.</ul>
|
||||
<tt>-I dir</tt>
|
||||
<ul>This parameter, which may be repeated, specifies a search path for
|
||||
include commands. For example:</ul>
|
||||
|
||||
<P>Where:
|
||||
<dd>
|
||||
<tt> msi -I "/home/phoebus/MRK/examples:." -I".." template</tt></dd>
|
||||
|
||||
<P><TT>-V</TT>
|
||||
<UL>If this parameter is specified then an error message is generated for
|
||||
all undefined macros.</UL>
|
||||
<TT>-I dir</TT>
|
||||
<UL>This parameter, which may be repeated, specifies a search path for
|
||||
include commands. For example:</UL>
|
||||
<dd>
|
||||
specifies the search path:</dd>
|
||||
|
||||
<DD>
|
||||
<TT> msi -I "/home/phoebus/MRK/examples:." -I".." template</TT></DD>
|
||||
<dd>
|
||||
<tt> /home/phoebus/MRK/examples:.:..</tt></dd>
|
||||
|
||||
<DD>
|
||||
specifies the search path:</DD>
|
||||
<br>-M substitutions
|
||||
<ul>This parameter, which may be repeated, specifies marco substitutions.
|
||||
For example:</ul>
|
||||
|
||||
<DD>
|
||||
<TT> /home/phoebus/MRK/examples:.:..</TT></DD>
|
||||
<dd>
|
||||
<tt> msi -M "a=aval,b=bval" -M"c=cval" template</tt></dd>
|
||||
|
||||
<BR>-M substitutions
|
||||
<UL>This parameter, which may be repeated, specifies marco substitutions.
|
||||
For example:</UL>
|
||||
<ul>specifies that in the template file each occurrence of:</ul>
|
||||
|
||||
<DD>
|
||||
<TT> msi -M "a=aval,b=bval" -M"c=cval" template</TT></DD>
|
||||
<ul>
|
||||
<dd>
|
||||
$(a) or ${a} is replaced by aval</dd>
|
||||
|
||||
<UL>specifies that in the template file each occurrence of:</UL>
|
||||
<dd>
|
||||
$(b) or ${b} is replaced by bval</dd>
|
||||
|
||||
<UL>
|
||||
<DD>
|
||||
$(a) or ${a} is replaced by aval</DD>
|
||||
|
||||
<DD>
|
||||
$(b) or ${b} is replaced by bval</DD>
|
||||
|
||||
<DD>
|
||||
$(c) or ${c} is replaced by cval</DD>
|
||||
|
||||
<BR>Note that substitutions may also be specified in the template file
|
||||
and via an optional substitution file.</UL>
|
||||
<dd>
|
||||
$(c) or ${c} is replaced by cval</dd>
|
||||
</ul>
|
||||
-S subfile
|
||||
<UL>The substitution file. See below for format.</UL>
|
||||
<ul>The substitution file. See below for format.</ul>
|
||||
template
|
||||
<UL>The input file. If no file is specified then input is taken from stdin,
|
||||
<ul>The input file. If no file is specified then input is taken from stdin,
|
||||
i.e. msi can be used as a filter. See below for a description of commands
|
||||
that can be imbedded in the template file.</UL>
|
||||
NOTE: Just issuing the command:
|
||||
<PRE> msi</PRE>
|
||||
that can be imbedded in the template file.</ul>
|
||||
NOTE: It is not possible to display usage by just typing <tt>msi</tt> since
|
||||
executing the command with no arguments i s a valid command. To show usage
|
||||
specify an illegal switch, e.g.
|
||||
<ul>
|
||||
<pre>msi -help</pre>
|
||||
</ul>
|
||||
|
||||
<UL>Is a valid command, i.e. no options and the input file is stdin.
|
||||
To see the usage just issue the command with an invalid switch. For example:
|
||||
<PRE>msi -?</PRE>
|
||||
</UL>
|
||||
|
||||
<H2>
|
||||
Template File Format</H2>
|
||||
<h2>
|
||||
Template File Format</h2>
|
||||
This file contains the text to be read and written to stdout after macro
|
||||
substitution is performed. If no file is given then input is read from
|
||||
stdin. In addition the file can have lines containing include and substitute
|
||||
commands. The format of these commands are:
|
||||
<PRE> include "file"</PRE>
|
||||
<pre> include "file"</pre>
|
||||
|
||||
<PRE> substitute "var=value,var=value,..."</PRE>
|
||||
<pre> substitute "var=value,var=value,..."</pre>
|
||||
For example let the command be:
|
||||
<PRE> msi template</PRE>
|
||||
<pre> msi template</pre>
|
||||
and file includeFile contain:
|
||||
<PRE> first name is ${first}
|
||||
family name is ${family}</PRE>
|
||||
<pre> first name is ${first}
|
||||
family name is ${family}</pre>
|
||||
and template is
|
||||
<BR>
|
||||
<PRE> substitute "first=Marty,family=Kraimer"
|
||||
<br>
|
||||
<pre> substitute "first=Marty,family=Kraimer"
|
||||
include "includeFile"
|
||||
substitute "first=Irma,family=Kraimer"
|
||||
include "includeFile"</PRE>
|
||||
include "includeFile"</pre>
|
||||
then the following is written to stdout.
|
||||
<PRE> first name is Marty
|
||||
<pre> first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer</PRE>
|
||||
family name is Kraimer</pre>
|
||||
|
||||
<H2>
|
||||
Substitution File Format</H2>
|
||||
The optional substitution file has two formats: regular and pattern. Lets
|
||||
discuss each separately
|
||||
<h2>
|
||||
Substitution File Format</h2>
|
||||
The optional substitution file has three formats: regular, pattern, and
|
||||
dbTemplate format. Lets discuss each separately
|
||||
<br>
|
||||
<h3>
|
||||
regular format</h3>
|
||||
|
||||
<P>regular format:
|
||||
<DD>
|
||||
{var1=value1,var2=value2,...}</DD>
|
||||
<blockquote>
|
||||
<pre>{var1=value1,var2=value2,...}
|
||||
{var1=value1,var2=value2,...}
|
||||
...</pre>
|
||||
</blockquote>
|
||||
After reading each set of replacements within braces, the template
|
||||
file is read and macro substitution performed.
|
||||
<br>
|
||||
<h3>
|
||||
pattern format:</h3>
|
||||
|
||||
<DD>
|
||||
{var1=value1,var2=value2,...}</DD>
|
||||
<blockquote>
|
||||
<pre>pattern {var1,var2,...}
|
||||
{value1,value2,...}
|
||||
{value1,value2,...}
|
||||
pattern {var1,var2,...}
|
||||
{value1,value2,...}
|
||||
{value1,value2,...}</pre>
|
||||
</blockquote>
|
||||
This is the same as the regular format:
|
||||
<blockquote>
|
||||
<pre>{var1=value1,var2=value2}
|
||||
...</pre>
|
||||
</blockquote>
|
||||
|
||||
<DD>
|
||||
...</DD>
|
||||
<h3>
|
||||
dbTemplate Format</h3>
|
||||
|
||||
<BR>After reading each set of replacements within braces, the
|
||||
template file is read and macro substitution performed.
|
||||
<blockquote>
|
||||
<pre>file template {
|
||||
pattern format or regular format
|
||||
}</pre>
|
||||
|
||||
<P>pattern format:
|
||||
<DD>
|
||||
pattern {var1,var2,...}</DD>
|
||||
|
||||
<DD>
|
||||
{value1,value2,...}</DD>
|
||||
|
||||
<DD>
|
||||
{value1,value2,...}</DD>
|
||||
|
||||
<H3>
|
||||
Regular substitution example</H3>
|
||||
<pre>file template {
|
||||
pattern format or regular format
|
||||
}</pre>
|
||||
</blockquote>
|
||||
For thedbTemplate format, the command line template argument is optional.
|
||||
If it specified it is used, otherwise the file template is used. This format
|
||||
is an extension of the format accepted by dbLoadTemplate. It allows templates
|
||||
to be expanded on the host rather via dbLoadTemplate.
|
||||
<h3>
|
||||
Regular substitution example</h3>
|
||||
Let the command be:
|
||||
<PRE> msi -S substitute template</PRE>
|
||||
and the template file
|
||||
<PRE> first name is ${first}
|
||||
family name is ${family}</PRE>
|
||||
and file substitute
|
||||
<PRE> {first=Marty,family=Kraimer}
|
||||
{first=Irma,family=Kraimer}</PRE>
|
||||
then the following is written to stdout.
|
||||
<PRE> first name is Marty
|
||||
<pre> msi -S substitute template</pre>
|
||||
<tt>template</tt> is
|
||||
<pre> first name is ${first}
|
||||
family name is ${family}</pre>
|
||||
<tt>substitute</tt> is
|
||||
<pre> {first=Marty,family=Kraimer}
|
||||
{first=Irma,family=Kraimer}</pre>
|
||||
The following is written to stdout.
|
||||
<pre> first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer</PRE>
|
||||
family name is Kraimer</pre>
|
||||
|
||||
<H3>
|
||||
Pattern substitution example</H3>
|
||||
<h3>
|
||||
Pattern substitution example</h3>
|
||||
Let the command be:
|
||||
<PRE> msi -S pattern template</PRE>
|
||||
and pattern file
|
||||
<PRE> pattern {first,last}
|
||||
{first=Marty,family=Kraimer}
|
||||
{first=Irma,family=Kraimer}</PRE>
|
||||
then the following is written to stdout.
|
||||
<PRE> first name is Marty
|
||||
<pre> msi -S pattern template</pre>
|
||||
<tt>pattern</tt> is
|
||||
<pre> pattern {first,last}
|
||||
{Marty,Kraimer}
|
||||
{Irma,Kraimer}</pre>
|
||||
<tt>template</tt> is the same as in the previous example.
|
||||
<p>The following is written to stdout.
|
||||
<pre> first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer</PRE>
|
||||
family name is Kraimer</pre>
|
||||
|
||||
<H2>
|
||||
Some Details</H2>
|
||||
<h3>
|
||||
dbTemplate example</h3>
|
||||
Let the command be
|
||||
<blockquote>
|
||||
<pre>msi -S xxx.substitutions</pre>
|
||||
</blockquote>
|
||||
<tt>xxx.substitutions</tt> is
|
||||
<blockquote>
|
||||
<pre>file template {
|
||||
pattern {first,last}
|
||||
{Marty,Kraimer}
|
||||
{Irma,Kraimer}
|
||||
pattern {last,first}
|
||||
{Smith,Bill}
|
||||
{Smith,Mary}
|
||||
}
|
||||
file template {
|
||||
{first=Marty,last=Kraimer}
|
||||
{first=Irma,last=Kraimer}
|
||||
}</pre>
|
||||
</blockquote>
|
||||
<tt>template</tt> is the same as in the previous example..
|
||||
<p>The following is written to stdout
|
||||
<blockquote>
|
||||
<pre>first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer
|
||||
first name is Bill
|
||||
last name is Smith
|
||||
first name is Mary
|
||||
last name is Smith
|
||||
first name is Marty
|
||||
family name is Kraimer
|
||||
first name is Irma
|
||||
family name is Kraimer</pre>
|
||||
</blockquote>
|
||||
|
||||
<h2>
|
||||
Some Details</h2>
|
||||
Building msi
|
||||
<UL>msi is built as a normal extensions product. It should be built with
|
||||
base version 3.13.0beta11 or later.</UL>
|
||||
<ul>msi is built as a normal extensions product. It should be built with
|
||||
base version 3.13.0beta11 or later.</ul>
|
||||
|
||||
<DT>
|
||||
Line length limits</DT>
|
||||
<dt>
|
||||
Line length limits</dt>
|
||||
|
||||
<UL>All buffers containing input or output lines are set for a maximum
|
||||
line length of 1024. Longer input or output lines will cause msi to fail.</UL>
|
||||
<ul>All buffers containing input or output lines are set for a maximum
|
||||
line length of 1024. Longer input or output lines will cause msi to fail.</ul>
|
||||
macLib
|
||||
<UL>Currently the only macLib documentation is in macLibNOTES and macLibREADME
|
||||
which are in base/src/libCom.</UL>
|
||||
<ul>Currently the only macLib documentation is in macLibNOTES and macLibREADME
|
||||
which are in base/src/libCom.</ul>
|
||||
template file syntax
|
||||
<UL>except for lines containing include or substitute commands each line
|
||||
<ul>except for lines containing include or substitute commands each line
|
||||
is just passed to macLib. Lines containing these commands MUST be of the
|
||||
form:</UL>
|
||||
form:</ul>
|
||||
|
||||
<PRE> include "<file name>"</PRE>
|
||||
<pre> include "<file name>"</pre>
|
||||
|
||||
<PRE> or</PRE>
|
||||
<pre> or</pre>
|
||||
|
||||
<PRE> substitute "<substitutions>"</PRE>
|
||||
<pre> substitute "<substitutions>"</pre>
|
||||
|
||||
<UL>White space is allowed before and after the command and after the quoted
|
||||
<ul>White space is allowed before and after the command and after the quoted
|
||||
string. If imbedded quotes are needed the \ character can be used as an
|
||||
escape character. For example:</UL>
|
||||
escape character. For example:</ul>
|
||||
|
||||
<PRE> substitute "a=\"val\""</PRE>
|
||||
<pre> substitute "a=\"val\""</pre>
|
||||
|
||||
<UL>specifies the substitution</UL>
|
||||
<ul>specifies the substitution</ul>
|
||||
|
||||
<PRE> a=val</PRE>
|
||||
<pre> a=val</pre>
|
||||
|
||||
<UL>If a line does have the above syntax it is just passed to macLib for
|
||||
processing without any notification. Thus the input line:</UL>
|
||||
<ul>If a line does have the above syntax it is just passed to macLib for
|
||||
processing without any notification. Thus the input line:</ul>
|
||||
|
||||
<PRE> include "myfile" #include file</PRE>
|
||||
<pre> include "myfile" #include file</pre>
|
||||
|
||||
<UL>would just be passed to macLib, i.e. it would NOT be considered an
|
||||
include command.</UL>
|
||||
<ul>would just be passed to macLib, i.e. it would NOT be considered an
|
||||
include command.</ul>
|
||||
substitution file syntax
|
||||
<UL>A comment line may appear anywhere and is just ignored. A comment line
|
||||
<ul>A comment line may appear anywhere and is just ignored. A comment line
|
||||
is any line beginning with the character #, which MUST be the very first
|
||||
character of the comment line.
|
||||
|
||||
<P>For items within braces separators may be given between items. A separator
|
||||
<p>For items within braces separators may be given between items. A separator
|
||||
is either white space or a comma. White space is any of the following:
|
||||
space, formfeed, newline, carriage return, tab, vertical tab.
|
||||
|
||||
<P>Each item within braces can be an alphanumeric token or a quoted string.
|
||||
<p>Each item within braces can be an alphanumeric token or a quoted string.
|
||||
The characters \" can be used for imbedded quotes. The rules for non quoted
|
||||
strings are actually more relaxed but any item that is not an alphanumeric
|
||||
string should be given as a quoted string.
|
||||
|
||||
<P>Thus
|
||||
<PRE> {a=aa b=bb c="\"cc\""}</PRE>
|
||||
<p>Thus
|
||||
<pre> {a=aa b=bb c="\"cc\""}</pre>
|
||||
and
|
||||
<PRE> {a=aa,b=bb,c="\"cc\""}</PRE>
|
||||
<pre> {a=aa,b=bb,c="\"cc\""}</pre>
|
||||
and
|
||||
<PRE> {
|
||||
<pre> {
|
||||
a="aa"
|
||||
b="bb",
|
||||
c="\"cc\""
|
||||
}</PRE>
|
||||
are all equivalent.</UL>
|
||||
}</pre>
|
||||
are all equivalent.</ul>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user