]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/options.cxx
Refactor SGSky handling and ownership - sink into Renderer, remove global variable...
[flightgear.git] / src / Main / options.cxx
index 5071f43624d9ba2b4abfc99684620c11bc128d0d..bcb5ccdad98cdb54fe941659ed60330e59dfbca0 100644 (file)
@@ -283,6 +283,56 @@ 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;
+    }
+}
+
 // parse a time string ([+/-]%f[:%f[:%f]]) into hours
 static double
 parse_time(const string& time_in) {
@@ -364,112 +414,63 @@ parse_time(const string& time_in) {
     return(sign * result);
 }
 
-
 // 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 +487,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 +812,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 +821,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;
 }
 
@@ -1457,16 +1470,16 @@ struct OptionDesc {
 #ifdef FG_JPEG_SERVER
     {"jpg-httpd",                    true,  OPTION_CHANNEL, "", false, "", 0 },
 #endif
-    {"native",                       true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"native-ctrls",                 true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"native-fdm",                   true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"native-gui",                   true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"opengc",                       true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"AV400",                        true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"AV400Sim",                     true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"AV400WSimA",                   true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"AV400WSimB",                   true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"garmin",                       true,  OPTION_CHANNEL, "", false, "", 0 },
+    {"native",                       true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"native-ctrls",                 true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"native-fdm",                   true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"native-gui",                   true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"opengc",                       true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"AV400",                        true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"AV400Sim",                     true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"AV400WSimA",                   true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"AV400WSimB",                   true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+    {"garmin",                       true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
     {"nmea",                         true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
     {"generic",                      true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
     {"props",                        true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
@@ -1478,12 +1491,12 @@ struct OptionDesc {
     {"jsclient",                     true,  OPTION_CHANNEL, "", false, "", 0 },
     {"proxy",                        true,  OPTION_FUNC,    "", false, "", fgSetupProxy },
     {"callsign",                     true,  OPTION_FUNC,    "", false, "", fgOptCallSign},
-    {"multiplay",                    true,  OPTION_CHANNEL, "", false, "", 0 },
+    {"multiplay",                    true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
 #ifdef FG_HAVE_HLA
     {"hla",                          true,  OPTION_CHANNEL, "", false, "", 0 },
 #endif
-    {"trace-read",                   true,  OPTION_FUNC,   "", false, "", fgOptTraceRead },
-    {"trace-write",                  true,  OPTION_FUNC,   "", false, "", fgOptTraceWrite },
+    {"trace-read",                   true,  OPTION_FUNC | OPTION_MULTI,   "", false, "", fgOptTraceRead },
+    {"trace-write",                  true,  OPTION_FUNC | OPTION_MULTI,   "", false, "", fgOptTraceWrite },
     {"log-level",                    true,  OPTION_FUNC,   "", false, "", fgOptLogLevel },
     {"view-offset",                  true,  OPTION_FUNC | OPTION_MULTI,   "", false, "", fgOptViewOffset },
     {"visibility",                   true,  OPTION_FUNC,   "", false, "", fgOptVisibilityMeters },
@@ -1938,14 +1951,17 @@ void Options::processOptions()
     exit(0);
   }
   
-  BOOST_FOREACH(const OptionValue& v, p->values) {
-    int result = p->processOption(v.desc, v.value);
+  // proces options in LIFO order, so earlier (first in) options are processed
+  // after, and hence override, later specified options.
+  OptionValueVec::const_reverse_iterator it = p->values.rbegin();
+  for (; it != p->values.rend(); ++it) {
+    int result = p->processOption(it->desc, it->value);
     if (result == FG_OPTIONS_ERROR) {
       showUsage();
       exit(-1);
     }
   }
-  
+
   BOOST_FOREACH(const SGPath& file, p->propertyFiles) {
     if (!file.exists()) {
       SG_LOG(SG_GENERAL, SG_ALERT, "config file not found:" << file.str());