From c2fd657f1677a3a0335224a68c4ae39c6c2713a3 Mon Sep 17 00:00:00 2001 From: schnetter Date: Tue, 17 Jun 2008 20:24:04 +0000 Subject: Cactus has currently an error in its parameter checking. It interprets ranges consisting of single numbers as allowing this number and all larger numbers. For example, the specification INT spatial_order "Order of spatial differencing" { 2 :: "second order" 4 :: "fourth order" } 2 allows all numbers not less than 2. This patch corrects this problem. Since this involves regular expressions which are often difficult to read, I have broken up the regular expressions into macros containing sub-expressions. I have also replaced calls to atoi and atof with calls to strtol and strtod, since these allow error checking which also was not present before. git-svn-id: http://svn.cactuscode.org/flesh/trunk@4496 17b73243-c579-4c4c-a9d2-2d5706c11dac --- src/util/Misc.c | 279 +++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 226 insertions(+), 53 deletions(-) (limited to 'src/util') diff --git a/src/util/Misc.c b/src/util/Misc.c index f8642e41..37c7ba2f 100644 --- a/src/util/Misc.c +++ b/src/util/Misc.c @@ -363,13 +363,11 @@ int Util_InList(const char *string1, int n_elements, ...) @@*/ int Util_IntInRange(int inval, const char *range) { - int retval; - regmatch_t pmatch[6]; + int retval = 0; + regmatch_t pmatch[8]; int start_closed, end_closed; int start, end, step; - retval = 0; - /* Valid ranges are of the form start:end:step * possibly preceeded by a [ or ( and ended by a ) or ] to indicate * closure. The end and step are optional. A * can also be used @@ -379,14 +377,37 @@ int Util_IntInRange(int inval, const char *range) * * 1 - [ or ( * 2 - start - * 3 - end - * 4 - step - * 5 - ) or ] + * 3 - whether end is present + * 4 - end + * 5 - whether step is present + * 6 - step + * 7 - ) or ] */ - if(CCTK_RegexMatch(range, - "(\\[|\\()?([^]):]*):?([^]):]*)?:?([^]):]*)?(\\]|\\))?", - 6, pmatch) != 0) +#define R_BEGIN "(\\[|\\()?" +#define R_VALUE "([^]):]*)" +#define R_SEP ":" +#define R_END "(\\]|\\))?" + +#define R_MAYBE(x) "(" x ")?" + + const char pattern[] = + R_BEGIN + R_VALUE + R_MAYBE(R_SEP + R_VALUE + R_MAYBE(R_SEP + R_VALUE)) + R_END; + +#undef R_BEGIN +#undef R_VALUE +#undef R_SEP +#undef R_END + +#undef R_MAYBE + + if(CCTK_RegexMatch(range, pattern, 8, pmatch) != 0) { /* First work out if the range is closed at the lower end. */ if(pmatch[1].rm_so != -1) @@ -408,7 +429,13 @@ int Util_IntInRange(int inval, const char *range) (pmatch[2].rm_eo-pmatch[2].rm_so > 0) && range[pmatch[2].rm_so] != '*') { - start = atoi(range+pmatch[2].rm_so); + char *endptr; + start = strtol(range+pmatch[2].rm_so, &endptr, 10); + if (endptr == range+pmatch[2].rm_so) + { + CCTK_Warn(1, __LINE__, __FILE__, "Flesh", "Invalid start"); + start = INT_MIN; + } } else { @@ -416,27 +443,57 @@ int Util_IntInRange(int inval, const char *range) start = INT_MIN; } - /* Next find the end of the range */ - if(pmatch[3].rm_so != -1 && - (pmatch[3].rm_eo-pmatch[3].rm_so > 0) && - range[pmatch[3].rm_so] != '*') + /* Next find whether end of the range is present */ + if(pmatch[3].rm_so != -1) { - end = atoi(range+pmatch[3].rm_so); + /* Next find the end of the range */ + if(pmatch[4].rm_so != -1 && + (pmatch[4].rm_eo-pmatch[4].rm_so > 0) && + range[pmatch[4].rm_so] != '*') + { + char *endptr; + end = strtol(range+pmatch[4].rm_so, &endptr, 10); + if (endptr == range+pmatch[4].rm_so) + { + CCTK_Warn(1, __LINE__, __FILE__, "Flesh", "Invalid end"); + end = INT_MIN; + } + } + else + { + /* No end range given, so use the largest integer available. */ + end = INT_MAX; + } } else { - /* No end range given, so use the largest integer available. */ - end = INT_MAX; + /* End range not given, so interval has length zero. */ + end = start; } - /* Next find the step of the range */ - if(pmatch[4].rm_so != -1 && (pmatch[4].rm_eo-pmatch[4].rm_so > 0)) + /* Next find whether step of the range is present */ + if(pmatch[5].rm_so != -1) { - step = atoi(range+pmatch[4].rm_so); + /* Next find the step of the range */ + if(pmatch[6].rm_so != -1 && (pmatch[6].rm_eo-pmatch[6].rm_so > 0)) + { + char *endptr; + step = strtol(range+pmatch[6].rm_so, &endptr, 10); + if (endptr == range+pmatch[6].rm_so) + { + CCTK_Warn(1, __LINE__, __FILE__, "Flesh", "Invalid step"); + step = 1; + } + } + else + { + /* No step given, so default to 1. */ + step = 1; + } } else { - /* No step given, so default to 1. */ + /* Step not given, so default to 1. */ step = 1; } if (step <= 0) @@ -446,9 +503,9 @@ int Util_IntInRange(int inval, const char *range) } /* Finally work out if the range is closed at the upper end. */ - if(pmatch[5].rm_so != -1) + if(pmatch[7].rm_so != -1) { - switch(range[pmatch[5].rm_so]) + switch(range[pmatch[7].rm_so]) { case ')' : end_closed = 0; break; case ']' : @@ -460,12 +517,12 @@ int Util_IntInRange(int inval, const char *range) end_closed = 1; } - /* Cast to unsigned int, because the subtraction (inval - start) + /* Cast to unsigned long, because the subtraction (inval - start) can overflow, and wrap-around is legal in C only for unsigned types. */ if(inval >= start + !start_closed && inval <= end - !end_closed && - ! (((unsigned int)inval-(unsigned int)start) % (unsigned int)step)) + ! (((unsigned long)inval-(unsigned long)start) % (unsigned long)step)) { retval = 1; } @@ -512,55 +569,159 @@ int Util_IntInRange(int inval, const char *range) @@*/ int Util_DoubleInRange(double inval, const char *range) { - int retval; - regmatch_t pmatch[6]; - double start, end; - - retval = 0; + int retval = 0; + regmatch_t pmatch[8]; + int start_closed, end_closed; + double start, end, step; /* * The following regular expression may match five substrings: * * 1 - [ or ( * 2 - start - * 3 - end - * 4 - step - * 5 - ) or ] + * 3 - whether end is present + * 4 - end + * 5 - whether step is present + * 6 - step + * 7 - ) or ] */ - if(CCTK_RegexMatch(range, - "(\\[|\\()?([^]):]*):?([^]):]*)?:?([^]):]*)?(\\]|\\))?", - 6, pmatch) != 0) +#define R_BEGIN "(\\[|\\()?" +#define R_VALUE "([^]):]*)" +#define R_SEP ":" +#define R_END "(\\]|\\))?" + +#define R_MAYBE(x) "(" x ")?" + + const char pattern[] = + R_BEGIN + R_VALUE + R_MAYBE(R_SEP + R_VALUE + R_MAYBE(R_SEP + R_VALUE)) + R_END; + +#undef R_BEGIN +#undef R_VALUE +#undef R_SEP +#undef R_END + +#undef R_MAYBE + + if(CCTK_RegexMatch(range, pattern, 8, pmatch) != 0) { + /* First work out if the range is closed at the lower end. */ + if(pmatch[1].rm_so != -1) + { + switch(range[pmatch[1].rm_so]) + { + case '(' : start_closed = 0; break; + case '[' : + default : start_closed = 1; + } + } + else + { + start_closed = 1; + } + /* Next find the start of the range */ if(pmatch[2].rm_so != -1 && (pmatch[2].rm_eo-pmatch[2].rm_so > 0) && range[pmatch[2].rm_so] != '*') { - start = atof(range+pmatch[2].rm_so); + char *endptr; + start = strtod(range+pmatch[2].rm_so, &endptr); + if (endptr == range+pmatch[2].rm_so) + { + CCTK_Warn(1, __LINE__, __FILE__, "Flesh", "Invalid start"); + start = -HUGE_VAL; + } + } + else + { + /* No start range given, so use the smallest double available. */ + start = -HUGE_VAL; + } + + /* Next find whether end of the range is present */ + if(pmatch[3].rm_so != -1) + { + /* Next find the end of the range */ + if(pmatch[4].rm_so != -1 && + (pmatch[4].rm_eo-pmatch[4].rm_so > 0) && + range[pmatch[4].rm_so] != '*') + { + char *endptr; + end = strtod(range+pmatch[4].rm_so, &endptr); + if (endptr == range+pmatch[4].rm_so) + { + CCTK_Warn(1, __LINE__, __FILE__, "Flesh", "Invalid end"); + end = HUGE_VAL; + } + } + else + { + /* No end range given, so use the largest double available. */ + end = HUGE_VAL; + } + } + else + { + /* End range not given, so interval has length zero. */ + end = start; + } + + /* Next find whether step of the range is present */ + if(pmatch[5].rm_so != -1) + { + /* Next find the step of the range */ + if(pmatch[6].rm_so != -1 && (pmatch[6].rm_eo-pmatch[6].rm_so > 0)) + { + char *endptr; + step = strtod(range+pmatch[6].rm_so, &endptr); + if (endptr == range+pmatch[6].rm_so) + { + CCTK_Warn(1, __LINE__, __FILE__, "Flesh", "Invalid step"); + step = 0; + } + } + else + { + /* No step given, so default to 0. */ + step = 0; + } } else { - /* No start range given, so use the smallest float available. */ - start = -DBL_MAX; + /* Step not given, so default to 0. */ + step = 0; + } + if (step < 0) + { + CCTK_Warn(1, __LINE__, __FILE__, "Flesh", "Invalid step"); + step = 0; } - /* Next find the end of the range */ - if(pmatch[3].rm_so != -1 && - (pmatch[3].rm_eo-pmatch[3].rm_so > 0) && - range[pmatch[3].rm_so] != '*') + /* Finally work out if the range is closed at the upper end. */ + if(pmatch[7].rm_so != -1) { - end = atof(range+pmatch[3].rm_so); + switch(range[pmatch[7].rm_so]) + { + case ')' : end_closed = 0; break; + case ']' : + default : end_closed = 1; + } } else { - /* No end range given, so use the largest float available. */ - end = DBL_MAX; + end_closed = 1; } - if(inval >= start /*+ !start_closed */&& - inval <= end /* - !end_closed */ /* && - ! ((inval-start) % step)*/) + if((start_closed ? inval >= start : inval > start) && + (end_closed ? inval <= end : inval < end ) && + (step ? ! fmod (inval - start, step) : 1)) { retval = 1; } @@ -746,6 +907,7 @@ int CCTK_SetDoubleInRangeList(CCTK_REAL *data, const char *value, va_list ap; char *element; + char *endptr; CCTK_REAL inval; @@ -757,7 +919,7 @@ int CCTK_SetDoubleInRangeList(CCTK_REAL *data, const char *value, strncpy(temp, value, sizeof(temp) - 1); temp[sizeof(temp) - 1] = 0; - for (p=0;p