summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorknarf <knarf@17b73243-c579-4c4c-a9d2-2d5706c11dac>2009-09-25 18:42:07 +0000
committerknarf <knarf@17b73243-c579-4c4c-a9d2-2d5706c11dac>2009-09-25 18:42:07 +0000
commit57a188f38541709550334b5be2d2563059cb042d (patch)
tree674f8e4f64818e59458172a4756baf47812e6a85 /src/util
parent90d60e6cd3146547d7ec34695be76a6c8798c010 (diff)
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
Diffstat (limited to 'src/util')
-rw-r--r--src/util/ParseFile.c647
1 files changed, 455 insertions, 192 deletions
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <string.h>
+
+#include <cctk.h>
#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 * <b>in place</b>. 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<strlen(s);i++)
+ {
+ if (s[i] != ' ' && s[i] != '\t' && s[i] != '\n' && s[i] != '\r')
+ {
+ stripMe[j++] = s[i];
+ }
+ stripMe[j] = '\0';
+ }
+ }
+
+ free(s);
+}
+
+
+/* #define TEST_ParseFile */
+
+#ifdef TEST_ParseFile
+
+int parameter_printer(const char *param, const char *val)
+{
+ printf("Parameter %s has value %s\n", param, val);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int retval;
+ FILE *parameter_file;
+
+ if(argc > 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 <filename>\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
+ <ul>
+ <li>a = b
+ <li>a,b,c = d,e,f
+ <li># rest of the line is ignored
+ <li>x = "string value"
+ </ul>
+ So it is easy to parse
+ <p>
+ 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 * <b>in place</b>. 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<strlen(s);i++)
- {
- if (s[i] != ' ' && s[i] != '\t' && s[i] != '\n' && s[i] != '\r')
- {
- stripMe[j++] = s[i];
- }
- stripMe[j] = '\0';
- }
- }
-
- free(s);
-}
-
-
-/* #define TEST_ParseFile */
-
-#ifdef TEST_ParseFile
-
-int parameter_printer(const char *param, const char *val)
-{
- printf("Parameter %s has value %s\n", param, val);
-
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- int retval;
- FILE *parameter_file;
-
- if(argc > 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 <filename>\n", argv[0]);
- retval = 1;
- };
-
- return 0;
-}
-
-#endif