EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: [Merge] lp:~ralph-lange/epics-base/msi-join into lp:epics-base
From: Ralph Lange <[email protected]>
To: [email protected]
Date: Mon, 23 Aug 2010 19:50:55 -0000
Ralph Lange has proposed merging lp:~ralph-lange/epics-base/msi-join into lp:epics-base.

Requested reviews:
  EPICS Core Developers (epics-core)


Andrew converted the extensions msi CVS repo into a Bazaar repo, I included it in base/src/dbtools.

This branch builds msi as part of dbtools and - in CONFIG_BASE - points MSI to it as a default.

I moved the files that obviously are intended for testing into a test subdir, but I have no idea what tests should be run with them.

I tested that msi basically works with a slightly modified example app.

It still is msi as converted from extensions CVS - none of the recently suggested changes have been applied yet, as I thought that should better be done under Bazaar.

Remaining issues:
Should host-side blow up be included in the example app?
What about the documentation? The App-Dev-Guide? Is that still officially a Frame document?

-- 
https://code.launchpad.net/~ralph-lange/epics-base/msi-join/+merge/33439
Your team EPICS Core Developers is requested to review the proposed merge of lp:~ralph-lange/epics-base/msi-join into lp:epics-base.
=== modified file 'configure/CONFIG_BASE'
--- configure/CONFIG_BASE	2008-08-29 21:07:04 +0000
+++ configure/CONFIG_BASE	2010-08-23 19:50:55 +0000
@@ -110,7 +110,7 @@
 endif
 
 ifndef MSI
-MSI = msi
+MSI = $(EPICS_BASE_HOST_BIN)/msi
 endif
 
 

=== modified file 'src/dbtools/Makefile'
--- src/dbtools/Makefile	2009-03-11 19:11:21 +0000
+++ src/dbtools/Makefile	2010-08-23 19:50:55 +0000
@@ -14,17 +14,20 @@
 INC += dbLoadTemplate.h
 INC += dbtoolsIocRegister.h
 
+LIBRARY_IOC = dbtoolsIoc
+
 LIB_SRCS += dbLoadTemplate.c
 LIB_SRCS += dbtoolsIocRegister.c
-
-LIBRARY_IOC = dbtoolsIoc
-
 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

