From 57a188f38541709550334b5be2d2563059cb042d Mon Sep 17 00:00:00 2001 From: knarf Date: Fri, 25 Sep 2009 18:42:07 +0000 Subject: This patch improves the parser used by Cactus to prepocess parameter files. The main changes are: - when reading a parameter file do not parse the file while reading, but read it first into a buffer, preprocess that and parse the buffer after that - replace the code which changes $parfile into the parameter file name to use this buffer preprocessing - replace $ENV{'*'} "defines" by environment variable values (*), e.g. $ENV{'HOME'} with $HOME. Frank git-svn-id: http://svn.cactuscode.org/flesh/trunk@4573 17b73243-c579-4c4c-a9d2-2d5706c11dac --- src/util/ParseFile.c | 647 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 455 insertions(+), 192 deletions(-) (limited to 'src/util') diff --git a/src/util/ParseFile.c b/src/util/ParseFile.c index 86172217..bd6bd71e 100644 --- a/src/util/ParseFile.c +++ b/src/util/ParseFile.c @@ -7,7 +7,6 @@ to a user-supplied subroutine. Currently taken from the old cactus ones and slightly modifed. @enddesc - @version $Id$ @@*/ /*#define DEBUG*/ @@ -15,6 +14,9 @@ #include #include #include +#include + +#include #include "cctk_Flesh.h" #include "cctk_CommandLine.h" @@ -38,6 +40,11 @@ CCTK_FILEVERSION(util_ParseFile_c); static void CheckBuf(int, int); static void removeSpaces(char *stripMe); +static char *ReadFile(FILE *file, unsigned long *filesize); +static char *ParseDefines(char *buffer, unsigned long *buffersize); +int ParseBuffer(char *buffer, + int (*set_function)(const char *, const char *, int), + tFleshConfig *ConfigData); /******************************************************************** ********************* Other Routine Prototypes ********************* @@ -63,7 +70,7 @@ static int lineno = 1; /*@@ @routine ParseFile - @author Paul Walker + @author Paul Walker, Frank Loeffler @desc This routine actually parses the parameter file. The syntax we allow is @@ -83,6 +90,7 @@ static int lineno = 1; @hdesc Moved to CCTK. Changed to pass data to arbitrary function. Changed to take a file descriptor rather than a filename. + Use a buffer to parse which can be preprocessed before main parsing @endhistory @var ifp @vdesc The filestream to parse @@ -111,10 +119,434 @@ static int lineno = 1; 0 - success @endreturndesc @@*/ + int ParseFile(FILE *ifp, int (*set_function)(const char *, const char *, int), tFleshConfig *ConfigData) { + int retval; + unsigned long buffersize; + char *buffer = ReadFile(ifp, &buffersize); + if (!buffer) + return 1; + buffer = ParseDefines(buffer, &buffersize); + retval = ParseBuffer(buffer, set_function, ConfigData); + free(buffer); + return retval; +} + +/******************************************************************** + ********************* Local Routines ************************* + ********************************************************************/ + + /*@@ + @routine CheckBuf + @author Paul Walker + @desc + A simple description and warning message in case of + a fixed parse buffer overflow. + @enddesc + @calls + @calledby + @history + + @endhistory + @var p + @vdesc buffer location + @vtype int + @vio in + @vcomment + + @endvar + @var l + @vdesc Line number + @vtype int + @vio in + @vcomment + + @endvar + +@@*/ + +static void CheckBuf(int p, int l) +{ + if (p >= BUF_SZ) + { + fprintf(stderr,"WARNING: Parser buffer overflow on line %d\n", + l); + fprintf(stderr,"This indicates either an incorrect parm file or\n"); + fprintf(stderr,"the need to recompile " __FILE__ " with a bigger\n"); + fprintf(stderr,"BUF_SZ parm.\n"); + + assert(0); + exit(1); + } +} + + + /*@@ + @routine removeSpaces + @author Paul Walker + @desc + removes the spaces from a char * in place. Beware + that this function will change the input value and if you + want to keep a copy you have to do so yourself! + @enddesc + @calls + @calledby + @history + + @endvar + @var stripMe + @vdesc String to strip + @vtype char * + @vio inout + @vcomment + + @endvar + +@@*/ +static void removeSpaces(char *stripMe) +{ + char *s; + unsigned int i,j; + s = (char *)malloc((strlen(stripMe)+2)*sizeof(char)); + + if(s) + { + strcpy(s,stripMe); + for (i=0,j=0;i 1) + { + parameter_file = fopen(argv[1], "r"); + if(parameter_file) + { + ParseFile(parameter_file, parameter_printer); + fclose(parameter_file); + retval = 0; + } + else + { + retval=2; + } + } + else + { + printf("Usage: %s \n", argv[0]); + retval = 1; + }; + + return 0; +} + +#endif + + + /*@@ + @routine ReadFile + @author Frank Loeffler + @desc + This routine reads a file into a buffer + @enddesc + @history + @var file + @vdesc The filestream to read + @vtype FILE * + @vio in + @vcomment + + @endvar + @var filesize + @vdesc The size of the file + @vtype *unsigned long + @vio out + @vcomment + + @endvar + + @returntype char * + @returndesc + NULL - failure + !NULL allocated buffer + @endreturndesc +@@*/ +static char *ReadFile(FILE *file, unsigned long *filesize) +{ + char *buffer; + + if (!file) + { + fprintf(stderr, "Could not use file for reading.\n"); + return NULL; + } + /* Get the file size */ + fseek(file, 0, SEEK_END); + *filesize = ftell(file); + fseek(file, 0, SEEK_SET); + /* Allocate buffer */ + buffer = (char *)malloc(*filesize+1); + if (!buffer) + { + fprintf(stderr, "Could not allocate memory.\n"); + return NULL; + } + /* Read file into buffer and return */ + fread(buffer, *filesize, 1, file); + /* Protect buffer for string operations */ + buffer[*filesize] = '\0'; + return buffer; +} + + /*@@ + @routine ParseDefines + @author Frank Loeffler + @desc + This routine parses a buffer for defines of the form \$[^ \n] and + replaces them with some predefined defines, returning the new buffer, + which might be the same as the old buffer. Otherwise the old buffer + gets freed by this function. In case of parsing errors, the whole + parsing is stopped and the old buffer is returned + (FIXME: Should we return NULL?) + @enddesc + @history + @var buffer + @vdesc The buffer to parse + @vtype char * + @vio in + @vcomment + + @endvar + @var buffersize + @vdesc The size of the buffer + @vtype *unsigned long + @vio out + @vcomment + + @endvar + + @returntype char * + @returndesc + !NULL - new buffer, might be == buffer + @endreturndesc +@@*/ +static char *ParseDefines(char *buffer, unsigned long *buffersize) +{ + /* define name */ + char define[1024]; + /* Position in define name */ + char defpos = 0; + /* Current position in buffer */ + size_t pos = 0; + /* Character at current position */ + char c; + /* Position of start of found define */ + size_t def_start = 0; + /* Flag to indicate if we are inside a definition name */ + int indef = 0; + if (!buffer) + return buffer; + /* Main loop over the buffer */ + while (((c=buffer[pos]) != '\0') && (pos < *buffersize) ) + { + /* Check if we found a define */ + if (c == '$') + { + /* Mark the state and location and go on */ + indef = 1; + def_start = pos; + } + /* If we are inside a define */ + else if (indef) + { + /* Look for the end of the define name */ + if (c == '}' || c == '\0' || c == '\n') + { + /* make the define name a proper string */ + define[defpos] = '\0'; + /* this holds the value of the define to be filled in */ + char *value = NULL; + /* a new buffer for the whole thing */ + char * new_buffer; + unsigned long new_size; + /* Check for different kinds of defines */ + /* Environment variables */ + if ((defpos > 6) && + (strncmp(define, "ENV{'", 5) == 0) && + (define[defpos-1] == '\'')) + { + /* overwrite the trailing ' */ + define[defpos-1] = '\0'; + value = getenv(define+5); + if (!value) + { + CCTK_VWarn(CCTK_WARN_ALERT, __LINE__, __FILE__, CCTK_THORNSTRING, + "No environment variable %s found\n", define+5); + /* TODO: Should we abort here? (return NULL) */ + } + /* increase pos to jump over the trailing } */ + if (pos+1 < *buffersize) { pos++; } + } + /* Parameter file name ? */ + else if (strcmp(define, "parfile") == 0) + { + char path[500]; + CCTK_ParameterFilename(500, path); + value = strrchr (path, '/'); + if (value == NULL) + { + value = path; + } + else + { + value++; + } + /* skip the parameter file extension */ + if (strcmp (value + strlen (value) - 4, ".par") == 0) + { + value[strlen (value) - 4] = '\0'; + } + } + /* Else: unknown define - or no define at all: ignore */ + if (value) + { + /* Replace the old buffer with the new, copying in all the data */ + new_size = *buffersize - strlen(define) + strlen(value) + 1; + if (new_size < def_start) + { + CCTK_WARN(0, "Something is wrong with me, HELP!"); + return buffer; + } + new_buffer = (char *)malloc(new_size); + if (!new_buffer) + { + CCTK_WARN(0, "I am out of memory and give up parsing for defines."); + return buffer; + } + new_buffer[0]='\0'; + strncat(new_buffer, buffer, def_start); + strncat(new_buffer, value, new_size-1); + strncat(new_buffer, buffer+pos, new_size-1); + new_buffer[new_size-1] = '\0'; + /* free the old buffer */ + free(buffer); + /* Start further processing of new buffer */ + pos = def_start + strlen(define); + buffer = new_buffer; + *buffersize = new_size; + } + /* General define cleanup */ + indef = 0; + defpos = 0; + define[0] = '\0'; + def_start = 0; + } + else if (defpos > 1023) + { + /* We only print this warning and ignore the possible define problem. + * It might not be a define after all but a valid, long parameter + * value containing a '$'.*/ + define[1023] = '\0'; + CCTK_VWarn(CCTK_WARN_PICKY, __LINE__, __FILE__, CCTK_THORNSTRING, + "Possible define too long: %s", define); + indef = 0; + defpos = 0; + define[0] = '\0'; + def_start = 0; + } + else + define[defpos++] = c; + } + pos++; + } + return buffer; +} + + /*@@ + @routine ParseBuffer + @author Paul Walker + @desc + This routine actually parses the parameter file. The + syntax we allow is +
    +
  • a = b +
  • a,b,c = d,e,f +
  • # rest of the line is ignored +
  • x = "string value" +
