Files
ci-scripts/add-msi-to-314.patch
Michael Davidsaver 27a1224d6d Refresh MSI 3.14 patch to allow using it
- set MSI to $EPICS_BASE_BIN/msi
- make patch file more symmetrical (patch with -p1)
- closes #20 (again), closes #36
2020-04-30 09:19:03 +02:00

852 lines
24 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
diff --git a/config/RULES.Db b/config/RULES.Db
index b4946c7aa..90b76ed08 100644
--- a/config/RULES.Db
+++ b/config/RULES.Db
@@ -12,11 +12,7 @@
#
MAKEBPT = $(EPICS_BASE_HOST_BIN)/makeBpt$(EXE)
-ifndef MSI
-# Tool from R3.14 extensions bin, R3.13 extensions bin, or user path
-MSI = $(firstword $(wildcard $(EPICS_EXTENSIONS_HOST_BIN)/msi$(HOSTEXE) \
- $(EPICS_EXTENSIONS)/bin/$(HOST_ARCH)/msi$(HOSTEXE)) msi$(HOSTEXE))
-endif
+MSI = $(EPICS_BASE_HOST_BIN)/msi$(HOSTEXE)
DBEXPAND = $(EPICS_BASE_HOST_BIN)/dbExpand$(EXE)
DBST = dbst
diff --git a/configure/CONFIG_BASE b/configure/CONFIG_BASE
index 7ee5a5b89..9a9793093 100644
--- a/configure/CONFIG_BASE
+++ b/configure/CONFIG_BASE
@@ -112,8 +112,5 @@ ifndef DBST
DBST = dbst
endif
-ifndef MSI
-MSI = msi
-endif
-
+MSI = $(EPICS_BASE_HOST_BIN)/msi$(HOSTEXE)
diff --git a/src/dbtools/Makefile b/src/dbtools/Makefile
index 38ed52c9e..8655a5337 100644
--- a/src/dbtools/Makefile
+++ b/src/dbtools/Makefile
@@ -11,6 +11,11 @@ TOP=../..
include $(TOP)/configure/CONFIG
+PROD_HOST += msi
+
+msi_SRCS = msi.c
+msi_LIBS += Com
+
INC += dbLoadTemplate.h
INC += dbtoolsIocRegister.h
diff --git a/src/dbtools/msi.c b/src/dbtools/msi.c
new file mode 100644
index 000000000..525d4f25b
--- /dev/null
+++ b/src/dbtools/msi.c
@@ -0,0 +1,798 @@
+/*************************************************************************\
+* 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 */
+
+/*
+ * Modification Log:
+ * -----------------
+ * .01 08DEC97 mrk Original version
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <epicsVersion.h>
+#include <dbDefs.h>
+#include <macLib.h>
+#include <ellLib.h>
+#include <errlog.h>
+
+#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);
+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 char *substituteGetReplacements(void *substitutePvt);
+
+/*Exit status*/
+static int exitStatus = 0;
+
+int opt_V = 0;
+
+
+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,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);
+ }
+ } 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; i<argc; i++) argv[i] = argv[i + narg];
+ }
+ if(argc>2) {
+ fprintf(stderr,"too many filename arguments\n");
+ usageExit();
+ }
+ if(argc==2) {
+ templateName = calloc(strlen(argv[1])+1,sizeof(char));
+ strcpy(templateName,argv[1]);
+ }
+ if(!substitutionName) {
+ makeSubstitutions(inputPvt,macPvt,templateName);
+ } else {
+ void *substitutePvt;
+ char *filename = 0;
+
+ substituteOpen(&substitutePvt,substitutionName);
+ while(substituteGetNextSet(substitutePvt,&filename)) {
+ if(templateName) filename = templateName;
+ if(!filename) {
+ fprintf(stderr,"no template file\n");
+ usageExit();
+ }
+ macPushScope(macPvt);
+ while((pval = substituteGetReplacements(substitutePvt))){
+ addMacroReplacements(macPvt,pval);
+ makeSubstitutions(inputPvt,macPvt,filename);
+ }
+ macPopScope(macPvt);
+ }
+ substituteDestruct(substitutePvt);
+ }
+ errlogFlush();
+ inputDestruct(inputPvt);
+ free((void *)templateName);
+ free((void *)substitutionName);
+ return(exitStatus);
+}
+
+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");
+ 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);
+}
+
+typedef enum {cmdInclude,cmdSubstitute} cmdType;
+static const char *cmdNames[] = {"include","substitute"};
+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;
+
+ 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;
+ }
+endif:
+ if (expand) {
+ n = macExpandString(macPvt,input,buffer,MAX_BUFFER_SIZE-1);
+ fputs(buffer,stdout);
+ if (!unexpWarned && n<0) {
+ const char * pErrMsg = "Warning: Undefined macros present, use msi -V to list\n";
+ if ( opt_V ) {
+ exitStatus = 2;
+ pErrMsg = "Error: Undefined macros present\n";
+ }
+ fprintf( stderr, pErrMsg );
+ unexpWarned++;
+ }
+ }
+ }
+}
+
+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 void 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;
+ 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,".");
+ }
+ }
+ return;
+}
+
+static void inputBegin(void *pvt,char *fileName)
+{
+ inputData *pinputData = (inputData *)pvt;
+
+ 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 void inputOpenFile(inputData *pinputData,char *filename)
+{
+ ELLLIST *ppathList = &pinputData->pathList;
+ pathNode *ppathNode = 0;
+ inputFile *pinputFile;
+ char *fullname = 0;
+ 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);
+ 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);
+ } 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);
+}
+
+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 {
+ 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;
+}patternNode;
+
+typedef struct subInfo {
+ subFile *psubFile;
+ int isFile;
+ char *filename;
+ int isPattern;
+ ELLLIST patternList;
+ size_t size;
+ size_t curLength;
+ char *macroReplacements;
+}subInfo;
+
+static char *subGetNextLine(subFile *psubFile);
+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)
+{
+ 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;
+}
+
+void freePattern(subInfo *psubInfo)
+{
+ patternNode *ppatternNode;
+ while((ppatternNode = (patternNode *)ellFirst(&psubInfo->patternList))) {
+ ellDelete(&psubInfo->patternList,&ppatternNode->node);
+ free(ppatternNode->var);
+ free(ppatternNode);
+ }
+ psubInfo->isPattern = 0;
+}
+
+static void substituteDestruct(void *pvt)
+{
+ subInfo *psubInfo = (subInfo *)pvt;
+
+ freeSubFile(psubInfo);
+ freePattern(psubInfo);
+ free((void *)psubInfo);
+ return;
+}
+
+static void substituteOpen(void **ppvt,char *substitutionName)
+{
+ subInfo *psubInfo;
+ subFile *psubFile;
+ FILE *fp;
+
+ 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);
+ }
+ psubFile->substitutionName = substitutionName;
+ psubFile->fp = fp;
+ psubFile->lineNum = 0;
+ psubFile->inputBuffer[0] = 0;
+ psubFile->pnextChar = &psubFile->inputBuffer[0];
+ subGetNextToken(psubFile);
+ return;
+}
+
+static int substituteGetNextSet(void *pvt,char **filename)
+{
+ subInfo *psubInfo = (subInfo *)pvt;
+ subFile *psubFile = psubInfo->psubFile;
+ patternNode *ppatternNode;
+
+ *filename = 0;
+ while(psubFile->token==tokenSeparater) subGetNextToken(psubFile);
+ if(psubFile->token==tokenEOF) return(0);
+ if(psubFile->token==tokenString && strcmp(psubFile->string,"file")==0) {
+ psubInfo->isFile = 1;
+ if(subGetNextToken(psubFile)!=tokenString) {
+ subFileErrPrint(psubFile,"Expecting filename");
+ exit(1);
+ }
+ freePattern(psubInfo);
+ free((void *)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);
+ }
+ else {
+ psubInfo->filename = macEnvExpand(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(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 = 1;
+ while(subGetNextToken(psubFile)==tokenSeparater);
+ if(psubFile->token!=tokenLBrace) {
+ subFileErrPrint(psubFile,"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!=tokenRBrace) {
+ subFileErrPrint(psubFile,"Expecting }");
+ exit(1);
+ }
+ subGetNextToken(psubFile);
+ return(1);
+}
+
+static char *substituteGetReplacements(void *pvt)
+{
+ subInfo *psubInfo = (subInfo *)pvt;
+ subFile *psubFile = psubInfo->psubFile;
+ patternNode *ppatternNode;
+
+ 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((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 = 0;
+
+ while(subGetNextToken(psubFile)==tokenSeparater);
+ 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");
+ exit(-1);
+ }
+ if(gotFirstPattern) catMacroReplacements(psubInfo,",");
+ gotFirstPattern = 1;
+ if(ppatternNode) {
+ catMacroReplacements(psubInfo,ppatternNode->var);
+ catMacroReplacements(psubInfo,"=");
+ catMacroReplacements(psubInfo,psubFile->string);
+ ppatternNode = (patternNode *)ellNext(&ppatternNode->node);
+ } else {
+ subFileErrPrint(psubFile,"more values than patterns");
+ }
+ while(subGetNextToken(psubFile)==tokenSeparater);
+ }
+ } else while(1) {
+ switch(subGetNextToken(psubFile)) {
+ case tokenRBrace:
+ subGetNextToken(psubFile);
+ return(psubInfo->macroReplacements);
+ case tokenSeparater:
+ catMacroReplacements(psubInfo,",");
+ break;
+ case tokenString:
+ catMacroReplacements(psubInfo,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);
+ ++psubFile->lineNum;
+ 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;
+ psubFile->pnextChar = 0;
+ return(0);
+ }
+ psubFile->pnextChar = &psubFile->inputBuffer[0];
+ return(&psubFile->inputBuffer[0]);
+}
+
+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);
+}
+
+
+static tokenType subGetNextToken(subFile *psubFile)
+{
+ 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);}
+ else { psubFile->token = tokenSeparater; return(tokenSeparater);}
+ }
+ while(isspace(*p)) p++;
+ if(*p=='{') {
+ psubFile->token = tokenLBrace;
+ psubFile->pnextChar = ++p;
+ return(tokenLBrace);
+ }
+ if(*p=='}') {
+ 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);
+ }
+ /*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);
+ }
+ /*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;
+ psubFile->pnextChar = p;
+ 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 %Zu\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;
+}