=== added file 'src/dbtools/msi.c'
--- src/dbtools/msi.c	1970-01-01 00:00:00 +0000
+++ src/dbtools/msi.c	2010-08-23 19:50:55 +0000
@@ -0,0 +1,792 @@
+/*************************************************************************\
+* 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>
+
+#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);
+    }
+    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) {
+		fprintf(stderr, "Warning: Undefined macros present%s\n",
+			opt_V ? "" : ", use  msi -V  to list");
+		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;
+}

=== added file 'src/dbtools/msi.html'
--- src/dbtools/msi.html	1970-01-01 00:00:00 +0000
+++ src/dbtools/msi.html	2010-08-23 19:50:55 +0000
@@ -0,0 +1,433 @@
+<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+  <title></title>
+  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+</head>
+
+<body>
+
+<h1>msi: Macro Substitution and Include Tool</h1>
+
+<blockquote>
+<p>Version 1.5, 10th November, 2008</p>
+</blockquote>
+
+<h2>Introduction</h2>
+
+<p>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: <tt>include</tt> and <tt>substitute</tt>. 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.</p>
+
+<p>msi also allows substitutions to be specified via a separate substitution
+file. This substitution file allows the same format as the substitution files
+accepted by the EPICS IOC's dbLoadTemplate command.</p>
+
+<h2>Command Syntax:</h2>
+
+<pre>msi -V -o<i>outfile</i> -I<i>dir</i> -M<i>subs</i> -S<i>subfile</i> <i>template</i></pre>
+
+<p>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.</p>
+
+<p>Switches have the following meanings:</p>
+
+<dl>
+  <dt><tt>-V</tt></dt>
+    <dd>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.</dd>
+
+  <dt><tt>-o</tt> <i>file</i></dt>
+    <dd>Output will be written to the specifed file rather than to the standard
+    output.</dd>
+
+  <dt><tt>-I</tt> <i>dir</i></dt>
+    <dd>This parameter, which may be repeated, specifies a search path for
+    include commands. For example:
+
+    <blockquote>
+    <pre>msi -I /home/mrk/examples:. -I.. template</pre>
+    </blockquote>
+
+    specifies that all named files should be searched for in the following
+    locations in the order given:
+
+    <ol>
+      <li><tt>/home/mrk/examples</tt></li>
+      <li><tt>.</tt> (the current directory)</li>
+      <li><tt>..</tt> (the parent of the current directory)</li>
+    </ol>
+  </dd>
+
+  <dt><tt>-M</tt> <i>substitutions</i></dt>
+    <dd>This parameter specifies macro values for the template instance.
+    Multiple macro values can be specified in one substitution parameter, or in
+    multiple <tt>-M</tt> parameters. For example:
+
+    <blockquote>
+    <pre>msi -M "a=aval,b=bval" -Mc=cval template</pre>
+    </blockquote>
+
+    specifies that in the template file each occurrence of:
+
+    <dl>
+      <dd><tt>$(a)</tt> or <tt>${a}</tt> is replaced by <tt>aval</tt></dd>
+      <dd><tt>$(b)</tt> or <tt>${b}</tt> is replaced by <tt>bval</tt></dd>
+      <dd><tt>$(c)</tt> or <tt>${c}</tt> is replaced by <tt>cval</tt></dd>
+    </dl>
+  </dd>
+
+  <dt><tt>-S</tt> <i>subfile</i></dt>
+    <dd>The substitution file. See below for format.</dd>
+
+  <dt><i>template</i></dt>
+    <dd> 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.</dd>
+</dl>
+
+<p>It is not possible to display usage by just typing <tt>msi</tt> since
+executing the command with no arguments is a valid command. To show usage
+specify an illegal switch, e.g.</p>
+
+<blockquote>
+<pre>msi -help</pre>
+</blockquote>
+
+<h2>Exit Status</h2>
+
+<dl>
+  <dt>0<dd>Success.
+  <dt>1<dd>Can't open/create file, or other I/O error.
+  <dt>2<dd>Undefined macros encountered with the <tt>-V</tt> option specified.
+</dl>
+
+<h2>Template File Format</h2>
+
+<p>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.
+Variable instances to be substituted by macro values are expressed in the
+template using the syntax <tt>$(</tt><i>name</i><tt>)</tt> or
+<tt>${</tt><i>name</i><tt>}</tt>. 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
+<tt>$(</tt><i>name</i><tt>=</tt><i>default</i><tt>)</tt> or
+<tt>${</tt><i>name</i><tt>=</tt><i>default</i><tt>}</tt>.</p>
+
+<p>For example, using the command</p>
+
+<blockquote>
+<pre>msi -M name=Marty template</pre>
+</blockquote>
+
+<p>where the file template contains</p>
+
+<blockquote>
+<pre>My name is $(name)
+My age is $(age=none of your business)</pre>
+</blockquote>
+
+<p>results in this output:</p>
+
+<blockquote>
+<pre>My name is Marty
+My age is none of your business</pre>
+</blockquote>
+
+<p>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.</p>
+
+<p>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
+&mdash; 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 <tt>$</tt> is
+preceded by a back-slash character <tt>\</tt>, but as with the standard Unix
+shells, variables inside double quoted strings are expanded properly.</p>
+
+<p>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.</p>
+
+<h3>Template file commands</h3>
+
+<p>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:</p>
+
+<blockquote>
+<pre>include "file"
+substitute "var=value,var=value,..."</pre>
+</blockquote>
+
+<p>Lines containing commands must be in one of these forms:</p>
+
+<ul>
+  <li><tt>include "</tt><i>filename</i><tt>"</tt></li>
+  <li><tt>substitute "</tt><i>name1=value1, name2=value2, ...</i><tt>"</tt></li>
+</ul>
+
+<p>White space is allowed before and after the command verb, and after the
+quoted string. If embedded quotes are needed, the backslash character
+<tt>\</tt> can be used as an escape character. For example</p>
+
+<blockquote>
+<pre>substitute "a=\"val\""</pre>
+</blockquote>
+
+<p>specifies that (unless <tt>a</tt> is subsequently redefined) wherever a
+<tt>$(a)</tt> macro appears in the template below this point, the text
+<tt>"val"</tt> (including the double quote characters) will appear in the
+output instead.</p>
+
+<p>If a line does match either syntax above it is just passed to macLib for
+processing without any notification. Thus the input line:</p>
+
+<blockquote>
+<pre>include "myfile" #include file</pre>
+</blockquote>
+
+<p>would just be passed to macLib, i.e. it would <em>not</em> be considered an
+include command.</p>
+
+<p>As an example of these commands, let the Unix command be:</p>
+
+<blockquote>
+<pre>msi template</pre>
+</blockquote>
+
+<p>and file includeFile contain:</p>
+
+<blockquote>
+<pre>first name is ${first}
+family name is ${family}</pre>
+</blockquote>
+
+<p>and template is</p>
+
+<blockquote>
+<pre>substitute "first=Marty,family=Kraimer"
+include "includeFile"
+substitute "first=Irma,family=Kraimer"
+include "includeFile"</pre>
+</blockquote>
+
+<p>then the following is written to the output.</p>
+
+<blockquote>
+<pre>first name is Marty
+family name is Kraimer
+first name is Irma
+family name is Kraimer</pre>
+</blockquote>
+
+<p>Note that on an IOC when using the <tt>dbLoadTemplate</tt> command, the
+template file does not support the <tt>substitute</tt> command, although
+<tt>include</tt> is supported.</p>
+
+<h2>Substitution File Format</h2>
+
+<p>The optional substitution file has three formats: regular, pattern, and
+dbTemplate format. We will discuss each separately.</p>
+
+<h3>Regular format</h3>
+
+<blockquote>
+<pre>{var1=set1_val1, var2=set1_val2, ...}
+{var2=set2_val2, var1=set2_val1, ...}
+{var1=set3_val1, var2=set3_val2, ...}
+{var2=set4_val2, var1=set4_val1, ...}</pre>
+</blockquote>
+
+<p>The template file is output with macro substitutions performed once for each
+set of braces containing macro replacement values.</p> 
+
+<h3>Pattern format</h3>
+
+<blockquote>
+<pre>pattern {var1, var2, ...}
+{set1_val1, set1_val2, ...}
+{set2_val1, set2_val2, ...}
+pattern {var2, var1, ...}
+{set3_val2, set3_val1, ...}
+{set4_val2, set4_val2, ...}</pre>
+</blockquote>
+
+<p>This produces the same result as the regular format example above.</p>
+
+<h3>dbTemplate Format</h3>
+
+<p>This format is an extension of the format accepted by the EPICS IOC command
+<tt>dbLoadTemplate</tt>, and allows templates to be expanded on the host rather
+by using dbLoadTemplate at IOC boot time.</p>
+
+<blockquote>
+<pre>file template {
+    <i>pattern format or regular format</i>
+}
+file "${WHERE}/template2" {
+    <i>pattern format or regular format</i>
+}</pre>
+</blockquote>
+
+<p>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.</p>
+
+<h3>Syntax for all formats</h3>
+
+<p>A comment line may appear anywhere in a substitution file, and will be
+ignored. A comment line is any line beginning with the character <tt>#</tt>,
+which must be the very first character on the line.</p>
+
+<p>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).</p>
+
+<p>Each item within braces can be an alphanumeric token, or a double-quoted
+string. A back-slash character <tt>\</tt> can be used to escape a quote
+character needed inside a quoted string. These three sets of substitutions are
+all equivalent:</p>
+
+<blockquote>
+<pre>{a=aa b=bb c="\"cc\""}
+{b="bb",a=aa,c="\"cc\""}
+{
+    c="\"cc\""
+    b=bb
+    a="aa"
+}</pre>
+</blockquote>
+
+<p>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.</p>
+
+<h3>Regular substitution example</h3>
+
+<p>Let the command be:</p>
+
+<blockquote>
+<pre>msi -S substitute template</pre>
+</blockquote>
+
+<p>The file <tt>template</tt> contains</p>
+
+<blockquote>
+<pre>first name is ${first}
+family name is ${family}</pre>
+</blockquote>
+
+<p> and the file <tt>substitute</tt> is</p>
+
+<blockquote>
+<pre>{first=Marty,family=Kraimer}
+{first=Irma,family=Kraimer}</pre>
+</blockquote>
+
+<p>The following is the output produced:</p>
+
+<blockquote>
+<pre>first name is Marty
+family name is Kraimer
+first name is Irma
+family name is Kraimer</pre>
+</blockquote>
+
+<h3>Pattern substitution example</h3>
+
+<p>Let the command be:</p>
+
+<blockquote>
+<pre>msi -S pattern template</pre>
+</blockquote>
+
+<p>The file <tt>pattern</tt> contains</p>
+
+<blockquote>
+<pre>pattern {first,last}
+{Marty,Kraimer}
+{Irma,Kraimer}</pre>
+</blockquote>
+
+<p>and <tt>template</tt> is the same as the previous example:</p>
+
+<blockquote>
+<pre>first name is ${first}
+family name is ${family}</pre>
+</blockquote>
+
+<p>This is the output:</p>
+
+<blockquote>
+<pre>first name is Marty
+family name is Kraimer
+first name is Irma
+family name is Kraimer</pre>
+</blockquote>
+
+<h3>dbTemplate example</h3>
+Let the command be
+
+<blockquote>
+<pre>msi -S xxx.substitutions</pre>
+</blockquote>
+
+<tt>xxx.substitutions</tt> is
+
+<blockquote>
+<pre>file template {
+pattern {first,last}
+{Marty,Kraimer}
+{Irma,Kraimer}
+pattern {last,first}
+{Smith,Bill}
+{Smith,Mary}
+}
+file template {
+{first=Marty,last=Kraimer}
+{first=Irma,last=Kraimer}
+}</pre>
+</blockquote>
+<tt>template</tt> is the same as in the previous example..
+
+<p>The following is written to the output</p>
+
+<blockquote>
+<pre>first name is Marty
+family name is Kraimer
+first name is Irma
+family name is Kraimer
+first name is Bill
+last name is Smith
+first name is Mary
+last name is Smith
+first name is Marty
+family name is Kraimer
+first name is Irma
+family name is Kraimer</pre>
+</blockquote>
+
+<h2>Building msi</h2>
+
+<p>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.</p>
+
+</body>
+</html>

=== added directory 'src/dbtools/test'
=== added file 'src/dbtools/test/pattern'
--- src/dbtools/test/pattern	1970-01-01 00:00:00 +0000
+++ src/dbtools/test/pattern	2010-08-23 19:50:55 +0000
@@ -0,0 +1,9 @@
+#test of a pattern
+   pattern {a,b}
+{xxx,"yyy"}
+   {zzz   ,   ttt}
+
+{
+    vvv
+    zzz
+}

=== added file 'src/dbtools/test/substitute'
--- src/dbtools/test/substitute	1970-01-01 00:00:00 +0000
+++ src/dbtools/test/substitute	2010-08-23 19:50:55 +0000
@@ -0,0 +1,5 @@
+{a=111,b="222"}
+{ 	a 	= 	aaa   ,   b=bbb}
+{a=	aaa
+b=	bbb
+}

=== added file 'src/dbtools/test/template'
--- src/dbtools/test/template	1970-01-01 00:00:00 +0000
+++ src/dbtools/test/template	2010-08-23 19:50:55 +0000
@@ -0,0 +1,4 @@
+# comment line
+$(a)
+this is a test $(b)
+$(d)

=== added file 'src/dbtools/test/testfile'
--- src/dbtools/test/testfile	1970-01-01 00:00:00 +0000
+++ src/dbtools/test/testfile	2010-08-23 19:50:55 +0000
@@ -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

=== added file 'src/dbtools/test/testfile1'
--- src/dbtools/test/testfile1	1970-01-01 00:00:00 +0000
+++ src/dbtools/test/testfile1	2010-08-23 19:50:55 +0000
@@ -0,0 +1,4 @@
+This is testfile1
+in testfile1 $(a)=a
+in testfile1 $(b)=b
+end of testfile1


Navigate by Date:
Prev: Re: Fixed: Segfaults in 3.14 branch since merging ca-over-tcp Ralph Lange
Next: [Merge] lp:~ralph-lange/epics-base/cac-dtor-racecond-fix into lp:epics-base Ralph Lange
Index: 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: devLib extensions review and testing request Davidsaver, Michael
Next: [Merge] lp:~ralph-lange/epics-base/cac-dtor-racecond-fix into lp:epics-base Ralph Lange
Index: 2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·