From d55e5536d62055613ffd174df77db41b7ff386ed Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Thu, 18 Dec 1997 16:39:03 +0000 Subject: [PATCH 01/50] Standard project directories initialized by cvs2svn. From 9519e920353d2370debeca75bb1f0c6a018ddfee Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Thu, 18 Dec 1997 16:39:03 +0000 Subject: [PATCH 02/50] First version --- Makefile | 10 + Makefile.Unix | 16 ++ msi.c | 654 ++++++++++++++++++++++++++++++++++++++++++++++++++ pattern | 9 + substitute | 2 + template | 4 + testfile | 13 + testfile1 | 4 + 8 files changed, 712 insertions(+) create mode 100644 Makefile create mode 100644 Makefile.Unix create mode 100644 msi.c create mode 100644 pattern create mode 100644 substitute create mode 100644 template create mode 100644 testfile create mode 100644 testfile1 diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..d3a001c71 --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +# +# $Id$ +# + +EPICS=../../.. + +include $(EPICS)/config/CONFIG_EXTENSIONS + +include $(EPICS)/config/RULES_ARCHS + diff --git a/Makefile.Unix b/Makefile.Unix new file mode 100644 index 000000000..e9ccd1dff --- /dev/null +++ b/Makefile.Unix @@ -0,0 +1,16 @@ +EPICS = ../../../.. +include Target.include +include $(EPICS)/config/CONFIG_EXTENSIONS + +DEPLIBS = $(EPICS_BASE_LIB)/libCom.a $(EPICS_EXTENSIONS_LIB)/libpprsyd.a +USR_LDLIBS = -lpprsyd -lCom +USR_INCLUDES = -I$(EPICS_EXTENSIONS_INCLUDE) +USR_CFLAGS = -L$(EPICS_EXTENSIONS_LIB) + +#CMPLR = OLD + +SRCS.c= ../msi.c +PROD = msi + +include $(EPICS)/config/RULES.Unix + diff --git a/msi.c b/msi.c new file mode 100644 index 000000000..4b1a6aab8 --- /dev/null +++ b/msi.c @@ -0,0 +1,654 @@ +/*msi - macro sunstitutions and include */ +/***************************************************************** + COPYRIGHT NOTIFICATION +***************************************************************** + +(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO + +This software was developed under a United States Government license +described on the COPYRIGHT_UniversityOfChicago file included as part +of this distribution. +**********************************************************************/ + +/* + * Modification Log: + * ----------------- + * .01 08DEC97 mrk Original version + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define MAX_BUFFER_SIZE 1024 + +/*Forward references to local routines*/ +static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval); +static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName); + +/*Routines that read the template files */ +static void inputConstruct(void **inputPvt); +static void inputDestruct(void *inputPvt); +static void inputAddPath(void *inputPvt, char *pval); +static void inputBegin(void *inputPvt,char *fileName); +static char *inputNextLine(void *inputPvt); +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 char *substituteGetReplacements(void *substitutePvt); +#define USAGEEXIT \ +{\ + fprintf(stderr,"usage: msi -V -Idir ... -Msub ... -Ssubfile template \n");\ + exit(1);\ +} + +int main(int argc,char **argv) +{ + void *inputPvt; + MAC_HANDLE *macPvt; + char *pval; + int narg; + char *substitutionName=0; + char *templateName=0; + int i; + + inputConstruct(&inputPvt); + macCreateHandle(&macPvt,0); + macSuppressWarning(macPvt,TRUE); + while((argc>1) && (argv[1][0] == '-')) { + narg = (strlen(argv[1])==2) ? 2 : 1; + pval = (narg==1) ? (argv[1]+2) : argv[2]; + if(strncmp(argv[1],"-I",2)==0) { + inputAddPath(inputPvt,pval); + } else if(strncmp(argv[1],"-M",2)==0) { + addMacroReplacements(macPvt,pval); + } else if(strncmp(argv[1],"-S",2)==0) { + substitutionName = calloc(strlen(pval)+1,sizeof(char)); + strcpy(substitutionName,pval); + } else if(strncmp(argv[1],"-V",2)==0) { + macSuppressWarning(macPvt,FALSE); + narg = 1; /* no argument for this option */ + } else { + USAGEEXIT + } + argc -= narg; + for(i=1; i2) { + fprintf(stderr,"too many files\n"); + USAGEEXIT + } + if(argc==2) templateName = argv[1]; + if(!substitutionName) { + makeSubstitutions(inputPvt,macPvt,templateName); + } else { + void *substitutePvt; + + 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); + } + substituteDestruct(substitutePvt); + } + inputDestruct(inputPvt); + return(0); +} + +static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval) +{ + char **pairs; + long status; + + status = macParseDefns(macPvt,pval,&pairs); + status = macInstallMacros(macPvt,pairs); + free((void *)pairs); +} + + +#define cmdNumberOf 2 +typedef enum {cmdInclude,cmdSubstitute} cmdType; +static char *cmdName[cmdNumberOf] = {"include","substitute"}; +static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) +{ + char *input; + static char buffer[MAX_BUFFER_SIZE]; + int n; + char *subStringLocation; + + inputBegin(inputPvt,templateName); + while(input = inputNextLine(inputPvt)) { + int expand=TRUE; + char *p; + char *command = 0; + + p = input; + /*skip whitespace at beginning of line*/ + while(*p && (isspace(*p))) ++p; + /*Look for i or s */ + if(*p && (*p=='i' || *p=='s')) command = p; + if(command) { + char *pstart; + char *pend; + char *copy; + int cmdind=-1; + int i; + + for(i=0; i< cmdNumberOf; i++) { + if(strstr(command,cmdName[i])) { + cmdind = i; + } + } + if(cmdind<0) goto endif; + p = command + strlen(cmdName[cmdind]); + /*skip whitespace after command*/ + while(*p && (isspace(*p))) ++p; + /*Next character must be quote*/ + if((*p==0) || (*p!='"')) goto endif; + pstart = ++p; + /*Look for end quote*/ + while(*p && (*p!='"')) { + /*allow escape for imbeded quote*/ + if((*p=='\\') && *(p+1)=='"') { + p += 2; continue; + } else { + if(*p=='"') break; + } + ++p; + } + if(*p==0) goto endif; + pend = p; + copy = calloc(pend-pstart+1,sizeof(char)); + strncpy(copy,pstart,pend-pstart); + switch(cmdind) { + case cmdInclude: + inputNewIncludeFile(inputPvt,copy); + break; + case cmdSubstitute: + addMacroReplacements(macPvt,copy); + break; + default: + fprintf(stderr,"Logic Error: makeSubstitutions\n"); + inputErrPrint(inputPvt); + exit(1); + } + free(copy); + expand = FALSE; + } +endif: + if(expand) { + n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1); + if(n<0) { + inputErrPrint(inputPvt); + } else { + printf("%s",buffer); + } + } + } +} + +typedef struct inputFile{ + ELLNODE node; + char *filename; + FILE *fp; + int lineNum; +}inputFile; + +typedef struct pathNode { + ELLNODE node; + char *directory; +} pathNode; + +typedef struct inputData { + ELLLIST inputFileList; + ELLLIST pathList; + char inputBuffer[MAX_BUFFER_SIZE]; +}inputData; + + +static char *inputOpenFile(inputData *pinputData,char *filename); +static void inputCloseFile(inputData *pinputData); +static void inputCloseAllFiles(inputData *pinputData); + +static void inputConstruct(void **ppvt) +{ + inputData *pinputData; + + pinputData = calloc(1,sizeof(inputData)); + ellInit(&pinputData->inputFileList); + ellInit(&pinputData->pathList); + *ppvt = pinputData; +} + +static void inputDestruct(void *pvt) +{ + inputData *pinputData = (inputData *)pvt; + pathNode *ppathNode; + + inputCloseAllFiles(pinputData); + while(ppathNode = (pathNode *)ellFirst(&pinputData->pathList)) { + ellDelete(&pinputData->pathList,&ppathNode->node); + free((void *)ppathNode->directory); + free((void *)ppathNode); + } + free(pvt); +} + +static void inputAddPath(void *pvt, char *path) +{ + inputData *pinputData = (inputData *)pvt; + ELLLIST *ppathList = &pinputData->pathList; + pathNode *ppathNode; + const char *pcolon; + const char *pdir; + int len; + + pdir = path; + while(pdir) { + if(*pdir == ':') { + pdir++; + continue; + } + ppathNode = (pathNode *)calloc(1,sizeof(pathNode)); + ellAdd(ppathList,&ppathNode->node); + pcolon = strchr(pdir,':'); + len = (pcolon ? (pcolon - pdir) : strlen(pdir)); + ppathNode->directory = (char *)calloc(1,len+1); + strncpy(ppathNode->directory,pdir,len); + pdir = (pcolon ? (pcolon+1) : 0); + } + return; +} + +static void inputBegin(void *pvt,char *fileName) +{ + inputData *pinputData = (inputData *)pvt; + inputFile *pinputFile; + + inputCloseAllFiles(pinputData); + inputOpenFile(pinputData,fileName); +} + +static char *inputNextLine(void *pvt) +{ + inputData *pinputData = (inputData *)pvt; + inputFile *pinputFile; + char *pline; + + while(pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList)) { + pline = fgets(pinputData->inputBuffer,MAX_BUFFER_SIZE,pinputFile->fp); + if(pline) { + ++pinputFile->lineNum; + return(pline); + } + inputCloseFile(pinputData); + } + return(0); +} + +static void inputNewIncludeFile(void *pvt,char *name) +{ + inputData *pinputData = (inputData *)pvt; + + inputOpenFile(pinputData,name); +} + +static void inputErrPrint(void *pvt) +{ + inputData *pinputData = (inputData *)pvt; + inputFile *pinputFile; + + fprintf(stderr,"input: %s which is ",pinputData->inputBuffer); + pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList); + while(pinputFile) { + fprintf(stderr,"line %d of ",pinputFile->lineNum); + if(pinputFile->filename) { + fprintf(stderr," file %s\n",pinputFile->filename); + } else { + fprintf(stderr,"stdin:\n"); + } + pinputFile = (inputFile *)ellNext(&pinputFile->node); + if(pinputFile) { + fprintf(stderr," which is included from "); + } else { + fprintf(stderr,"\n"); + } + } + fprintf(stderr,"\n"); +} + +static char *inputOpenFile(inputData *pinputData,char *filename) +{ + ELLLIST *ppathList = &pinputData->pathList; + pathNode *ppathNode = 0; + inputFile *pinputFile; + char *fullname; + FILE *fp = 0; + + if(!filename) { + fp = stdin; + } else if((ellCount(ppathList)==0) || strchr(filename,'/')){ + fp = fopen(filename,"r"); + } else { + ppathNode = (pathNode *)ellFirst(ppathList); + while(ppathNode) { + fullname = calloc(strlen(filename)+strlen(ppathNode->directory) +2, + sizeof(char)); + strcpy(fullname,ppathNode->directory); + strcat(fullname,"/"); + strcat(fullname,filename); + fp = fopen(fullname,"r"); + if(fp) break; + free((void *)fullname); + ppathNode = (pathNode *)ellNext(&ppathNode->node); + } + } + if(!fp) { + fprintf(stderr,"Could not open %s\n",filename); + return(0); + } + pinputFile = calloc(1,sizeof(inputFile)); + if(ppathNode) { + pinputFile->filename = calloc(1,strlen(fullname)+1); + strcpy(pinputFile->filename,fullname); + free((void *)fullname); + } else if(filename) { + pinputFile->filename = calloc(1,strlen(filename)+1); + strcpy(pinputFile->filename,filename); + } else { + pinputFile->filename = calloc(1,strlen("stdin")+1); + strcpy(pinputFile->filename,"stdin"); + } + pinputFile->fp = fp; + ellInsert(&pinputData->inputFileList,0,&pinputFile->node); + return(0); +} + +static void inputCloseFile(inputData *pinputData) +{ + inputFile *pinputFile; + + pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList); + if(!pinputFile) return; + ellDelete(&pinputData->inputFileList,&pinputFile->node); + if(fclose(pinputFile->fp)) + fprintf(stderr,"fclose failed: file %s\n",pinputFile->filename); + free(pinputFile->filename); + free(pinputFile); +} + +static void inputCloseAllFiles(inputData *pinputData) +{ + inputFile *pinputFile; + + while(pinputFile=(inputFile *)ellFirst(&pinputData->inputFileList)){ + inputCloseFile(pinputData); + } +} + +/*start of code that handles substitution file*/ +typedef enum { + tokenLBrace,tokenRBrace,tokenSeparater,tokenString,tokenEOF +}tokenType; + +typedef struct subFile { + FILE *fp; + int lineNum; + char inputBuffer[MAX_BUFFER_SIZE]; + char *pnextChar; + tokenType token; + char string[MAX_BUFFER_SIZE]; +} subFile; + +typedef struct patternNode { + ELLNODE node; + char *var; +}patternNode; + +typedef struct subInfo { + subFile *psubFile; + int isPattern; + ELLLIST patternList; + char macroReplacements[MAX_BUFFER_SIZE]; +}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; + + psubInfo = calloc(1,sizeof(subInfo)); + psubFile = calloc(1,sizeof(subFile)); + ellInit(&psubInfo->patternList); + psubInfo->psubFile = psubFile; + *pvt = psubInfo; + return; +} + +static void substituteDestruct(void *pvt) +{ + 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; +} + +static void substituteOpen(void *pvt,char *substitutionName) +{ + subInfo *psubInfo = (subInfo *)pvt; + subFile *psubFile = psubInfo->psubFile; + FILE *fp; + patternNode *ppatternNode; + + fp = fopen(substitutionName,"r"); + if(!fp) { + fprintf(stderr,"Could not open %s\n",substitutionName); + exit(1); + } + psubFile->fp = fp; + psubFile->lineNum = 0; + psubFile->inputBuffer[0] = 0; + psubFile->pnextChar = &psubFile->inputBuffer[0]; + while(subGetNextToken(psubFile)==tokenSeparater); + if(psubFile->token!=tokenString + || strcmp(psubFile->string,"pattern")!=0) { + psubInfo->isPattern = FALSE; + return; + } + psubInfo->isPattern = TRUE; + while(subGetNextToken(psubFile)==tokenSeparater); + if(psubFile->token!=tokenLBrace) { + subFileErrPrint(psubFile,"Expecting {"); + 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; + } + if(psubFile->token!=tokenRBrace) { + subFileErrPrint(psubFile,"Expecting }"); + exit(1); + } + return; +} + +static char *substituteGetReplacements(void *pvt) +{ + subInfo *psubInfo = (subInfo *)pvt; + subFile *psubFile = psubInfo->psubFile; + char *pNext; + patternNode *ppatternNode; + + pNext = &psubInfo->macroReplacements[0]; + psubInfo->macroReplacements[0] = 0; + if(psubFile->token!=tokenLBrace) + while(subGetNextToken(psubFile)==tokenSeparater); + if(psubFile->token==tokenEOF) return(0); + if(psubFile->token!=tokenLBrace) { + subFileErrPrint(psubFile,"Expecting {"); + exit(1); + } + if(psubInfo->isPattern) { + int gotFirstPattern = FALSE; + + 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); + + } + } else while(TRUE) { + switch(subGetNextToken(psubFile)) { + case tokenRBrace: return(psubInfo->macroReplacements); + case tokenSeparater: + strcat(psubInfo->macroReplacements,","); + break; + case tokenString: + strcat(psubInfo->macroReplacements,psubFile->string); + break; + default: + subFileErrPrint(psubFile,"Illegal token"); + exit(1); + } + } +} + +static char *subGetNextLine(subFile *psubFile) +{ + char *pline; + + pline = fgets(psubFile->inputBuffer,MAX_BUFFER_SIZE,psubFile->fp); + while(pline && psubFile->inputBuffer[0]=='#') + pline = fgets(psubFile->inputBuffer,MAX_BUFFER_SIZE,psubFile->fp); + if(!pline) { + psubFile->token = tokenEOF; + psubFile->inputBuffer[0] = 0; + psubFile->pnextChar = 0; + return(0); + } + psubFile->pnextChar = &psubFile->inputBuffer[0]; + ++psubFile->lineNum; + return(&psubFile->inputBuffer[0]); +} + +static void subFileErrPrint(subFile *psubFile,char * message) +{ + fprintf(stderr,"substitution file line %d: %s", + psubFile->lineNum,psubFile->inputBuffer); + fprintf(stderr,"%s\n",message); +} + + +static tokenType subGetNextToken(subFile *psubFile) +{ + char *p; + char *pto; + + p = psubFile->pnextChar; + if(!p) return(tokenEOF); + if(*p==0 || *p=='\n') { + p = subGetNextLine(psubFile); + if(!p) return(tokenEOF); + } + if(*p=='{') { + psubFile->token = tokenLBrace; + psubFile->pnextChar = ++p; + return(tokenLBrace); + } + if(*p=='}') { + psubFile->token = tokenRBrace; + psubFile->pnextChar = ++p; + return(tokenRBrace); + } + if(isspace(*p) || *p==',') { + while(isspace(*p) || *p==',') p++; + psubFile->token = tokenSeparater; + psubFile->pnextChar = p; + return(tokenSeparater); + } + /*now handle quoted strings*/ + if(*p=='"') { + pto = &psubFile->string[0]; + *pto++ = *p++; + while(*p!='"') { + if(*p==0) { + subFileErrPrint(psubFile,"Strings must be on single line\n"); + exit(1); + } + /*allow escape for imbeded quote*/ + if((*p=='\\') && *(p+1)=='"') { + *pto++ = *p++; + *pto++ = *p++; + continue; + } + *pto++ = *p++; + } + *pto++ = *p++; + psubFile->pnextChar = p; + *pto = 0; + psubFile->token = tokenString; + return(tokenString); + } + /*Now take anything up to next non String token*/ + pto = &psubFile->string[0]; + while(!isspace(*p) && (strspn(p,"\",{}")==0)) *pto++ = *p++; + *pto = 0; + psubFile->pnextChar = p; + psubFile->token = tokenString; + return(tokenString); +} diff --git a/pattern b/pattern new file mode 100644 index 000000000..e847f7d9f --- /dev/null +++ b/pattern @@ -0,0 +1,9 @@ +#test of a pattern + pattern {a,b} +{xxx,"yyy"} + {zzz , ttt} + +{ + vvv + zzz +} diff --git a/substitute b/substitute new file mode 100644 index 000000000..c249b940e --- /dev/null +++ b/substitute @@ -0,0 +1,2 @@ +{a=xxx,b="yyy"} +{a=zzz , b=ttt} diff --git a/template b/template new file mode 100644 index 000000000..38ced3cb2 --- /dev/null +++ b/template @@ -0,0 +1,4 @@ +# comment line +$(a) +this is a test $(b) +$(d) diff --git a/testfile b/testfile new file mode 100644 index 000000000..845648365 --- /dev/null +++ b/testfile @@ -0,0 +1,13 @@ +This is a test file +This is second line +include "testfile1" +a=${a} +b=$(b) +substitute "a=aaa,b=bbb" +a=${a} +b=$(b) +substitute "a=\"aa\"" +${a} +$(a) +This is last line +%report diff --git a/testfile1 b/testfile1 new file mode 100644 index 000000000..3a61424bc --- /dev/null +++ b/testfile1 @@ -0,0 +1,4 @@ +This is testfile1 +in testfile1 $(a)=a +in testfile1 $(b)=b +end of testfile1 From 84f08a153a9f7c6e87cc74147bb0d1cd58ed717f Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Mon, 14 Dec 1998 14:46:26 +0000 Subject: [PATCH 03/50] fix imcompatibilities with subtool --- Makefile | 17 +++++++++++------ Makefile.Host | 11 +++++++++++ Makefile.Unix | 4 ++-- msi.c | 53 ++++++++++++++++++++++++++++++++++----------------- substitute | 7 +++++-- 5 files changed, 65 insertions(+), 27 deletions(-) create mode 100644 Makefile.Host diff --git a/Makefile b/Makefile index d3a001c71..39cb7cad1 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,15 @@ # # $Id$ # - -EPICS=../../.. - -include $(EPICS)/config/CONFIG_EXTENSIONS - -include $(EPICS)/config/RULES_ARCHS +TOP = ../.. +ifneq ($(wildcard $(TOP)/config)x,x) + # New Makefile.Host config file location + include $(TOP)/config/CONFIG_EXTENSIONS + include $(TOP)/config/RULES_ARCHS +else + # Old Makefile.Unix config file location + EPICS=../../.. + include $(EPICS)/config/CONFIG_EXTENSIONS + include $(EPICS)/config/RULES_ARCHS +endif diff --git a/Makefile.Host b/Makefile.Host new file mode 100644 index 000000000..65fea75e8 --- /dev/null +++ b/Makefile.Host @@ -0,0 +1,11 @@ +TOP = ../../.. +include $(TOP)/config/CONFIG_EXTENSIONS + + +PROD_LIBS += Com + +SRCS.c= ../msi.c +PROD = msi + +include $(TOP)/config/RULES.Host + diff --git a/Makefile.Unix b/Makefile.Unix index e9ccd1dff..f33d079ce 100644 --- a/Makefile.Unix +++ b/Makefile.Unix @@ -2,8 +2,8 @@ EPICS = ../../../.. include Target.include include $(EPICS)/config/CONFIG_EXTENSIONS -DEPLIBS = $(EPICS_BASE_LIB)/libCom.a $(EPICS_EXTENSIONS_LIB)/libpprsyd.a -USR_LDLIBS = -lpprsyd -lCom +DEPLIBS = $(EPICS_BASE_LIB)/libCom.a +USR_LDLIBS = -lCom USR_INCLUDES = -I$(EPICS_EXTENSIONS_INCLUDE) USR_CFLAGS = -L$(EPICS_EXTENSIONS_LIB) diff --git a/msi.c b/msi.c index 4b1a6aab8..744544a52 100644 --- a/msi.c +++ b/msi.c @@ -47,8 +47,10 @@ static void substituteOpen(void *substitutePvt,char *substitutionName); static char *substituteGetReplacements(void *substitutePvt); #define USAGEEXIT \ {\ - fprintf(stderr,"usage: msi -V -Idir ... -Msub ... -Ssubfile template \n");\ - exit(1);\ + 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) @@ -219,7 +221,6 @@ typedef struct inputData { char inputBuffer[MAX_BUFFER_SIZE]; }inputData; - static char *inputOpenFile(inputData *pinputData,char *filename); static void inputCloseFile(inputData *pinputData); static void inputCloseAllFiles(inputData *pinputData); @@ -256,20 +257,32 @@ static void inputAddPath(void *pvt, char *path) const char *pcolon; const char *pdir; int len; + int emptyName; pdir = path; - while(pdir) { - if(*pdir == ':') { - pdir++; - continue; - } + /*an empty name at beginning, middle, or end means current directory*/ + while(pdir && *pdir) { + emptyName = ((*pdir == ':') ? TRUE : FALSE); + if(emptyName) ++pdir; ppathNode = (pathNode *)calloc(1,sizeof(pathNode)); ellAdd(ppathList,&ppathNode->node); - pcolon = strchr(pdir,':'); - len = (pcolon ? (pcolon - pdir) : strlen(pdir)); - ppathNode->directory = (char *)calloc(1,len+1); - strncpy(ppathNode->directory,pdir,len); - pdir = (pcolon ? (pcolon+1) : 0); + if(!emptyName) { + pcolon = strchr(pdir,':'); + len = (pcolon ? (pcolon - pdir) : strlen(pdir)); + if(len>0) { + ppathNode->directory = (char *)calloc(len+1,sizeof(char)); + strncpy(ppathNode->directory,pdir,len); + pdir = pcolon; + /*unless at end skip past first colon*/ + if(pdir && *(pdir+1)!=0) ++pdir; + } else { /*must have been trailing : */ + emptyName=TRUE; + } + } + if(emptyName) { + ppathNode->directory = (char *)calloc(2,sizeof(char)); + strcpy(ppathNode->directory,"."); + } } return; } @@ -406,6 +419,7 @@ typedef enum { }tokenType; typedef struct subFile { + char *substitutionName; FILE *fp; int lineNum; char inputBuffer[MAX_BUFFER_SIZE]; @@ -473,6 +487,7 @@ static void substituteOpen(void *pvt,char *substitutionName) fprintf(stderr,"Could not open %s\n",substitutionName); exit(1); } + psubFile->substitutionName = substitutionName; psubFile->fp = fp; psubFile->lineNum = 0; psubFile->inputBuffer[0] = 0; @@ -517,9 +532,10 @@ static char *substituteGetReplacements(void *pvt) pNext = &psubInfo->macroReplacements[0]; psubInfo->macroReplacements[0] = 0; - if(psubFile->token!=tokenLBrace) - while(subGetNextToken(psubFile)==tokenSeparater); - if(psubFile->token==tokenEOF) return(0); + while(psubFile->token!=tokenLBrace) { + if(psubFile->token==tokenEOF) return(0); + subGetNextToken(psubFile); + } if(psubFile->token!=tokenLBrace) { subFileErrPrint(psubFile,"Expecting {"); exit(1); @@ -588,7 +604,8 @@ static char *subGetNextLine(subFile *psubFile) static void subFileErrPrint(subFile *psubFile,char * message) { - fprintf(stderr,"substitution file line %d: %s", + fprintf(stderr,"substitution file %s line %d: %s", + psubFile->substitutionName, psubFile->lineNum,psubFile->inputBuffer); fprintf(stderr,"%s\n",message); } @@ -604,7 +621,9 @@ static tokenType subGetNextToken(subFile *psubFile) if(*p==0 || *p=='\n') { p = subGetNextLine(psubFile); if(!p) return(tokenEOF); + else return(tokenSeparater); } + while(isspace(*p)) p++; if(*p=='{') { psubFile->token = tokenLBrace; psubFile->pnextChar = ++p; diff --git a/substitute b/substitute index c249b940e..22c98bb0e 100644 --- a/substitute +++ b/substitute @@ -1,2 +1,5 @@ -{a=xxx,b="yyy"} -{a=zzz , b=ttt} +{a=111,b="222"} +{ a = aaa , b=bbb} +{a= aaa +b= bbb +} From 9780eeb9fe12a4c61c1a911a8318024ce264b4f0 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Tue, 13 Apr 1999 14:12:01 +0000 Subject: [PATCH 04/50] in substutition file count comments lines --- msi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/msi.c b/msi.c index 744544a52..e4fc976d0 100644 --- a/msi.c +++ b/msi.c @@ -589,8 +589,10 @@ static char *subGetNextLine(subFile *psubFile) char *pline; pline = fgets(psubFile->inputBuffer,MAX_BUFFER_SIZE,psubFile->fp); - while(pline && psubFile->inputBuffer[0]=='#') + while(pline && psubFile->inputBuffer[0]=='#') { pline = fgets(psubFile->inputBuffer,MAX_BUFFER_SIZE,psubFile->fp); + ++psubFile->lineNum; + } if(!pline) { psubFile->token = tokenEOF; psubFile->inputBuffer[0] = 0; From cbfac53f5a30152e13483b5267c6199b58723a48 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Tue, 13 Apr 1999 17:49:15 +0000 Subject: [PATCH 05/50] add msi.html --- Makefile.Host | 2 + msi.html | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 msi.html diff --git a/Makefile.Host b/Makefile.Host index 65fea75e8..684d1d8e6 100644 --- a/Makefile.Host +++ b/Makefile.Host @@ -4,6 +4,8 @@ include $(TOP)/config/CONFIG_EXTENSIONS PROD_LIBS += Com +HTMLS += msi.html + SRCS.c= ../msi.c PROD = msi diff --git a/msi.html b/msi.html new file mode 100644 index 000000000..ddec90752 --- /dev/null +++ b/msi.html @@ -0,0 +1,240 @@ + + + + + + + +

+msi: Macro Substitution and Include Tool

+Marty Kraimer +
Argonne National Laboratory - Advanced Photon Source +
Original: December 1997 +

+Introduction

+msi is a general purpose macro substitution/include tool. It accepts as +input an ascii template file. It looks for lines containing two reserved +command names: include and substitute. It also looks for and performs substitutions +on macros of the form $(var) and ${var}. It uses the macLib, an epics base +library created by William Lupton, to perform the substitutions. + +

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. +
  +

+Command Syntax:

+ +
msi -V -Idir -Msub -Ssubfile template
+NOTE: All parameters are optional and a space is optional between  +-I, -M, and -S  and the  associated value. Output is written +to stdout. + +

Where: + +

-V +

    If this parameter is specified then an error message is generated for +all undefined macros.
+-I dir +
    This parameter, which may be repeated, specifies a search path for +include commands. For example:
+ +
+    msi -I "/home/phoebus/MRK/examples:." -I".." template
+ +
+specifies the search path:
+ +
+    /home/phoebus/MRK/examples:.:..
+ +
-M substitutions +
    This parameter, which may be repeated, specifies marco substitutions. +For example:
+ +
+    msi -M "a=aval,b=bval" -M"c=cval" template
+ +
    specifies that in the template file each occurrence of:
+ +
    +
    +$(a) or ${a} is replaced by aval
    + +
    +$(b) or ${b} is replaced by bval
    + +
    +$(c) or ${c} is replaced by cval
    + +
    Note that substitutions may also be specified in the template file +and via an optional substitution file.
+-S subfile +
    The substitution file. See below for format.
+template +
    The input file. If no file is specified then input is taken from stdin, +i.e. msi can be used as a filter. See below for a description of commands +that can be imbedded in the template file.
+NOTE: Just issuing the command: +
    msi
+ +
    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: +
    msi -?
    +
+ +

+Template File Format

