EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  1995  1996  1997  1998  1999  2000  2001  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: Re: msi again
From: Benjamin Franksen <[email protected]>
To: [email protected]
Date: Mon, 23 Aug 2010 11:24:36 +0200
On Friday, August 20, 2010, Allison, Stephanie wrote:
> Thanks for the work on msi.  I implemented your patches from last week
> and would like those 3 lines that you mention.  Or all your changes.  If
> it isn't too much trouble or if you are sending out your changes to
> others, can you send them to me too?

On Friday, August 20, 2010, Andrew Johnson wrote:
> I think Ben's "global { <definition-list> }" syntax provides a good
> solution, and I'll be happy to merge a patch that implements it in MSI. 
> I will work on adding it to base/src/dbtools as well to keep the
> functional equivalence in dbLoadTemplates.

Ok, I have attached my latest version (it is just one not-too-long C file). 
It has the global {...} feature implemented, contains all our BESSY-local 
fixes (for empty definition-lists, etc), and enables scoped definitions only 
if the user gives the additional command line argument -c. If it is desired 
that the default be the same as the one for dbLoadTemplate on the IOC, you 
can easily negate the logic to make -c (or some other switch) disable 
scoping.

On Friday, August 20, 2010, Ralph Lange wrote:
> On the MSI move: I am volunteering to move it into dbtools, keeping the 
> history.
> (I have been reluctantly doing too many repository conversions lately, 
> and this one is actually interesting: it will require merging from an 
> unrelated repo, which probably makes "swiss army knife" git the best 
> candidate for the operation. I will create a bzr branch on LP that you 
> can merge in after 3.14.12 is out.)

The problem with moving msi into base is that it makes it more difficult to 
apply site-specific changes. This may not be a strong argument against, 
though.

BTW

Please try to avoid moving discussions on tech-talk to private mailing 
"lists". If you think it gets too technical, then move the discussion to 
core-talk. There are so many advantages to using the public lists, not least 
among them that everything gets archived. It is easy to ignore threads that 
you are not interested in, but it it is hard if not impossible to follow 
something you *are* interested in (even if you do not actively participate 
in the discussion) if the stuff is discussed only in a private circle.

Cheers
Ben

Helmholtz-Zentrum Berlin fÃr Materialien und Energie GmbH   
Hahn-Meitner-Platz 1, 14109 Berlin   
Vorsitzende des Aufsichtsrates: Prof. Dr. Dr. h.c. mult. Joachim Treusch   
Stellvertretende Vorsitzende: Dr. Beatrix Vierkorn-Rudolph GeschÃftsfÃhrer: Prof. Dr. Anke Rita Kaysser-Pyzalla, Prof. Dr. Dr. h.c. Wolfgang Eberhardt, Dr. Ulrich Breuer   
Sitz der Gesellschaft: Berlin Handelsregister: AG Charlottenburg, 89 HRB 5583   

Disclaimer automatically attached by the E-Mail Security Appliance   
mail0.bessy.de 08/23/10 at Helmholtz-Zentrum Berlin GmbH. 
/*************************************************************************\
* 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 <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 int substituteGetGlobalSet(void *substitutePvt);
static char *substituteGetReplacements(void *substitutePvt);

/*Exit status*/
static int exitStatus = 0;


int main(int argc,char **argv)
{
    void *inputPvt;
    MAC_HANDLE *macPvt;
    char *pval;
    int  narg;
    char *substitutionName=0;
    char *templateName=0;
    int  i;
    int  optScoped=0;

    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);
	    narg = 1; /* no argument for this option */
	} else if(strncmp(argv[1],"-c",2)==0) {
            optScoped = 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(substituteGetGlobalSet(substitutePvt)) {
            pval = substituteGetReplacements(substitutePvt);
            if(pval) {
                addMacroReplacements(macPvt,pval);
            }
        }
        while(substituteGetNextSet(substitutePvt,&filename)) {
            if(templateName) filename = templateName;
            if(!filename) {
	        fprintf(stderr,"no template file\n");
	        usageExit();
            }
            if (optScoped) macPushScope(macPvt);
	    while((pval = substituteGetReplacements(substitutePvt))){
	        addMacroReplacements(macPvt,pval);
	        makeSubstitutions(inputPvt,macPvt,filename);
	    }
            if (optScoped) macPopScope(macPvt);
        }
        substituteDestruct(substitutePvt);
    }
    inputDestruct(inputPvt);
    free((void *)templateName);
    free((void *)substitutionName);
    return(exitStatus);
}

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<DIR>   place output file in directory <DIR> (default is '.')\n");
    fprintf(stderr,"  -I<DIR>   add <DIR> to include file search path\n");
    fprintf(stderr,"  -M<SUBST> add <SUBST> to (global) macro definitions\n");
    fprintf(stderr,"            (<SUBST> is of the form VAR=VALUE,...)\n");
    fprintf(stderr,"  -S<PATH>  expand a substitution file\n");
    fprintf(stderr,"  -c        macro definitions are scoped (in substitution files)\n");
    exit(1);
}

static void addMacroReplacements(MAC_HANDLE *macPvt,char *pval)
{
    char **pairs;
    long status;

    status = macParseDefns(macPvt,pval,&pairs);
    if(status==-1) {
        fprintf(stderr,"Error macParseDefns error\n");
        usageExit();
    }
    if(status) {
        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: unexpanded macros in ouput\n");
		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 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;

    *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(1);
    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);
                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);
	}
    }
}

static char *subGetNextLine(subFile *psubFile)
{
    char *pline;

    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->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;
}

Replies:
Re: msi again Benjamin Franksen
Re: msi again Ralph Lange
References:
msi again Benjamin Franksen

Navigate by Date:
Prev: Re: MEDM/Motif problem Andrew Wagner
Next: Re: Asyn and I/O intr scanning Hinko Kocevar
Index: 1994  1995  1996  1997  1998  1999  2000  2001  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: Re: msi again Andrew Johnson
Next: Re: msi again Benjamin Franksen
Index: 1994  1995  1996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  <20102011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Sep 2010 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·