]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/options.cxx
Hopefully fix the shadow disappearing because of range animation issue in a more...
[flightgear.git] / src / Main / options.cxx
index d6ab0b7dffa08d7f58f2f397212c6e37b5123325..78ec58d87138524195ee0ebcafb7e92de92fa8d6 100644 (file)
@@ -79,6 +79,8 @@ using std::sort;
 using std::cout;
 using std::cerr;
 using std::endl;
+using std::vector;
+using std::cin;
 
 #define NEW_DEFAULT_MODEL_HZ 120
 
@@ -174,7 +176,7 @@ fgSetDefaults ()
     // specified so we can do the right thing for voodoo-1/2 cards.
     // fgSetString("/sim/startup/mouse-pointer", "disabled");
     fgSetString("/sim/control-mode", "joystick");
-    fgSetBool("/sim/auto-coordination", false);
+    fgSetBool("/controls/flight/auto-coordination", false);
 #if defined(WIN32)
     fgSetString("/sim/startup/browser-app", "webrun.bat");
 #elif defined(__APPLE__)
@@ -182,7 +184,7 @@ fgSetDefaults ()
 #elif defined(sgi)
     fgSetString("/sim/startup/browser-app", "launchWebJumper");
 #else
-    char* browserEnv = ::getenv( "WEBBROWSER" );
+    const char* browserEnv = ::getenv( "WEBBROWSER" );
     if (!browserEnv) browserEnv = "netscape";
     fgSetString("/sim/startup/browser-app", browserEnv);
 #endif
@@ -282,6 +284,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) {
@@ -363,112 +415,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);
 }
 
@@ -485,9 +488,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);
 
@@ -810,7 +813,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;
@@ -819,24 +822,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;
 }
 
@@ -885,29 +900,20 @@ fgOptTraceRead( const char *arg )
 static int
 fgOptLogLevel( const char *arg )
 {
-    fgSetString("/sim/logging/classes", "all");
     fgSetString("/sim/logging/priority", arg);
-
-    string priority = arg;
-    logbuf::set_log_classes(SG_ALL);
-    if (priority == "bulk") {
-      logbuf::set_log_priority(SG_BULK);
-    } else if (priority == "debug") {
-      logbuf::set_log_priority(SG_DEBUG);
-    } else if (priority == "info") {
-      logbuf::set_log_priority(SG_INFO);
-    } else if (priority == "warn") {
-      logbuf::set_log_priority(SG_WARN);
-    } else if (priority == "alert") {
-      logbuf::set_log_priority(SG_ALERT);
-    } else {
-      SG_LOG(SG_GENERAL, SG_WARN, "Unknown logging priority " << priority);
-    }
-    SG_LOG(SG_GENERAL, SG_DEBUG, "Logging priority is " << priority);
+    setLoggingPriority(arg);
 
     return FG_OPTIONS_OK;
 }
 
+static int
+fgOptLogClasses( const char *arg )
+{
+    fgSetString("/sim/logging/classes", arg);
+    setLoggingClasses (arg);
+
+    return FG_OPTIONS_OK;
+}
 
 static int
 fgOptTraceWrite( const char *arg )