+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: +
    include "file"
+ +
    substitute "var=value,var=value,..."
+For example let the command be: +
    msi template
+and file includeFile contain: +
    first name is ${first}
+    family name is ${family}
+and template is +
  +
    substitute "first=Marty,family=Kraimer"
+    include "includeFile"
+    substitute "first=Irma,family=Kraimer"
+    include "includeFile"
+then the following is written to stdout. +
    first name is Marty
+    family name is Kraimer
+    first name is Irma
+    family name is Kraimer
+ +

+Substitution File Format

+The optional substitution file has two formats: regular and pattern. Lets +discuss  each separately + +

regular format: +

+{var1=value1,var2=value2,...}
+ +
+{var1=value1,var2=value2,...}
+ +
+...
+ +
After reading each set of replacements within braces,   the +template file is read and macro substitution performed. + +

pattern  format: +

+pattern {var1,var2,...}
+ +
+{value1,value2,...}
+ +
+{value1,value2,...}
+ +

+Regular substitution example

+Let the command be: +
    msi -S substitute template
+and the template file +
    first name is ${first}
+    family name is ${family}
+and file substitute +
    {first=Marty,family=Kraimer}
+    {first=Irma,family=Kraimer}
+then the following is written to stdout. +
    first name is Marty
+    family name is Kraimer
+    first name is Irma
+    family name is Kraimer
+ +

+Pattern substitution example

+Let the command be: +
    msi -S pattern template
+and pattern file +
    pattern {first,last}
+    {first=Marty,family=Kraimer}
+    {first=Irma,family=Kraimer}
+then the following is written to stdout. +
    first name is Marty
+    family name is Kraimer
+    first name is Irma
+    family name is Kraimer
+ +

+Some Details

+Building msi +
    msi is built as a normal extensions product. It should be built with +base version 3.13.0beta11 or later.
+ +
+Line length limits
+ +
    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.
+macLib +
    Currently the only macLib documentation is in macLibNOTES and macLibREADME +which are in base/src/libCom.
+template file syntax +
    except for lines containing include or substitute commands each line +is just passed to macLib. Lines containing these commands MUST be of the +form:
+ +
        include "<file name>"
+ +
        or
+ +
        substitute "<substitutions>"
+ +
    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:
+ +
        substitute "a=\"val\""
+ +
    specifies the substitution
+ +
        a=val
+ +
    If a line does have the above syntax it is just passed to macLib for +processing without any notification. Thus the input line:
+ +
        include "myfile" #include file
+ +
    would just be passed to macLib, i.e. it would NOT be considered an +include command.
+substitution  file syntax +
    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. + +

    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. + +

    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. + +

    Thus +

        {a=aa b=bb c="\"cc\""}
    +and +
        {a=aa,b=bb,c="\"cc\""}
    +and +
        {
    +        a="aa"
    +        b="bb",
    +        c="\"cc\""
    +    }
    +are all equivalent.
+ + + From 999ef9fd5086392b258f5e9f83de4cea5317c287 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Tue, 13 Apr 1999 17:49:16 +0000 Subject: [PATCH 06/50] This commit was manufactured by cvs2svn to create tag 'MSI-R1-1'. From 3e6e54d80103347490c76ac4b7871aa489dcc222 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Mon, 3 May 1999 13:21:09 +0000 Subject: [PATCH 07/50] provide support for dbTemplate expansion --- msi.c | 280 ++++++++++++++++++++++++++---------------- msi.html | 368 +++++++++++++++++++++++++++++++------------------------ 2 files changed, 384 insertions(+), 264 deletions(-) diff --git a/msi.c b/msi.c index e4fc976d0..70e97d505 100644 --- a/msi.c +++ b/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; i2) { 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; diff --git a/msi.html b/msi.html index ddec90752..eb9a6a027 100644 --- a/msi.html +++ b/msi.html @@ -1,240 +1,292 @@ - - - - - - + + + + + + + -

-msi: Macro Substitution and Include Tool

+

+msi: Macro Substitution and Include Tool

Marty Kraimer -
Argonne National Laboratory - Advanced Photon Source -
Original: December 1997 -

-Introduction

+
Argonne National Laboratory - Advanced Photon Source +
Original:  April 26, 1999 +

+Introduction

msi is a general purpose macro substitution/include tool. It accepts as input an ascii template file. It looks for lines containing two reserved command names: include and substitute. It also looks for and performs substitutions on macros of the form $(var) and ${var}. It uses the macLib, an epics base library created by William Lupton, to perform the substitutions. +

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. +
  +

+Command Syntax:

-

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. -
  -

-Command Syntax:

- -
msi -V -Idir -Msub -Ssubfile template
+
msi -V -Idir -Msub -Ssubfile template
NOTE: All parameters are optional and a space is optional between  -I, -M, and -S  and the  associated value. Output is written to stdout. +

Where: +

-V +

    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.
+-I dir +
    This parameter, which may be repeated, specifies a search path for +include commands. For example:
-

Where: +

+    msi -I "/home/phoebus/MRK/examples:." -I".." template
-

-V -

    If this parameter is specified then an error message is generated for -all undefined macros.
--I dir -
    This parameter, which may be repeated, specifies a search path for -include commands. For example:
+
+specifies the search path:
-
-    msi -I "/home/phoebus/MRK/examples:." -I".." template
+
+    /home/phoebus/MRK/examples:.:..
-
-specifies the search path:
+
-M substitutions +
    This parameter, which may be repeated, specifies marco substitutions. +For example:
-
-    /home/phoebus/MRK/examples:.:..
+
+    msi -M "a=aval,b=bval" -M"c=cval" template
-
-M substitutions -
    This parameter, which may be repeated, specifies marco substitutions. -For example:
+
    specifies that in the template file each occurrence of:
-
-    msi -M "a=aval,b=bval" -M"c=cval" template
+
    +
    +$(a) or ${a} is replaced by aval
    -
      specifies that in the template file each occurrence of:
    +
    +$(b) or ${b} is replaced by bval
    -
      -
      -$(a) or ${a} is replaced by aval
      - -
      -$(b) or ${b} is replaced by bval
      - -
      -$(c) or ${c} is replaced by cval
      - -
      Note that substitutions may also be specified in the template file -and via an optional substitution file.
    +
    +$(c) or ${c} is replaced by cval
    +
-S subfile -
    The substitution file. See below for format.
+
    The substitution file. See below for format.
template -
    The input file. If no file is specified then input is taken from stdin, +
      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.
    -NOTE: Just issuing the command: -
        msi
    +that can be imbedded in the template file.
+NOTE: It is not possible to display usage by just typing msi since +executing the command with no arguments i s a valid command. To show usage +specify an illegal switch, e.g. +
    +
    msi -help
    +
-
    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: -
    msi -?
    -
- -

-Template File Format

+

+Template File Format

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: -
    include "file"
+
    include "file"
-
    substitute "var=value,var=value,..."
+
    substitute "var=value,var=value,..."
For example let the command be: -
    msi template
+
    msi template
and file includeFile contain: -
    first name is ${first}
-    family name is ${family}
+
    first name is ${first}
+    family name is ${family}
and template is -
  -
    substitute "first=Marty,family=Kraimer"
+
  +
    substitute "first=Marty,family=Kraimer"
     include "includeFile"
     substitute "first=Irma,family=Kraimer"
-    include "includeFile"
+    include "includeFile"
then the following is written to stdout. -
    first name is Marty
+
    first name is Marty
     family name is Kraimer
     first name is Irma
-    family name is Kraimer
+    family name is Kraimer
-

-Substitution File Format

-The optional substitution file has two formats: regular and pattern. Lets -discuss  each separately +

+Substitution File Format

+The optional substitution file has three formats: regular, pattern, and +dbTemplate format. Lets discuss  each separately +
  +

+regular format

-

regular format: -

-{var1=value1,var2=value2,...}
+
+
{var1=value1,var2=value2,...}
+{var1=value1,var2=value2,...}
+...
+
+After reading each set of replacements within braces,   the template +file is read and macro substitution performed. +
  +

+pattern  format:

-
-{var1=value1,var2=value2,...}
+
+
pattern {var1,var2,...}
+{value1,value2,...}
+{value1,value2,...}
+pattern {var1,var2,...}
+{value1,value2,...}
+{value1,value2,...}
+
+This is the same as the regular format: +
+
{var1=value1,var2=value2}
+...
+
-
-...
+

+dbTemplate Format

-
After reading each set of replacements within braces,   the -template file is read and macro substitution performed. +
+
file template {
+    pattern format or regular format
+}
-

pattern  format: -

-pattern {var1,var2,...}
- -
-{value1,value2,...}
- -
-{value1,value2,...}
- -

-Regular substitution example

+
file template {
+    pattern format or regular format
+}
+
+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. +

+Regular substitution example

Let the command be: -
    msi -S substitute template
-and the template file -
    first name is ${first}
-    family name is ${family}
-and file substitute -
    {first=Marty,family=Kraimer}
-    {first=Irma,family=Kraimer}
-then the following is written to stdout. -
    first name is Marty
+
    msi -S substitute template
+template is +
    first name is ${first}
+    family name is ${family}
+substitute is +
    {first=Marty,family=Kraimer}
+    {first=Irma,family=Kraimer}
+The following is written to stdout. +
    first name is Marty
     family name is Kraimer
     first name is Irma
-    family name is Kraimer
+    family name is Kraimer
-

-Pattern substitution example

+

+Pattern substitution example

Let the command be: -
    msi -S pattern template
-and pattern file -
    pattern {first,last}
-    {first=Marty,family=Kraimer}
-    {first=Irma,family=Kraimer}
-then the following is written to stdout. -
    first name is Marty
+
    msi -S pattern template
+pattern is +
    pattern {first,last}
+    {Marty,Kraimer}
+    {Irma,Kraimer}
+template is the same as in the previous example. +

The following is written to stdout. +

    first name is Marty
     family name is Kraimer
     first name is Irma
-    family name is Kraimer
+    family name is Kraimer
-

-Some Details

+

+dbTemplate example

+Let the command be +
+
msi -S xxx.substitutions
+
+xxx.substitutions is +
+
file template {
+    pattern {first,last}
+    {Marty,Kraimer}
+    {Irma,Kraimer}
+    pattern {last,first}
+    {Smith,Bill}
+    {Smith,Mary}
+}
+file template {
+    {first=Marty,last=Kraimer}
+    {first=Irma,last=Kraimer}
+}
+
+template is the same as in the previous example.. +

The following is written to stdout +

+
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
+
+ +

+Some Details

Building msi -
    msi is built as a normal extensions product. It should be built with -base version 3.13.0beta11 or later.
+
    msi is built as a normal extensions product. It should be built with +base version 3.13.0beta11 or later.
-
-Line length limits
+
+Line length limits
-
    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.
+
    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.
macLib -
    Currently the only macLib documentation is in macLibNOTES and macLibREADME -which are in base/src/libCom.
+
    Currently the only macLib documentation is in macLibNOTES and macLibREADME +which are in base/src/libCom.
template file syntax -
    except for lines containing include or substitute commands each line +
      except for lines containing include or substitute commands each line is just passed to macLib. Lines containing these commands MUST be of the -form:
    +form:
-
        include "<file name>"
+
        include "<file name>"
-
        or
+
        or
-
        substitute "<substitutions>"
+
        substitute "<substitutions>"
-
    White space is allowed before and after the command and after the quoted +
      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:
    +escape character. For example:
-
        substitute "a=\"val\""
+
        substitute "a=\"val\""
-
    specifies the substitution
+
    specifies the substitution
-
        a=val
+
        a=val
-
    If a line does have the above syntax it is just passed to macLib for -processing without any notification. Thus the input line:
+
    If a line does have the above syntax it is just passed to macLib for +processing without any notification. Thus the input line:
-
        include "myfile" #include file
+
        include "myfile" #include file
-
    would just be passed to macLib, i.e. it would NOT be considered an -include command.
+
    would just be passed to macLib, i.e. it would NOT be considered an +include command.
substitution  file syntax -
    A comment line may appear anywhere and is just ignored. A comment line +
      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. - -

      For items within braces separators may be given between items. A separator +

      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. - -

      Each item within braces can be an alphanumeric token or a quoted string. +

      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. - -

      Thus -

          {a=aa b=bb c="\"cc\""}
      +

      Thus +

          {a=aa b=bb c="\"cc\""}
      and -
          {a=aa,b=bb,c="\"cc\""}
      +
          {a=aa,b=bb,c="\"cc\""}
      and -
          {
      +
          {
               a="aa"
               b="bb",
               c="\"cc\""
      -    }
      -are all equivalent.
    +    } +are all equivalent.
- - + + From 086703a07a70d197a45085c28f3c7398c0b98672 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Thu, 6 Jan 2000 22:03:28 +0000 Subject: [PATCH 08/50] make MAX_BUFFER_SIZE larger; allow empty substitutions --- msi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msi.c b/msi.c index 70e97d505..766c73a8f 100644 --- a/msi.c +++ b/msi.c @@ -25,7 +25,7 @@ of this distribution. #include #include -#define MAX_BUFFER_SIZE 1024 +#define MAX_BUFFER_SIZE 4096 /*Forward references to local routines*/ static void usageExit(void); @@ -558,6 +558,7 @@ static int substituteGetNextSet(void *pvt,char **filename) *filename = psubInfo->filename; while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); if(psubFile->token==tokenLBrace) return(TRUE); + if(psubFile->token==tokenRBrace) return(FALSE); if(psubFile->token!=tokenString || strcmp(psubFile->string,"pattern")!=0) { subFileErrPrint(psubFile,"Expecting pattern"); From 34431b0a811f3c9fc855a40dc3af5d397dc21256 Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Wed, 5 Apr 2000 14:22:21 +0000 Subject: [PATCH 09/50] allow substitutions buffer to grow --- msi.c | 48 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/msi.c b/msi.c index 766c73a8f..f8308c423 100644 --- a/msi.c +++ b/msi.c @@ -459,7 +459,9 @@ typedef struct subInfo { char *filename; int isPattern; ELLLIST patternList; - char macroReplacements[MAX_BUFFER_SIZE]; + size_t size; + size_t curLength; + char *macroReplacements; }subInfo; static char *subGetNextLine(subFile *psubFile); @@ -467,6 +469,7 @@ static tokenType subGetNextToken(subFile *psubFile); static void subFileErrPrint(subFile *psubFile,char * message); static void freeSubFile(subInfo *psubInfo); static void freePattern(subInfo *psubInfo); +static void catMacroReplacements(subInfo *psubInfo,const char *value); void freeSubFile(subInfo *psubInfo) { @@ -591,11 +594,10 @@ static char *substituteGetReplacements(void *pvt) { subInfo *psubInfo = (subInfo *)pvt; subFile *psubFile = psubInfo->psubFile; - char *pNext; patternNode *ppatternNode; - pNext = &psubInfo->macroReplacements[0]; - psubInfo->macroReplacements[0] = 0; + if(psubInfo->macroReplacements) psubInfo->macroReplacements[0] = 0; + psubInfo->curLength = 0; while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); if(psubFile->token==tokenRBrace && psubInfo->isFile) { psubInfo->isFile = FALSE; @@ -623,12 +625,12 @@ static char *substituteGetReplacements(void *pvt) subFileErrPrint(psubFile,"Illegal token"); exit(-1); } - if(gotFirstPattern) strcat(psubInfo->macroReplacements,","); + if(gotFirstPattern) catMacroReplacements(psubInfo,","); gotFirstPattern = TRUE; if(ppatternNode) { - strcat(psubInfo->macroReplacements,ppatternNode->var); - strcat(psubInfo->macroReplacements,"="); - strcat(psubInfo->macroReplacements,psubFile->string); + catMacroReplacements(psubInfo,ppatternNode->var); + catMacroReplacements(psubInfo,"="); + catMacroReplacements(psubInfo,psubFile->string); ppatternNode = (patternNode *)ellNext(&ppatternNode->node); } else { subFileErrPrint(psubFile,"more values than patterns"); @@ -641,10 +643,10 @@ static char *substituteGetReplacements(void *pvt) subGetNextToken(psubFile); return(psubInfo->macroReplacements); case tokenSeparater: - strcat(psubInfo->macroReplacements,","); + catMacroReplacements(psubInfo,","); break; case tokenString: - strcat(psubInfo->macroReplacements,psubFile->string); + catMacroReplacements(psubInfo,psubFile->string); break; default: subFileErrPrint(psubFile,"Illegal token"); @@ -742,3 +744,29 @@ static tokenType subGetNextToken(subFile *psubFile) psubFile->token = tokenString; return(tokenString); } + +static void catMacroReplacements(subInfo *psubInfo,const char *value) +{ + size_t len = strlen(value); + + if(psubInfo->size <= (psubInfo->curLength + len)) { + size_t newsize = psubInfo->size + MAX_BUFFER_SIZE; + char *newbuf; + + if(newsize <= psubInfo->curLength + len) + newsize = psubInfo->curLength + len + 1; + newbuf = calloc(1,newsize); + if(!newbuf) { + fprintf(stderr,"calloc failed for size %d\n",newsize); + exit(1); + } + if(psubInfo->macroReplacements) { + memcpy(newbuf,psubInfo->macroReplacements,psubInfo->curLength); + free(psubInfo->macroReplacements); + } + psubInfo->size = newsize; + psubInfo->macroReplacements = newbuf; + } + strcat(psubInfo->macroReplacements,value); + psubInfo->curLength += len; +} From db2724bbc9c655e5518dafd95d7494f2db2971fe Mon Sep 17 00:00:00 2001 From: "Janet B. Anderson" Date: Fri, 2 Aug 2002 15:39:51 +0000 Subject: [PATCH 10/50] Added license information. --- LICENSE | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 21 ++++++++--------- Makefile.Host | 8 +++++++ Makefile.Unix | 16 ------------- msi.c | 18 +++++++-------- 5 files changed, 90 insertions(+), 37 deletions(-) create mode 100644 LICENSE delete mode 100644 Makefile.Unix diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..9f03a0c48 --- /dev/null +++ b/LICENSE @@ -0,0 +1,64 @@ +Copyright (c) 2002 University of Chicago. All rights reserved. + +msi is distributed subject to the following license conditions: + + SOFTWARE LICENSE AGREEMENT + Software: Macro Substitution and Include Tool (msi) + + 1. The "Software", below, refers to msi (in either source code, or + binary form and accompanying documentation). Each licensee is + addressed as "you" or "Licensee." + + 2. The copyright holders shown above and their third-party licensors + hereby grant Licensee a royalty-free nonexclusive license, subject to + the limitations stated herein and U.S. Government license rights. + + 3. You may modify and make a copy or copies of the Software for use + within your organization, if you meet the following conditions: + a. Copies in source code must include the copyright notice and this + Software License Agreement. + b. Copies in binary form must include the copyright notice and this + Software License Agreement in the documentation and/or other + materials provided with the copy. + + 4. You may modify a copy or copies of the Software or any portion of it, + thus forming a work based on the Software, and distribute copies of + such work outside your organization, if you meet all of the following + conditions: + a. Copies in source code must include the copyright notice and this + Software License Agreement; + b. Copies in binary form must include the copyright notice and this + Software License Agreement in the documentation and/or other + materials provided with the copy; + c. Modified copies and works based on the Software must carry + prominent notices stating that you changed specified portions of + the Software. + + 5. Portions of the Software resulted from work developed under a U.S. + Government contract and are subject to the following license: the + Government is granted for itself and others acting on its behalf a + paid-up, nonexclusive, irrevocable worldwide license in this computer + software to reproduce, prepare derivative works, and perform publicly + and display publicly. + + 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY + OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE + UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR + EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS + FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME + ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, + OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE + SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT + THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE + OR THAT ANY ERRORS WILL BE CORRECTED. + + 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR + THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT + OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, + CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, + INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY + REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF + CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR + OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE + POSSIBILITY OF SUCH LOSS OR DAMAGES. diff --git a/Makefile b/Makefile index 39cb7cad1..c4e78f1c4 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,14 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# This file is distributed subject to a Software License Agreement found +# in the file LICENSE that is included with this distribution. +#************************************************************************* # # $Id$ # TOP = ../.. -ifneq ($(wildcard $(TOP)/config)x,x) - # New Makefile.Host config file location - include $(TOP)/config/CONFIG_EXTENSIONS - include $(TOP)/config/RULES_ARCHS -else - # Old Makefile.Unix config file location - EPICS=../../.. - include $(EPICS)/config/CONFIG_EXTENSIONS - include $(EPICS)/config/RULES_ARCHS -endif - +include $(TOP)/config/CONFIG_EXTENSIONS +include $(TOP)/config/RULES_ARCHS diff --git a/Makefile.Host b/Makefile.Host index 684d1d8e6..1e5493b63 100644 --- a/Makefile.Host +++ b/Makefile.Host @@ -1,3 +1,11 @@ +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# This file is distributed subject to a Software License Agreement found +# in the file LICENSE that is included with this distribution. +#************************************************************************* TOP = ../../.. include $(TOP)/config/CONFIG_EXTENSIONS diff --git a/Makefile.Unix b/Makefile.Unix deleted file mode 100644 index f33d079ce..000000000 --- a/Makefile.Unix +++ /dev/null @@ -1,16 +0,0 @@ -EPICS = ../../../.. -include Target.include -include $(EPICS)/config/CONFIG_EXTENSIONS - -DEPLIBS = $(EPICS_BASE_LIB)/libCom.a -USR_LDLIBS = -lCom -USR_INCLUDES = -I$(EPICS_EXTENSIONS_INCLUDE) -USR_CFLAGS = -L$(EPICS_EXTENSIONS_LIB) - -#CMPLR = OLD - -SRCS.c= ../msi.c -PROD = msi - -include $(EPICS)/config/RULES.Unix - diff --git a/msi.c b/msi.c index f8308c423..88d5ed506 100644 --- a/msi.c +++ b/msi.c @@ -1,14 +1,12 @@ +/*************************************************************************\ +* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2002 The Regents of the University of California, as +* Operator of Los Alamos National Laboratory. +* This file is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ /*msi - macro sunstitutions and include */ -/***************************************************************** - COPYRIGHT NOTIFICATION -***************************************************************** - -(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO - -This software was developed under a United States Government license -described on the COPYRIGHT_UniversityOfChicago file included as part -of this distribution. -**********************************************************************/ /* * Modification Log: From 0b6dfa961d9c9685ccd65ab38005a8b69797f151 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Fri, 2 Aug 2002 15:39:52 +0000 Subject: [PATCH 11/50] This commit was manufactured by cvs2svn to create tag 'MSI-R1-2'. From e79662e0e101e30a897a8871ddd2c8b4a951bac5 Mon Sep 17 00:00:00 2001 From: "W. Eric Norum" Date: Thu, 14 Aug 2003 13:52:35 +0000 Subject: [PATCH 12/50] Add -o command-line option to specify output file. Perform environment variable macro expansion of substitution file names. --- msi.c | 17 ++++++++++++++--- msi.html | 32 +++++++++++++++++++------------- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/msi.c b/msi.c index 88d5ed506..82ae20aaf 100644 --- a/msi.c +++ b/msi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,11 @@ int main(int argc,char **argv) pval = (narg==1) ? (argv[1]+2) : argv[2]; if(strncmp(argv[1],"-I",2)==0) { inputAddPath(inputPvt,pval); + } else if(strncmp(argv[1],"-o",2)==0) { + if(freopen(pval,"w",stdout)==NULL) { + fprintf(stderr,"Can't open %s for writing: %s\n", pval, strerror(errno)); + exit(1); + } } else if(strncmp(argv[1],"-M",2)==0) { addMacroReplacements(macPvt,pval); } else if(strncmp(argv[1],"-S",2)==0) { @@ -113,7 +119,7 @@ int main(int argc,char **argv) void usageExit(void) { - fprintf(stderr,"usage: msi -V -Ipath ... -Msub ... -Ssubfile template\n"); + fprintf(stderr,"usage: msi -V -opath -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); @@ -547,8 +553,13 @@ static int substituteGetNextSet(void *pvt,char **filename) } freePattern(psubInfo); free((void *)psubInfo->filename); - psubInfo->filename = calloc(strlen(psubFile->string)+1,sizeof(char)); - strcpy(psubInfo->filename,psubFile->string); + if(psubFile->string[0]=='"'&&psubFile->string[strlen(psubFile->string)-1]=='"') { + psubFile->string[strlen(psubFile->string)-1]='\0'; + psubInfo->filename = macEnvExpand(psubFile->string+1); + } + else { + psubInfo->filename = macEnvExpand(psubFile->string); + } while(subGetNextToken(psubFile)==tokenSeparater); if(psubFile->token!=tokenLBrace) { subFileErrPrint(psubFile,"Expecting {"); diff --git a/msi.html b/msi.html index eb9a6a027..328e8f0f0 100644 --- a/msi.html +++ b/msi.html @@ -25,15 +25,18 @@ files accepted by dbLoadTemplate or subtool.

Command Syntax:

-
msi -V -Idir -Msub -Ssubfile template
+
msi -V -ofile -Idir -Msub -Ssubfile template
NOTE: All parameters are optional and a space is optional between  --I, -M, and -S  and the  associated value. Output is written -to stdout. +-o, -I, -M, and -S  and the  associated value. Output is written +to stdout unless the -o option is given.

Where:

-V

    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.
+is not written to the output. +-o file +
    Output will be written to the specifed file rather than to the standard output.
+ -I dir
    This parameter, which may be repeated, specifies a search path for include commands. For example:
@@ -71,7 +74,7 @@ $(c) or ${c} is replaced by cval template
    The input file. If no file is specified then input is taken from stdin, i.e. msi can be used as a filter. See below for a description of commands -that can be imbedded in the template file.
+that can be embedded in the template file. NOTE: It is not possible to display usage by just typing msi since executing the command with no arguments i s a valid command. To show usage specify an illegal switch, e.g. @@ -81,7 +84,7 @@ specify an illegal switch, e.g.

Template File Format

-This file contains the text to be read and written to stdout after macro +This file contains the text to be read and written to the output after macro substitution is performed. If no file is given then input is read from stdin. In addition the file can have lines containing include and substitute commands. The format of these commands are: @@ -99,7 +102,7 @@ and template is     include "includeFile"     substitute "first=Irma,family=Kraimer"     include "includeFile" -then the following is written to stdout. +then the following is written to the output.
    first name is Marty
     family name is Kraimer
     first name is Irma
@@ -150,10 +153,13 @@ dbTemplate Format
     pattern format or regular format
 }
-For thedbTemplate format, the command line template argument is optional. +For the template 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. +The file name may appear inside double quotation marks; these are only required +if the name contains any environment variable macros of the form ${MOTOR} which +will be expanded before the file is opened.

Regular substitution example

Let the command be: @@ -164,7 +170,7 @@ Let the command be: substitute is
    {first=Marty,family=Kraimer}
     {first=Irma,family=Kraimer}
-The following is written to stdout. +The following is written to the output.
    first name is Marty
     family name is Kraimer
     first name is Irma
@@ -179,7 +185,7 @@ Let the command be:
     {Marty,Kraimer}
     {Irma,Kraimer}
template is the same as in the previous example. -

The following is written to stdout. +

The following is written to the output.

    first name is Marty
     family name is Kraimer
     first name is Irma
@@ -207,7 +213,7 @@ file template {
 }
template is the same as in the previous example.. -

The following is written to stdout +

The following is written to the output

first name is Marty
 family name is Kraimer
@@ -249,7 +255,7 @@ form:
 
        substitute "<substitutions>"
    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 +string. If embedded quotes are needed the \ character can be used as an escape character. For example:
        substitute "a=\"val\""
@@ -273,7 +279,7 @@ character of the comment line. is either white space or a comma. White space is any of the following: space, formfeed, newline, carriage return, tab, vertical tab.

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 +The characters \" can be used for embedded 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.