+ So it is easy to parse +

+ We go through the file looking for stuff and then set + it in the global database using calls to the passed in set_function. + @enddesc + @history + @hdate Tue Jan 12 16:41:36 1999 @hauthor Tom Goodale + @hdesc Moved to CCTK. + Changed to pass data to arbitrary function. + Changed to take a file descriptor rather than a filename. + Use a buffer to parse which can be preprocessed before main parsing + @endhistory + @var buffer + @vdesc The buffer to parse + @vtype char * + @vio in + @vcomment + + @endvar + @var set_function + @vdesc The function to call to set the value of a parameter + @vtype int (*)(const char *, const char *) + @vio in + @vcomment + + @endvar + @var ConfigData + @vdesc Flesh configuration data + @vtype tFleshConfig * + @vio in + @vcomment + + @endvar + + @returntype int + @returndesc + 0 - success + @endreturndesc +@@*/ +int ParseBuffer(char *buffer, + int (*set_function)(const char *, const char *, int), + tFleshConfig *ConfigData) +{ + /* position in buffer */ + unsigned int pos = 0; /* Buffers for parsing from the file */ char *tokens, *value; char *subtoken, *subvalue; @@ -122,10 +554,8 @@ int ParseFile(FILE *ifp, int ntokens; /* Status flags */ int intoken, inval; - /* Current char. Have to make it an int so we can compare with - EOF. See man 3 fgetc - */ - int c; + /* Current char */ + char c; int num_errors; /* number of errors in file parsing */ num_errors = 0; @@ -141,7 +571,7 @@ int ParseFile(FILE *ifp, intoken = 0; inval = 0; - while ((c=fgetc(ifp)) != EOF) + while ((c=buffer[pos++]) != '\0') { #ifdef DEBUG printf("%c",c); @@ -150,7 +580,7 @@ int ParseFile(FILE *ifp, while (c == '#' || c == '!' ) { /* Comment line. So forget rest of line */ - while ((c=fgetc(ifp)) != '\n' && c != '\r' && c != EOF) + while ((c=buffer[pos++]) != '\n' && c != '\r' && c != '\0') { #ifdef DEBUG printf("%c",c); @@ -160,7 +590,7 @@ int ParseFile(FILE *ifp, { lineno++; } - c = fgetc(ifp); + c = buffer[pos++]; #ifdef DEBUG printf("%c",c); #endif @@ -220,7 +650,7 @@ int ParseFile(FILE *ifp, * and check if the value is a string or not. * This parser DOES strip quotes off of the strings. */ - while ((c = fgetc(ifp)) == ' ' || c == '\n' || c == '\r' || c == '\t') + while ((c = buffer[pos++]) == ' ' || c == '\n' || c == '\r' || c == '\t') { #ifdef DEBUG printf("%c",c); @@ -251,7 +681,7 @@ int ParseFile(FILE *ifp, free (tokens); return 1; } - while ((c = fgetc(ifp)) != '"') + while ((c = buffer[pos++]) != '"') { #ifdef DEBUG printf("%c",c); @@ -265,7 +695,7 @@ int ParseFile(FILE *ifp, #endif lineno++; } - else if (c == EOF) + else if (c == '\0') { break; } @@ -274,9 +704,9 @@ int ParseFile(FILE *ifp, if (c == '"') { int is_comment = 0; - while ((c = fgetc(ifp)) != '\n') + while ((c = buffer[pos++]) != '\n') { - if (c == EOF) + if (c == '\0') { break; } @@ -295,7 +725,7 @@ int ParseFile(FILE *ifp, return 1; } } - if (c == '\n' || c == EOF) + if (c == '\n' || c == '\0') { if (c == '\n') lineno++; /* mark it as properly quoted string value */ @@ -319,39 +749,6 @@ int ParseFile(FILE *ifp, #endif set_function(tokens,value, lineno); } - else if (c == '$') - { - /* We got a define */ - /* FIXME: Assume it is a parameter file for now */ - char path[500]; - char *parfile; - - CCTK_ParameterFilename(500,path); - parfile = strrchr (path, '/'); - if (parfile == NULL) - { - parfile = path; - } - else - { - parfile++; - } - /* skip the parameter file extension */ - if (strcmp (parfile + strlen (parfile) - 4, ".par") == 0) - { - parfile[strlen (parfile) - 4] = 0; - } - - /* ignore everything else on the line */ - while (!(c==' ' || c=='\t' || c == '\n' || c == '\r' || c == EOF)) - { - c = fgetc(ifp); -#ifdef DEBUG - printf("%c",c); -#endif - } - set_function(tokens,parfile,lineno); - } else { @@ -362,15 +759,15 @@ int ParseFile(FILE *ifp, /* Simple case. We have an int or a double which contain no spaces! */ - c = fgetc(ifp); + c = buffer[pos++]; #ifdef DEBUG printf("%c",c); #endif - while (!(c==' ' || c=='\t' || c == '\n' || c == '\r' || c == EOF)) + while (!(c==' ' || c=='\t' || c == '\n' || c == '\r' || c == '\0')) { value[p++] = (char)c; CheckBuf(p,lineno); - c = fgetc(ifp); + c = buffer[pos++]; #ifdef DEBUG printf("%c",c); #endif @@ -402,11 +799,11 @@ int ParseFile(FILE *ifp, ntokens-1 commas, stripping spaces, and make a nice little string. */ - c = fgetc(ifp); + c = buffer[pos++]; #ifdef DEBUG printf("%c",c); #endif - while (ncommas < ntokens-1 && c != EOF) + while (ncommas < ntokens-1 && c != '\0') { if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) { @@ -414,7 +811,7 @@ int ParseFile(FILE *ifp, CheckBuf(pp,lineno); } if (c == ',') ncommas ++; - c = fgetc(ifp); + c = buffer[pos++]; #ifdef DEBUG printf("%c",c); #endif @@ -422,7 +819,7 @@ int ParseFile(FILE *ifp, if (c == ' ' || c == '\t') { /* Great now strip out the spaces */ - while((c = fgetc(ifp)) == ' ' || c=='\t' || c == '\n' || c == '\r') + while((c = buffer[pos++]) == ' ' || c=='\t' || c == '\n' || c == '\r') { #ifdef DEBUG printf("%c",c); @@ -441,15 +838,15 @@ int ParseFile(FILE *ifp, value[pp++] = (char)c; CheckBuf(p,lineno); - c = fgetc(ifp); + c = buffer[pos++]; #ifdef DEBUG printf("%c",c); #endif - while (c != ' ' && c != '\t' && c != '\n' && c != '\r' && c != EOF) + while (c != ' ' && c != '\t' && c != '\n' && c != '\r' && c != '\0') { value[pp++] = (char)c; CheckBuf(pp,lineno); - c = fgetc(ifp); + c = buffer[pos++]; #ifdef DEBUG printf("%c",c); #endif @@ -525,137 +922,3 @@ int ParseFile(FILE *ifp, return num_errors; } -/******************************************************************** - ********************* Local Routines ************************* - ********************************************************************/ - - /*@@ - @routine CheckBuf - @author Paul Walker - @desc - A simple description and warning message in case of - a fixed parse buffer overflow. - @enddesc - @calls - @calledby - @history - - @endhistory - @var p - @vdesc buffer location - @vtype int - @vio in - @vcomment - - @endvar - @var l - @vdesc Line number - @vtype int - @vio in - @vcomment - - @endvar - -@@*/ - -static void CheckBuf(int p, int l) -{ - if (p >= BUF_SZ) - { - fprintf(stderr,"WARNING: Parser buffer overflow on line %d\n", - l); - fprintf(stderr,"This indicates either an incorrect parm file or\n"); - fprintf(stderr,"the need to recompile " __FILE__ " with a bigger\n"); - fprintf(stderr,"BUF_SZ parm.\n"); - - assert(0); - exit(1); - } -} - - - /*@@ - @routine removeSpaces - @author Paul Walker - @desc - removes the spaces from a char * in place. Beware - that this function will change the input value and if you - want to keep a copy you have to do so yourself! - @enddesc - @calls - @calledby - @history - - @endvar - @var stripMe - @vdesc String to strip - @vtype char * - @vio inout - @vcomment - - @endvar - -@@*/ -static void removeSpaces(char *stripMe) -{ - char *s; - unsigned int i,j; - s = (char *)malloc((strlen(stripMe)+2)*sizeof(char)); - - if(s) - { - strcpy(s,stripMe); - for (i=0,j=0;i 1) - { - parameter_file = fopen(argv[1], "r"); - if(parameter_file) - { - ParseFile(parameter_file, parameter_printer); - fclose(parameter_file); - retval = 0; - } - else - { - retval=2; - } - } - else - { - printf("Usage: %s \n", argv[0]); - retval = 1; - }; - - return 0; -} - -#endif -- cgit v1.2.3