@@ -1325,6 +1331,8 @@ struct OptionDesc {
     } fgOptionArray[] = {
 
     {"language",                     true,  OPTION_FUNC,   "", false, "", fgOptLanguage },
+    {"disable-rembrandt",            false, OPTION_BOOL,   "/sim/rendering/rembrandt", false, "", 0 },
+    {"enable-rembrandt",             false, OPTION_BOOL,   "/sim/rendering/rembrandt", true, "", 0 },
     {"disable-game-mode",            false, OPTION_BOOL,   "/sim/startup/game-mode", false, "", 0 },
     {"enable-game-mode",             false, OPTION_BOOL,   "/sim/startup/game-mode", true, "", 0 },
     {"disable-splash-screen",        false, OPTION_BOOL,   "/sim/startup/splash-screen", false, "", 0 },
@@ -1353,8 +1361,8 @@ struct OptionDesc {
     {"disable-anti-alias-hud",       false, OPTION_BOOL,   "/sim/hud/color/antialiased", false, "", 0 },
     {"enable-anti-alias-hud",        false, OPTION_BOOL,   "/sim/hud/color/antialiased", true, "", 0 },
     {"control",                      true,  OPTION_STRING, "/sim/control-mode", false, "", 0 },
-    {"disable-auto-coordination",    false, OPTION_BOOL,   "/sim/auto-coordination", false, "", 0 },
-    {"enable-auto-coordination",     false, OPTION_BOOL,   "/sim/auto-coordination", true, "", 0 },
+    {"disable-auto-coordination",    false, OPTION_BOOL,   "/controls/flight/auto-coordination", false, "", 0 },
+    {"enable-auto-coordination",     false, OPTION_BOOL,   "/controls/flight/auto-coordination", true, "", 0 },
     {"browser-app",                  true,  OPTION_STRING, "/sim/startup/browser-app", false, "", 0 },
     {"disable-hud",                  false, OPTION_BOOL,   "/sim/hud/visibility[1]", false, "", 0 },
     {"enable-hud",                   false, OPTION_BOOL,   "/sim/hud/visibility[1]", true, "", 0 },
@@ -1451,25 +1459,25 @@ struct OptionDesc {
     {"hud-tris",                     false, OPTION_STRING, "/sim/hud/frame-stat-type", false, "tris", 0 },
     {"hud-culled",                   false, OPTION_STRING, "/sim/hud/frame-stat-type", false, "culled", 0 },
     {"atcsim",                       true,  OPTION_CHANNEL, "", false, "dummy", 0 },
-    {"atlas",                        true,  OPTION_CHANNEL, "", false, "", 0 },
+    {"atlas",                        true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
     {"httpd",                        true,  OPTION_CHANNEL, "", false, "", 0 },
 #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 },
-    {"nmea",                         true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"generic",                      true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"props",                        true,  OPTION_CHANNEL, "", false, "", 0 },
-    {"telnet",                       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 },
+    {"telnet",                       true,  OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
     {"pve",                          true,  OPTION_CHANNEL, "", false, "", 0 },
     {"ray",                          true,  OPTION_CHANNEL, "", false, "", 0 },
     {"rul",                          true,  OPTION_CHANNEL, "", false, "", 0 },
@@ -1477,13 +1485,14 @@ 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 },
+    {"log-class",                    true,  OPTION_FUNC,   "", false, "", fgOptLogClasses },
     {"view-offset",                  true,  OPTION_FUNC | OPTION_MULTI,   "", false, "", fgOptViewOffset },
     {"visibility",                   true,  OPTION_FUNC,   "", false, "", fgOptVisibilityMeters },
     {"visibility-miles",             true,  OPTION_FUNC,   "", false, "", fgOptVisibilityMiles },
@@ -1546,6 +1555,10 @@ public:
   {
     OptionValueVec::const_iterator it = values.begin();
     for (; it != values.end(); ++it) {
+      if (!it->desc) {
+        continue; // ignore markers
+      }
+      
       if (it->desc->option == key) {
         return it;
       }
@@ -1566,6 +1579,10 @@ public:
   
   int processOption(OptionDesc* desc, const string& arg_value)
   {
+    if (!desc) {
+      return FG_OPTIONS_OK; // tolerate marker options
+    }
+    
     switch ( desc->type & 0xffff ) {
       case OPTION_BOOL:
         fgSetBool( desc->property, desc->b_param );
@@ -1633,10 +1650,36 @@ public:
     
     return FG_OPTIONS_OK;
   }
+    
+  /**
+   * insert a marker value into the values vector. This is necessary
+   * when processing options, to ensure the correct ordering, where we scan
+   * for marker values in reverse, and then forwards within each group.
+   */
+  void insertGroupMarker()
+  {
+    values.push_back(OptionValue(NULL, "-"));
+  }
+  
+  /**
+   * given a current iterator into the values, find the preceeding group marker,
+   * or return the beginning of the value vector.
+   */
+  OptionValueVec::const_iterator rfindGroup(OptionValueVec::const_iterator pos) const
+  {
+    while (--pos != values.begin()) {
+      if (pos->desc == NULL) {
+        return pos; // found a marker, we're done
+      }
+    }
+    
+    return pos;
+  }
   
   bool showHelp,
     verbose,
     showAircraft;
+
   OptionDescDict options;
   OptionValueVec values;
   simgear::PathList propertyFiles;
@@ -1661,7 +1704,8 @@ Options::Options() :
 // build option map
   OptionDesc *desc = &fgOptionArray[ 0 ];
   while ( desc->option != 0 ) {
-    p->options[ desc->option ] = desc++;
+    p->options[ desc->option ] = desc;
+    ++desc;
   }
 }
   
@@ -1669,7 +1713,7 @@ Options::~Options()
 {
 }
   
-void Options::init(int argc, char **argv)
+void Options::init(int argc, char **argv, const SGPath& appDataPath)
 {
   fgSetDefaults();
   
@@ -1695,6 +1739,7 @@ void Options::init(int argc, char **argv)
       p->propertyFiles.push_back(f);
     }
   } // of arguments iteration
+  p->insertGroupMarker(); // command line is one group
   
 // then config files
   SGPath config;
@@ -1715,6 +1760,13 @@ void Options::init(int argc, char **argv)
     readConfig(config);
   }
   
+// check for a config file in app data
+  SGPath appDataConfig(appDataPath);
+  appDataConfig.append("fgfsrc");
+  if (appDataConfig.exists()) {
+    readConfig(appDataConfig);
+  }
+  
 // setup FG_ROOT
   setupRoot();
   
@@ -1828,6 +1880,7 @@ void Options::readConfig(const SGPath& path)
     in >> skipcomment;
   }
 
+  p->insertGroupMarker(); // each config file is a group
 }
   
 int Options::parseOption(const string& s)
@@ -1876,6 +1929,7 @@ int Options::addOption(const string &key, const string &value)
 {
   OptionDesc* desc = p->findOption(key);
   if (!desc) {
+    SG_LOG(SG_GENERAL, SG_ALERT, "unknown option:" << key);
     return FG_OPTIONS_ERROR;
   }
   
@@ -1912,6 +1966,10 @@ string_list Options::valuesForOption(const std::string& key) const
   string_list result;
   OptionValueVec::const_iterator it = p->values.begin();
   for (; it != p->values.end(); ++it) {
+    if (!it->desc) {
+      continue; // ignore marker values
+    }
+    
     if (it->desc->option == key) {
       result.push_back(it->value);
     }
@@ -1929,12 +1987,33 @@ void Options::processOptions()
     exit(0);
   }
   
-  BOOST_FOREACH(const OptionValue& v, p->values) {
-    int result = p->processOption(v.desc, v.value);
-    if (result == FG_OPTIONS_ERROR) {
-      showUsage();
-      exit(-1);
+  // processing order is complicated. We must process groups LIFO, but the
+  // values *within* each group in FIFO order, to retain consistency with
+  // older versions of FG, and existing user configs.
+  // in practice this means system.fgfsrc must be *processed* before
+  // .fgfsrc, which must be processed before the command line args, and so on.
+  OptionValueVec::const_iterator groupEnd = p->values.end();
+    
+  while (groupEnd != p->values.begin()) {
+    OptionValueVec::const_iterator groupBegin = p->rfindGroup(groupEnd);
+  // run over the group in FIFO order
+    OptionValueVec::const_iterator it;
+    for (it = groupBegin; it != groupEnd; ++it) {      
+      int result = p->processOption(it->desc, it->value);
+      switch(result)
+      {
+          case FG_OPTIONS_ERROR:
+              showUsage();
+              exit(-1); // exit and return an error
+          case FG_OPTIONS_EXIT:
+              exit(0);  // clean exit
+              break;
+          default:
+              break;
+      }
     }
+    
+    groupEnd = groupBegin;
   }
   
   BOOST_FOREACH(const SGPath& file, p->propertyFiles) {
@@ -1953,9 +2032,33 @@ void Options::processOptions()
   if (envp) {
     globals->append_fg_scenery(envp);
   }
+    
+// terrasync directory fixup
+  if (fgGetBool("/sim/terrasync/enabled")) {
+    string terrasyncDir = fgGetString("/sim/terrasync/scenery-dir");
+    if (terrasyncDir.empty()) {
+      SGPath p(fgGetString("/sim/fg-home"));
+      p.append("TerraSync");
+      if (!p.exists()) {
+        simgear::Dir dd(p);
+        dd.create(0700);
+      }
+      
+      terrasyncDir = p.str();
+      SG_LOG(SG_GENERAL, SG_INFO,
+             "Using default TerraSync dir: " << terrasyncDir);
+      fgSetString("/sim/terrasync/scenery-dir", terrasyncDir);
+    }
+    
+    const string_list& scenery_paths(globals->get_fg_scenery());
+    if (std::find(scenery_paths.begin(), scenery_paths.end(), terrasyncDir) == scenery_paths.end()) {
+      // terrasync dir is not in the scenery paths, add it
+      globals->append_fg_scenery(terrasyncDir);
+    }
+  }
   
   if (globals->get_fg_scenery().empty()) {
-  // no scenery paths set *at all*, use the data in FG_ROOT
+    // no scenery paths set *at all*, use the data in FG_ROOT
     SGPath root(globals->get_fg_root());
     root.append("Scenery");
     globals->append_fg_scenery(root.str());
@@ -2088,8 +2191,8 @@ void Options::showUsage() const
     cout << "For a complete list of options use --help --verbose" << endl;
   }
 #ifdef _MSC_VER
-  cout << "Hit a key to continue..." << endl;
-  cin.get();
+  std::cout << "Hit a key to continue..." << std::endl;
+  std::cin.get();
 #endif
 }
   
@@ -2152,7 +2255,7 @@ void Options::setupRoot()
   globals->set_fg_root(root);
   
 // validate it
-  static char required_version[] = "2.5.0";
+  static char required_version[] = FLIGHTGEAR_VERSION;
   string base_version = fgBasePackageVersion();
   if ( !(base_version == required_version) ) {
     // tell the operator how to use this application