Thus From 3b47c2f4ece8c2e0c58bacce7ad5da6e249f7bd0 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Thu, 14 Aug 2003 13:52:36 +0000 Subject: [PATCH 13/50] This commit was manufactured by cvs2svn to create tag 'MSI-R1-3'. From 7ad050fba67b0925bb08e48be82881da673e31ec Mon Sep 17 00:00:00 2001 From: Marty Kraimer Date: Tue, 11 May 2004 14:44:21 +0000 Subject: [PATCH 14/50] remove warnings from GNU compiler --- msi.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/msi.c b/msi.c index 82ae20aaf..b223518d5 100644 --- a/msi.c +++ b/msi.c @@ -104,7 +104,7 @@ int main(int argc,char **argv) fprintf(stderr,"no template file\n"); usageExit(); } - while(pval = substituteGetReplacements(substitutePvt)){ + while((pval = substituteGetReplacements(substitutePvt))){ addMacroReplacements(macPvt,pval); makeSubstitutions(inputPvt,macPvt,filename); } @@ -151,10 +151,9 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) char *input; static char buffer[MAX_BUFFER_SIZE]; int n; - char *subStringLocation; inputBegin(inputPvt,templateName); - while(input = inputNextLine(inputPvt)) { + while((input = inputNextLine(inputPvt))) { int expand=TRUE; char *p; char *command = 0; @@ -265,7 +264,7 @@ static void inputDestruct(void *pvt) pathNode *ppathNode; inputCloseAllFiles(pinputData); - while(ppathNode = (pathNode *)ellFirst(&pinputData->pathList)) { + while((ppathNode = (pathNode *)ellFirst(&pinputData->pathList))) { ellDelete(&pinputData->pathList,&ppathNode->node); free((void *)ppathNode->directory); free((void *)ppathNode); @@ -314,7 +313,6 @@ static void inputAddPath(void *pvt, char *path) static void inputBegin(void *pvt,char *fileName) { inputData *pinputData = (inputData *)pvt; - inputFile *pinputFile; inputCloseAllFiles(pinputData); inputOpenFile(pinputData,fileName); @@ -326,7 +324,7 @@ static char *inputNextLine(void *pvt) inputFile *pinputFile; char *pline; - while(pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList)) { + while((pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList))) { pline = fgets(pinputData->inputBuffer,MAX_BUFFER_SIZE,pinputFile->fp); if(pline) { ++pinputFile->lineNum; @@ -373,7 +371,7 @@ static void inputOpenFile(inputData *pinputData,char *filename) ELLLIST *ppathList = &pinputData->pathList; pathNode *ppathNode = 0; inputFile *pinputFile; - char *fullname; + char *fullname = 0; FILE *fp = 0; if(!filename) { @@ -432,7 +430,7 @@ static void inputCloseAllFiles(inputData *pinputData) { inputFile *pinputFile; - while(pinputFile=(inputFile *)ellFirst(&pinputData->inputFileList)){ + while((pinputFile=(inputFile *)ellFirst(&pinputData->inputFileList))){ inputCloseFile(pinputData); } } @@ -490,7 +488,7 @@ void freeSubFile(subInfo *psubInfo) void freePattern(subInfo *psubInfo) { patternNode *ppatternNode; - while(ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList)) { + while((ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList))) { ellDelete(&psubInfo->patternList,&ppatternNode->node); free(ppatternNode->var); free(ppatternNode); @@ -501,10 +499,8 @@ void freePattern(subInfo *psubInfo) static void substituteDestruct(void *pvt) { subInfo *psubInfo = (subInfo *)pvt; - subFile *psubFile = psubInfo->psubFile; freePattern(psubInfo); - freeSubFile(psubInfo); free((void *)psubInfo); return; } @@ -514,7 +510,6 @@ static void substituteOpen(void **ppvt,char *substitutionName) subInfo *psubInfo; subFile *psubFile; FILE *fp; - patternNode *ppatternNode; psubInfo = calloc(1,sizeof(subInfo)); *ppvt = (void *)psubInfo; @@ -539,7 +534,6 @@ static int substituteGetNextSet(void *pvt,char **filename) { subInfo *psubInfo = (subInfo *)pvt; subFile *psubFile = psubInfo->psubFile; - FILE *fp; patternNode *ppatternNode; *filename = 0; From d813690363acf5234fbfb74b9739da7191ec4020 Mon Sep 17 00:00:00 2001 From: "W. Eric Norum" Date: Thu, 3 Jun 2004 21:09:20 +0000 Subject: [PATCH 15/50] Limit scope of macro definitions to a single template file. --- msi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/msi.c b/msi.c index b223518d5..de578e309 100644 --- a/msi.c +++ b/msi.c @@ -104,10 +104,12 @@ int main(int argc,char **argv) fprintf(stderr,"no template file\n"); usageExit(); } + macPushScope(macPvt); while((pval = substituteGetReplacements(substitutePvt))){ addMacroReplacements(macPvt,pval); makeSubstitutions(inputPvt,macPvt,filename); } + macPopScope(macPvt); } substituteDestruct(substitutePvt); } From 6a9163988d4b1ceb0c1229474cd3f699002e01ab Mon Sep 17 00:00:00 2001 From: "W. Eric Norum" Date: Thu, 3 Jun 2004 21:34:55 +0000 Subject: [PATCH 16/50] 1) Always print expanded line regardless of the state of the -V flag and the presence or absence of undefined macros. 2) Exit with status 2 if warnings are enabled (-V) and one or more macros is undefined. --- msi.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/msi.c b/msi.c index de578e309..6cee34fbe 100644 --- a/msi.c +++ b/msi.c @@ -45,6 +45,10 @@ static void substituteDestruct(void *substitutePvt); static void substituteOpen(void **substitutePvt,char *substitutionName); static int substituteGetNextSet(void *substitutePvt,char **filename); static char *substituteGetReplacements(void *substitutePvt); + +/*Exit status*/ +static int exitStatus = 0; + int main(int argc,char **argv) { @@ -116,7 +120,7 @@ int main(int argc,char **argv) inputDestruct(inputPvt); free((void *)templateName); free((void *)substitutionName); - return(0); + return(exitStatus); } void usageExit(void) @@ -219,10 +223,10 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) endif: if(expand) { n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1); + fputs(buffer,stdout); if(n<0) { inputErrPrint(inputPvt); - } else { - printf("%s",buffer); + exitStatus = 2; } } } From 8e417d3032dc508f65be97fc720e464fceea3a28 Mon Sep 17 00:00:00 2001 From: "W. Eric Norum" Date: Fri, 4 Jun 2004 13:59:40 +0000 Subject: [PATCH 17/50] Add exit status description. --- msi.html | 315 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 164 insertions(+), 151 deletions(-) diff --git a/msi.html b/msi.html index 328e8f0f0..82c168791 100644 --- a/msi.html +++ b/msi.html @@ -1,103 +1,108 @@ - + - - + + - -

-msi: Macro Substitution and Include Tool

-Marty Kraimer -
Argonne National Laboratory - Advanced Photon Source -
Original:  April 26, 1999 -

-Introduction

-msi is a general purpose macro substitution/include tool. It accepts as -input an ascii template file. It looks for lines containing two reserved -command names: include and substitute. It also looks for and performs substitutions + +

msi: Macro Substitution and Include Tool

+Marty Kraimer
+Argonne National Laboratory - Advanced Photon Source
+Original:  April 26, 1999 + +

Introduction

+msi is a general purpose macro substitution/include tool. It accepts as input +an ascii template file. It looks for lines containing two reserved command +names: include and substitute. It also looks for and performs substitutions on macros of the form $(var) and ${var}. It uses the macLib, an epics base library created by William Lupton, to perform the substitutions. +

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. -
  -

-Command Syntax:

+file. This substitution file allows the same format as the substitution files +accepted by dbLoadTemplate or subtool.

+

Command Syntax:

msi -V -ofile -Idir -Msub -Ssubfile template
-NOTE: All parameters are optional and a space is optional between  --o, -I, -M, and -S  and the  associated value. Output is written -to stdout unless the -o option is given. -

Where: -

-V -

    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 the output.
--o file -
    Output will be written to the specifed file rather than to the standard output.
+NOTE: All parameters are optional and a space is optional between  -o, +-I, -M, and -S  and the  associated value. Output is written to +stdout unless the -o option is given. --I dir -
    This parameter, which may be repeated, specifies a search path for -include commands. For example:
- -
-    msi -I "/home/phoebus/MRK/examples:." -I".." template
- -
-specifies the search path:
- -
-    /home/phoebus/MRK/examples:.:..
- -
-M substitutions -
    This parameter, which may be repeated, specifies marco substitutions. -For example:
- -
-    msi -M "a=aval,b=bval" -M"c=cval" template
- -
    specifies that in the template file each occurrence of:
+

Where:

+

-V

    -
    -$(a) or ${a} is replaced by aval
    + If this parameter is specified then an undefined macro is considered an + error. An error message is generated and when msi terminates it will do so + with an exit status of 2. -
    -$(b) or ${b} is replaced by bval
    +

    +
+-o file +
    + Output will be written to the specifed file rather than to the standard + output. -
    -$(c) or ${c} is replaced by cval
    +

    +
+-I dir +
    + This parameter, which may be repeated, specifies a search path for include + commands. For example:
+
+
    msi -I "/home/phoebus/MRK/examples:." -I".." + template
+
+
specifies the search path:
+
    /home/phoebus/MRK/examples:.:..
+
+-M substitutions +
    + This parameter, which may be repeated, specifies marco substitutions. For + example:
+
+
    msi -M "a=aval,b=bval" -M"c=cval" + template
+
+
    + specifies that in the template file each occurrence of:
+
    +
    +
    $(a) or ${a} is replaced by aval
    +
    +
    $(b) or ${b} is replaced by bval
    +
    $(c) or ${c} is replaced by cval
-S subfile -
    The substitution file. See below for format.
+
    + The substitution file. See below for format.
template -
    The input file. If no file is specified then input is taken from stdin, -i.e. msi can be used as a filter. See below for a description of commands -that can be embedded in the template file.
+
    + The input file. If no file is specified then input is taken from stdin, + i.e. msi can be used as a filter. See below for a description of commands + that can be embedded in the template file.
NOTE: It is not possible to display usage by just typing msi since executing the command with no arguments i s a valid command. To show usage specify an illegal switch, e.g.
    -
    msi -help
+
msi -help
-

-Template File Format

+

Template File Format

This file contains the text to be read and written to the output after macro -substitution is performed. If no file is given then input is read from -stdin. In addition the file can have lines containing include and substitute +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:
    include "file"
-
    substitute "var=value,var=value,..."
For example let the command be:
    msi template
and file includeFile contain:
    first name is ${first}
     family name is ${family}
-and template is -
  +and template is
    substitute "first=Marty,family=Kraimer"
     include "includeFile"
     substitute "first=Irma,family=Kraimer"
@@ -108,27 +113,26 @@ then the following is written to the output.
     first name is Irma
     family name is Kraimer
-

-Substitution File Format

+

Substitution File Format

The optional substitution file has three formats: regular, pattern, and -dbTemplate format. Lets discuss  each separately -
  -

-regular format

+dbTemplate format. Lets discuss  each separately
+  + +

regular format

-
{var1=value1,var2=value2,...}
+  
{var1=value1,var2=value2,...}
 {var1=value1,var2=value2,...}
 ...
-After reading each set of replacements within braces,   the template -file is read and macro substitution performed. -
  -

-pattern  format:

+After reading each set of replacements within braces,   the +template file is read and macro substitution performed.
+  + +

pattern  format:

-
pattern {var1,var2,...}
+  
pattern {var1,var2,...}
 {value1,value2,...}
 {value1,value2,...}
 pattern {var1,var2,...}
@@ -136,32 +140,31 @@ pattern {var1,var2,...}
 {value1,value2,...}
This is the same as the regular format: +
-
{var1=value1,var2=value2}
+  
{var1=value1,var2=value2}
 ...
-

-dbTemplate Format

+

dbTemplate Format

-
file template {
+  
file template {
     pattern format or regular format
 }
- -
file template {
+  
file template {
     pattern format or regular format
 }
-For the template 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. -The file name may appear inside double quotation marks; these are only required -if the name contains any environment variable macros of the form ${MOTOR} which -will be expanded before the file is opened. -

-Regular substitution example

+For the template 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. The file name may +appear inside double quotation marks; these are only required if the name +contains any environment variable macros of the form ${MOTOR} which will be +expanded before the file is opened. + +

Regular substitution example

Let the command be:
    msi -S substitute template
template is @@ -176,8 +179,7 @@ The following is written to the output.     first name is Irma     family name is Kraimer
-

-Pattern substitution example

+

Pattern substitution example

Let the command be:
    msi -S pattern template
pattern is @@ -185,21 +187,23 @@ Let the command be:     {Marty,Kraimer}     {Irma,Kraimer} template is the same as in the previous example. -

The following is written to the output. + +

The following is written to the output.

    first name is Marty
     family name is Kraimer
     first name is Irma
     family name is Kraimer
-

-dbTemplate example

+

dbTemplate example

Let the command be +
-
msi -S xxx.substitutions
+
msi -S xxx.substitutions
xxx.substitutions is +
-
file template {
+  
file template {
     pattern {first,last}
     {Marty,Kraimer}
     {Irma,Kraimer}
@@ -213,9 +217,11 @@ file template {
 }
template is the same as in the previous example.. -

The following is written to the output + +

The following is written to the output

+
-
first name is Marty
+  
first name is Marty
 family name is Kraimer
 first name is Irma
 family name is Kraimer
@@ -229,60 +235,61 @@ first name is Irma
 family name is Kraimer
-

-Some Details

+

Some Details

Building msi -
    msi is built as a normal extensions product. It should be built with -base version 3.13.0beta11 or later.
- -
-Line length limits
- -
    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.
+
    + msi is built as a normal extensions product. It should be built with base + version 3.13.0beta11 or later.
+
+
Line length limits
+
+
    + 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.
macLib -
    Currently the only macLib documentation is in macLibNOTES and macLibREADME -which are in base/src/libCom.
+
    + Currently the only macLib documentation is in macLibNOTES and macLibREADME + which are in base/src/libCom.
template file syntax -
    except for lines containing include or substitute commands each line -is just passed to macLib. Lines containing these commands MUST be of the +
      + except for lines containing include or substitute commands each line is + just passed to macLib. Lines containing these commands MUST be of the form:
    - -
            include "<file name>"
    - +
            include "<file name>"
            or
    - -
            substitute "<substitutions>"
    - -
      White space is allowed before and after the command and after the quoted -string. If embedded quotes are needed the \ character can be used as an -escape character. For example:
    - +
            substitute "<substitutions>"
    +
      + White space is allowed before and after the command and after the quoted + string. If embedded quotes are needed the \ character can be used as an + escape character. For example:
            substitute "a=\"val\""
    - -
      specifies the substitution
    - +
      + specifies the substitution
            a=val
    - -
      If a line does have the above syntax it is just passed to macLib for -processing without any notification. Thus the input line:
    - +
      + If a line does have the above syntax it is just passed to macLib for + processing without any notification. Thus the input line:
            include "myfile" #include file
    +
      + would just be passed to macLib, i.e. it would NOT be considered an include + command.
    +substitution  file syntax +
      + 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. -
        would just be passed to macLib, i.e. it would NOT be considered an -include command.
      -substitution  file syntax -
        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. -

        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. -

        Each item within braces can be an alphanumeric token or a quoted string. -The characters \" can be used for embedded 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. -

        Thus +

        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.

        + +

        Each item within braces can be an alphanumeric token or a quoted string. + The characters \" can be used for embedded 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.

        + +

        Thus

        +
          {a=aa b=bb c="\"cc\""}
      and
          {a=aa,b=bb,c="\"cc\""}
      @@ -292,7 +299,13 @@ and         b="bb",         c="\"cc\""     } -are all equivalent.
    +are all equivalent. +

    + +

    Exit Status

    +

    0 - Success.

    +

    1 - Can't open/create file, or other I/O error.

    +

    2 - -V option specified and one or more undefined macros were encountered.

    From d5d828aa7ba8c38e3b3cfb93a46dd88c877cda52 Mon Sep 17 00:00:00 2001 From: "W. Eric Norum" Date: Mon, 14 Jun 2004 18:02:00 +0000 Subject: [PATCH 18/50] Let this compile and run (with reduced capability) on R3.13. --- msi.c | 4 ++++ msi.html | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/msi.c b/msi.c index 6cee34fbe..278746682 100644 --- a/msi.c +++ b/msi.c @@ -26,6 +26,10 @@ #define MAX_BUFFER_SIZE 4096 +#if ((EPICS_VERSION <= 3) && (EPICS_REVISION <= 13)) +#define macEnvExpand(x) strdup(x) +#endif + /*Forward references to local routines*/ static void usageExit(void); static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval); diff --git a/msi.html b/msi.html index 82c168791..86ec39018 100644 --- a/msi.html +++ b/msi.html @@ -161,8 +161,9 @@ 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. The file name may appear inside double quotation marks; these are only required if the name -contains any environment variable macros of the form ${MOTOR} which will be -expanded before the file is opened. +contains any environment variable macros of the form ${ENV_VAR} which will be +expanded before the file is opened. Environment variable macro expansion +is available when msi is linked with EPICS base R3.14.3 or newer.

    Regular substitution example

    Let the command be: From b14965dee5f607d5d3a0af422b6b7dc1015ffd90 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 17 Jun 2004 16:19:47 +0000 Subject: [PATCH 19/50] Build with R3.14 rules if available (not tested...) --- Makefile | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c4e78f1c4..635fdf5ee 100644 --- a/Makefile +++ b/Makefile @@ -10,5 +10,20 @@ # $Id$ # TOP = ../.. -include $(TOP)/config/CONFIG_EXTENSIONS -include $(TOP)/config/RULES_ARCHS + +# If a /configure directory exists, build with 3.14 rules, else +# use /config and the 3.13 rules. +ifeq (0, $(words $(notdir $(wildcard $(TOP)/configure)))) + include $(TOP)/config/CONFIG_EXTENSIONS + include $(TOP)/config/RULES_ARCHS +else + include $(TOP)/configure/CONFIG + + PROD = msi + HTMLS = msi.html + + msi_SRCS = msi.c + PROD_LIBS += Com + + include $(TOP)/configure/RULES +endif From 42b80245b34bdb828ca29ebb4c153ac9fec96e39 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 17 Jun 2004 18:22:06 +0000 Subject: [PATCH 20/50] Significantly revised, added stuff about default values. --- msi.html | 579 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 350 insertions(+), 229 deletions(-) diff --git a/msi.html b/msi.html index 86ec39018..639553968 100644 --- a/msi.html +++ b/msi.html @@ -6,215 +6,400 @@ +

    msi: Macro Substitution and Include Tool

    -Marty Kraimer
    -Argonne National Laboratory - Advanced Photon Source
    -Original:  April 26, 1999 + +
    +

    Version 1.4, June 2004
    +Marty Kraimer (Advanced Photon Source, Argonne National Laboratory)

    +

    Introduction

    -msi is a general purpose macro substitution/include tool. It accepts as input -an ascii template file. It looks for lines containing two reserved command -names: include and substitute. It also looks for and performs substitutions -on macros of the form $(var) and ${var}. It uses the macLib, an epics base -library created by William Lupton, to perform the substitutions. + +

    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 macLib, an EPICS +Base library created by William Lupton, to perform the substitutions.

    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.

    +accepted by dbLoadTemplate or subtool.

    Command Syntax:

    +
    msi -V -ofile -Idir -Msub -Ssubfile template
    -NOTE: All parameters are optional and a space is optional between  -o, --I, -M, and -S  and the  associated value. Output is written to -stdout unless the -o option is given. -

    Where:

    +

    All parameters are optional. The -o, -I, -M, and -S switches may be +separated from their associated value string by spaces if desired. Output will +be written to stdout unless the -o option is given.

    -

    -V

    -
      - If this parameter is specified then an undefined macro is considered an - error. An error message is generated and when msi terminates it will do so - with an exit status of 2. +

      Switches have the following meanings:

      -

      -
    --o file -
      - Output will be written to the specifed file rather than to the standard - output. - -

      -
    --I dir -
      - This parameter, which may be repeated, specifies a search path for include - commands. For example:
    -
        msi -I "/home/phoebus/MRK/examples:." -I".." - template
    +
    -V
    +
    If this parameter is specified then any undefined macro discovered in + the template file which does not have an associated default value is + considered an error. An error message is generated and when msi terminates + it will do so with an exit status of 2.
    + +
    -o file
    +
    Output will be written to the specifed file rather than to the standard + output.
    + +
    -I dir
    +
    This parameter, which may be repeated, specifies a search path for + include commands. For example: + +
    +
    msi -I "/home/phoebus/MRK/examples:." -I".." template
    +
    + + specifies that all named files should be searched for in the following + locations in the order given: + +
      +
    1. /home/phoebus/MRK/examples
    2. +
    3. . (the current directory)
    4. +
    5. .. (the parent of the current directory)
    6. +
    +
    + +
    -M substitutions
    +
    This parameter specifies macro values for the template instance. + Multiple macro values can be specified in one substitution parameter, or in + multiple -M parameters. For example: + +
    +
    msi -M "a=aval,b=bval" -Mc=cval template
    +
    + + specifies that in the template file each occurrence of: + +
    +
    $(a) or ${a} is replaced by aval
    +
    $(b) or ${b} is replaced by bval
    +
    $(c) or ${c} is replaced by cval
    +
    +
    + +
    -S subfile
    +
    The substitution file. See below for format.
    + +
    template
    +
    The input file. If no file is specified then input is taken from + stdin, i.e. msi can be used as a filter. See below for a description of + commands that can be embedded in the template file.
    -
    specifies the search path:
    -
        /home/phoebus/MRK/examples:.:..
    -
    --M substitutions -
      - This parameter, which may be repeated, specifies marco substitutions. For - example:
    -
    -
        msi -M "a=aval,b=bval" -M"c=cval" - template
    -
    -
      - specifies that in the template file each occurrence of:
    -
      -
      -
      $(a) or ${a} is replaced by aval
      -
      -
      $(b) or ${b} is replaced by bval
      -
      $(c) or ${c} is replaced by cval
      -
    --S subfile -
      - The substitution file. See below for format.
    -template -
      - The input file. If no file is specified then input is taken from stdin, - i.e. msi can be used as a filter. See below for a description of commands - that can be embedded in the template file.
    -NOTE: It is not possible to display usage by just typing msi since -executing the command with no arguments i s a valid command. To show usage -specify an illegal switch, e.g. -
      -
    + +

    It is not possible to display usage by just typing msi since +executing the command with no arguments is a valid command. To show usage +specify an illegal switch, e.g.

    + +
    msi -help
    +
    + +

    Exit Status

    + +
    +
    0
    Success. +
    1
    Can't open/create file, or other I/O error. +
    2
    Undefined macros encountered with the -V option specified. +

    Template File Format

    -This file contains the text to be read and written to the output after macro + +

    This file contains the text to be read and written to the output after macro substitution is performed. If no file is given then input is read from stdin. -In addition the file can have lines containing include and substitute -commands. The format of these commands are: -

        include "file"
    -
        substitute "var=value,var=value,..."
    -For example let the command be: -
        msi template
    -and file includeFile contain: -
        first name is ${first}
    -    family name is ${family}
    -and template is
    -  -
        substitute "first=Marty,family=Kraimer"
    -    include "includeFile"
    -    substitute "first=Irma,family=Kraimer"
    -    include "includeFile"
    -then the following is written to the output. -
        first name is Marty
    -    family name is Kraimer
    -    first name is Irma
    -    family name is Kraimer
    +Variable instances to be substituted by macro values are expressed in the +template using the syntax $(name) or +${name}. If msi has been built with EPICS Base version +3.14.7 or later, the template can also provide default values to be used when a +macro has not been given a value, using the syntax +$(name=default) or +${name=default}.

    + +

    For example, using the command

    + +
    +
    msi -M name=Marty template
    +
    + +

    where the file template contains

    + +
    +
    My name is $(name)
    +My age is $(age=none of your business)
    +
    + +

    results in this output:

    + +
    +
    My name is Marty
    +My age is none of your business
    +
    + +

    Macro variables and their default values can be expressed in terms of other +macros if necessary, to almost any level of complexity. Recursive definitions +will generate warning messages on stderr and result in undefined output.

    + +

    The template file is read and processed one line at a time, where the +maximum length of a line before and/or after macro expansion is 1023 characters +— longer input or output lines will cause msi to fail. Within the context +of a single line, macro expansion does not occur when the variable instance +appears inside a single-quoted string, or where the dollar sign $ is +preceded by a back-slash character \, but as with the standard Unix +shells, variables inside double quoted strings are expanded properly.

    + +

    However neither back-slash characters nor quotes or either variety are +removed when generating the output file, so depending on what is being output +the single quote behaviour may not be useful and may even be a hinderance. It +cannot be disabled in the current version of msi.

    + +

    Template file commands

    + +

    In addition to the regular text and variable instances described above, the +template file may also contain commands which allow the insertion of other +template files and the ability to set macro values inside the template file +itself. These commands are:

    + +
    +
    include "file"
    +substitute "var=value,var=value,..."
    +
    + +

    Lines containing commands must be in one of these forms:

    + +
      +
    • include "filename"
    • +
    • substitute "name1=value1, name2=value2, ..."
    • +
    + +

    White space is allowed before and after the command verb, and after the +quoted string. If embedded quotes are needed, the backslash character +\ can be used as an escape character. For example

    + +
    +
    substitute "a=\"val\""
    +
    + +

    specifies that (unless a is subsequently redefined) wherever a +$(a) macro appears in the template below this point, the text +"val" (including the double quote characters) will appear in the +output instead.

    + +

    If a line does match either syntax above it is just passed to macLib for +processing without any notification. Thus the input line:

    + +
    +
    include "myfile" #include file
    +
    + +

    would just be passed to macLib, i.e. it would not be considered an +include command.

    + +

    As an example of these commands, let the Unix command be:

    + +
    +
    msi template
    +
    + +

    and file includeFile contain:

    + +
    +
    first name is ${first}
    +family name is ${family}
    +
    + +

    and template is

    + +
    +
    substitute "first=Marty,family=Kraimer"
    +include "includeFile"
    +substitute "first=Irma,family=Kraimer"
    +include "includeFile"
    +
    + +

    then the following is written to the output.

    + +
    +
    first name is Marty
    +family name is Kraimer
    +first name is Irma
    +family name is Kraimer
    +
    + +

    Note that on an IOC when using the dbLoadTemplate command, the +template file does not support the substitute command, although +include is supported.

    Substitution File Format

    -The optional substitution file has three formats: regular, pattern, and -dbTemplate format. Lets discuss  each separately
    -  -

    regular format

    +

    The optional substitution file has three formats: regular, pattern, and +dbTemplate format. We will discuss each separately.

    + +

    Regular format

    -
    {var1=value1,var2=value2,...}
    -{var1=value1,var2=value2,...}
    -...
    +
    {var1=set1_val1, var2=set1_val2, ...}
    +{var2=set2_val2, var1=set2_val1, ...}
    +{var1=set3_val1, var2=set3_val2, ...}
    +{var2=set4_val2, var1=set4_val1, ...}
    -After reading each set of replacements within braces,   the -template file is read and macro substitution performed.
    -  -

    pattern  format:

    +

    The template file is output with macro substitutions performed once for each +set of braces containing macro replacement values.

    + +

    Pattern format

    -
    pattern {var1,var2,...}
    -{value1,value2,...}
    -{value1,value2,...}
    -pattern {var1,var2,...}
    -{value1,value2,...}
    -{value1,value2,...}
    +
    pattern {var1, var2, ...}
    +{set1_val1, set1_val2, ...}
    +{set2_val1, set2_val2, ...}
    +pattern {var2, var1, ...}
    +{set3_val2, set3_val1, ...}
    +{set4_val2, set4_val2, ...}
    -This is the same as the regular format: -
    -
    {var1=value1,var2=value2}
    -...
    -
    +

    This produces the same result as the regular format example above.

    dbTemplate Format

    +

    This format is an extension of the format accepted by the EPICS IOC command +dbLoadTemplate, and allows templates to be expanded on the host rather +by using dbLoadTemplate at IOC boot time.

    +
    -
    file template {
    -    pattern format or regular format
    -}
    -
    file template {
    -    pattern format or regular format
    +
    file template {
    +    pattern format or regular format
    +}
    +file "${WHERE}/template2" {
    +    pattern format or regular format
     }
    -For the template 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. The file name may -appear inside double quotation marks; these are only required if the name -contains any environment variable macros of the form ${ENV_VAR} which will be -expanded before the file is opened. Environment variable macro expansion -is available when msi is linked with EPICS base R3.14.3 or newer. + +

    For the dbTemplate format, the template filename does not have to be given +on the command line, and is usually specified in the substitutions file +instead. If a template filename is given on the command line it will override +the filenames listed in the substitutions files.

    + +

    Syntax for all formats

    + +

    A comment line may appear anywhere in a substitution file, and will be +ignored. A comment line is any line beginning with the character #, +which must be the very first character on the line.

    + +

    For definitions within braces given in any of the file formats, a separator +must be given between items. A separator is either a comma, or one or more of +the standard white space characters (space, formfeed, newline, carriage return, +tab or vertical tab).

    + +

    Each item within braces can be an alphanumeric token, or a double-quoted +string. A back-slash character \ can be used to escape a quote +character needed inside a quoted string. These three sets of substitutions are +all equivalent:

    + +
    +
    {a=aa b=bb c="\"cc\""}
    +{b="bb",a=aa,c="\"cc\""}
    +{
    +    c="\"cc\""
    +    b=bb
    +    a="aa"
    +}
    +
    + +

    Within a substitutions file, the file name may appear inside double +quotation marks; these are only required if the name contains environment +variable macros of the form ${ENV_VAR} or $(ENV_VAR), which will be expanded +before the file is opened. Environment variable macro expansion is only +available when msi has been built using EPICS base R3.14.3 or newer.

    Regular substitution example

    -Let the command be: -
        msi -S substitute template
    -template is -
        first name is ${first}
    -    family name is ${family}
    -substitute is -
        {first=Marty,family=Kraimer}
    -    {first=Irma,family=Kraimer}
    -The following is written to the output. -
        first name is Marty
    -    family name is Kraimer
    -    first name is Irma
    -    family name is Kraimer
    + +

    Let the command be:

    + +
    +
    msi -S substitute template
    +
    + +

    The file template contains

    + +
    +
    first name is ${first}
    +family name is ${family}
    +
    + +

    and the file substitute is

    + +
    +
    {first=Marty,family=Kraimer}
    +{first=Irma,family=Kraimer}
    +
    + +

    The following is the output produced:

    + +
    +
    first name is Marty
    +family name is Kraimer
    +first name is Irma
    +family name is Kraimer
    +

    Pattern substitution example

    -Let the command be: -
        msi -S pattern template
    -pattern is -
        pattern {first,last}
    -    {Marty,Kraimer}
    -    {Irma,Kraimer}
    -template is the same as in the previous example. -

    The following is written to the output.

    -
        first name is Marty
    -    family name is Kraimer
    -    first name is Irma
    -    family name is Kraimer
    +

    Let the command be:

    + +
    +
    msi -S pattern template
    +
    + +

    The file pattern contains

    + +
    +
    pattern {first,last}
    +{Marty,Kraimer}
    +{Irma,Kraimer}
    +
    + +

    and template is the same as the previous example:

    + +
    +
    first name is ${first}
    +family name is ${family}
    +
    + +

    This is the output:

    + +
    +
    first name is Marty
    +family name is Kraimer
    +first name is Irma
    +family name is Kraimer
    +

    dbTemplate example

    Let the command be
    -
    msi -S xxx.substitutions
    +
    msi -S xxx.substitutions
    + xxx.substitutions is
    -
    file template {
    -    pattern {first,last}
    -    {Marty,Kraimer}
    -    {Irma,Kraimer}
    -    pattern {last,first}
    -    {Smith,Bill}
    -    {Smith,Mary}
    +
    file template {
    +pattern {first,last}
    +{Marty,Kraimer}
    +{Irma,Kraimer}
    +pattern {last,first}
    +{Smith,Bill}
    +{Smith,Mary}
     }
     file template {
    -    {first=Marty,last=Kraimer}
    -    {first=Irma,last=Kraimer}
    +{first=Marty,last=Kraimer}
    +{first=Irma,last=Kraimer}
     }
    template is the same as in the previous example.. @@ -222,7 +407,7 @@ file template {

    The following is written to the output

    -
    first name is Marty
    +
    first name is Marty
     family name is Kraimer
     first name is Irma
     family name is Kraimer
    @@ -236,77 +421,13 @@ first name is Irma
     family name is Kraimer
    -

    Some Details

    -Building msi -
      - msi is built as a normal extensions product. It should be built with base - version 3.13.0beta11 or later.
    -
    -
    Line length limits
    -
    -
      - 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.
    -macLib -
      - Currently the only macLib documentation is in macLibNOTES and macLibREADME - which are in base/src/libCom.
    -template file syntax -
      - except for lines containing include or substitute commands each line is - just passed to macLib. Lines containing these commands MUST be of the -form:
    -
            include "<file name>"
    -
            or
    -
            substitute "<substitutions>"
    -
      - White space is allowed before and after the command and after the quoted - string. If embedded quotes are needed the \ character can be used as an - escape character. For example:
    -
            substitute "a=\"val\""
    -
      - specifies the substitution
    -
            a=val
    -
      - If a line does have the above syntax it is just passed to macLib for - processing without any notification. Thus the input line:
    -
            include "myfile" #include file
    -
      - would just be passed to macLib, i.e. it would NOT be considered an include - command.
    -substitution  file syntax -
      - 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. +

      Building msi

      -

      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.

      +

      msi is built as a normal extensions product, and can be built with any +version of EPICS Base from 3.13.0beta11 onwards. Base version 3.14.3 or later +is required if the ability to expand environment variables in filenames is +needed. Base version 3.14.7 or later is required to allow the use of default +macro values in template files.

      -

      Each item within braces can be an alphanumeric token or a quoted string. - The characters \" can be used for embedded 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.

      - -

      Thus

      -
    -
        {a=aa b=bb c="\"cc\""}
    -and -
        {a=aa,b=bb,c="\"cc\""}
    -and -
        {
    -        a="aa"
    -        b="bb",
    -        c="\"cc\""
    -    }
    -are all equivalent. - -

    - -

    Exit Status

    -

    0 - Success.

    -

    1 - Can't open/create file, or other I/O error.

    -

    2 - -V option specified and one or more undefined macros were encountered.

    From 460ba036f3b91bf43e48ba3b6587f5995227554e Mon Sep 17 00:00:00 2001 From: "Janet B. Anderson" Date: Fri, 8 Oct 2004 15:20:49 +0000 Subject: [PATCH 21/50] Build msi only for host target. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 635fdf5ee..899de4dd4 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ ifeq (0, $(words $(notdir $(wildcard $(TOP)/configure)))) else include $(TOP)/configure/CONFIG - PROD = msi + PROD_HOST = msi HTMLS = msi.html msi_SRCS = msi.c From 9b3af852af10c7b76a152c25f5ced0dffcb12e24 Mon Sep 17 00:00:00 2001 From: "Janet B. Anderson" Date: Fri, 18 May 2007 16:16:49 +0000 Subject: [PATCH 22/50] Converted to R3.14 Makefiles. --- Makefile | 19 ++++++------------- Makefile.Host | 21 --------------------- 2 files changed, 6 insertions(+), 34 deletions(-) delete mode 100644 Makefile.Host diff --git a/Makefile b/Makefile index 899de4dd4..5ab39416a 100644 --- a/Makefile +++ b/Makefile @@ -11,19 +11,12 @@ # TOP = ../.. -# If a /configure directory exists, build with 3.14 rules, else -# use /config and the 3.13 rules. -ifeq (0, $(words $(notdir $(wildcard $(TOP)/configure)))) - include $(TOP)/config/CONFIG_EXTENSIONS - include $(TOP)/config/RULES_ARCHS -else - include $(TOP)/configure/CONFIG +include $(TOP)/configure/CONFIG - PROD_HOST = msi - HTMLS = msi.html +PROD_HOST = msi +HTMLS = msi.html - msi_SRCS = msi.c - PROD_LIBS += Com +msi_SRCS = msi.c +PROD_LIBS += Com - include $(TOP)/configure/RULES -endif +include $(TOP)/configure/RULES diff --git a/Makefile.Host b/Makefile.Host deleted file mode 100644 index 1e5493b63..000000000 --- a/Makefile.Host +++ /dev/null @@ -1,21 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# This file is distributed subject to a Software License Agreement found -# in the file LICENSE that is included with this distribution. -#************************************************************************* -TOP = ../../.. -include $(TOP)/config/CONFIG_EXTENSIONS - - -PROD_LIBS += Com - -HTMLS += msi.html - -SRCS.c= ../msi.c -PROD = msi - -include $(TOP)/config/RULES.Host - From 83d06f25694d7141e260d8a305040ba4eb45bc7b Mon Sep 17 00:00:00 2001 From: "Janet B. Anderson" Date: Mon, 25 Jun 2007 19:59:12 +0000 Subject: [PATCH 23/50] Initial version. --- README.1st | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.1st diff --git a/README.1st b/README.1st new file mode 100644 index 000000000..60ebbddde --- /dev/null +++ b/README.1st @@ -0,0 +1,2 @@ +The extension distribution file should be unziped and untared +in the extensions/src directory. From 1d9bcafe440dd1a119d71358b123aae75d88633b Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Mon, 25 Jun 2007 19:59:13 +0000 Subject: [PATCH 24/50] This commit was manufactured by cvs2svn to create tag 'MSI-R1-4'. From 0e45345891d8d1034b235016db47c5b21d4dde94 Mon Sep 17 00:00:00 2001 From: "W. Eric Norum" Date: Tue, 29 Apr 2008 23:04:29 +0000 Subject: [PATCH 25/50] Headers no longer provide TRUE/FALSE defines. --- msi.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/msi.c b/msi.c index 278746682..0f316629e 100644 --- a/msi.c +++ b/msi.c @@ -66,7 +66,7 @@ int main(int argc,char **argv) inputConstruct(&inputPvt); macCreateHandle(&macPvt,0); - macSuppressWarning(macPvt,TRUE); + macSuppressWarning(macPvt,1); while((argc>1) && (argv[1][0] == '-')) { narg = (strlen(argv[1])==2) ? 2 : 1; pval = (narg==1) ? (argv[1]+2) : argv[2]; @@ -83,7 +83,7 @@ int main(int argc,char **argv) substitutionName = calloc(strlen(pval)+1,sizeof(char)); strcpy(substitutionName,pval); } else if(strncmp(argv[1],"-V",2)==0) { - macSuppressWarning(macPvt,FALSE); + macSuppressWarning(macPvt,0); narg = 1; /* no argument for this option */ } else { usageExit(); @@ -164,7 +164,7 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) inputBegin(inputPvt,templateName); while((input = inputNextLine(inputPvt))) { - int expand=TRUE; + int expand=1; char *p; char *command = 0; @@ -222,7 +222,7 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) exit(1); } free(copy); - expand = FALSE; + expand = 0; } endif: if(expand) { @@ -295,7 +295,7 @@ static void inputAddPath(void *pvt, char *path) pdir = path; /*an empty name at beginning, middle, or end means current directory*/ while(pdir && *pdir) { - emptyName = ((*pdir == ':') ? TRUE : FALSE); + emptyName = ((*pdir == ':') ? 1 : 0); if(emptyName) ++pdir; ppathNode = (pathNode *)calloc(1,sizeof(pathNode)); ellAdd(ppathList,&ppathNode->node); @@ -309,7 +309,7 @@ static void inputAddPath(void *pvt, char *path) /*unless at end skip past first colon*/ if(pdir && *(pdir+1)!=0) ++pdir; } else { /*must have been trailing : */ - emptyName=TRUE; + emptyName=1; } } if(emptyName) { @@ -503,7 +503,7 @@ void freePattern(subInfo *psubInfo) free(ppatternNode->var); free(ppatternNode); } - psubInfo->isPattern = FALSE; + psubInfo->isPattern = 0; } static void substituteDestruct(void *pvt) @@ -548,9 +548,9 @@ static int substituteGetNextSet(void *pvt,char **filename) *filename = 0; while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); - if(psubFile->token==tokenEOF) return(FALSE); + if(psubFile->token==tokenEOF) return(0); if(psubFile->token==tokenString && strcmp(psubFile->string,"file")==0) { - psubInfo->isFile = TRUE; + psubInfo->isFile = 1; if(subGetNextToken(psubFile)!=tokenString) { subFileErrPrint(psubFile,"Expecting filename"); exit(1); @@ -573,21 +573,21 @@ static int substituteGetNextSet(void *pvt,char **filename) } *filename = psubInfo->filename; while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); - if(psubFile->token==tokenLBrace) return(TRUE); - if(psubFile->token==tokenRBrace) return(FALSE); + if(psubFile->token==tokenLBrace) return(1); + if(psubFile->token==tokenRBrace) return(0); if(psubFile->token!=tokenString || strcmp(psubFile->string,"pattern")!=0) { subFileErrPrint(psubFile,"Expecting pattern"); exit(1); } freePattern(psubInfo); - psubInfo->isPattern = TRUE; + psubInfo->isPattern = 1; while(subGetNextToken(psubFile)==tokenSeparater); if(psubFile->token!=tokenLBrace) { subFileErrPrint(psubFile,"Expecting {"); exit(1); } - while(TRUE) { + while(1) { while(subGetNextToken(psubFile)==tokenSeparater); if(psubFile->token!=tokenString) break; ppatternNode = calloc(1,sizeof(patternNode)); @@ -600,7 +600,7 @@ static int substituteGetNextSet(void *pvt,char **filename) exit(1); } subGetNextToken(psubFile); - return(TRUE); + return(1); } static char *substituteGetReplacements(void *pvt) @@ -613,7 +613,7 @@ static char *substituteGetReplacements(void *pvt) psubInfo->curLength = 0; while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); if(psubFile->token==tokenRBrace && psubInfo->isFile) { - psubInfo->isFile = FALSE; + psubInfo->isFile = 0; free((void *)psubInfo->filename); psubInfo->filename = 0; freePattern(psubInfo); @@ -623,11 +623,11 @@ static char *substituteGetReplacements(void *pvt) if(psubFile->token==tokenEOF) return(0); if(psubFile->token!=tokenLBrace) return(0); if(psubInfo->isPattern) { - int gotFirstPattern = FALSE; + int gotFirstPattern = 0; while(subGetNextToken(psubFile)==tokenSeparater); ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList); - while(TRUE) { + while(1) { if(psubFile->token==tokenRBrace) { if(ppatternNode) subFileErrPrint(psubFile,"less values than patterns"); @@ -639,7 +639,7 @@ static char *substituteGetReplacements(void *pvt) exit(-1); } if(gotFirstPattern) catMacroReplacements(psubInfo,","); - gotFirstPattern = TRUE; + gotFirstPattern = 1; if(ppatternNode) { catMacroReplacements(psubInfo,ppatternNode->var); catMacroReplacements(psubInfo,"="); @@ -650,7 +650,7 @@ static char *substituteGetReplacements(void *pvt) } while(subGetNextToken(psubFile)==tokenSeparater); } - } else while(TRUE) { + } else while(1) { switch(subGetNextToken(psubFile)) { case tokenRBrace: subGetNextToken(psubFile); From a117a73987c23f40654e4dd08a7c7690e81c15c7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 22 May 2008 18:55:08 +0000 Subject: [PATCH 26/50] Make undefined macros a warning, not an error; only report once. --- msi.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/msi.c b/msi.c index 0f316629e..5f241d053 100644 --- a/msi.c +++ b/msi.c @@ -161,6 +161,7 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) char *input; static char buffer[MAX_BUFFER_SIZE]; int n; + static int unexpWarned = 0; inputBegin(inputPvt,templateName); while((input = inputNextLine(inputPvt))) { @@ -225,12 +226,12 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) expand = 0; } endif: - if(expand) { + if (expand) { n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1); fputs(buffer,stdout); - if(n<0) { - inputErrPrint(inputPvt); - exitStatus = 2; + if (!unexpWarned && n<0) { + fprintf(stderr,"Warning: unexpanded macros in ouput\n"); + unexpWarned++; } } } @@ -510,6 +511,7 @@ static void substituteDestruct(void *pvt) { subInfo *psubInfo = (subInfo *)pvt; + freeSubFile(psubInfo); freePattern(psubInfo); free((void *)psubInfo); return; @@ -770,7 +772,7 @@ static void catMacroReplacements(subInfo *psubInfo,const char *value) newsize = psubInfo->curLength + len + 1; newbuf = calloc(1,newsize); if(!newbuf) { - fprintf(stderr,"calloc failed for size %d\n",newsize); + fprintf(stderr,"calloc failed for size %u\n",newsize); exit(1); } if(psubInfo->macroReplacements) { From 97ccca54743cc0a8fd1513e8702b041999b76a2b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 10 Nov 2008 20:46:27 +0000 Subject: [PATCH 27/50] Cleanup, warnings. --- msi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/msi.c b/msi.c index 5f241d053..e6b5ec422 100644 --- a/msi.c +++ b/msi.c @@ -20,7 +20,8 @@ #include #include #include - + +#include #include #include @@ -92,7 +93,7 @@ int main(int argc,char **argv) for(i=1; i2) { - fprintf(stderr,"too many files\n"); + fprintf(stderr,"too many filename arguments\n"); usageExit(); } if(argc==2) { @@ -153,9 +154,8 @@ static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval) free((void *)pairs); } -#define cmdNumberOf 2 typedef enum {cmdInclude,cmdSubstitute} cmdType; -static char *cmdName[cmdNumberOf] = {"include","substitute"}; +static const char *cmdNames[] = {"include","substitute"}; static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) { char *input; @@ -181,13 +181,13 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) int cmdind=-1; int i; - for(i=0; i< cmdNumberOf; i++) { - if(strstr(command,cmdName[i])) { + for(i=0; i< NELEMENTS(cmdNames); i++) { + if(strstr(command,cmdNames[i])) { cmdind = i; } } if(cmdind<0) goto endif; - p = command + strlen(cmdName[cmdind]); + p = command + strlen(cmdNames[cmdind]); /*skip whitespace after command*/ while(*p && (isspace(*p))) ++p; /*Next character must be quote*/ @@ -772,7 +772,7 @@ static void catMacroReplacements(subInfo *psubInfo,const char *value) newsize = psubInfo->curLength + len + 1; newbuf = calloc(1,newsize); if(!newbuf) { - fprintf(stderr,"calloc failed for size %u\n",newsize); + fprintf(stderr,"calloc failed for size %Zu\n",newsize); exit(1); } if(psubInfo->macroReplacements) { From 02d21255f5192dec361bb78546590562c65f0340 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 10 Nov 2008 20:47:06 +0000 Subject: [PATCH 28/50] Modified for release 1.5 --- msi.html | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/msi.html b/msi.html index 639553968..7fd58c6a5 100644 --- a/msi.html +++ b/msi.html @@ -10,25 +10,25 @@

    msi: Macro Substitution and Include Tool

    -

    Version 1.4, June 2004
    -Marty Kraimer (Advanced Photon Source, Argonne National Laboratory)

    +

    Version 1.5, 10th November, 2008

    Introduction

    -

    msi is a general purpose macro substitution/include tool. It accepts as -input an ascii template file. It looks for lines containing two reserved -command names: include and substitute. It also looks for and performs -substitutions on macros of the form $(var) and ${var}. It uses macLib, an EPICS -Base library created by William Lupton, to perform the substitutions.

    +

    msi is a general purpose macro substitution/include tool. It accepts as input +an ascii template file. It looks for lines containing two reserved command +names: include and substitute. It also looks for and performs +substitutions on macros of the form $(var) and ${var}. It uses the macLib +routines from EPICS Base to perform the substitutions, so it also accepts the +default value and value definition syntax that macLib implements.

    msi also allows substitutions to be specified via a separate substitution file. This substitution file allows the same format as the substitution files -accepted by dbLoadTemplate or subtool.

    +accepted by the EPICS IOC's dbLoadTemplate command.

    Command Syntax:

    -
    msi -V -ofile -Idir -Msub -Ssubfile template
    +
    msi -V -ooutfile -Idir -Msubs -Ssubfile template

    All parameters are optional. The -o, -I, -M, and -S switches may be separated from their associated value string by spaces if desired. Output will @@ -52,14 +52,14 @@ be written to stdout unless the -o option is given.

    include commands. For example:
    -
    msi -I "/home/phoebus/MRK/examples:." -I".." template
    +
    msi -I /home/mrk/examples:. -I.. template
    specifies that all named files should be searched for in the following locations in the order given:
      -
    1. /home/phoebus/MRK/examples
    2. +
    3. /home/mrk/examples
    4. . (the current directory)
    5. .. (the parent of the current directory)
    @@ -146,13 +146,13 @@ will generate warning messages on stderr and result in undefined output.

    The template file is read and processed one line at a time, where the maximum length of a line before and/or after macro expansion is 1023 characters -— longer input or output lines will cause msi to fail. Within the context +— longer input or output lines will cause msi to fail. Within the context of a single line, macro expansion does not occur when the variable instance appears inside a single-quoted string, or where the dollar sign $ is preceded by a back-slash character \, but as with the standard Unix shells, variables inside double quoted strings are expanded properly.

    -

    However neither back-slash characters nor quotes or either variety are +

    However neither back-slash characters nor quotes of either variety are removed when generating the output file, so depending on what is being output the single quote behaviour may not be useful and may even be a hinderance. It cannot be disabled in the current version of msi.

    From d0c061cf1f8be528cb2bfd05dc0a7ab0faab2715 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Mon, 10 Nov 2008 20:47:07 +0000 Subject: [PATCH 29/50] This commit was manufactured by cvs2svn to create tag 'MSI-R1-5'. From 359a4571f561abe86bf015dc8a80e29f6da39dfc Mon Sep 17 00:00:00 2001 From: "Janet B. Anderson" Date: Tue, 22 Sep 2009 16:34:47 +0000 Subject: [PATCH 30/50] Modified test of warning message. --- msi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/msi.c b/msi.c index e6b5ec422..faa825b1a 100644 --- a/msi.c +++ b/msi.c @@ -230,7 +230,8 @@ endif: n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1); fputs(buffer,stdout); if (!unexpWarned && n<0) { - fprintf(stderr,"Warning: unexpanded macros in ouput\n"); + fprintf(stderr, "Warning: Some macros cannot be expanded:\n" + " %s\n", input); unexpWarned++; } } From 0164402bad568ccd380397103921621e9bd01765 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 28 Oct 2009 19:30:02 +0000 Subject: [PATCH 31/50] Need epicsVersion.h to support macEnvExpand() properly. --- msi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/msi.c b/msi.c index faa825b1a..65c8fe5b6 100644 --- a/msi.c +++ b/msi.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include From 8c6f940e1f50ccc4d530823607a3d0186dbe4ee0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 28 Oct 2009 19:47:00 +0000 Subject: [PATCH 32/50] Improve warning message, suggest using -V flag. --- msi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/msi.c b/msi.c index 65c8fe5b6..1f88c1519 100644 --- a/msi.c +++ b/msi.c @@ -55,6 +55,8 @@ static char *substituteGetReplacements(void *substitutePvt); /*Exit status*/ static int exitStatus = 0; +int opt_V = 0; + int main(int argc,char **argv) { @@ -86,6 +88,7 @@ int main(int argc,char **argv) strcpy(substitutionName,pval); } else if(strncmp(argv[1],"-V",2)==0) { macSuppressWarning(macPvt,0); + opt_V = 1; narg = 1; /* no argument for this option */ } else { usageExit(); @@ -231,8 +234,8 @@ endif: n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1); fputs(buffer,stdout); if (!unexpWarned && n<0) { - fprintf(stderr, "Warning: Some macros cannot be expanded:\n" - " %s\n", input); + fprintf(stderr, "Warning: Undefined macros present%s\n", + opt_V ? "" : ", use msi -V to list"); unexpWarned++; } } From 3db5427e1d7b714f96eefff28362891d179afea4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Aug 2010 17:50:52 -0500 Subject: [PATCH 33/50] dbtools: Source code clean-up, code layout changes only. --- src/dbtools/dbLoadTemplate.h | 3 +- src/dbtools/dbLoadTemplate.y | 390 +++++++++++++++---------------- src/dbtools/dbLoadTemplate_lex.l | 46 ++-- 3 files changed, 218 insertions(+), 221 deletions(-) diff --git a/src/dbtools/dbLoadTemplate.h b/src/dbtools/dbLoadTemplate.h index a341b8098..29f7a0b52 100644 --- a/src/dbtools/dbLoadTemplate.h +++ b/src/dbtools/dbLoadTemplate.h @@ -3,8 +3,7 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found +* EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /* dbLoadTemplate.h */ diff --git a/src/dbtools/dbLoadTemplate.y b/src/dbtools/dbLoadTemplate.y index 0a919dda6..5fb4fbfa7 100644 --- a/src/dbtools/dbLoadTemplate.y +++ b/src/dbtools/dbLoadTemplate.y @@ -30,7 +30,7 @@ static int yyerror(); static char *sub_collect = NULL; static char** vars = NULL; static char* db_file_name = NULL; -static int var_count,sub_count; +static int var_count, sub_count; %} @@ -45,7 +45,7 @@ static int var_count,sub_count; %union { - int Int; + int Int; char Char; char *Str; double Real; @@ -54,191 +54,192 @@ static int var_count,sub_count; %% template: templs - | subst - ; + | subst + ; templs: templs templ - | templ - ; + | templ + ; templ: templ_head O_BRACE subst C_BRACE - | templ_head - { - if(db_file_name) - dbLoadRecords(db_file_name,NULL); - else - fprintf(stderr,"Error: no db file name given\n"); - } - ; + | templ_head + { + if (db_file_name) + dbLoadRecords(db_file_name, NULL); + else + fprintf(stderr, "Error: no db file name given\n"); + } + ; templ_head: DBFILE WORD - { - var_count=0; - if(db_file_name) dbmfFree(db_file_name); - db_file_name = dbmfMalloc(strlen($2)+1); - strcpy(db_file_name,$2); - dbmfFree($2); - } - | DBFILE QUOTE - { - var_count=0; - if(db_file_name) dbmfFree(db_file_name); - db_file_name = dbmfMalloc(strlen($2)+1); - strcpy(db_file_name,$2); - dbmfFree($2); - } - ; + { + var_count = 0; + if (db_file_name) + dbmfFree(db_file_name); + db_file_name = dbmfMalloc(strlen($2)+1); + strcpy(db_file_name, $2); + dbmfFree($2); + } + | DBFILE QUOTE + { + var_count = 0; + if (db_file_name) + dbmfFree(db_file_name); + db_file_name = dbmfMalloc(strlen($2)+1); + strcpy(db_file_name, $2); + dbmfFree($2); + } + ; subst: PATTERN pattern subs - | PATTERN pattern - | var_subs - ; + | PATTERN pattern + | var_subs + ; pattern: O_BRACE vars C_BRACE - { + { #ifdef ERROR_STUFF - int i; - for(i=0;i;] %% -"pattern" { return(PATTERN); } -"file" { return(DBFILE); } +"pattern" { return(PATTERN); } +"file" { return(DBFILE); } {doublequote}({dstringchar}|{escape})*{doublequote} | {singlequote}({sstringchar}|{escape})*{singlequote} { - yylval.Str = dbmfStrdup(yytext+1); - yylval.Str[strlen(yylval.Str)-1] = '\0'; - return(QUOTE); - } + yylval.Str = dbmfStrdup(yytext+1); + yylval.Str[strlen(yylval.Str)-1] = '\0'; + return(QUOTE); +} {bareword}+ { - yylval.Str = dbmfStrdup(yytext); - return(WORD); - } + yylval.Str = dbmfStrdup(yytext); + return(WORD); +} -"=" { return(EQUALS); } -"," { return(COMMA); } -"{" { return(O_BRACE); } -"}" { return(C_BRACE); } +"=" { return(EQUALS); } +"," { return(COMMA); } +"{" { return(O_BRACE); } +"}" { return(C_BRACE); } -{comment}.* ; -{whitespace} ; -{newline} { line_num++; } +{comment}.* ; +{whitespace} ; +{newline} { line_num++; } . { - char message[40]; + char message[40]; - sprintf(message,"invalid character '%c'", yytext[0]); - yyerror(message); + sprintf(message, "invalid character '%c'", yytext[0]); + yyerror(message); - /* Suppress compiler warning messages */ - if (0) yyunput('c',NULL); - if (0) yy_switch_to_buffer(NULL); - } + /* Suppress compiler warning messages */ + if (0) yyunput('c',NULL); + if (0) yy_switch_to_buffer(NULL); +} %% From 4a637c04cfcce5c8846c9515e21494936258e2a5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Aug 2010 17:59:38 -0500 Subject: [PATCH 34/50] dbtools: Added command-line variable parameters. --- src/dbtools/dbLoadTemplate.h | 7 +--- src/dbtools/dbLoadTemplate.y | 63 ++++++++++++++++++-------------- src/dbtools/dbLoadTemplate_lex.l | 1 + src/dbtools/dbtoolsIocRegister.c | 13 ++++--- 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/dbtools/dbLoadTemplate.h b/src/dbtools/dbLoadTemplate.h index 29f7a0b52..0de0235bb 100644 --- a/src/dbtools/dbLoadTemplate.h +++ b/src/dbtools/dbLoadTemplate.h @@ -12,10 +12,7 @@ #define INCdbLoadTemplateh #include "shareLib.h" -epicsShareFunc int epicsShareAPI dbLoadTemplate(char* sub_file); +epicsShareFunc int epicsShareAPI dbLoadTemplate( + const char *sub_file, const char *cmd_collect); #endif /*INCdbLoadTemplateh*/ - - - - diff --git a/src/dbtools/dbLoadTemplate.y b/src/dbtools/dbLoadTemplate.y index 5fb4fbfa7..a9d8d2eb8 100644 --- a/src/dbtools/dbLoadTemplate.y +++ b/src/dbtools/dbLoadTemplate.y @@ -22,12 +22,13 @@ #include "dbLoadTemplate.h" static int line_num; -static int yyerror(); +static int yyerror(char* str); #define VAR_MAX_VAR_STRING 5000 #define VAR_MAX_VARS 100 static char *sub_collect = NULL; +static char *gbl_collect; static char** vars = NULL; static char* db_file_name = NULL; static int var_count, sub_count; @@ -39,6 +40,7 @@ static int var_count, sub_count; %token WORD QUOTE %token DBFILE %token PATTERN +%token GLOBAL %token EQUALS COMMA %left O_PAREN C_PAREN %left O_BRACE C_BRACE @@ -127,7 +129,7 @@ subs: subs sub sub: WORD O_BRACE vals C_BRACE { - sub_collect[strlen(sub_collect) - 1] = '\0'; + gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */ #ifdef ERROR_STUFF fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect); #endif @@ -136,12 +138,12 @@ sub: WORD O_BRACE vals C_BRACE else fprintf(stderr, "Error: no db file name given\n"); dbmfFree($1); - sub_collect[0] = '\0'; + *gbl_collect = '\0'; sub_count = 0; } | O_BRACE vals C_BRACE { - sub_collect[strlen(sub_collect) - 1] = '\0'; + gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */ #ifdef ERROR_STUFF fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect); #endif @@ -149,7 +151,7 @@ sub: WORD O_BRACE vals C_BRACE dbLoadRecords(db_file_name, sub_collect); else fprintf(stderr, "Error: no db file name given\n"); - sub_collect[0] = '\0'; + *gbl_collect = '\0'; sub_count = 0; } ; @@ -162,10 +164,10 @@ vals: vals val val: QUOTE { if (sub_count <= var_count) { - strcat(sub_collect, vars[sub_count]); - strcat(sub_collect, "=\""); - strcat(sub_collect, $1); - strcat(sub_collect, "\","); + strcat(gbl_collect, vars[sub_count]); + strcat(gbl_collect, "=\""); + strcat(gbl_collect, $1); + strcat(gbl_collect, "\","); sub_count++; } dbmfFree($1); @@ -173,10 +175,10 @@ val: QUOTE | WORD { if (sub_count <= var_count) { - strcat(sub_collect, vars[sub_count]); - strcat(sub_collect, "="); - strcat(sub_collect, $1); - strcat(sub_collect, ","); + strcat(gbl_collect, vars[sub_count]); + strcat(gbl_collect, "="); + strcat(gbl_collect, $1); + strcat(gbl_collect, ","); sub_count++; } dbmfFree($1); @@ -189,7 +191,7 @@ var_subs: var_subs var_sub var_sub: WORD O_BRACE sub_pats C_BRACE { - sub_collect[strlen(sub_collect) - 1] = '\0'; + gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */ #ifdef ERROR_STUFF fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect); #endif @@ -198,12 +200,12 @@ var_sub: WORD O_BRACE sub_pats C_BRACE else fprintf(stderr, "Error: no db file name given\n"); dbmfFree($1); - sub_collect[0] = '\0'; + *gbl_collect = '\0'; sub_count = 0; } | O_BRACE sub_pats C_BRACE { - sub_collect[strlen(sub_collect) - 1] = '\0'; + gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */ #ifdef ERROR_STUFF fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect); #endif @@ -211,7 +213,7 @@ var_sub: WORD O_BRACE sub_pats C_BRACE dbLoadRecords(db_file_name, sub_collect); else fprintf(stderr, "Error: no db file name given\n"); - sub_collect[0] = '\0'; + *gbl_collect = '\0'; sub_count = 0; } ; @@ -223,19 +225,19 @@ sub_pats: sub_pats sub_pat sub_pat: WORD EQUALS WORD { - strcat(sub_collect, $1); - strcat(sub_collect, "="); - strcat(sub_collect, $3); - strcat(sub_collect, ","); + strcat(gbl_collect, $1); + strcat(gbl_collect, "="); + strcat(gbl_collect, $3); + strcat(gbl_collect, ","); dbmfFree($1); dbmfFree($3); sub_count++; } | WORD EQUALS QUOTE { - strcat(sub_collect, $1); - strcat(sub_collect, "=\""); - strcat(sub_collect, $3); - strcat(sub_collect, "\","); + strcat(gbl_collect, $1); + strcat(gbl_collect, "=\""); + strcat(gbl_collect, $3); + strcat(gbl_collect, "\","); dbmfFree($1); dbmfFree($3); sub_count++; } @@ -257,7 +259,7 @@ static int yyerror(char* str) static int is_not_inited = 1; -int epicsShareAPI dbLoadTemplate(char* sub_file) +int epicsShareAPI dbLoadTemplate(const char *sub_file, const char *cmd_collect) { FILE *fp; int ind; @@ -285,7 +287,14 @@ int epicsShareAPI dbLoadTemplate(char* sub_file) return -1; } - sub_collect[0] = '\0'; + if (cmd_collect && *cmd_collect) { + strcpy(sub_collect, cmd_collect); + strcat(sub_collect, ","); + gbl_collect = sub_collect + strlen(sub_collect); + } else { + gbl_collect = sub_collect; + *gbl_collect = '\0'; + } var_count = 0; sub_count = 0; diff --git a/src/dbtools/dbLoadTemplate_lex.l b/src/dbtools/dbLoadTemplate_lex.l index 06b4f22da..afb729517 100644 --- a/src/dbtools/dbLoadTemplate_lex.l +++ b/src/dbtools/dbLoadTemplate_lex.l @@ -20,6 +20,7 @@ bareword [a-zA-Z0-9_\-+:./\\\[\]<>;] "pattern" { return(PATTERN); } "file" { return(DBFILE); } +"global" { return(GLOBAL); } {doublequote}({dstringchar}|{escape})*{doublequote} | {singlequote}({sstringchar}|{escape})*{singlequote} { diff --git a/src/dbtools/dbtoolsIocRegister.c b/src/dbtools/dbtoolsIocRegister.c index 9fbe1096b..3ff446872 100644 --- a/src/dbtools/dbtoolsIocRegister.c +++ b/src/dbtools/dbtoolsIocRegister.c @@ -13,17 +13,20 @@ /* dbLoadTemplate */ -static const iocshArg dbLoadTemplateArg0 = { "file name",iocshArgString}; -static const iocshArg * const dbLoadTemplateArgs[1] = {&dbLoadTemplateArg0}; +static const iocshArg dbLoadTemplateArg0 = {"filename", iocshArgString}; +static const iocshArg dbLoadTemplateArg1 = {"var=value", iocshArgString}; +static const iocshArg * const dbLoadTemplateArgs[2] = { + &dbLoadTemplateArg0, &dbLoadTemplateArg1 +}; static const iocshFuncDef dbLoadTemplateFuncDef = - {"dbLoadTemplate",1,dbLoadTemplateArgs}; + {"dbLoadTemplate", 2, dbLoadTemplateArgs}; static void dbLoadTemplateCallFunc(const iocshArgBuf *args) { - dbLoadTemplate(args[0].sval); + dbLoadTemplate(args[0].sval, args[1].sval); } void epicsShareAPI dbtoolsIocRegister(void) { - iocshRegister(&dbLoadTemplateFuncDef,dbLoadTemplateCallFunc); + iocshRegister(&dbLoadTemplateFuncDef, dbLoadTemplateCallFunc); } From 52f4c8ae8f94071560874f419d4f8512392f9121 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Mon, 23 Aug 2010 14:48:43 -0400 Subject: [PATCH 35/50] dbtools: shuffle files towards a reasonable layout, keep test files in test dir --- src/dbtools/Makefile | 13 +++--- src/dbtools/{msi => }/msi.c | 0 src/dbtools/{msi => }/msi.html | 0 src/dbtools/msi/LICENSE | 64 ---------------------------- src/dbtools/msi/Makefile | 22 ---------- src/dbtools/msi/README.1st | 2 - src/dbtools/{msi => test}/pattern | 0 src/dbtools/{msi => test}/substitute | 0 src/dbtools/{msi => test}/template | 0 src/dbtools/{msi => test}/testfile | 0 src/dbtools/{msi => test}/testfile1 | 0 11 files changed, 8 insertions(+), 93 deletions(-) rename src/dbtools/{msi => }/msi.c (100%) rename src/dbtools/{msi => }/msi.html (100%) delete mode 100644 src/dbtools/msi/LICENSE delete mode 100644 src/dbtools/msi/Makefile delete mode 100644 src/dbtools/msi/README.1st rename src/dbtools/{msi => test}/pattern (100%) rename src/dbtools/{msi => test}/substitute (100%) rename src/dbtools/{msi => test}/template (100%) rename src/dbtools/{msi => test}/testfile (100%) rename src/dbtools/{msi => test}/testfile1 (100%) diff --git a/src/dbtools/Makefile b/src/dbtools/Makefile index 38ed52c9e..036f2afc7 100644 --- a/src/dbtools/Makefile +++ b/src/dbtools/Makefile @@ -14,17 +14,20 @@ include $(TOP)/configure/CONFIG INC += dbLoadTemplate.h INC += dbtoolsIocRegister.h -LIB_SRCS += dbLoadTemplate.c -LIB_SRCS += dbtoolsIocRegister.c - LIBRARY_IOC = dbtoolsIoc +LIB_SRCS += dbLoadTemplate.c +LIB_SRCS += dbtoolsIocRegister.c dbtoolsIoc_LIBS = dbIoc dbStaticIoc Com - dbtoolsIoc_RCS = dbtoolsIoc.rc - HTMLS += dbLoadTemplate.html +PROD_HOST = msi + +msi_SRCS = msi.c +msi_LIBS += Com +HTMLS = msi.html + # For R3.13 compatibility only ifeq ($(strip $(COMPAT_313)),YES) OBJLIB_vxWorks=dbtoolsIoc diff --git a/src/dbtools/msi/msi.c b/src/dbtools/msi.c similarity index 100% rename from src/dbtools/msi/msi.c rename to src/dbtools/msi.c diff --git a/src/dbtools/msi/msi.html b/src/dbtools/msi.html similarity index 100% rename from src/dbtools/msi/msi.html rename to src/dbtools/msi.html diff --git a/src/dbtools/msi/LICENSE b/src/dbtools/msi/LICENSE deleted file mode 100644 index 9f03a0c48..000000000 --- a/src/dbtools/msi/LICENSE +++ /dev/null @@ -1,64 +0,0 @@ -Copyright (c) 2002 University of Chicago. All rights reserved. - -msi is distributed subject to the following license conditions: - - SOFTWARE LICENSE AGREEMENT - Software: Macro Substitution and Include Tool (msi) - - 1. The "Software", below, refers to msi (in either source code, or - binary form and accompanying documentation). Each licensee is - addressed as "you" or "Licensee." - - 2. The copyright holders shown above and their third-party licensors - hereby grant Licensee a royalty-free nonexclusive license, subject to - the limitations stated herein and U.S. Government license rights. - - 3. You may modify and make a copy or copies of the Software for use - within your organization, if you meet the following conditions: - a. Copies in source code must include the copyright notice and this - Software License Agreement. - b. Copies in binary form must include the copyright notice and this - Software License Agreement in the documentation and/or other - materials provided with the copy. - - 4. You may modify a copy or copies of the Software or any portion of it, - thus forming a work based on the Software, and distribute copies of - such work outside your organization, if you meet all of the following - conditions: - a. Copies in source code must include the copyright notice and this - Software License Agreement; - b. Copies in binary form must include the copyright notice and this - Software License Agreement in the documentation and/or other - materials provided with the copy; - c. Modified copies and works based on the Software must carry - prominent notices stating that you changed specified portions of - the Software. - - 5. Portions of the Software resulted from work developed under a U.S. - Government contract and are subject to the following license: the - Government is granted for itself and others acting on its behalf a - paid-up, nonexclusive, irrevocable worldwide license in this computer - software to reproduce, prepare derivative works, and perform publicly - and display publicly. - - 6. WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" WITHOUT WARRANTY - OF ANY KIND. THE COPYRIGHT HOLDERS, THEIR THIRD PARTY LICENSORS, THE - UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND THEIR - EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR IMPLIED, INCLUDING - BUT NOT LIMITED TO ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS - FOR A PARTICULAR PURPOSE, TITLE OR NON-INFRINGEMENT, (2) DO NOT ASSUME - ANY LEGAL LIABILITY OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, - OR USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF THE - SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) DO NOT WARRANT - THAT THE SOFTWARE WILL FUNCTION UNINTERRUPTED, THAT IT IS ERROR-FREE - OR THAT ANY ERRORS WILL BE CORRECTED. - - 7. LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT HOLDERS, THEIR - THIRD PARTY LICENSORS, THE UNITED STATES, THE UNITED STATES DEPARTMENT - OF ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, INCIDENTAL, - CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF ANY KIND OR NATURE, - INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS OR LOSS OF DATA, FOR ANY - REASON WHATSOEVER, WHETHER SUCH LIABILITY IS ASSERTED ON THE BASIS OF - CONTRACT, TORT (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR - OTHERWISE, EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE - POSSIBILITY OF SUCH LOSS OR DAMAGES. diff --git a/src/dbtools/msi/Makefile b/src/dbtools/msi/Makefile deleted file mode 100644 index 5ab39416a..000000000 --- a/src/dbtools/msi/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# This file is distributed subject to a Software License Agreement found -# in the file LICENSE that is included with this distribution. -#************************************************************************* -# -# $Id$ -# -TOP = ../.. - -include $(TOP)/configure/CONFIG - -PROD_HOST = msi -HTMLS = msi.html - -msi_SRCS = msi.c -PROD_LIBS += Com - -include $(TOP)/configure/RULES diff --git a/src/dbtools/msi/README.1st b/src/dbtools/msi/README.1st deleted file mode 100644 index 60ebbddde..000000000 --- a/src/dbtools/msi/README.1st +++ /dev/null @@ -1,2 +0,0 @@ -The extension distribution file should be unziped and untared -in the extensions/src directory. diff --git a/src/dbtools/msi/pattern b/src/dbtools/test/pattern similarity index 100% rename from src/dbtools/msi/pattern rename to src/dbtools/test/pattern diff --git a/src/dbtools/msi/substitute b/src/dbtools/test/substitute similarity index 100% rename from src/dbtools/msi/substitute rename to src/dbtools/test/substitute diff --git a/src/dbtools/msi/template b/src/dbtools/test/template similarity index 100% rename from src/dbtools/msi/template rename to src/dbtools/test/template diff --git a/src/dbtools/msi/testfile b/src/dbtools/test/testfile similarity index 100% rename from src/dbtools/msi/testfile rename to src/dbtools/test/testfile diff --git a/src/dbtools/msi/testfile1 b/src/dbtools/test/testfile1 similarity index 100% rename from src/dbtools/msi/testfile1 rename to src/dbtools/test/testfile1 From 6b6de69f1d25114b36e9a3debafea1a9e25b3e23 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Mon, 23 Aug 2010 15:08:24 -0400 Subject: [PATCH 36/50] build: Point default MSI to the base version. --- configure/CONFIG_BASE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure/CONFIG_BASE b/configure/CONFIG_BASE index dd559536d..514e1a2a7 100644 --- a/configure/CONFIG_BASE +++ b/configure/CONFIG_BASE @@ -110,7 +110,7 @@ DBST = dbst endif ifndef MSI -MSI = msi +MSI = $(EPICS_BASE_HOST_BIN)/msi endif From e2464c857268f1346a54d86fc17f2c01f50ac0a0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 24 Aug 2010 19:01:19 -0500 Subject: [PATCH 37/50] Implemented "global" variables in substitution files. Rewrote the YACC grammar, with help from Benjamin Franksen in formally defining the substitution file format in EBNF. This version also changes the way in which variables are added to the sub_collect string; previously it appended a ',' after every entry, and removed it off the end before calling dbLoadRecords(), but now we put the ',' at the beginning of each entry, and just offer dbLoadRecords() the string starting at the second character (not that this really matters, macLib will quite happily ignore either a leading or a trailing comma in the variable definition string). We now warn if there are substitution values for which we have no name, or if the file uses the deprecated syntax which permitted a bareword token in front of the variable substitution or pattern definition braces. --- src/dbtools/dbLoadTemplate.html | 137 --------------- src/dbtools/dbLoadTemplate.y | 288 ++++++++++++++++++-------------- 2 files changed, 167 insertions(+), 258 deletions(-) delete mode 100644 src/dbtools/dbLoadTemplate.html diff --git a/src/dbtools/dbLoadTemplate.html b/src/dbtools/dbLoadTemplate.html deleted file mode 100644 index 4943b8c6f..000000000 --- a/src/dbtools/dbLoadTemplate.html +++ /dev/null @@ -1,137 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - - -
    -
    -
    -
    -

    NAME

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

    SYNOPSIS

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

    DESCRIPTION

    -     These routines are available from IOC core  on  the  vxWorks
    -     command  line.  Both provide a way to load ascii ".db" files
    -     (usually created by gdct(1) ) into the IOC. The ".db"  files
    -     contain ascii versions of record instances and are described
    -     in more detail in dbfile(5).  In  addition  to  loading  the
    -     ".db"  ascii  files  into  the  IOC, both routines provide a
    -     method of performing variable substitution on  record  names
    -     and field values.
    -
    -     dbLoadRecords() reads the ".db" file db_file performing sub-
    -     stitutions  specified in string substitutions. The substitu-
    -     tion must be a string specified as follows:
    -
    -     "var1=sub1,var2=sub3,..."
    -
    -     Variables   are   specified   in   the   ".db"    file    as
    -     $(variable_name).      If     the     substitution    string
    -     "a=1,b=2,c=\"this is a  test\""  were  used,  any  variables
    -     $(a),  $(b), or $(c) would be substituted with the appropri-
    -     ate data.  See the EXAMPLES section for more details.
    -
    -     dbLoadTemplate()   will   read    a    template_file.    The
    -     template_file  resides  in  the  your IOC boot directory and
    -     contains rules about loading ".db" files and performing sub-
    -     stitutions.   The  template_file must be in the form used by
    -     an IOC and is described in  templatefile(5).   The  EXAMPLES
    -     section descibes how it can be used.
    -
    -
    -
    -

    EXAMPLES

    -     The next two  examples  of  dbLoadRecords()  and  dbLoadTem-
    -     plate() will use the following ".db" file named test.db :
    -
    -     database(test)
    -     {
    -          record(ai,"$(pre)testrec1")
    -          record(ai,"$(pre)testrec2")
    -          record(stringout,"$(pre)testrec3")
    -          {
    -               field(VAL,"$(STRING)")
    -               field(SCAN,"$(SCAN)")
    -          }
    -     }
    -     Running dbLoadRecords ("test.db","pre=TEST,STRING=\"this  is
    -     a  test\",SCAN=Passive")  will produce the following records
    -     in the IOC's database:
    -
    -          TESTtestrec1
    -          TESTtestrec2
    -          TESTtestrec3
    -
    -     The third record will have VAL set to "this is a  test"  and
    -     SCAN set to "Passive".
    -
    -     Running dbLoadTemplate ("test.template") with  test.template
    -     containing:
    -     file test.db
    -     {
    -          {pre=TEST1, STRING = "this is a test two", SCAN="1 Second" }
    -          {pre=TEST2, STRING = "this is a test one", SCAN=Passive }
    -          {pre=TEST3, STRING = "this is a test three", SCAN=Passive }
    -     }
    -     will produce a total of nine records in the IOC's database:
    -          TEST1testrec1
    -          TEST1testrec2
    -          TEST1testrec3 - (VAL="this is a test two", SCAN="1 Second")
    -          TEST2testrec1
    -          TEST2testrec2
    -          TEST2testrec3 - (VAL="this is a test one", SCAN="Passive")
    -          TEST3testrec1
    -          TEST3testrec2
    -          TEST3testrec3 - (VAL="this is a test three", SCAN="Passive")
    -
    -
    -
    -

    NOTES

    -     The binary file default.dctsdr must be loaded prior to  run-
    -     ning either of these routines.  This file contains the rules
    -     on how to construct records and change field values.
    -
    -     After the default.dctsdr file is loaded, these routines  can
    -     be run as many times as desired until iocInit is run.
    -
    -
    -
    -

    SEE ALSO

    -     gdct(1), templatefile(5), dbfile(5)
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -Man(1) output converted with -man2html -
    - - diff --git a/src/dbtools/dbLoadTemplate.y b/src/dbtools/dbLoadTemplate.y index a9d8d2eb8..1364e1978 100644 --- a/src/dbtools/dbLoadTemplate.y +++ b/src/dbtools/dbLoadTemplate.y @@ -27,15 +27,15 @@ static int yyerror(char* str); #define VAR_MAX_VAR_STRING 5000 #define VAR_MAX_VARS 100 -static char *sub_collect = NULL; -static char *gbl_collect; +static char *sub_collect; +static char *sub_locals; static char** vars = NULL; static char* db_file_name = NULL; static int var_count, sub_count; %} -%start template +%start substitution_file %token WORD QUOTE %token DBFILE @@ -55,67 +55,83 @@ static int var_count, sub_count; %% -template: templs - | subst +substitution_file: global_or_template + | substitution_file global_or_template ; -templs: templs templ - | templ +global_or_template: global_definitions + | template_substitutions ; -templ: templ_head O_BRACE subst C_BRACE - | templ_head +global_definitions: GLOBAL O_BRACE C_BRACE + | GLOBAL O_BRACE variable_definitions C_BRACE { - if (db_file_name) - dbLoadRecords(db_file_name, NULL); - else - fprintf(stderr, "Error: no db file name given\n"); + #ifdef ERROR_STUFF + fprintf(stderr, "global_definitions: %s\n", sub_collect+1); + #endif + sub_locals += strlen(sub_locals); } ; -templ_head: DBFILE WORD +template_substitutions: template_filename O_BRACE C_BRACE { + #ifdef ERROR_STUFF + fprintf(stderr, "template_substitutions: %s unused\n", db_file_name); + #endif + dbmfFree(db_file_name); + db_file_name = NULL; + } + | template_filename O_BRACE substitutions C_BRACE + { + #ifdef ERROR_STUFF + fprintf(stderr, "template_substitutions: %s finished\n", db_file_name); + #endif + dbmfFree(db_file_name); + db_file_name = NULL; + } + ; + +template_filename: DBFILE WORD + { + #ifdef ERROR_STUFF + fprintf(stderr, "template_filename: %s\n", $2); + #endif var_count = 0; - if (db_file_name) - dbmfFree(db_file_name); db_file_name = dbmfMalloc(strlen($2)+1); strcpy(db_file_name, $2); dbmfFree($2); } | DBFILE QUOTE { + #ifdef ERROR_STUFF + fprintf(stderr, "template_filename: \"%s\"\n", $2); + #endif var_count = 0; - if (db_file_name) - dbmfFree(db_file_name); db_file_name = dbmfMalloc(strlen($2)+1); strcpy(db_file_name, $2); dbmfFree($2); } ; -subst: PATTERN pattern subs - | PATTERN pattern - | var_subs +substitutions: pattern_substitutions + | variable_substitutions ; -pattern: O_BRACE vars C_BRACE - { -#ifdef ERROR_STUFF - int i; - for (i = 0; i < var_count; i++) - fprintf(stderr, "variable = (%s)\n", vars[i]); - fprintf(stderr, "var_count = %d\n", var_count); -#endif - } +pattern_substitutions: PATTERN O_BRACE C_BRACE + | PATTERN O_BRACE pattern_names C_BRACE + | PATTERN O_BRACE pattern_names C_BRACE pattern_definitions ; -vars: vars var - | vars COMMA var - | var +pattern_names: pattern_name + | pattern_names COMMA + | pattern_names pattern_name ; -var: WORD +pattern_name: WORD { + #ifdef ERROR_STUFF + fprintf(stderr, "pattern_name: [%d] = %s\n", var_count, $1); + #endif vars[var_count] = dbmfMalloc(strlen($1)+1); strcpy(vars[var_count], $1); var_count++; @@ -123,123 +139,153 @@ var: WORD } ; -subs: subs sub - | sub +pattern_definitions: pattern_definition + | pattern_definitions pattern_definition ; -sub: WORD O_BRACE vals C_BRACE +pattern_definition: O_BRACE C_BRACE { - gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */ -#ifdef ERROR_STUFF - fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect); -#endif - if (db_file_name) - dbLoadRecords(db_file_name, sub_collect); - else - fprintf(stderr, "Error: no db file name given\n"); + #ifdef ERROR_STUFF + fprintf(stderr, "pattern_definition: pattern_values empty\n"); + fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); + #endif + dbLoadRecords(db_file_name, sub_collect+1); + } + | O_BRACE pattern_values C_BRACE + { + #ifdef ERROR_STUFF + fprintf(stderr, "pattern_definition:\n"); + fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); + #endif + dbLoadRecords(db_file_name, sub_collect+1); + *sub_locals = '\0'; + sub_count = 0; + } + | WORD O_BRACE pattern_values C_BRACE + { /* DEPRECATED SYNTAX */ + fprintf(stderr, + "dbLoadTemplate: Substitution file uses deprecated syntax.\n" + " the string '%s' on line %d that comes just before the\n" + " '{' character is extraneous and should be removed.\n", + $1, line_num); + #ifdef ERROR_STUFF + fprintf(stderr, "pattern_definition:\n"); + fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); + #endif + dbLoadRecords(db_file_name, sub_collect+1); dbmfFree($1); - *gbl_collect = '\0'; - sub_count = 0; - } - | O_BRACE vals C_BRACE - { - gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */ -#ifdef ERROR_STUFF - fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect); -#endif - if (db_file_name) - dbLoadRecords(db_file_name, sub_collect); - else - fprintf(stderr, "Error: no db file name given\n"); - *gbl_collect = '\0'; + *sub_locals = '\0'; sub_count = 0; } ; -vals: vals val - | vals COMMA val - | val +pattern_values: pattern_value + | pattern_values COMMA + | pattern_values pattern_value ; -val: QUOTE +pattern_value: QUOTE { - if (sub_count <= var_count) { - strcat(gbl_collect, vars[sub_count]); - strcat(gbl_collect, "=\""); - strcat(gbl_collect, $1); - strcat(gbl_collect, "\","); + #ifdef ERROR_STUFF + fprintf(stderr, "pattern_value: [%d] = \"%s\"\n", sub_count, $1); + #endif + if (sub_count < var_count) { + strcat(sub_locals, ","); + strcat(sub_locals, vars[sub_count]); + strcat(sub_locals, "=\""); + strcat(sub_locals, $1); + strcat(sub_locals, "\""); sub_count++; + } else { + fprintf(stderr, "dbLoadTemplate: Too many values given, line %d.\n", + line_num); } dbmfFree($1); } | WORD { - if (sub_count <= var_count) { - strcat(gbl_collect, vars[sub_count]); - strcat(gbl_collect, "="); - strcat(gbl_collect, $1); - strcat(gbl_collect, ","); + #ifdef ERROR_STUFF + fprintf(stderr, "pattern_value: [%d] = %s\n", sub_count, $1); + #endif + if (sub_count < var_count) { + strcat(sub_locals, ","); + strcat(sub_locals, vars[sub_count]); + strcat(sub_locals, "="); + strcat(sub_locals, $1); sub_count++; + } else { + fprintf(stderr, "dbLoadTemplate: Too many values given, line %d.\n", + line_num); } dbmfFree($1); } ; -var_subs: var_subs var_sub - | var_sub +variable_substitutions: variable_substitution + | variable_substitutions variable_substitution ; -var_sub: WORD O_BRACE sub_pats C_BRACE +variable_substitution: O_BRACE C_BRACE { - gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */ -#ifdef ERROR_STUFF - fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect); -#endif - if (db_file_name) - dbLoadRecords(db_file_name, sub_collect); - else - fprintf(stderr, "Error: no db file name given\n"); + #ifdef ERROR_STUFF + fprintf(stderr, "variable_substitution: variable_definitions empty\n"); + fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); + #endif + dbLoadRecords(db_file_name, sub_collect+1); + } + | O_BRACE variable_definitions C_BRACE + { + #ifdef ERROR_STUFF + fprintf(stderr, "variable_substitution:\n"); + fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); + #endif + dbLoadRecords(db_file_name, sub_collect+1); + *sub_locals = '\0'; + } + | WORD O_BRACE variable_definitions C_BRACE + { /* DEPRECATED SYNTAX */ + fprintf(stderr, + "dbLoadTemplate: Substitution file uses deprecated syntax.\n" + " the string '%s' on line %d that comes just before the\n" + " '{' character is extraneous and should be removed.\n", + $1, line_num); + #ifdef ERROR_STUFF + fprintf(stderr, "variable_substitution:\n"); + fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); + #endif + dbLoadRecords(db_file_name, sub_collect+1); dbmfFree($1); - *gbl_collect = '\0'; - sub_count = 0; - } - | O_BRACE sub_pats C_BRACE - { - gbl_collect[strlen(gbl_collect) - 1] = '\0'; /* drop ',' */ -#ifdef ERROR_STUFF - fprintf(stderr, "dbLoadRecords(%s)\n", sub_collect); -#endif - if (db_file_name) - dbLoadRecords(db_file_name, sub_collect); - else - fprintf(stderr, "Error: no db file name given\n"); - *gbl_collect = '\0'; - sub_count = 0; + *sub_locals = '\0'; } ; -sub_pats: sub_pats sub_pat - | sub_pats COMMA sub_pat - | sub_pat +variable_definitions: variable_definition + | variable_definitions COMMA + | variable_definitions variable_definition ; -sub_pat: WORD EQUALS WORD +variable_definition: WORD EQUALS WORD { - strcat(gbl_collect, $1); - strcat(gbl_collect, "="); - strcat(gbl_collect, $3); - strcat(gbl_collect, ","); + #ifdef ERROR_STUFF + fprintf(stderr, "variable_definition: %s = %s\n", $1, $3); + #endif + strcat(sub_locals, ","); + strcat(sub_locals, $1); + strcat(sub_locals, "="); + strcat(sub_locals, $3); dbmfFree($1); dbmfFree($3); - sub_count++; } | WORD EQUALS QUOTE { - strcat(gbl_collect, $1); - strcat(gbl_collect, "=\""); - strcat(gbl_collect, $3); - strcat(gbl_collect, "\","); + #ifdef ERROR_STUFF + fprintf(stderr, "variable_definition: %s = \"%s\"\n", $1, $3); + #endif + strcat(sub_locals, ","); + strcat(sub_locals, $1); + strcat(sub_locals, "=\""); + strcat(sub_locals, $3); + strcat(sub_locals, "\""); dbmfFree($1); dbmfFree($3); - sub_count++; } ; @@ -262,7 +308,7 @@ static int is_not_inited = 1; int epicsShareAPI dbLoadTemplate(const char *sub_file, const char *cmd_collect) { FILE *fp; - int ind; + int i; line_num = 1; @@ -286,14 +332,14 @@ int epicsShareAPI dbLoadTemplate(const char *sub_file, const char *cmd_collect) fprintf(stderr, "dbLoadTemplate: Out of memory!\n"); return -1; } + strcpy(sub_collect, ","); if (cmd_collect && *cmd_collect) { - strcpy(sub_collect, cmd_collect); - strcat(sub_collect, ","); - gbl_collect = sub_collect + strlen(sub_collect); + strcat(sub_collect, cmd_collect); + sub_locals = sub_collect + strlen(sub_collect); } else { - gbl_collect = sub_collect; - *gbl_collect = '\0'; + sub_locals = sub_collect; + *sub_locals = '\0'; } var_count = 0; sub_count = 0; @@ -307,8 +353,8 @@ int epicsShareAPI dbLoadTemplate(const char *sub_file, const char *cmd_collect) yyparse(); - for (ind = 0; ind < var_count; ind++) { - dbmfFree(vars[ind]); + for (i = 0; i < var_count; i++) { + dbmfFree(vars[i]); } free(vars); free(sub_collect); From ac32658bf4750cd926216b07757812cafe9dc9bc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 25 Aug 2010 13:21:24 -0500 Subject: [PATCH 38/50] dbtools: Added another possibility for pattern_substitutions rule. --- src/dbtools/dbLoadTemplate.y | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dbtools/dbLoadTemplate.y b/src/dbtools/dbLoadTemplate.y index 1364e1978..902481feb 100644 --- a/src/dbtools/dbLoadTemplate.y +++ b/src/dbtools/dbLoadTemplate.y @@ -118,6 +118,7 @@ substitutions: pattern_substitutions ; pattern_substitutions: PATTERN O_BRACE C_BRACE + | PATTERN O_BRACE C_BRACE pattern_definitions | PATTERN O_BRACE pattern_names C_BRACE | PATTERN O_BRACE pattern_names C_BRACE pattern_definitions ; From 46e723575eba21c089de9bfb9b60f4a0b775e20c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 8 Sep 2010 16:56:13 -0500 Subject: [PATCH 39/50] dbtools: This is Ben's version of msi.c that implements global {} and restores the variable scope for every instantiation of the teplate. He's now having second thoughts on the design though, so this might be not useful. --- src/dbtools/msi.c | 717 ++++++++++++++++++++++++---------------------- 1 file changed, 369 insertions(+), 348 deletions(-) diff --git a/src/dbtools/msi.c b/src/dbtools/msi.c index 1f88c1519..3e8445558 100644 --- a/src/dbtools/msi.c +++ b/src/dbtools/msi.c @@ -1,18 +1,13 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* This file is distributed subject to a Software License Agreement found +* EPICS Base is distributed subject to a Software License Agreement found * in the file LICENSE that is included with this distribution. \*************************************************************************/ -/*msi - macro sunstitutions and include */ - -/* - * Modification Log: - * ----------------- - * .01 08DEC97 mrk Original version - */ + +/* msi - macro substitutions and include */ #include #include @@ -21,17 +16,12 @@ #include #include -#include #include #include #include #define MAX_BUFFER_SIZE 4096 -#if ((EPICS_VERSION <= 3) && (EPICS_REVISION <= 13)) -#define macEnvExpand(x) strdup(x) -#endif - /*Forward references to local routines*/ static void usageExit(void); static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval); @@ -50,12 +40,11 @@ static void inputErrPrint(void *inputPvt); static void substituteDestruct(void *substitutePvt); static void substituteOpen(void **substitutePvt,char *substitutionName); static int substituteGetNextSet(void *substitutePvt,char **filename); +static int substituteGetGlobalSet(void *substitutePvt); static char *substituteGetReplacements(void *substitutePvt); -/*Exit status*/ -static int exitStatus = 0; - -int opt_V = 0; +/*Global variables */ +static int dontWarnUndef = 1; int main(int argc,char **argv) @@ -67,76 +56,96 @@ int main(int argc,char **argv) char *substitutionName=0; char *templateName=0; int i; + int optScoped=1; inputConstruct(&inputPvt); macCreateHandle(&macPvt,0); macSuppressWarning(macPvt,1); while((argc>1) && (argv[1][0] == '-')) { - narg = (strlen(argv[1])==2) ? 2 : 1; - pval = (narg==1) ? (argv[1]+2) : argv[2]; - if(strncmp(argv[1],"-I",2)==0) { - inputAddPath(inputPvt,pval); - } else if(strncmp(argv[1],"-o",2)==0) { - if(freopen(pval,"w",stdout)==NULL) { - fprintf(stderr,"Can't open %s for writing: %s\n", pval, strerror(errno)); - exit(1); + narg = (strlen(argv[1])==2) ? 2 : 1; + pval = (narg==1) ? (argv[1]+2) : argv[2]; + if(strncmp(argv[1],"-I",2)==0) { + inputAddPath(inputPvt,pval); + } else if(strncmp(argv[1],"-o",2)==0) { + if(freopen(pval,"w",stdout)==NULL) { + fprintf(stderr,"msi: Can't open %s for writing: %s\n", + pval, strerror(errno)); + exit(1); + } + } else if(strncmp(argv[1],"-M",2)==0) { + addMacroReplacements(macPvt,pval); + } else if(strncmp(argv[1],"-S",2)==0) { + substitutionName = calloc(strlen(pval)+1,sizeof(char)); + strcpy(substitutionName,pval); + } else if(strncmp(argv[1],"-V",2)==0) { + macSuppressWarning(macPvt,0); + dontWarnUndef = 0; + narg = 1; /* no argument for this option */ + } else if(strncmp(argv[1],"-c",2)==0) { + optScoped = 0; + narg = 1; /* no argument for this option */ + } else { + usageExit(); } - } else if(strncmp(argv[1],"-M",2)==0) { - addMacroReplacements(macPvt,pval); - } else if(strncmp(argv[1],"-S",2)==0) { - substitutionName = calloc(strlen(pval)+1,sizeof(char)); - strcpy(substitutionName,pval); - } else if(strncmp(argv[1],"-V",2)==0) { - macSuppressWarning(macPvt,0); - opt_V = 1; - narg = 1; /* no argument for this option */ - } else { - usageExit(); - } - argc -= narg; - for(i=1; i2) { - fprintf(stderr,"too many filename arguments\n"); - usageExit(); + fprintf(stderr,"msi: Too many arguments\n"); + usageExit(); } if(argc==2) { templateName = calloc(strlen(argv[1])+1,sizeof(char)); strcpy(templateName,argv[1]); } if(!substitutionName) { - makeSubstitutions(inputPvt,macPvt,templateName); + makeSubstitutions(inputPvt,macPvt,templateName); } else { - void *substitutePvt; + void *substitutePvt; char *filename = 0; + int isGlobal, isFile; - substituteOpen(&substitutePvt,substitutionName); - while(substituteGetNextSet(substitutePvt,&filename)) { - if(templateName) filename = templateName; - if(!filename) { - fprintf(stderr,"no template file\n"); - usageExit(); + substituteOpen(&substitutePvt,substitutionName); + do { + if ((isGlobal = substituteGetGlobalSet(substitutePvt))) { + pval = substituteGetReplacements(substitutePvt); + if(pval) { + addMacroReplacements(macPvt,pval); + } + } else if ((isFile = substituteGetNextSet(substitutePvt,&filename))) { + if(templateName) filename = templateName; + if(!filename) { + fprintf(stderr,"msi: No template file\n"); + usageExit(); + } + while((pval = substituteGetReplacements(substitutePvt))){ + if (optScoped) macPushScope(macPvt); + addMacroReplacements(macPvt,pval); + makeSubstitutions(inputPvt,macPvt,filename); + if (optScoped) macPopScope(macPvt); + } } - macPushScope(macPvt); - while((pval = substituteGetReplacements(substitutePvt))){ - addMacroReplacements(macPvt,pval); - makeSubstitutions(inputPvt,macPvt,filename); - } - macPopScope(macPvt); - } + } while (isGlobal || isFile); substituteDestruct(substitutePvt); } inputDestruct(inputPvt); free((void *)templateName); free((void *)substitutionName); - return(exitStatus); + return 0; } void usageExit(void) { - fprintf(stderr,"usage: msi -V -opath -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"); + fprintf(stderr,"usage: msi [options] [template]\n"); + fprintf(stderr,"stdin is used if neither template nor substitution file is given\n"); + fprintf(stderr,"options:\n"); + fprintf(stderr," -V don't suppress warnings\n"); + fprintf(stderr," -o save output to \n"); + fprintf(stderr," -I add to include file search path\n"); + fprintf(stderr," -M add to (global) macro definitions\n"); + fprintf(stderr," ( is of the form VAR=VALUE,...)\n"); + fprintf(stderr," -S expand a substitution file\n"); + fprintf(stderr," -c macro definitions are scoped (in substitution files)\n"); exit(1); } @@ -146,16 +155,18 @@ static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval) long status; status = macParseDefns(macPvt,pval,&pairs); - if(!status) { - fprintf(stderr,"Error macParseDefns error\n"); + if(status==-1) { + fprintf(stderr,"msi: Error from macParseDefns\n"); usageExit(); } - status = macInstallMacros(macPvt,pairs); - if(!status) { - fprintf(stderr,"Error macInstallMacros error\n"); - usageExit(); + if(status) { + status = macInstallMacros(macPvt,pairs); + if(!status) { + fprintf(stderr,"Error from macInstallMacros\n"); + usageExit(); + } + free((void *)pairs); } - free((void *)pairs); } typedef enum {cmdInclude,cmdSubstitute} cmdType; @@ -165,99 +176,97 @@ static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) char *input; static char buffer[MAX_BUFFER_SIZE]; int n; - static int unexpWarned = 0; inputBegin(inputPvt,templateName); while((input = inputNextLine(inputPvt))) { - int expand=1; - char *p; - char *command = 0; + int expand=1; + char *p; + char *command = 0; - p = input; - /*skip whitespace at beginning of line*/ - while(*p && (isspace(*p))) ++p; - /*Look for i or s */ - if(*p && (*p=='i' || *p=='s')) command = p; - if(command) { - char *pstart; - char *pend; - char *copy; - int cmdind=-1; - int i; - - for(i=0; i< NELEMENTS(cmdNames); i++) { - if(strstr(command,cmdNames[i])) { - cmdind = i; - } - } - if(cmdind<0) goto endif; - p = command + strlen(cmdNames[cmdind]); - /*skip whitespace after command*/ - while(*p && (isspace(*p))) ++p; - /*Next character must be quote*/ - if((*p==0) || (*p!='"')) goto endif; - pstart = ++p; - /*Look for end quote*/ - while(*p && (*p!='"')) { - /*allow escape for imbeded quote*/ - if((*p=='\\') && *(p+1)=='"') { - p += 2; continue; - } else { - if(*p=='"') break; - } - ++p; - } - pend = p; - if(*p==0) goto endif; + p = input; + /*skip whitespace at beginning of line*/ + while(*p && (isspace(*p))) ++p; + /*Look for i or s */ + if(*p && (*p=='i' || *p=='s')) command = p; + if(command) { + char *pstart; + char *pend; + char *copy; + int cmdind=-1; + int i; + + for(i=0; i< NELEMENTS(cmdNames); i++) { + if(strstr(command,cmdNames[i])) { + cmdind = i; + } + } + if(cmdind<0) goto endif; + p = command + strlen(cmdNames[cmdind]); + /*skip whitespace after command*/ + while(*p && (isspace(*p))) ++p; + /*Next character must be quote*/ + if((*p==0) || (*p!='"')) goto endif; + pstart = ++p; + /*Look for end quote*/ + while(*p && (*p!='"')) { + /*allow escape for imbeded quote*/ + if((*p=='\\') && *(p+1)=='"') { + p += 2; continue; + } else { + if(*p=='"') break; + } + ++p; + } + 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) { - case cmdInclude: - inputNewIncludeFile(inputPvt,copy); - break; - case cmdSubstitute: - addMacroReplacements(macPvt,copy); - break; - default: - fprintf(stderr,"Logic Error: makeSubstitutions\n"); - inputErrPrint(inputPvt); - exit(1); - } - free(copy); - expand = 0; - } + copy = calloc(pend-pstart+1,sizeof(char)); + strncpy(copy,pstart,pend-pstart); + switch(cmdind) { + case cmdInclude: + inputNewIncludeFile(inputPvt,copy); + break; + case cmdSubstitute: + addMacroReplacements(macPvt,copy); + break; + default: + fprintf(stderr,"msi: Logic error in makeSubstitutions\n"); + inputErrPrint(inputPvt); + exit(1); + } + free(copy); + expand = 0; + } endif: - if (expand) { - n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1); - fputs(buffer,stdout); - if (!unexpWarned && n<0) { - fprintf(stderr, "Warning: Undefined macros present%s\n", - opt_V ? "" : ", use msi -V to list"); - unexpWarned++; - } - } + if (expand) { + n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1); + fputs(buffer,stdout); + if (!dontWarnUndef && n<0) { + fprintf(stderr,"msi: Warning, undefined macros present\n"); + dontWarnUndef++; + } + } } } typedef struct inputFile{ - ELLNODE node; - char *filename; - FILE *fp; - int lineNum; + ELLNODE node; + char *filename; + FILE *fp; + int lineNum; }inputFile; typedef struct pathNode { - ELLNODE node; - char *directory; + ELLNODE node; + char *directory; } pathNode; typedef struct inputData { - ELLLIST inputFileList; - ELLLIST pathList; - char inputBuffer[MAX_BUFFER_SIZE]; + ELLLIST inputFileList; + ELLLIST pathList; + char inputBuffer[MAX_BUFFER_SIZE]; }inputData; static void inputOpenFile(inputData *pinputData,char *filename); @@ -266,7 +275,7 @@ static void inputCloseAllFiles(inputData *pinputData); static void inputConstruct(void **ppvt) { - inputData *pinputData; + inputData *pinputData; pinputData = calloc(1,sizeof(inputData)); ellInit(&pinputData->inputFileList); @@ -276,59 +285,59 @@ static void inputConstruct(void **ppvt) static void inputDestruct(void *pvt) { - inputData *pinputData = (inputData *)pvt; - pathNode *ppathNode; + inputData *pinputData = (inputData *)pvt; + pathNode *ppathNode; inputCloseAllFiles(pinputData); while((ppathNode = (pathNode *)ellFirst(&pinputData->pathList))) { - ellDelete(&pinputData->pathList,&ppathNode->node); - free((void *)ppathNode->directory); - free((void *)ppathNode); + ellDelete(&pinputData->pathList,&ppathNode->node); + free((void *)ppathNode->directory); + free((void *)ppathNode); } free(pvt); } static void inputAddPath(void *pvt, char *path) { - inputData *pinputData = (inputData *)pvt; - ELLLIST *ppathList = &pinputData->pathList; - pathNode *ppathNode; - const char *pcolon; - const char *pdir; - int len; - int emptyName; + inputData *pinputData = (inputData *)pvt; + ELLLIST *ppathList = &pinputData->pathList; + pathNode *ppathNode; + const char *pcolon; + const char *pdir; + int len; + int emptyName; pdir = path; /*an empty name at beginning, middle, or end means current directory*/ while(pdir && *pdir) { - emptyName = ((*pdir == ':') ? 1 : 0); - if(emptyName) ++pdir; - ppathNode = (pathNode *)calloc(1,sizeof(pathNode)); - ellAdd(ppathList,&ppathNode->node); - if(!emptyName) { - pcolon = strchr(pdir,':'); - len = (pcolon ? (pcolon - pdir) : strlen(pdir)); - if(len>0) { - ppathNode->directory = (char *)calloc(len+1,sizeof(char)); - strncpy(ppathNode->directory,pdir,len); - pdir = pcolon; - /*unless at end skip past first colon*/ - if(pdir && *(pdir+1)!=0) ++pdir; - } else { /*must have been trailing : */ - emptyName=1; - } - } - if(emptyName) { - ppathNode->directory = (char *)calloc(2,sizeof(char)); - strcpy(ppathNode->directory,"."); - } + emptyName = ((*pdir == ':') ? 1 : 0); + if(emptyName) ++pdir; + ppathNode = (pathNode *)calloc(1,sizeof(pathNode)); + ellAdd(ppathList,&ppathNode->node); + if(!emptyName) { + pcolon = strchr(pdir,':'); + len = (pcolon ? (pcolon - pdir) : strlen(pdir)); + if(len>0) { + ppathNode->directory = (char *)calloc(len+1,sizeof(char)); + strncpy(ppathNode->directory,pdir,len); + pdir = pcolon; + /*unless at end skip past first colon*/ + if(pdir && *(pdir+1)!=0) ++pdir; + } else { /*must have been trailing : */ + emptyName=1; + } + } + if(emptyName) { + ppathNode->directory = (char *)calloc(2,sizeof(char)); + strcpy(ppathNode->directory,"."); + } } return; } static void inputBegin(void *pvt,char *fileName) { - inputData *pinputData = (inputData *)pvt; + inputData *pinputData = (inputData *)pvt; inputCloseAllFiles(pinputData); inputOpenFile(pinputData,fileName); @@ -336,94 +345,94 @@ static void inputBegin(void *pvt,char *fileName) static char *inputNextLine(void *pvt) { - inputData *pinputData = (inputData *)pvt; - inputFile *pinputFile; - char *pline; + inputData *pinputData = (inputData *)pvt; + inputFile *pinputFile; + char *pline; while((pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList))) { pline = fgets(pinputData->inputBuffer,MAX_BUFFER_SIZE,pinputFile->fp); - if(pline) { - ++pinputFile->lineNum; - return(pline); - } - inputCloseFile(pinputData); + if(pline) { + ++pinputFile->lineNum; + return(pline); + } + inputCloseFile(pinputData); } return(0); } static void inputNewIncludeFile(void *pvt,char *name) { - inputData *pinputData = (inputData *)pvt; + inputData *pinputData = (inputData *)pvt; inputOpenFile(pinputData,name); } static void inputErrPrint(void *pvt) { - inputData *pinputData = (inputData *)pvt; - inputFile *pinputFile; + inputData *pinputData = (inputData *)pvt; + inputFile *pinputFile; - fprintf(stderr,"input: %s which is ",pinputData->inputBuffer); + fprintf(stderr,"input: '%s' at ",pinputData->inputBuffer); pinputFile = (inputFile *)ellFirst(&pinputData->inputFileList); while(pinputFile) { - fprintf(stderr,"line %d of ",pinputFile->lineNum); - if(pinputFile->filename) { - fprintf(stderr," file %s\n",pinputFile->filename); - } else { - fprintf(stderr,"stdin:\n"); - } - pinputFile = (inputFile *)ellNext(&pinputFile->node); - if(pinputFile) { - fprintf(stderr," which is included from "); - } else { - fprintf(stderr,"\n"); - } + fprintf(stderr,"line %d of ",pinputFile->lineNum); + if(pinputFile->filename) { + fprintf(stderr," file %s\n",pinputFile->filename); + } else { + fprintf(stderr,"stdin:\n"); + } + pinputFile = (inputFile *)ellNext(&pinputFile->node); + if(pinputFile) { + fprintf(stderr," included from "); + } else { + fprintf(stderr,"\n"); + } } fprintf(stderr,"\n"); } static void inputOpenFile(inputData *pinputData,char *filename) { - ELLLIST *ppathList = &pinputData->pathList; - pathNode *ppathNode = 0; - inputFile *pinputFile; - char *fullname = 0; - FILE *fp = 0; + ELLLIST *ppathList = &pinputData->pathList; + pathNode *ppathNode = 0; + inputFile *pinputFile; + char *fullname = 0; + FILE *fp = 0; if(!filename) { - fp = stdin; + fp = stdin; } else if((ellCount(ppathList)==0) || strchr(filename,'/')){ - fp = fopen(filename,"r"); + fp = fopen(filename,"r"); } else { ppathNode = (pathNode *)ellFirst(ppathList); while(ppathNode) { - fullname = calloc(strlen(filename)+strlen(ppathNode->directory) +2, - sizeof(char)); - strcpy(fullname,ppathNode->directory); - strcat(fullname,"/"); - strcat(fullname,filename); - fp = fopen(fullname,"r"); - if(fp) break; - free((void *)fullname); - ppathNode = (pathNode *)ellNext(&ppathNode->node); - } + fullname = calloc(strlen(filename)+strlen(ppathNode->directory) +2, + sizeof(char)); + strcpy(fullname,ppathNode->directory); + strcat(fullname,"/"); + strcat(fullname,filename); + fp = fopen(fullname,"r"); + if(fp) break; + free((void *)fullname); + ppathNode = (pathNode *)ellNext(&ppathNode->node); + } } if(!fp) { - fprintf(stderr,"Could not open %s\n",filename); + fprintf(stderr,"msi: Can't open file '%s'\n",filename); inputErrPrint((void *)pinputData); exit(1); } pinputFile = calloc(1,sizeof(inputFile)); if(ppathNode) { - pinputFile->filename = calloc(1,strlen(fullname)+1); - strcpy(pinputFile->filename,fullname); - free((void *)fullname); + pinputFile->filename = calloc(1,strlen(fullname)+1); + strcpy(pinputFile->filename,fullname); + free((void *)fullname); } else if(filename) { pinputFile->filename = calloc(1,strlen(filename)+1); strcpy(pinputFile->filename,filename); } else { - pinputFile->filename = calloc(1,strlen("stdin")+1); - strcpy(pinputFile->filename,"stdin"); + pinputFile->filename = calloc(1,strlen("stdin")+1); + strcpy(pinputFile->filename,"stdin"); } pinputFile->fp = fp; ellInsert(&pinputData->inputFileList,0,&pinputFile->node); @@ -437,17 +446,17 @@ static void inputCloseFile(inputData *pinputData) if(!pinputFile) return; ellDelete(&pinputData->inputFileList,&pinputFile->node); if(fclose(pinputFile->fp)) - fprintf(stderr,"fclose failed: file %s\n",pinputFile->filename); + fprintf(stderr,"msi: Can't close input file '%s'\n",pinputFile->filename); free(pinputFile->filename); free(pinputFile); } static void inputCloseAllFiles(inputData *pinputData) { - inputFile *pinputFile; + inputFile *pinputFile; while((pinputFile=(inputFile *)ellFirst(&pinputData->inputFileList))){ - inputCloseFile(pinputData); + inputCloseFile(pinputData); } } @@ -457,29 +466,29 @@ typedef enum { }tokenType; typedef struct subFile { - char *substitutionName; - FILE *fp; - int lineNum; - char inputBuffer[MAX_BUFFER_SIZE]; - char *pnextChar; - tokenType token; - char string[MAX_BUFFER_SIZE]; + char *substitutionName; + FILE *fp; + int lineNum; + char inputBuffer[MAX_BUFFER_SIZE]; + char *pnextChar; + tokenType token; + char string[MAX_BUFFER_SIZE]; } subFile; typedef struct patternNode { - ELLNODE node; - char *var; + ELLNODE node; + char *var; }patternNode; typedef struct subInfo { - subFile *psubFile; - int isFile; - char *filename; - int isPattern; - ELLLIST patternList; - size_t size; - size_t curLength; - char *macroReplacements; + subFile *psubFile; + int isFile; + char *filename; + int isPattern; + ELLLIST patternList; + size_t size; + size_t curLength; + char *macroReplacements; }subInfo; static char *subGetNextLine(subFile *psubFile); @@ -491,10 +500,10 @@ static void catMacroReplacements(subInfo *psubInfo,const char *value); void freeSubFile(subInfo *psubInfo) { - subFile *psubFile = psubInfo->psubFile; + subFile *psubFile = psubInfo->psubFile; if(psubFile->fp) { if(fclose(psubFile->fp)) - fprintf(stderr,"fclose failed on substitution file\n"); + fprintf(stderr,"msi: Can't close substitution file\n"); } free((void *)psubFile); free((void *)psubInfo->filename); @@ -503,18 +512,18 @@ void freeSubFile(subInfo *psubInfo) void freePattern(subInfo *psubInfo) { - patternNode *ppatternNode; + patternNode *ppatternNode; while((ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList))) { - ellDelete(&psubInfo->patternList,&ppatternNode->node); - free(ppatternNode->var); - free(ppatternNode); + ellDelete(&psubInfo->patternList,&ppatternNode->node); + free(ppatternNode->var); + free(ppatternNode); } psubInfo->isPattern = 0; } static void substituteDestruct(void *pvt) { - subInfo *psubInfo = (subInfo *)pvt; + subInfo *psubInfo = (subInfo *)pvt; freeSubFile(psubInfo); freePattern(psubInfo); @@ -524,9 +533,9 @@ static void substituteDestruct(void *pvt) static void substituteOpen(void **ppvt,char *substitutionName) { - subInfo *psubInfo; - subFile *psubFile; - FILE *fp; + subInfo *psubInfo; + subFile *psubFile; + FILE *fp; psubInfo = calloc(1,sizeof(subInfo)); *ppvt = (void *)psubInfo; @@ -535,23 +544,36 @@ static void substituteOpen(void **ppvt,char *substitutionName) ellInit(&psubInfo->patternList); fp = fopen(substitutionName,"r"); if(!fp) { - fprintf(stderr,"Could not open %s\n",substitutionName); + fprintf(stderr,"msi: Can't open file '%s'\n",substitutionName); exit(1); } psubFile->substitutionName = substitutionName; psubFile->fp = fp; - psubFile->lineNum = 0; + psubFile->lineNum = 1; psubFile->inputBuffer[0] = 0; psubFile->pnextChar = &psubFile->inputBuffer[0]; subGetNextToken(psubFile); return; } - + +static int substituteGetGlobalSet(void *pvt) +{ + subInfo *psubInfo = (subInfo *)pvt; + subFile *psubFile = psubInfo->psubFile; + + while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); + if(psubFile->token==tokenString && strcmp(psubFile->string,"global")==0) { + subGetNextToken(psubFile); + return(1); + } + return(0); +} + static int substituteGetNextSet(void *pvt,char **filename) { - subInfo *psubInfo = (subInfo *)pvt; - subFile *psubFile = psubInfo->psubFile; - patternNode *ppatternNode; + subInfo *psubInfo = (subInfo *)pvt; + subFile *psubFile = psubInfo->psubFile; + patternNode *ppatternNode; *filename = 0; while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); @@ -559,7 +581,7 @@ static int substituteGetNextSet(void *pvt,char **filename) if(psubFile->token==tokenString && strcmp(psubFile->string,"file")==0) { psubInfo->isFile = 1; if(subGetNextToken(psubFile)!=tokenString) { - subFileErrPrint(psubFile,"Expecting filename"); + subFileErrPrint(psubFile,"Parse error, expecting filename"); exit(1); } freePattern(psubInfo); @@ -573,7 +595,7 @@ static int substituteGetNextSet(void *pvt,char **filename) } while(subGetNextToken(psubFile)==tokenSeparater); if(psubFile->token!=tokenLBrace) { - subFileErrPrint(psubFile,"Expecting {"); + subFileErrPrint(psubFile,"Parse error, expecting {"); exit(1); } subGetNextToken(psubFile); @@ -581,30 +603,30 @@ static int substituteGetNextSet(void *pvt,char **filename) *filename = psubInfo->filename; while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); if(psubFile->token==tokenLBrace) return(1); - if(psubFile->token==tokenRBrace) return(0); + if(psubFile->token==tokenRBrace) return(1); if(psubFile->token!=tokenString || strcmp(psubFile->string,"pattern")!=0) { - subFileErrPrint(psubFile,"Expecting pattern"); + subFileErrPrint(psubFile,"Parse error, expecting pattern"); exit(1); } freePattern(psubInfo); psubInfo->isPattern = 1; while(subGetNextToken(psubFile)==tokenSeparater); if(psubFile->token!=tokenLBrace) { - subFileErrPrint(psubFile,"Expecting {"); - exit(1); + subFileErrPrint(psubFile,"Parse error, expecting {"); + exit(1); } while(1) { 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!=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); + subFileErrPrint(psubFile,"Parse error, expecting }"); + exit(1); } subGetNextToken(psubFile); return(1); @@ -612,8 +634,8 @@ static int substituteGetNextSet(void *pvt,char **filename) static char *substituteGetReplacements(void *pvt) { - subInfo *psubInfo = (subInfo *)pvt; - subFile *psubFile = psubInfo->psubFile; + subInfo *psubInfo = (subInfo *)pvt; + subFile *psubFile = psubInfo->psubFile; patternNode *ppatternNode; if(psubInfo->macroReplacements) psubInfo->macroReplacements[0] = 0; @@ -630,48 +652,49 @@ static char *substituteGetReplacements(void *pvt) if(psubFile->token==tokenEOF) return(0); if(psubFile->token!=tokenLBrace) return(0); if(psubInfo->isPattern) { - int gotFirstPattern = 0; + int gotFirstPattern = 0; while(subGetNextToken(psubFile)==tokenSeparater); - ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList); - while(1) { + ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList); + while(1) { 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"); + subFileErrPrint(psubFile,"Parse error, illegal token"); exit(-1); } - if(gotFirstPattern) catMacroReplacements(psubInfo,","); - gotFirstPattern = 1; + if(gotFirstPattern) catMacroReplacements(psubInfo,","); + gotFirstPattern = 1; if(ppatternNode) { - catMacroReplacements(psubInfo,ppatternNode->var); - catMacroReplacements(psubInfo,"="); - catMacroReplacements(psubInfo,psubFile->string); + catMacroReplacements(psubInfo,ppatternNode->var); + catMacroReplacements(psubInfo,"="); + catMacroReplacements(psubInfo,psubFile->string); ppatternNode = (patternNode *)ellNext(&ppatternNode->node); } else { - subFileErrPrint(psubFile,"more values than patterns"); + subFileErrPrint(psubFile,"Warning, too many values given"); } while(subGetNextToken(psubFile)==tokenSeparater); - } + } } else while(1) { switch(subGetNextToken(psubFile)) { - case tokenRBrace: + case tokenRBrace: subGetNextToken(psubFile); + if (!psubInfo->macroReplacements) { + catMacroReplacements(psubInfo,""); + } return(psubInfo->macroReplacements); - case tokenSeparater: - catMacroReplacements(psubInfo,","); - break; - case tokenString: - catMacroReplacements(psubInfo,psubFile->string); - break; - default: - subFileErrPrint(psubFile,"Illegal token"); - exit(1); - } + case tokenSeparater: + catMacroReplacements(psubInfo,","); + break; + case tokenString: + catMacroReplacements(psubInfo,psubFile->string); + break; + default: + subFileErrPrint(psubFile,"Parse error, illegal token"); + exit(1); + } } } @@ -679,17 +702,15 @@ 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); + do { + pline = fgets(psubFile->inputBuffer,MAX_BUFFER_SIZE,psubFile->fp); ++psubFile->lineNum; - } + } while(pline && psubFile->inputBuffer[0]=='#'); if(!pline) { - psubFile->token = tokenEOF; - psubFile->inputBuffer[0] = 0; - psubFile->pnextChar = 0; - return(0); + psubFile->token = tokenEOF; + psubFile->inputBuffer[0] = 0; + psubFile->pnextChar = 0; + return(0); } psubFile->pnextChar = &psubFile->inputBuffer[0]; return(&psubFile->inputBuffer[0]); @@ -697,64 +718,64 @@ static char *subGetNextLine(subFile *psubFile) static void subFileErrPrint(subFile *psubFile,char * message) { - fprintf(stderr,"substitution file %s line %d: %s", - psubFile->substitutionName, - psubFile->lineNum,psubFile->inputBuffer); - fprintf(stderr,"%s\n",message); + fprintf(stderr,"msi: %s\n",message); + fprintf(stderr," in substitution file '%s' at line %d:\n %s", + psubFile->substitutionName, + psubFile->lineNum,psubFile->inputBuffer); } static tokenType subGetNextToken(subFile *psubFile) { - char *p; - char *pto; + char *p; + char *pto; p = psubFile->pnextChar; if(!p) { psubFile->token = tokenEOF; return(tokenEOF);} if(*p==0 || *p=='\n' || *p=='#') { - p = subGetNextLine(psubFile); - if(!p) { psubFile->token = tokenEOF; return(tokenEOF);} + p = subGetNextLine(psubFile); + if(!p) { psubFile->token = tokenEOF; return(tokenEOF);} else { psubFile->token = tokenSeparater; return(tokenSeparater);} } while(isspace(*p)) p++; if(*p=='{') { - psubFile->token = tokenLBrace; - psubFile->pnextChar = ++p; - return(tokenLBrace); + psubFile->token = tokenLBrace; + psubFile->pnextChar = ++p; + return(tokenLBrace); } if(*p=='}') { - psubFile->token = tokenRBrace; - psubFile->pnextChar = ++p; - return(tokenRBrace); + psubFile->token = tokenRBrace; + psubFile->pnextChar = ++p; + return(tokenRBrace); } if(*p==0 || isspace(*p) || *p==',') { - while(isspace(*p) || *p==',') p++; - psubFile->token = tokenSeparater; - psubFile->pnextChar = p; - return(tokenSeparater); + while(isspace(*p) || *p==',') p++; + psubFile->token = tokenSeparater; + psubFile->pnextChar = p; + return(tokenSeparater); } /*now handle quoted strings*/ if(*p=='"') { - pto = &psubFile->string[0]; - *pto++ = *p++; - while(*p!='"') { - if(*p==0 || *p=='\n') { - subFileErrPrint(psubFile,"Strings must be on single line\n"); - exit(1); - } - /*allow escape for imbeded quote*/ - if((*p=='\\') && *(p+1)=='"') { - *pto++ = *p++; - *pto++ = *p++; - continue; - } - *pto++ = *p++; - } - *pto++ = *p++; - psubFile->pnextChar = p; - *pto = 0; - psubFile->token = tokenString; - return(tokenString); + pto = &psubFile->string[0]; + *pto++ = *p++; + while(*p!='"') { + if(*p==0 || *p=='\n') { + subFileErrPrint(psubFile,"Strings must be on single line\n"); + exit(1); + } + /*allow escape for imbeded quote*/ + if((*p=='\\') && *(p+1)=='"') { + *pto++ = *p++; + *pto++ = *p++; + continue; + } + *pto++ = *p++; + } + *pto++ = *p++; + psubFile->pnextChar = p; + *pto = 0; + psubFile->token = tokenString; + return(tokenString); } /*Now take anything up to next non String token and not space*/ pto = &psubFile->string[0]; @@ -767,7 +788,7 @@ static tokenType subGetNextToken(subFile *psubFile) static void catMacroReplacements(subInfo *psubInfo,const char *value) { - size_t len = strlen(value); + size_t len = strlen(value); if(psubInfo->size <= (psubInfo->curLength + len)) { size_t newsize = psubInfo->size + MAX_BUFFER_SIZE; From a7d733639201ec137a65979dbccc07d993c3c473 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 8 Sep 2010 16:59:10 -0500 Subject: [PATCH 40/50] dbtools: Added dbltExpand.c This is a test program which implements the template expansion capabilities of msi, but using the dbLoadTemplate.c code. It should be useful for testing, to make sure that both versions generate the same output. It won't work on Windows at the moment due to a clash in the function decorations of the dbLoadRecords() function. --- src/dbtools/test/Makefile | 24 ++++++++ src/dbtools/test/dbltExpand.c | 100 ++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 src/dbtools/test/Makefile create mode 100644 src/dbtools/test/dbltExpand.c diff --git a/src/dbtools/test/Makefile b/src/dbtools/test/Makefile new file mode 100644 index 000000000..58acbd355 --- /dev/null +++ b/src/dbtools/test/Makefile @@ -0,0 +1,24 @@ +#************************************************************************* +# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in the file LICENSE that is included with this distribution. +#************************************************************************* +TOP=../../.. + +include $(TOP)/configure/CONFIG + +TESTPROD_HOST += dbltExpand +dbltExpand_SRCS += dbltExpand.c +dbltExpand_LIBS += dbtoolsIoc dbStaticHost Com + + +#TESTPROD_HOST += callbackTest +#callbackTest_SRCS += callbackTest.c +#TESTS += callbackTest + + +TESTSCRIPTS_HOST += $(TESTS:%=%.t) + +include $(TOP)/configure/RULES + diff --git a/src/dbtools/test/dbltExpand.c b/src/dbtools/test/dbltExpand.c new file mode 100644 index 000000000..6326d288e --- /dev/null +++ b/src/dbtools/test/dbltExpand.c @@ -0,0 +1,100 @@ +/*************************************************************************\ +* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS Base is distributed subject to a Software License Agreement found +* in the file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* This is a simple version of msi for testing the dbLoadTemplate() code. + * + * It calls dbLoadTemplate() to parse the substitution file, but replaces + * dbLoadRecords() with its own version that reads the template file, + * expands any macros in the text and prints the result to stdout. + * + * This technique won't work on Windows, dbLoadRecords() has to be + * epicsShare... decorated and loaded from a shared library. + */ + +#include +#include +#include +#include + +#include "macLib.h" +#include "dbLoadTemplate.h" + + +#define BUFFER_SIZE 0x10000 + +static char *input_buffer, *output_buffer; + +int dbLoadRecords(const char *file, const char *macros) +{ + MAC_HANDLE *macHandle = NULL; + char **macPairs; + FILE *fp; + size_t input_len; + + if (macCreateHandle(&macHandle, NULL)) { + fprintf(stderr, "macCreateHandle failed\n"); + exit(1); + } + + macSuppressWarning(macHandle, 1); + macParseDefns(macHandle, macros, &macPairs); + if (!macPairs) { + macDeleteHandle(macHandle); + macHandle = NULL; + } else { + macInstallMacros(macHandle, macPairs); + free(macPairs); + } + + fp = fopen(file, "r"); + if (!fp) { + fprintf(stderr, "fopen('%s') failed: %s\n", file, strerror(errno)); + exit(1); + } + + input_len = fread(input_buffer, 1, BUFFER_SIZE, fp); + if (!feof(fp)) { + fprintf(stderr, "input file > 64K!\n"); + fclose(fp); + exit(1); + } + input_buffer[input_len] = 0; + + if (fclose(fp)) { + fprintf(stderr, "fclose('%s') failed: %s\n", file, strerror(errno)); + exit(1); + } + + macExpandString(macHandle, input_buffer, output_buffer, BUFFER_SIZE-1); + printf(output_buffer); + + if (macHandle) macDeleteHandle(macHandle); + + return 0; +} + +int main(int argc, char **argv) +{ + input_buffer = malloc(BUFFER_SIZE); + output_buffer = malloc(BUFFER_SIZE); + + if (!input_buffer || !output_buffer) { + fprintf(stderr, "malloc(%d) failed\n", BUFFER_SIZE); + exit(1); + } + + if (argc != 2) { + fprintf(stderr, "Usage: %s file.sub\n", argv[0]); + exit(1); + } + + dbLoadTemplate(argv[1], NULL); + + free(output_buffer); + free(input_buffer); + return 0; +} From 6923f82119807c685f322c47d1d5aadd1a8c1c83 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 8 Sep 2010 17:02:23 -0500 Subject: [PATCH 41/50] dbtools: Modified and added test files. --- src/dbtools/test/include-file | 5 +++++ src/dbtools/test/s1.sub | 20 ++++++++++++++++++++ src/dbtools/test/t1.txt | 1 + src/dbtools/test/test-file | 14 ++++++++++++++ src/dbtools/test/testfile | 13 ------------- src/dbtools/test/testfile1 | 4 ---- 6 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 src/dbtools/test/include-file create mode 100644 src/dbtools/test/s1.sub create mode 100644 src/dbtools/test/t1.txt create mode 100644 src/dbtools/test/test-file delete mode 100644 src/dbtools/test/testfile delete mode 100644 src/dbtools/test/testfile1 diff --git a/src/dbtools/test/include-file b/src/dbtools/test/include-file new file mode 100644 index 000000000..718635415 --- /dev/null +++ b/src/dbtools/test/include-file @@ -0,0 +1,5 @@ +This is include-file $(include-file-again=) + a = $(a=default value used when a is undefined) + b = $(b=default value used when b is undefined) +substitute "include-file-again=again" +End of include-file. diff --git a/src/dbtools/test/s1.sub b/src/dbtools/test/s1.sub new file mode 100644 index 000000000..3046b1923 --- /dev/null +++ b/src/dbtools/test/s1.sub @@ -0,0 +1,20 @@ +global {a=gbl-a, b=gbl-b} +file t1.txt { + pattern {a, b, c} + {} + {pat-a} + {pat-a, pat-b} + {pat-a, pat-b, pat-c} + {pat-a, pat-b} + {pat-a} + {} +} +file t1.txt { + {} + {a=val-a} + {a=val-a, b=val-b} + {a=val-a, b=val-b, c=val-c} + {a=val-a, b=val-b} + {a=val-a} + {} +} diff --git a/src/dbtools/test/t1.txt b/src/dbtools/test/t1.txt new file mode 100644 index 000000000..c4ac7b427 --- /dev/null +++ b/src/dbtools/test/t1.txt @@ -0,0 +1 @@ +a = $(a=def-a) b = $(b=def-b) c = $(c=def-c) d = $(d,undef) diff --git a/src/dbtools/test/test-file b/src/dbtools/test/test-file new file mode 100644 index 000000000..6da35ffe9 --- /dev/null +++ b/src/dbtools/test/test-file @@ -0,0 +1,14 @@ +This is test-file + +With $(a) & ${b}: +include "include-file" + +substitute "a=aaa,b=bbb" +On defining a=$(a) & b=${b}: +include "include-file" + +substitute "a=\"aa\"" +On setting a=$(a): +include "include-file" + +End of test-file. diff --git a/src/dbtools/test/testfile b/src/dbtools/test/testfile deleted file mode 100644 index 845648365..000000000 --- a/src/dbtools/test/testfile +++ /dev/null @@ -1,13 +0,0 @@ -This is a test file -This is second line -include "testfile1" -a=${a} -b=$(b) -substitute "a=aaa,b=bbb" -a=${a} -b=$(b) -substitute "a=\"aa\"" -${a} -$(a) -This is last line -%report diff --git a/src/dbtools/test/testfile1 b/src/dbtools/test/testfile1 deleted file mode 100644 index 3a61424bc..000000000 --- a/src/dbtools/test/testfile1 +++ /dev/null @@ -1,4 +0,0 @@ -This is testfile1 -in testfile1 $(a)=a -in testfile1 $(b)=b -end of testfile1 From e1a92fcf3f4196ef0db4a7b94b91d5f9036db053 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Apr 2012 13:15:07 -0500 Subject: [PATCH 42/50] Refactoring for maintainability Replaced all void * pointers with pointers to private structures. Removed several unnecessary casts. --- src/dbtools/msi.c | 126 ++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 67 deletions(-) diff --git a/src/dbtools/msi.c b/src/dbtools/msi.c index 3e8445558..7c6b07772 100644 --- a/src/dbtools/msi.c +++ b/src/dbtools/msi.c @@ -22,26 +22,30 @@ #define MAX_BUFFER_SIZE 4096 -/*Forward references to local routines*/ +/* Module to read the template files */ +typedef struct inputData inputData; + +static void inputConstruct(inputData **ppvt); +static void inputDestruct(inputData *pvt); +static void inputAddPath(inputData *pvt, char *pval); +static void inputBegin(inputData *pvt, char *fileName); +static char *inputNextLine(inputData *pvt); +static void inputNewIncludeFile(inputData *pvt, char *name); +static void inputErrPrint(inputData *pvt); + +/* Module to read the substitution file */ +typedef struct subInfo subInfo; + +static void substituteOpen(subInfo **ppvt, char *substitutionName); +static void substituteDestruct(subInfo *pvt); +static int substituteGetNextSet(subInfo *pvt, char **filename); +static int substituteGetGlobalSet(subInfo *pvt); +static char *substituteGetReplacements(subInfo *pvt); + +/* 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); - -/*Routines that read the template files */ -static void inputConstruct(void **inputPvt); -static void inputDestruct(void *inputPvt); -static void inputAddPath(void *inputPvt, char *pval); -static void inputBegin(void *inputPvt,char *fileName); -static char *inputNextLine(void *inputPvt); -static void inputNewIncludeFile(void *inputPvt,char *name); -static void inputErrPrint(void *inputPvt); - -/*Routines that read the substitution file */ -static void substituteDestruct(void *substitutePvt); -static void substituteOpen(void **substitutePvt,char *substitutionName); -static int substituteGetNextSet(void *substitutePvt,char **filename); -static int substituteGetGlobalSet(void *substitutePvt); -static char *substituteGetReplacements(void *substitutePvt); +static void addMacroReplacements(MAC_HANDLE *macPvt, char *pval); +static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *templateName); /*Global variables */ static int dontWarnUndef = 1; @@ -49,7 +53,7 @@ static int dontWarnUndef = 1; int main(int argc,char **argv) { - void *inputPvt; + inputData *inputPvt; MAC_HANDLE *macPvt; char *pval; int narg; @@ -101,7 +105,7 @@ int main(int argc,char **argv) if(!substitutionName) { makeSubstitutions(inputPvt,macPvt,templateName); } else { - void *substitutePvt; + subInfo *substitutePvt; char *filename = 0; int isGlobal, isFile; @@ -129,8 +133,8 @@ int main(int argc,char **argv) substituteDestruct(substitutePvt); } inputDestruct(inputPvt); - free((void *)templateName); - free((void *)substitutionName); + free(templateName); + free(substitutionName); return 0; } @@ -165,13 +169,14 @@ static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval) fprintf(stderr,"Error from macInstallMacros\n"); usageExit(); } - free((void *)pairs); + free(pairs); } } typedef enum {cmdInclude,cmdSubstitute} cmdType; static const char *cmdNames[] = {"include","substitute"}; -static void makeSubstitutions(void *inputPvt,void *macPvt,char *templateName) + +static void makeSubstitutions(inputData *inputPvt, MAC_HANDLE *macPvt, char *templateName) { char *input; static char buffer[MAX_BUFFER_SIZE]; @@ -263,17 +268,17 @@ typedef struct pathNode { char *directory; } pathNode; -typedef struct inputData { +struct inputData { ELLLIST inputFileList; ELLLIST pathList; char inputBuffer[MAX_BUFFER_SIZE]; -}inputData; +}; static void inputOpenFile(inputData *pinputData,char *filename); static void inputCloseFile(inputData *pinputData); static void inputCloseAllFiles(inputData *pinputData); -static void inputConstruct(void **ppvt) +static void inputConstruct(inputData **ppvt) { inputData *pinputData; @@ -283,23 +288,21 @@ static void inputConstruct(void **ppvt) *ppvt = pinputData; } -static void inputDestruct(void *pvt) +static void inputDestruct(inputData *pinputData) { - inputData *pinputData = (inputData *)pvt; pathNode *ppathNode; inputCloseAllFiles(pinputData); while((ppathNode = (pathNode *)ellFirst(&pinputData->pathList))) { ellDelete(&pinputData->pathList,&ppathNode->node); - free((void *)ppathNode->directory); - free((void *)ppathNode); + free(ppathNode->directory); + free(ppathNode); } - free(pvt); + free(pinputData); } -static void inputAddPath(void *pvt, char *path) +static void inputAddPath(inputData *pinputData, char *path) { - inputData *pinputData = (inputData *)pvt; ELLLIST *ppathList = &pinputData->pathList; pathNode *ppathNode; const char *pcolon; @@ -335,17 +338,14 @@ static void inputAddPath(void *pvt, char *path) return; } -static void inputBegin(void *pvt,char *fileName) +static void inputBegin(inputData *pinputData, char *fileName) { - inputData *pinputData = (inputData *)pvt; - inputCloseAllFiles(pinputData); inputOpenFile(pinputData,fileName); } -static char *inputNextLine(void *pvt) +static char *inputNextLine(inputData *pinputData) { - inputData *pinputData = (inputData *)pvt; inputFile *pinputFile; char *pline; @@ -360,16 +360,13 @@ static char *inputNextLine(void *pvt) return(0); } -static void inputNewIncludeFile(void *pvt,char *name) +static void inputNewIncludeFile(inputData *pinputData, char *name) { - inputData *pinputData = (inputData *)pvt; - inputOpenFile(pinputData,name); } -static void inputErrPrint(void *pvt) +static void inputErrPrint(inputData *pinputData) { - inputData *pinputData = (inputData *)pvt; inputFile *pinputFile; fprintf(stderr,"input: '%s' at ",pinputData->inputBuffer); @@ -413,20 +410,20 @@ static void inputOpenFile(inputData *pinputData,char *filename) strcat(fullname,filename); fp = fopen(fullname,"r"); if(fp) break; - free((void *)fullname); + free(fullname); ppathNode = (pathNode *)ellNext(&ppathNode->node); } } if(!fp) { fprintf(stderr,"msi: Can't open file '%s'\n",filename); - inputErrPrint((void *)pinputData); + inputErrPrint(pinputData); exit(1); } pinputFile = calloc(1,sizeof(inputFile)); if(ppathNode) { pinputFile->filename = calloc(1,strlen(fullname)+1); strcpy(pinputFile->filename,fullname); - free((void *)fullname); + free(fullname); } else if(filename) { pinputFile->filename = calloc(1,strlen(filename)+1); strcpy(pinputFile->filename,filename); @@ -478,9 +475,9 @@ typedef struct subFile { typedef struct patternNode { ELLNODE node; char *var; -}patternNode; +} patternNode; -typedef struct subInfo { +struct subInfo { subFile *psubFile; int isFile; char *filename; @@ -489,7 +486,7 @@ typedef struct subInfo { size_t size; size_t curLength; char *macroReplacements; -}subInfo; +}; static char *subGetNextLine(subFile *psubFile); static tokenType subGetNextToken(subFile *psubFile); @@ -505,8 +502,8 @@ void freeSubFile(subInfo *psubInfo) if(fclose(psubFile->fp)) fprintf(stderr,"msi: Can't close substitution file\n"); } - free((void *)psubFile); - free((void *)psubInfo->filename); + free(psubFile); + free(psubInfo->filename); psubInfo->psubFile = 0; } @@ -521,24 +518,22 @@ void freePattern(subInfo *psubInfo) psubInfo->isPattern = 0; } -static void substituteDestruct(void *pvt) +static void substituteDestruct(subInfo *psubInfo) { - subInfo *psubInfo = (subInfo *)pvt; - freeSubFile(psubInfo); freePattern(psubInfo); - free((void *)psubInfo); + free(psubInfo); return; } -static void substituteOpen(void **ppvt,char *substitutionName) +static void substituteOpen(subInfo **ppvt,char *substitutionName) { subInfo *psubInfo; subFile *psubFile; FILE *fp; psubInfo = calloc(1,sizeof(subInfo)); - *ppvt = (void *)psubInfo; + *ppvt = psubInfo; psubFile = calloc(1,sizeof(subFile)); psubInfo->psubFile = psubFile; ellInit(&psubInfo->patternList); @@ -556,9 +551,8 @@ static void substituteOpen(void **ppvt,char *substitutionName) return; } -static int substituteGetGlobalSet(void *pvt) +static int substituteGetGlobalSet(subInfo *psubInfo) { - subInfo *psubInfo = (subInfo *)pvt; subFile *psubFile = psubInfo->psubFile; while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); @@ -569,9 +563,8 @@ static int substituteGetGlobalSet(void *pvt) return(0); } -static int substituteGetNextSet(void *pvt,char **filename) +static int substituteGetNextSet(subInfo *psubInfo,char **filename) { - subInfo *psubInfo = (subInfo *)pvt; subFile *psubFile = psubInfo->psubFile; patternNode *ppatternNode; @@ -585,7 +578,7 @@ static int substituteGetNextSet(void *pvt,char **filename) exit(1); } freePattern(psubInfo); - free((void *)psubInfo->filename); + free(psubInfo->filename); if(psubFile->string[0]=='"'&&psubFile->string[strlen(psubFile->string)-1]=='"') { psubFile->string[strlen(psubFile->string)-1]='\0'; psubInfo->filename = macEnvExpand(psubFile->string+1); @@ -632,9 +625,8 @@ static int substituteGetNextSet(void *pvt,char **filename) return(1); } -static char *substituteGetReplacements(void *pvt) +static char *substituteGetReplacements(subInfo *psubInfo) { - subInfo *psubInfo = (subInfo *)pvt; subFile *psubFile = psubInfo->psubFile; patternNode *ppatternNode; @@ -643,7 +635,7 @@ static char *substituteGetReplacements(void *pvt) while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); if(psubFile->token==tokenRBrace && psubInfo->isFile) { psubInfo->isFile = 0; - free((void *)psubInfo->filename); + free(psubInfo->filename); psubInfo->filename = 0; freePattern(psubInfo); subGetNextToken(psubFile); From 7a968bc5f5814cebb361971b33048c4c83c89956 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Apr 2012 14:01:51 -0500 Subject: [PATCH 43/50] Refactoring for maintainability Use epicsStrDup() Release macLib handle when finished --- src/dbtools/msi.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/dbtools/msi.c b/src/dbtools/msi.c index 7c6b07772..4f1d62562 100644 --- a/src/dbtools/msi.c +++ b/src/dbtools/msi.c @@ -19,6 +19,7 @@ #include #include #include +#include #define MAX_BUFFER_SIZE 4096 @@ -79,8 +80,7 @@ int main(int argc,char **argv) } else if(strncmp(argv[1],"-M",2)==0) { addMacroReplacements(macPvt,pval); } else if(strncmp(argv[1],"-S",2)==0) { - substitutionName = calloc(strlen(pval)+1,sizeof(char)); - strcpy(substitutionName,pval); + substitutionName = epicsStrDup(pval); } else if(strncmp(argv[1],"-V",2)==0) { macSuppressWarning(macPvt,0); dontWarnUndef = 0; @@ -99,8 +99,7 @@ int main(int argc,char **argv) usageExit(); } if(argc==2) { - templateName = calloc(strlen(argv[1])+1,sizeof(char)); - strcpy(templateName,argv[1]); + templateName = epicsStrDup(argv[1]); } if(!substitutionName) { makeSubstitutions(inputPvt,macPvt,templateName); @@ -132,6 +131,7 @@ int main(int argc,char **argv) } while (isGlobal || isFile); substituteDestruct(substitutePvt); } + macDeleteHandle(macPvt); inputDestruct(inputPvt); free(templateName); free(substitutionName); @@ -421,15 +421,11 @@ static void inputOpenFile(inputData *pinputData,char *filename) } pinputFile = calloc(1,sizeof(inputFile)); if(ppathNode) { - pinputFile->filename = calloc(1,strlen(fullname)+1); - strcpy(pinputFile->filename,fullname); - free(fullname); + pinputFile->filename = fullname; } else if(filename) { - pinputFile->filename = calloc(1,strlen(filename)+1); - strcpy(pinputFile->filename,filename); + pinputFile->filename = epicsStrDup(filename); } else { - pinputFile->filename = calloc(1,strlen("stdin")+1); - strcpy(pinputFile->filename,"stdin"); + pinputFile->filename = epicsStrDup("stdin"); } pinputFile->fp = fp; ellInsert(&pinputData->inputFileList,0,&pinputFile->node); @@ -614,8 +610,7 @@ static int substituteGetNextSet(subInfo *psubInfo,char **filename) 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); + ppatternNode->var = epicsStrDup(psubFile->string); } if(psubFile->token!=tokenRBrace) { subFileErrPrint(psubFile,"Parse error, expecting }"); From d61d7ebf9623e1254b3505bc9c682212217b9da0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Apr 2012 17:31:43 -0500 Subject: [PATCH 44/50] Fix bug with global definitions Pattern mode changes the behaviour of substituteGetReplacements() which breaks the parsing of global definitions. Add a separate routine substituteGetGlobalReplacements() which is used for parsing global definitions and ignores the isPattern flag. --- src/dbtools/msi.c | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/dbtools/msi.c b/src/dbtools/msi.c index 4f1d62562..bdde98ff6 100644 --- a/src/dbtools/msi.c +++ b/src/dbtools/msi.c @@ -42,6 +42,7 @@ static void substituteDestruct(subInfo *pvt); static int substituteGetNextSet(subInfo *pvt, char **filename); static int substituteGetGlobalSet(subInfo *pvt); static char *substituteGetReplacements(subInfo *pvt); +static char *substituteGetGlobalReplacements(subInfo *pvt); /* Forward references to local routines */ static void usageExit(void); @@ -111,7 +112,7 @@ int main(int argc,char **argv) substituteOpen(&substitutePvt,substitutionName); do { if ((isGlobal = substituteGetGlobalSet(substitutePvt))) { - pval = substituteGetReplacements(substitutePvt); + pval = substituteGetGlobalReplacements(substitutePvt); if(pval) { addMacroReplacements(macPvt,pval); } @@ -620,6 +621,44 @@ static int substituteGetNextSet(subInfo *psubInfo,char **filename) return(1); } +static char *substituteGetGlobalReplacements(subInfo *psubInfo) +{ + subFile *psubFile = psubInfo->psubFile; + + if(psubInfo->macroReplacements) psubInfo->macroReplacements[0] = 0; + psubInfo->curLength = 0; + while(psubFile->token==tokenSeparater) subGetNextToken(psubFile); + if(psubFile->token==tokenRBrace && psubInfo->isFile) { + psubInfo->isFile = 0; + free(psubInfo->filename); + psubInfo->filename = 0; + freePattern(psubInfo); + subGetNextToken(psubFile); + return(0); + } + if(psubFile->token==tokenEOF) return(0); + if(psubFile->token!=tokenLBrace) return(0); + while(1) { + switch(subGetNextToken(psubFile)) { + case tokenRBrace: + subGetNextToken(psubFile); + if (!psubInfo->macroReplacements) { + catMacroReplacements(psubInfo,""); + } + return(psubInfo->macroReplacements); + case tokenSeparater: + catMacroReplacements(psubInfo,","); + break; + case tokenString: + catMacroReplacements(psubInfo,psubFile->string); + break; + default: + subFileErrPrint(psubFile,"Parse error, illegal token"); + exit(1); + } + } +} + static char *substituteGetReplacements(subInfo *psubInfo) { subFile *psubFile = psubInfo->psubFile; From 653af6e366503ccf988a718242939c954f08ee0e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Apr 2012 17:35:26 -0500 Subject: [PATCH 45/50] Unify behaviour with msi. dbLoadTemplate must accept global definitions inside pattern and variable substitutions, since the new version of msi does that. --- src/dbtools/dbLoadTemplate.y | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dbtools/dbLoadTemplate.y b/src/dbtools/dbLoadTemplate.y index 902481feb..85be9e4e3 100644 --- a/src/dbtools/dbLoadTemplate.y +++ b/src/dbtools/dbLoadTemplate.y @@ -144,7 +144,8 @@ pattern_definitions: pattern_definition | pattern_definitions pattern_definition ; -pattern_definition: O_BRACE C_BRACE +pattern_definition: global_definitions + | O_BRACE C_BRACE { #ifdef ERROR_STUFF fprintf(stderr, "pattern_definition: pattern_values empty\n"); @@ -226,7 +227,8 @@ variable_substitutions: variable_substitution | variable_substitutions variable_substitution ; -variable_substitution: O_BRACE C_BRACE +variable_substitution: global_definitions + | O_BRACE C_BRACE { #ifdef ERROR_STUFF fprintf(stderr, "variable_substitution: variable_definitions empty\n"); From 492360a3d47871423d6bab5774bd6bbb8e98706e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Apr 2012 17:38:59 -0500 Subject: [PATCH 46/50] Documentation updates Clear out old stuff. Introduce global macro syntax. --- src/dbtools/msi.html | 53 +++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/src/dbtools/msi.html b/src/dbtools/msi.html index 7fd58c6a5..0be7bef5f 100644 --- a/src/dbtools/msi.html +++ b/src/dbtools/msi.html @@ -9,10 +9,6 @@

    msi: Macro Substitution and Include Tool

    -
    -

    Version 1.5, 10th November, 2008

    -
    -

    Introduction

    msi is a general purpose macro substitution/include tool. It accepts as input @@ -114,9 +110,8 @@ specify an illegal switch, e.g.

    substitution is performed. If no file is given then input is read from stdin. Variable instances to be substituted by macro values are expressed in the template using the syntax $(name) or -${name}. If msi has been built with EPICS Base version -3.14.7 or later, the template can also provide default values to be used when a -macro has not been given a value, using the syntax +${name}. The template can also provide default values +to be used when a macro has not been given a value, using the syntax $(name=default) or ${name=default}.

    @@ -230,9 +225,9 @@ first name is Irma family name is Kraimer
-

Note that on an IOC when using the dbLoadTemplate command, the -template file does not support the substitute command, although -include is supported.

+

Note that the IOC's dbLoadTemplate command does not support the +substitute syntax in template files, although the include +syntax is supported.

Substitution File Format

@@ -242,8 +237,10 @@ dbTemplate format. We will discuss each separately.

Regular format

-
{var1=set1_val1, var2=set1_val2, ...}
+
global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
+{var1=set1_val1, var2=set1_val2, ...}
 {var2=set2_val2, var1=set2_val1, ...}
+global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
 {var1=set3_val1, var2=set3_val2, ...}
 {var2=set4_val2, var1=set4_val1, ...}
@@ -254,24 +251,27 @@ set of braces containing macro replacement values.

Pattern format

-
pattern {var1, var2, ...}
+
global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
+pattern {var1, var2, ...}
 {set1_val1, set1_val2, ...}
 {set2_val1, set2_val2, ...}
 pattern {var2, var1, ...}
+global {gbl_var1=gbl_val3, gbl_var2=gbl_val4, ...}
 {set3_val2, set3_val1, ...}
 {set4_val2, set4_val2, ...}

This produces the same result as the regular format example above.

-

dbTemplate Format

+

dbLoadTemplate Format

This format is an extension of the format accepted by the EPICS IOC command dbLoadTemplate, and allows templates to be expanded on the host rather by using dbLoadTemplate at IOC boot time.

-
file template {
+
global {gbl_var1=gbl_val1, gbl_var2=gbl_val2, ...}
+file templatefile {
     pattern format or regular format
 }
 file "${WHERE}/template2" {
@@ -290,6 +290,11 @@ the filenames listed in the substitutions files.

ignored. A comment line is any line beginning with the character #, which must be the very first character on the line.

+

Global definitions may supplement or override the macro values supplied on +the command-line using the -M switch, and set default values that will +survive for the remainder of the file unless another global definition of the +same macro changes it.

+

For definitions within braces given in any of the file formats, a separator must be given between items. A separator is either a comma, or one or more of the standard white space characters (space, formfeed, newline, carriage return, @@ -310,11 +315,10 @@ all equivalent:

}
-

Within a substitutions file, the file name may appear inside double -quotation marks; these are only required if the name contains environment +

Within a substitutions file, the file name may appear inside double quotation +marks; these are required if the name contains certain characters or environment variable macros of the form ${ENV_VAR} or $(ENV_VAR), which will be expanded -before the file is opened. Environment variable macro expansion is only -available when msi has been built using EPICS base R3.14.3 or newer.

+before the file is opened.

Regular substitution example

@@ -334,8 +338,9 @@ family name is ${family}

and the file substitute is

-
{first=Marty,family=Kraimer}
-{first=Irma,family=Kraimer}
+
global {family=Kraimer}
+{first=Marty}
+{first=Irma}

The following is the output produced:

@@ -421,13 +426,5 @@ first name is Irma family name is Kraimer -

Building msi

- -

msi is built as a normal extensions product, and can be built with any -version of EPICS Base from 3.13.0beta11 onwards. Base version 3.14.3 or later -is required if the ability to expand environment variables in filenames is -needed. Base version 3.14.7 or later is required to allow the use of default -macro values in template files.

- From d5f050a9a2f654b96a9fc60b5d83ffd86128126a Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 31 May 2012 16:39:05 -0500 Subject: [PATCH 47/50] Support ';'-separated path lists on Windows Also renamed the '-c' option to '-g' (global scope) Updated documentation to match. --- src/dbtools/msi.c | 30 ++++++++++++++++-------------- src/dbtools/msi.html | 22 +++++++++++++++------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/dbtools/msi.c b/src/dbtools/msi.c index bdde98ff6..b2733199b 100644 --- a/src/dbtools/msi.c +++ b/src/dbtools/msi.c @@ -20,6 +20,7 @@ #include #include #include +#include #define MAX_BUFFER_SIZE 4096 @@ -62,7 +63,7 @@ int main(int argc,char **argv) char *substitutionName=0; char *templateName=0; int i; - int optScoped=1; + int localScope = 1; inputConstruct(&inputPvt); macCreateHandle(&macPvt,0); @@ -86,8 +87,8 @@ int main(int argc,char **argv) macSuppressWarning(macPvt,0); dontWarnUndef = 0; narg = 1; /* no argument for this option */ - } else if(strncmp(argv[1],"-c",2)==0) { - optScoped = 0; + } else if(strncmp(argv[1],"-g",2)==0) { + localScope = 0; narg = 1; /* no argument for this option */ } else { usageExit(); @@ -123,10 +124,10 @@ int main(int argc,char **argv) usageExit(); } while((pval = substituteGetReplacements(substitutePvt))){ - if (optScoped) macPushScope(macPvt); + if (localScope) macPushScope(macPvt); addMacroReplacements(macPvt,pval); makeSubstitutions(inputPvt,macPvt,filename); - if (optScoped) macPopScope(macPvt); + if (localScope) macPopScope(macPvt); } } } while (isGlobal || isFile); @@ -144,13 +145,13 @@ void usageExit(void) fprintf(stderr,"usage: msi [options] [template]\n"); fprintf(stderr,"stdin is used if neither template nor substitution file is given\n"); fprintf(stderr,"options:\n"); - fprintf(stderr," -V don't suppress warnings\n"); - fprintf(stderr," -o save output to \n"); - fprintf(stderr," -I add to include file search path\n"); - fprintf(stderr," -M add to (global) macro definitions\n"); - fprintf(stderr," ( is of the form VAR=VALUE,...)\n"); - fprintf(stderr," -S expand a substitution file\n"); - fprintf(stderr," -c macro definitions are scoped (in substitution files)\n"); + fprintf(stderr," -V Verbose warnings\n"); + fprintf(stderr," -g All macros have global scope\n"); + fprintf(stderr," -o Save output to \n"); + fprintf(stderr," -I Add to include file search path\n"); + fprintf(stderr," -M Add to (global) macro definitions\n"); + fprintf(stderr," ( takes the form VAR=VALUE,...)\n"); + fprintf(stderr," -S Expand the substitutions in FILE\n"); exit(1); } @@ -310,16 +311,17 @@ static void inputAddPath(inputData *pinputData, char *path) const char *pdir; int len; int emptyName; + const char sep = *OSI_PATH_LIST_SEPARATOR; pdir = path; /*an empty name at beginning, middle, or end means current directory*/ while(pdir && *pdir) { - emptyName = ((*pdir == ':') ? 1 : 0); + emptyName = ((*pdir == sep) ? 1 : 0); if(emptyName) ++pdir; ppathNode = (pathNode *)calloc(1,sizeof(pathNode)); ellAdd(ppathList,&ppathNode->node); if(!emptyName) { - pcolon = strchr(pdir,':'); + pcolon = strchr(pdir,sep); len = (pcolon ? (pcolon - pdir) : strlen(pdir)); if(len>0) { ppathNode->directory = (char *)calloc(len+1,sizeof(char)); diff --git a/src/dbtools/msi.html b/src/dbtools/msi.html index 0be7bef5f..b7e4e9e9e 100644 --- a/src/dbtools/msi.html +++ b/src/dbtools/msi.html @@ -24,7 +24,7 @@ accepted by the EPICS IOC's dbLoadTemplate command.

Command Syntax:

-
msi -V -ooutfile -Idir -Msubs -Ssubfile template
+
msi -V -g -ooutfile -Idir -Msubs -Ssubfile template

All parameters are optional. The -o, -I, -M, and -S switches may be separated from their associated value string by spaces if desired. Output will @@ -34,18 +34,26 @@ be written to stdout unless the -o option is given.

-V
-
If this parameter is specified then any undefined macro discovered in - the template file which does not have an associated default value is - considered an error. An error message is generated and when msi terminates - it will do so with an exit status of 2.
+
Verbose warnings; if this parameter is specified then any undefined + macro discovered in the template file which does not have an associated + default value is considered an error. An error message is generated, and + when msi terminates it will do so with an exit status of 2.
+ +
-g
+
When this flag is given all macros defined in a substitution file will + have global scope and thus their values will persist until a new value is + given for this macro. This flag is provided for backwards compatibility as + this was the behavior of previous versions of msi, but it does not follow + common scoping rules and is discouraged.
-o file
Output will be written to the specifed file rather than to the standard output.
-I dir
-
This parameter, which may be repeated, specifies a search path for - include commands. For example: +
This parameter, which may be repeated or contain a colon-separated (or + semi-colon separated on Windows) list of directory paths, specifies a search + path for include commands. For example:
msi -I /home/mrk/examples:. -I.. template
From efec22eea595d9233e55981af40168aee0416ec4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Jun 2012 14:03:53 -0500 Subject: [PATCH 48/50] Add automated tests for msi. --- src/dbtools/test/Makefile | 6 +-- src/dbtools/test/msi.plt | 42 +++++++++++++++++++ src/dbtools/test/pattern | 9 ---- src/dbtools/test/s1.sub | 20 --------- src/dbtools/test/substitute | 5 --- .../test/{include-file => t1-include.txt} | 4 +- src/dbtools/test/t1-result.txt | 21 ++++++++++ src/dbtools/test/t1-template.txt | 14 +++++++ src/dbtools/test/t2-result.txt | 6 +++ src/dbtools/test/t2-substitution.txt | 11 +++++ src/dbtools/test/{t1.txt => t2-template.txt} | 0 src/dbtools/test/t3-result.txt | 28 +++++++++++++ src/dbtools/test/t3-substitution.txt | 37 ++++++++++++++++ src/dbtools/test/t3-template.txt | 1 + src/dbtools/test/t4-result.txt | 6 +++ src/dbtools/test/t4-substitution.txt | 11 +++++ src/dbtools/test/t5-result.txt | 20 +++++++++ src/dbtools/test/t5-substitute.txt | 9 ++++ src/dbtools/test/t5-template.txt | 5 +++ src/dbtools/test/t6-result.txt | 20 +++++++++ src/dbtools/test/t6-substitute.txt | 13 ++++++ src/dbtools/test/t6-template.txt | 5 +++ src/dbtools/test/template | 7 ++-- src/dbtools/test/test-file | 14 ------- 24 files changed, 256 insertions(+), 58 deletions(-) create mode 100644 src/dbtools/test/msi.plt delete mode 100644 src/dbtools/test/pattern delete mode 100644 src/dbtools/test/s1.sub delete mode 100644 src/dbtools/test/substitute rename src/dbtools/test/{include-file => t1-include.txt} (66%) create mode 100644 src/dbtools/test/t1-result.txt create mode 100644 src/dbtools/test/t1-template.txt create mode 100644 src/dbtools/test/t2-result.txt create mode 100644 src/dbtools/test/t2-substitution.txt rename src/dbtools/test/{t1.txt => t2-template.txt} (100%) create mode 100644 src/dbtools/test/t3-result.txt create mode 100644 src/dbtools/test/t3-substitution.txt create mode 100644 src/dbtools/test/t3-template.txt create mode 100644 src/dbtools/test/t4-result.txt create mode 100644 src/dbtools/test/t4-substitution.txt create mode 100644 src/dbtools/test/t5-result.txt create mode 100644 src/dbtools/test/t5-substitute.txt create mode 100644 src/dbtools/test/t5-template.txt create mode 100644 src/dbtools/test/t6-result.txt create mode 100644 src/dbtools/test/t6-substitute.txt create mode 100644 src/dbtools/test/t6-template.txt delete mode 100644 src/dbtools/test/test-file diff --git a/src/dbtools/test/Makefile b/src/dbtools/test/Makefile index 58acbd355..c7030b1e6 100644 --- a/src/dbtools/test/Makefile +++ b/src/dbtools/test/Makefile @@ -12,11 +12,7 @@ TESTPROD_HOST += dbltExpand dbltExpand_SRCS += dbltExpand.c dbltExpand_LIBS += dbtoolsIoc dbStaticHost Com - -#TESTPROD_HOST += callbackTest -#callbackTest_SRCS += callbackTest.c -#TESTS += callbackTest - +TESTS += msi TESTSCRIPTS_HOST += $(TESTS:%=%.t) diff --git a/src/dbtools/test/msi.plt b/src/dbtools/test/msi.plt new file mode 100644 index 000000000..7671e903d --- /dev/null +++ b/src/dbtools/test/msi.plt @@ -0,0 +1,42 @@ +#!/usr/bin/perl +#************************************************************************* +# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne +# National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +# Script to run tests on the msi program + +use FindBin qw($Bin); # To find the msi executable + +use strict; +use Test; + +BEGIN {plan tests => 6} + +ok(msi('-I.. ../t1-template.txt'), slurp('../t1-result.txt')); +ok(msi('-I.. -S ../t2-substitution.txt'), slurp('../t2-result.txt')); +ok(msi('-I.. -S ../t3-substitution.txt'), slurp('../t3-result.txt')); +ok(msi('-g -I.. -S ../t4-substitution.txt'),slurp('../t4-result.txt')); +ok(msi('-S ../t5-substitute.txt ../t5-template.txt'), slurp('../t5-result.txt')); +ok(msi('-S ../t6-substitute.txt ../t6-template.txt'), slurp('../t6-result.txt')); + + +# Support routines + +sub slurp { + my ($file) = @_; + open my $in, '<', $file + or die "Can't open file $file: $!\n"; + my $contents = do { local $/; <$in> }; + return $contents; +} + +sub msi { + my ($args) = @_; + my $arch = $ENV{EPICS_HOST_ARCH}; + my $exe = ($^O eq 'MSWin32') || ($^O eq 'cygwin') ? '.exe' : ''; + my $msi = "$Bin/../../O.$arch/msi$exe"; + return `$msi $args`; +} diff --git a/src/dbtools/test/pattern b/src/dbtools/test/pattern deleted file mode 100644 index e847f7d9f..000000000 --- a/src/dbtools/test/pattern +++ /dev/null @@ -1,9 +0,0 @@ -#test of a pattern - pattern {a,b} -{xxx,"yyy"} - {zzz , ttt} - -{ - vvv - zzz -} diff --git a/src/dbtools/test/s1.sub b/src/dbtools/test/s1.sub deleted file mode 100644 index 3046b1923..000000000 --- a/src/dbtools/test/s1.sub +++ /dev/null @@ -1,20 +0,0 @@ -global {a=gbl-a, b=gbl-b} -file t1.txt { - pattern {a, b, c} - {} - {pat-a} - {pat-a, pat-b} - {pat-a, pat-b, pat-c} - {pat-a, pat-b} - {pat-a} - {} -} -file t1.txt { - {} - {a=val-a} - {a=val-a, b=val-b} - {a=val-a, b=val-b, c=val-c} - {a=val-a, b=val-b} - {a=val-a} - {} -} diff --git a/src/dbtools/test/substitute b/src/dbtools/test/substitute deleted file mode 100644 index 22c98bb0e..000000000 --- a/src/dbtools/test/substitute +++ /dev/null @@ -1,5 +0,0 @@ -{a=111,b="222"} -{ a = aaa , b=bbb} -{a= aaa -b= bbb -} diff --git a/src/dbtools/test/include-file b/src/dbtools/test/t1-include.txt similarity index 66% rename from src/dbtools/test/include-file rename to src/dbtools/test/t1-include.txt index 718635415..9793c73bd 100644 --- a/src/dbtools/test/include-file +++ b/src/dbtools/test/t1-include.txt @@ -1,5 +1,5 @@ -This is include-file $(include-file-again=) +This is t1-include.txt $(include-file-again=) a = $(a=default value used when a is undefined) b = $(b=default value used when b is undefined) substitute "include-file-again=again" -End of include-file. +End of t1-include.txt diff --git a/src/dbtools/test/t1-result.txt b/src/dbtools/test/t1-result.txt new file mode 100644 index 000000000..fcd065585 --- /dev/null +++ b/src/dbtools/test/t1-result.txt @@ -0,0 +1,21 @@ +This is t1-template.txt + +With $(a,undefined) & $(b,undefined): +This is t1-include.txt + a = default value used when a is undefined + b = default value used when b is undefined +End of t1-include.txt + +On defining a=aaa & b=bbb: +This is t1-include.txt again + a = aaa + b = bbb +End of t1-include.txt + +On setting a="aa": +This is t1-include.txt again + a = "aa" + b = bbb +End of t1-include.txt + +End of t1-template.txt diff --git a/src/dbtools/test/t1-template.txt b/src/dbtools/test/t1-template.txt new file mode 100644 index 000000000..9ef49e8fe --- /dev/null +++ b/src/dbtools/test/t1-template.txt @@ -0,0 +1,14 @@ +This is t1-template.txt + +With $(a) & ${b}: +include "t1-include.txt" + +substitute "a=aaa,b=bbb" +On defining a=$(a) & b=${b}: +include "t1-include.txt" + +substitute "a=\"aa\"" +On setting a=$(a): +include "t1-include.txt" + +End of t1-template.txt diff --git a/src/dbtools/test/t2-result.txt b/src/dbtools/test/t2-result.txt new file mode 100644 index 000000000..5239e6a05 --- /dev/null +++ b/src/dbtools/test/t2-result.txt @@ -0,0 +1,6 @@ +a = va1-a b = def-b c = def-c d = $(d,undefined) +a = va2-a b = va2-b c = def-c d = $(d,undefined) +a = va3-a b = va3-b c = va3-c d = $(d,undefined) +a = va4-a b = va4-b c = def-c d = $(d,undefined) +a = va5-a b = def-b c = def-c d = $(d,undefined) +a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined) diff --git a/src/dbtools/test/t2-substitution.txt b/src/dbtools/test/t2-substitution.txt new file mode 100644 index 000000000..a3f3d6874 --- /dev/null +++ b/src/dbtools/test/t2-substitution.txt @@ -0,0 +1,11 @@ +file t2-template.txt { + {a=va1-a} + {a=va2-a, b=va2-b} + {a=va3-a, b=va3-b, c=va3-c} + {a=va4-a, b=va4-b} + {a=va5-a} +} +file t2-template.txt { + pattern {a, b, c} + {pt3-a, pt3-b, pt3-c} +} diff --git a/src/dbtools/test/t1.txt b/src/dbtools/test/t2-template.txt similarity index 100% rename from src/dbtools/test/t1.txt rename to src/dbtools/test/t2-template.txt diff --git a/src/dbtools/test/t3-result.txt b/src/dbtools/test/t3-result.txt new file mode 100644 index 000000000..c6961507f --- /dev/null +++ b/src/dbtools/test/t3-result.txt @@ -0,0 +1,28 @@ +a = gb1-a b = gb1-b c = def-c d = $(d,undefined) +a = va1-a b = gb1-b c = def-c d = $(d,undefined) +a = va2-a b = va2-b c = def-c d = $(d,undefined) +a = va3-a b = va3-b c = va3-c d = $(d,undefined) +a = va4-a b = va4-b c = def-c d = $(d,undefined) +a = va5-a b = gb1-b c = def-c d = $(d,undefined) +a = gb1-a b = gb1-b c = def-c d = $(d,undefined) +a = gb2-a b = gb2-b c = def-c d = $(d,undefined) +a = va1-a b = gb2-b c = def-c d = $(d,undefined) +a = va2-a b = va2-b c = def-c d = $(d,undefined) +a = va3-a b = va3-b c = va3-c d = $(d,undefined) +a = va4-a b = va4-b c = def-c d = $(d,undefined) +a = va5-a b = gb2-b c = def-c d = $(d,undefined) +a = gb2-a b = gb2-b c = def-c d = $(d,undefined) +a = gb3-a b = gb3-b c = def-c d = $(d,undefined) +a = pt1-a b = gb3-b c = def-c d = $(d,undefined) +a = pt2-a b = pt2-b c = def-c d = $(d,undefined) +a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined) +a = pt4-a b = pt4-b c = def-c d = $(d,undefined) +a = pt5-a b = gb3-b c = def-c d = $(d,undefined) +a = gb3-a b = gb3-b c = def-c d = $(d,undefined) +a = gb4-a b = gb4-b c = def-c d = $(d,undefined) +a = pt1-a b = gb4-b c = def-c d = $(d,undefined) +a = pt2-a b = pt2-b c = def-c d = $(d,undefined) +a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined) +a = pt4-a b = pt4-b c = def-c d = $(d,undefined) +a = pt5-a b = gb4-b c = def-c d = $(d,undefined) +a = gb4-a b = gb4-b c = def-c d = $(d,undefined) diff --git a/src/dbtools/test/t3-substitution.txt b/src/dbtools/test/t3-substitution.txt new file mode 100644 index 000000000..30b0741d3 --- /dev/null +++ b/src/dbtools/test/t3-substitution.txt @@ -0,0 +1,37 @@ +global {a=gb1-a, b=gb1-b} +file t3-template.txt { + {} + {a=va1-a} + {a=va2-a, b=va2-b} + {a=va3-a, b=va3-b, c=va3-c} + {a=va4-a, b=va4-b} + {a=va5-a} + {} + global {a=gb2-a, b=gb2-b} + {} + {a=va1-a} + {a=va2-a, b=va2-b} + {a=va3-a, b=va3-b, c=va3-c} + {a=va4-a, b=va4-b} + {a=va5-a} + {} +} +global {b=gb3-b, a=gb3-a} +file t3-template.txt { + pattern {a, b, c} + {} + {pt1-a} + {pt2-a, pt2-b} + {pt3-a, pt3-b, pt3-c} + {pt4-a, pt4-b} + {pt5-a} + {} + global {b=gb4-b, a=gb4-a} + {} + {pt1-a} + {pt2-a, pt2-b} + {pt3-a, pt3-b, pt3-c} + {pt4-a, pt4-b} + {pt5-a} + {} +} diff --git a/src/dbtools/test/t3-template.txt b/src/dbtools/test/t3-template.txt new file mode 100644 index 000000000..c4ac7b427 --- /dev/null +++ b/src/dbtools/test/t3-template.txt @@ -0,0 +1 @@ +a = $(a=def-a) b = $(b=def-b) c = $(c=def-c) d = $(d,undef) diff --git a/src/dbtools/test/t4-result.txt b/src/dbtools/test/t4-result.txt new file mode 100644 index 000000000..664872013 --- /dev/null +++ b/src/dbtools/test/t4-result.txt @@ -0,0 +1,6 @@ +a = va1-a b = def-b c = def-c d = $(d,undefined) +a = va2-a b = va2-b c = def-c d = $(d,undefined) +a = va3-a b = va3-b c = va3-c d = $(d,undefined) +a = va4-a b = va4-b c = va3-c d = $(d,undefined) +a = va5-a b = va4-b c = va3-c d = $(d,undefined) +a = pt3-a b = pt3-b c = pt3-c d = $(d,undefined) diff --git a/src/dbtools/test/t4-substitution.txt b/src/dbtools/test/t4-substitution.txt new file mode 100644 index 000000000..a3f3d6874 --- /dev/null +++ b/src/dbtools/test/t4-substitution.txt @@ -0,0 +1,11 @@ +file t2-template.txt { + {a=va1-a} + {a=va2-a, b=va2-b} + {a=va3-a, b=va3-b, c=va3-c} + {a=va4-a, b=va4-b} + {a=va5-a} +} +file t2-template.txt { + pattern {a, b, c} + {pt3-a, pt3-b, pt3-c} +} diff --git a/src/dbtools/test/t5-result.txt b/src/dbtools/test/t5-result.txt new file mode 100644 index 000000000..19a57c87c --- /dev/null +++ b/src/dbtools/test/t5-result.txt @@ -0,0 +1,20 @@ +# comment line +a = 111 +b = 222 +c = xx +d = $(d,undefined) +# comment line +a = aaa +b = bbb +c = ccc +d = $(d,undefined) +# comment line +a = AA +b = BB +c = xx +d = $(d,undefined) +# comment line +a = aaa +b = bbb +c = yy +d = $(d,undefined) diff --git a/src/dbtools/test/t5-substitute.txt b/src/dbtools/test/t5-substitute.txt new file mode 100644 index 000000000..6b6ca985d --- /dev/null +++ b/src/dbtools/test/t5-substitute.txt @@ -0,0 +1,9 @@ +global {c=xx} +{a=111,b="222"} +{ a = aaa , b=bbb , c = ccc} +{a=AA,b='BB'} +global { c = yy } +{ + a= aaa + b= bbb +} diff --git a/src/dbtools/test/t5-template.txt b/src/dbtools/test/t5-template.txt new file mode 100644 index 000000000..561b52a0a --- /dev/null +++ b/src/dbtools/test/t5-template.txt @@ -0,0 +1,5 @@ +# comment line +a = $(a) +b = $(b) +c = $(c) +d = $(d) diff --git a/src/dbtools/test/t6-result.txt b/src/dbtools/test/t6-result.txt new file mode 100644 index 000000000..19a57c87c --- /dev/null +++ b/src/dbtools/test/t6-result.txt @@ -0,0 +1,20 @@ +# comment line +a = 111 +b = 222 +c = xx +d = $(d,undefined) +# comment line +a = aaa +b = bbb +c = ccc +d = $(d,undefined) +# comment line +a = AA +b = BB +c = xx +d = $(d,undefined) +# comment line +a = aaa +b = bbb +c = yy +d = $(d,undefined) diff --git a/src/dbtools/test/t6-substitute.txt b/src/dbtools/test/t6-substitute.txt new file mode 100644 index 000000000..7d80824fd --- /dev/null +++ b/src/dbtools/test/t6-substitute.txt @@ -0,0 +1,13 @@ +global {c=xx} +pattern {b,a} +{"222",111} +pattern {a b c} +{ aaa , bbb , ccc} +pattern { a , b } +{AA,'BB'} +global { c = yy } +pattern { a , b } +{ + aaa + bbb +} diff --git a/src/dbtools/test/t6-template.txt b/src/dbtools/test/t6-template.txt new file mode 100644 index 000000000..561b52a0a --- /dev/null +++ b/src/dbtools/test/t6-template.txt @@ -0,0 +1,5 @@ +# comment line +a = $(a) +b = $(b) +c = $(c) +d = $(d) diff --git a/src/dbtools/test/template b/src/dbtools/test/template index 38ced3cb2..561b52a0a 100644 --- a/src/dbtools/test/template +++ b/src/dbtools/test/template @@ -1,4 +1,5 @@ # comment line -$(a) -this is a test $(b) -$(d) +a = $(a) +b = $(b) +c = $(c) +d = $(d) diff --git a/src/dbtools/test/test-file b/src/dbtools/test/test-file deleted file mode 100644 index 6da35ffe9..000000000 --- a/src/dbtools/test/test-file +++ /dev/null @@ -1,14 +0,0 @@ -This is test-file - -With $(a) & ${b}: -include "include-file" - -substitute "a=aaa,b=bbb" -On defining a=$(a) & b=${b}: -include "include-file" - -substitute "a=\"aa\"" -On setting a=$(a): -include "include-file" - -End of test-file. From 37a9efa2901e8ac47089ac8766217e1677a0e232 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Jun 2012 14:16:13 -0500 Subject: [PATCH 49/50] Added test for msi -o option. --- src/dbtools/test/msi.plt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/dbtools/test/msi.plt b/src/dbtools/test/msi.plt index 7671e903d..f15a0b90c 100644 --- a/src/dbtools/test/msi.plt +++ b/src/dbtools/test/msi.plt @@ -13,15 +13,21 @@ use FindBin qw($Bin); # To find the msi executable use strict; use Test; -BEGIN {plan tests => 6} +BEGIN {plan tests => 7} -ok(msi('-I.. ../t1-template.txt'), slurp('../t1-result.txt')); -ok(msi('-I.. -S ../t2-substitution.txt'), slurp('../t2-result.txt')); -ok(msi('-I.. -S ../t3-substitution.txt'), slurp('../t3-result.txt')); -ok(msi('-g -I.. -S ../t4-substitution.txt'),slurp('../t4-result.txt')); +ok(msi('-I .. ../t1-template.txt'), slurp('../t1-result.txt')); +ok(msi('-I.. -S ../t2-substitution.txt'), slurp('../t2-result.txt')); +ok(msi('-I. -I.. -S ../t3-substitution.txt'), slurp('../t3-result.txt')); +ok(msi('-g -I.. -S ../t4-substitution.txt'), slurp('../t4-result.txt')); ok(msi('-S ../t5-substitute.txt ../t5-template.txt'), slurp('../t5-result.txt')); ok(msi('-S ../t6-substitute.txt ../t6-template.txt'), slurp('../t6-result.txt')); +# Check -o works +my $out = 't7-output.txt'; +unlink $out; +msi("-I.. -o $out ../t1-template.txt"); +ok(slurp($out), slurp('../t1-result.txt')); + # Support routines From e458e8fe2d720dbb8bbab0e9f585f49d2031d6e0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Jun 2012 14:33:55 -0500 Subject: [PATCH 50/50] Don't try to build dbltExpand on Win32. --- src/dbtools/test/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dbtools/test/Makefile b/src/dbtools/test/Makefile index c7030b1e6..10efb14d9 100644 --- a/src/dbtools/test/Makefile +++ b/src/dbtools/test/Makefile @@ -8,7 +8,8 @@ TOP=../../.. include $(TOP)/configure/CONFIG -TESTPROD_HOST += dbltExpand +TESTPROD_HOST_DEFAULT = dbltExpand +TESTPROD_HOST_WIN32 = -nil- dbltExpand_SRCS += dbltExpand.c dbltExpand_LIBS += dbtoolsIoc dbStaticHost Com