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