From acdf0dc4693abf7529d1f6f4cca2ddcd43cb3500 Mon Sep 17 00:00:00 2001 From: ThorstenB Date: Sun, 30 Oct 2011 14:48:53 +0100 Subject: [PATCH] Clean-up date/time option parser. Add range checks and provide error messages. Extend time offset to 64bit - so we're safe for 2038-01-19 (and the next couple of millions years beyond...). Support partial date/time strings, such as --start-date-gmt=2011 or --start-date-gmt=:::12:00:00 --- src/Main/options.cxx | 233 +++++++++++++++++++++------------------ src/Time/TimeManager.cxx | 4 +- src/Time/TimeManager.hxx | 2 +- 3 files changed, 127 insertions(+), 112 deletions(-) diff --git a/src/Main/options.cxx b/src/Main/options.cxx index 180b12fd6..5ca9cd2cf 100644 --- a/src/Main/options.cxx +++ b/src/Main/options.cxx @@ -283,6 +283,57 @@ parse_wind (const string &wind, double * min_hdg, double * max_hdg, return true; } +static bool +parseIntValue(char** ppParserPos, int* pValue,int min, int max, const char* field, const char* argument) +{ + if ( !strlen(*ppParserPos) ) + return true; + + char num[256]; + int i = 0; + + while ( isdigit((*ppParserPos)[0]) && (i<255) ) + { + num[i] = (*ppParserPos)[0]; + (*ppParserPos)++; + i++; + } + num[i] = '\0'; + + switch ((*ppParserPos)[0]) + { + case 0: + break; + case ':': + (*ppParserPos)++; + break; + default: + SG_LOG(SG_GENERAL, SG_ALERT, "Illegal character in time string for " << field << ": '" << + (*ppParserPos)[0] << "'."); + // invalid field - skip rest of string to avoid further errors + while ((*ppParserPos)[0]) + (*ppParserPos)++; + return false; + } + + if (i<=0) + return true; + + int value = atoi(num); + if ((value < min)||(value > max)) + { + SG_LOG(SG_GENERAL, SG_ALERT, "Invalid " << field << " in '" << argument << + "'. Valid range is " << min << "-" << max << "."); + return false; + } + else + { + *pValue = value; + return true; + } +} + +#ifndef HAVE_RINT // parse a time string ([+/-]%f[:%f[:%f]]) into hours static double parse_time(const string& time_in) { @@ -363,113 +414,65 @@ parse_time(const string& time_in) { return(sign * result); } - +#endif // parse a date string (yyyy:mm:dd:hh:mm:ss) into a time_t (seconds) static long int -parse_date( const string& date) +parse_date( const string& date, const char* timeType) { - struct tm gmt; - char * date_str, num[256]; - int i; - // initialize to zero - gmt.tm_sec = 0; - gmt.tm_min = 0; - gmt.tm_hour = 0; - gmt.tm_mday = 0; - gmt.tm_mon = 0; - gmt.tm_year = 0; - gmt.tm_isdst = 0; // ignore daylight savings time for the moment - date_str = (char *)date.c_str(); - // get year - if ( strlen(date_str) ) { - i = 0; - while ( (date_str[0] != ':') && (date_str[0] != '\0') ) { - num[i] = date_str[0]; - date_str++; - i++; - } - if ( date_str[0] == ':' ) { - date_str++; - } - num[i] = '\0'; - gmt.tm_year = atoi(num) - 1900; - } - // get month - if ( strlen(date_str) ) { - i = 0; - while ( (date_str[0] != ':') && (date_str[0] != '\0') ) { - num[i] = date_str[0]; - date_str++; - i++; - } - if ( date_str[0] == ':' ) { - date_str++; - } - num[i] = '\0'; - gmt.tm_mon = atoi(num) -1; - } - // get day - if ( strlen(date_str) ) { - i = 0; - while ( (date_str[0] != ':') && (date_str[0] != '\0') ) { - num[i] = date_str[0]; - date_str++; - i++; - } - if ( date_str[0] == ':' ) { - date_str++; - } - num[i] = '\0'; - gmt.tm_mday = atoi(num); - } - // get hour - if ( strlen(date_str) ) { - i = 0; - while ( (date_str[0] != ':') && (date_str[0] != '\0') ) { - num[i] = date_str[0]; - date_str++; - i++; - } - if ( date_str[0] == ':' ) { - date_str++; - } - num[i] = '\0'; - gmt.tm_hour = atoi(num); - } - // get minute - if ( strlen(date_str) ) { - i = 0; - while ( (date_str[0] != ':') && (date_str[0] != '\0') ) { - num[i] = date_str[0]; - date_str++; - i++; - } - if ( date_str[0] == ':' ) { - date_str++; - } - num[i] = '\0'; - gmt.tm_min = atoi(num); + struct tm gmt,*pCurrentTime; + int year,month,day,hour,minute,second; + char *argument, *date_str; + + SGTime CurrentTime = SGTime(); + CurrentTime.update(0,0,0,0); + + // FIXME This should obtain system/aircraft/GMT time depending on timeType + pCurrentTime = CurrentTime.getGmt(); + + // initialize all fields with current time + year = pCurrentTime->tm_year + 1900; + month = pCurrentTime->tm_mon + 1; + day = pCurrentTime->tm_mday; + hour = pCurrentTime->tm_hour; + minute = pCurrentTime->tm_min; + second = pCurrentTime->tm_sec; + + argument = (char *)date.c_str(); + date_str = argument; + + // start with parsing year + if (!strlen(date_str) || + !parseIntValue(&date_str,&year,0,9999,"year",argument)) + { + return -1; } - // get second - if ( strlen(date_str) ) { - i = 0; - while ( (date_str[0] != ':') && (date_str[0] != '\0') ) { - num[i] = date_str[0]; - date_str++; - i++; - } - if ( date_str[0] == ':' ) { - date_str++; - } - num[i] = '\0'; - gmt.tm_sec = atoi(num); + + if (year < 1970) + { + SG_LOG(SG_GENERAL, SG_ALERT, "Invalid year '" << year << "'. Use 1970 or later."); + return -1; } + + parseIntValue(&date_str, &month, 1, 12, "month", argument); + parseIntValue(&date_str, &day, 1, 31, "day", argument); + parseIntValue(&date_str, &hour, 0, 23, "hour", argument); + parseIntValue(&date_str, &minute, 0, 59, "minute", argument); + parseIntValue(&date_str, &second, 0, 59, "second", argument); + + gmt.tm_sec = second; + gmt.tm_min = minute; + gmt.tm_hour = hour; + gmt.tm_mday = day; + gmt.tm_mon = month - 1; + gmt.tm_year = year -1900; + gmt.tm_isdst = 0; // ignore daylight savings time for the moment + time_t theTime = sgTimeGetGMT( gmt.tm_year, gmt.tm_mon, gmt.tm_mday, - gmt.tm_hour, gmt.tm_min, gmt.tm_sec ); - //printf ("Date is %s\n", ctime(&theTime)); - //printf ("in seconds that is %d\n", theTime); - //exit(1); + gmt.tm_hour, gmt.tm_min, gmt.tm_sec ); + + SG_LOG(SG_GENERAL, SG_INFO, "Configuring startup time to " << ctime(&theTime)); + return (theTime); } @@ -486,9 +489,9 @@ parse_degree( const string& degree_str) { // parse time offset string into seconds -static int +static long int parse_time_offset( const string& time_str) { - int result; + long int result; // printf("time offset = %s\n", time_str); @@ -811,7 +814,7 @@ fgOptBpp( const char *arg ) static int fgOptTimeOffset( const char *arg ) { - fgSetInt("/sim/startup/time-offset", + fgSetLong("/sim/startup/time-offset", parse_time_offset( arg )); fgSetString("/sim/startup/time-offset-type", "system-offset"); return FG_OPTIONS_OK; @@ -820,24 +823,36 @@ fgOptTimeOffset( const char *arg ) static int fgOptStartDateSys( const char *arg ) { - fgSetInt("/sim/startup/time-offset", parse_date( arg ) ); - fgSetString("/sim/startup/time-offset-type", "system"); + long int theTime = parse_date( arg, "system" ); + if (theTime>=0) + { + fgSetLong("/sim/startup/time-offset", theTime); + fgSetString("/sim/startup/time-offset-type", "system"); + } return FG_OPTIONS_OK; } static int fgOptStartDateLat( const char *arg ) { - fgSetInt("/sim/startup/time-offset", parse_date( arg ) ); - fgSetString("/sim/startup/time-offset-type", "latitude"); + long int theTime = parse_date( arg, "latitude" ); + if (theTime>=0) + { + fgSetLong("/sim/startup/time-offset", theTime); + fgSetString("/sim/startup/time-offset-type", "latitude"); + } return FG_OPTIONS_OK; } static int fgOptStartDateGmt( const char *arg ) { - fgSetInt("/sim/startup/time-offset", parse_date( arg ) ); - fgSetString("/sim/startup/time-offset-type", "gmt"); + long int theTime = parse_date( arg, "gmt" ); + if (theTime>=0) + { + fgSetLong("/sim/startup/time-offset", theTime); + fgSetString("/sim/startup/time-offset-type", "gmt"); + } return FG_OPTIONS_OK; } diff --git a/src/Time/TimeManager.cxx b/src/Time/TimeManager.cxx index 5c5fd01a0..f19761ef5 100644 --- a/src/Time/TimeManager.cxx +++ b/src/Time/TimeManager.cxx @@ -302,12 +302,12 @@ void TimeManager::updateLocalTime() void TimeManager::initTimeOffset() { - int offset = fgGetInt("/sim/startup/time-offset"); + long int offset = fgGetLong("/sim/startup/time-offset"); string offset_type = fgGetString("/sim/startup/time-offset-type"); setTimeOffset(offset_type, offset); } -void TimeManager::setTimeOffset(const std::string& offset_type, int offset) +void TimeManager::setTimeOffset(const std::string& offset_type, long int offset) { // Handle potential user specified time offsets int orig_warp = _warp->getIntValue(); diff --git a/src/Time/TimeManager.hxx b/src/Time/TimeManager.hxx index 7ee53ecb4..6f0d35acb 100644 --- a/src/Time/TimeManager.hxx +++ b/src/Time/TimeManager.hxx @@ -44,7 +44,7 @@ public: // SGPropertyChangeListener overrides virtual void valueChanged(SGPropertyNode *); - void setTimeOffset(const std::string& offset_type, int offset); + void setTimeOffset(const std::string& offset_type, long int offset); private: /** -- 2.39.5