#include <boost/foreach.hpp>
-#include <math.h> // rint()
+#include <cmath> // rint()
#include <stdio.h>
-#include <stdlib.h> // atof(), atoi()
-#include <string.h> // strcmp()
+#include <stdlib.h> // atof(), atoi()
+#include <string.h> // strcmp()
#include <algorithm>
#include <iostream>
#include <string>
+#include <sstream>
#include <simgear/math/sg_random.h>
#include <simgear/props/props_io.hxx>
#include <simgear/sound/soundmgr_openal.hxx>
#include <simgear/misc/strutils.hxx>
#include <Autopilot/route_mgr.hxx>
+#include <Aircraft/replay.hxx>
+
#include <GUI/gui.h>
+#include <GUI/MessageBox.hxx>
+#if defined(HAVE_QT)
+#include <GUI/QtLauncher.hxx>
+#include <GUI/SetupRootDialog.hxx>
+#endif
+#include <Main/locale.hxx>
#include "globals.hxx"
#include "fg_init.hxx"
#include "fg_props.hxx"
#include "options.hxx"
#include "util.hxx"
-#include "viewmgr.hxx"
-#include <Main/viewer.hxx>
+#include "main.hxx"
+#include "locale.hxx"
+#include <Viewer/view.hxx>
+#include <Viewer/viewmgr.hxx>
#include <Environment/presets.hxx>
+#include <Network/http/httpd.hxx>
+#include "AircraftDirVisitorBase.hxx"
#include <osg/Version>
-
-#if defined( HAVE_VERSION_H ) && HAVE_VERSION_H
-# include <Include/version.h>
-# include <simgear/version.h>
-#else
-# include <Include/no_version.h>
-#endif
-
-#ifdef __APPLE__
-# include <CoreFoundation/CoreFoundation.h>
-#endif
+#include <Include/version.h>
+#include <simgear/version.h>
using std::string;
using std::sort;
using std::vector;
using std::cin;
-#define NEW_DEFAULT_MODEL_HZ 120
-
-// defined in bootstrap.cxx
-extern char *homedir;
-extern char *hostname;
+using namespace flightgear;
-enum
-{
- FG_OPTIONS_OK = 0,
- FG_OPTIONS_HELP = 1,
- FG_OPTIONS_ERROR = 2,
- FG_OPTIONS_EXIT = 3,
- FG_OPTIONS_VERBOSE_HELP = 4,
- FG_OPTIONS_SHOW_AIRCRAFT = 5,
- FG_OPTIONS_SHOW_SOUND_DEVICES = 6
-};
+#define NEW_DEFAULT_MODEL_HZ 120
static flightgear::Options* shared_instance = NULL;
* in case, we provide some initial sane values here. This method
* should be invoked *before* reading any init files.
*/
-static void
-fgSetDefaults ()
+void fgSetDefaults ()
{
// Position (deliberately out of range)
fgSetBool("/sim/presets/trim", false);
// Miscellaneous
- fgSetBool("/sim/startup/game-mode", false);
fgSetBool("/sim/startup/splash-screen", true);
- fgSetBool("/sim/startup/intro-music", true);
// we want mouse-pointer to have an undefined value if nothing is
// 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("/controls/flight/auto-coordination", false);
-#if defined(WIN32)
- fgSetString("/sim/startup/browser-app", "webrun.bat");
-#elif defined(__APPLE__)
- fgSetString("/sim/startup/browser-app", "open");
-#elif defined(sgi)
- fgSetString("/sim/startup/browser-app", "launchWebJumper");
-#else
- const char* browserEnv = ::getenv( "WEBBROWSER" );
- if (!browserEnv) browserEnv = "netscape";
- fgSetString("/sim/startup/browser-app", browserEnv);
-#endif
fgSetString("/sim/logging/priority", "alert");
// Features
fgSetBool("/sim/panel/visibility", true);
fgSetBool("/sim/sound/enabled", true);
fgSetBool("/sim/sound/working", true);
+ fgSetBool("/sim/fgcom/enabled", false);
// Flight Model options
fgSetString("/sim/flight-model", "jsb");
fgSetString("/sim/aero", "c172");
fgSetInt("/sim/model-hz", NEW_DEFAULT_MODEL_HZ);
- fgSetInt("/sim/speed-up", 1);
+ fgSetDouble("/sim/speed-up", 1.0);
// Rendering options
fgSetString("/sim/rendering/fog", "nicest");
fgSetBool("/environment/clouds/status", true);
fgSetBool("/sim/startup/fullscreen", false);
fgSetBool("/sim/rendering/shading", true);
- fgSetBool("/sim/rendering/skyblend", true);
- fgSetBool("/sim/rendering/textures", true);
fgTie( "/sim/rendering/filtering", SGGetTextureFilter, SGSetTextureFilter, false);
fgSetInt("/sim/rendering/filtering", 1);
fgSetBool("/sim/rendering/wireframe", false);
fgSetBool("/sim/rendering/distance-attenuation", false);
fgSetBool("/sim/rendering/specular-highlight", true);
fgSetString("/sim/rendering/materials-file", "materials.xml");
- fgSetInt("/sim/startup/xsize", 800);
- fgSetInt("/sim/startup/ysize", 600);
- fgSetInt("/sim/rendering/bits-per-pixel", 16);
+ fgSetInt("/sim/startup/xsize", 1024);
+ fgSetInt("/sim/startup/ysize", 768);
+ fgSetInt("/sim/rendering/bits-per-pixel", 32);
fgSetString("/sim/view-mode", "pilot");
fgSetDouble("/sim/current-view/heading-offset-deg", 0);
fgSetInt("/sim/multiplay/rxport", 0);
fgSetInt("/sim/multiplay/txport", 0);
- fgSetString("/sim/version/flightgear", FLIGHTGEAR_VERSION);
- fgSetString("/sim/version/simgear", SG_STRINGIZE(SIMGEAR_VERSION));
- fgSetString("/sim/version/openscenegraph", osgGetVersion());
- fgSetString("/sim/version/revision", REVISION);
- fgSetInt("/sim/version/build-number", HUDSON_BUILD_NUMBER);
- fgSetString("/sim/version/build-id", HUDSON_BUILD_ID);
-
- char* envp = ::getenv( "http_proxy" );
+ SGPropertyNode* v = globals->get_props()->getNode("/sim/version", true);
+ v->setValueReadOnly("flightgear", FLIGHTGEAR_VERSION);
+ v->setValueReadOnly("simgear", SG_STRINGIZE(SIMGEAR_VERSION));
+ v->setValueReadOnly("openscenegraph", osgGetVersion());
+ v->setValueReadOnly("openscenegraph-thread-safe-reference-counting",
+ osg::Referenced::getThreadSafeReferenceCounting());
+ v->setValueReadOnly("revision", REVISION);
+ v->setValueReadOnly("build-number", HUDSON_BUILD_NUMBER);
+ v->setValueReadOnly("build-id", HUDSON_BUILD_ID);
+ v->setValueReadOnly("hla-support", bool(FG_HAVE_HLA));
+#if defined(FG_NIGHTLY)
+ v->setValueReadOnly("nightly-build", true);
+#else
+ v->setValueReadOnly("nightly-build", false);
+#endif
+
+ char* envp = ::getenv( "http_proxy" );
if( envp != NULL )
fgSetupProxy( envp );
}
+///////////////////////////////////////////////////////////////////////////////
+// helper object to implement the --show-aircraft command.
+// resides here so we can share the fgFindAircraftInDir template above,
+// and hence ensure this command lists exectly the same aircraft as the normal
+// loading path.
+class ShowAircraft : public AircraftDirVistorBase
+{
+public:
+ ShowAircraft()
+ {
+ _minStatus = getNumMaturity(fgGetString("/sim/aircraft-min-status", "all"));
+ }
+
+
+ void show(const vector<SGPath> & path_list)
+ {
+ for (vector<SGPath>::const_iterator p = path_list.begin();
+ p != path_list.end(); ++p)
+ visitDir(*p, 0);
+
+ simgear::requestConsole(); // ensure console is shown on Windows
+
+ std::sort(_aircraft.begin(), _aircraft.end(), ciLessLibC());
+ cout << "Available aircraft:" << endl;
+ for ( unsigned int i = 0; i < _aircraft.size(); i++ ) {
+ cout << _aircraft[i] << endl;
+ }
+ }
+
+private:
+ virtual VisitResult visit(const SGPath& path)
+ {
+ SGPropertyNode root;
+ try {
+ readProperties(path.str(), &root);
+ } catch (sg_exception& ) {
+ return VISIT_CONTINUE;
+ }
+
+ int maturity = 0;
+ string descStr(" ");
+ descStr += path.file();
+ // trim common suffix from file names
+ int nPos = descStr.rfind("-set.xml");
+ if (nPos == (int)(descStr.size() - 8)) {
+ descStr.resize(nPos);
+ }
+
+ SGPropertyNode *node = root.getNode("sim");
+ if (node) {
+ SGPropertyNode* desc = node->getNode("description");
+ // if a status tag is found, read it in
+ if (node->hasValue("status")) {
+ maturity = getNumMaturity(node->getStringValue("status"));
+ }
+
+ if (desc) {
+ if (descStr.size() <= 27+3) {
+ descStr.append(29+3-descStr.size(), ' ');
+ } else {
+ descStr += '\n';
+ descStr.append( 32, ' ');
+ }
+ descStr += desc->getStringValue();
+ }
+ } // of have 'sim' node
+
+ if (maturity >= _minStatus) {
+ _aircraft.push_back(descStr);
+ }
+
+ return VISIT_CONTINUE;
+ }
+
+
+ int getNumMaturity(const char * str)
+ {
+ // changes should also be reflected in $FG_ROOT/data/options.xml &
+ // $FG_ROOT/data/Translations/string-default.xml
+ const char* levels[] = {"alpha","beta","early-production","production"};
+
+ if (!strcmp(str, "all")) {
+ return 0;
+ }
+
+ for (size_t i=0; i<(sizeof(levels)/sizeof(levels[0]));i++)
+ if (strcmp(str,levels[i])==0)
+ return i;
+
+ return 0;
+ }
+
+ // recommended in Meyers, Effective STL when internationalization and embedded
+ // NULLs aren't an issue. Much faster than the STL or Boost lex versions.
+ struct ciLessLibC : public std::binary_function<string, string, bool>
+ {
+ bool operator()(const std::string &lhs, const std::string &rhs) const
+ {
+ return strcasecmp(lhs.c_str(), rhs.c_str()) < 0 ? 1 : 0;
+ }
+ };
+
+ int _minStatus;
+ string_list _aircraft;
+};
+
+/*
+ * Search in the current directory, and in on directory deeper
+ * for <aircraft>-set.xml configuration files and show the aircaft name
+ * and the contents of the<description> tag in a sorted manner.
+ *
+ * @parampath the directory to search for configuration files
+ */
+void fgShowAircraft(const vector<SGPath> &path_list)
+{
+ ShowAircraft s;
+ s.show(path_list);
+
+#ifdef _MSC_VER
+ cout << "Hit a key to continue..." << endl;
+ std::cin.get();
+#endif
+}
+
+
static bool
parse_wind (const string &wind, double * min_hdg, double * max_hdg,
double * speed, double * gust)
int year,month,day,hour,minute,second;
char *argument, *date_str;
- SGTime CurrentTime = SGTime();
- CurrentTime.update(0,0,0,0);
+ SGTime CurrentTime;
+ CurrentTime.update(SGGeod(),0,0);
// FIXME This should obtain system/aircraft/GMT time depending on timeType
pCurrentTime = CurrentTime.getGmt();
return true;
}
-static int
-fgOptLanguage( const char *arg )
-{
- globals->set_locale( fgInitLocale( arg ) );
- return FG_OPTIONS_OK;
-}
-
static void
clearLocation ()
{
static int
fgOptRoc( const char *arg )
{
- fgSetDouble("/velocities/vertical-speed-fps", atof(arg)/60);
+ fgSetDouble("/sim/presets/vertical-speed-fps", atof(arg)/60);
return FG_OPTIONS_OK;
}
static int
fgOptFgScenery( const char *arg )
{
- globals->append_fg_scenery(arg);
+ globals->append_fg_scenery(arg, true);
+ return FG_OPTIONS_OK;
+}
+
+static int
+fgOptTerrasyncDir( const char *arg )
+{
+ globals->append_fg_scenery(arg, true);
+ fgSetString("/sim/terrasync/scenery-dir", arg);
return FG_OPTIONS_OK;
}
return FG_OPTIONS_OK;
}
+static int
+fgOptJpgHttpd( const char * arg )
+{
+ SG_LOG(SG_ALL,SG_ALERT,
+ "the option --jpg-httpd is no longer supported! Please use --httpd instead."
+ " URL for the screenshot within the new httpd is http://YourFgServer:xxxx/screenshot");
+ return FG_OPTIONS_EXIT;
+}
+
+static int
+fgOptHttpd( const char * arg )
+{
+ // port may be any valid address:port notation
+ // like 127.0.0.1:8080
+ // or just the port 8080
+ string port = simgear::strutils::strip(string(arg));
+ if( port.empty() ) return FG_OPTIONS_ERROR;
+ fgSetString( string(flightgear::http::PROPERTY_ROOT).append("/options/listening-port").c_str(), port );
+ return FG_OPTIONS_OK;
+}
+
static int
fgSetupProxy( const char *arg )
{
return FG_OPTIONS_OK;
}
+static int
+fgOptMetar( const char *arg )
+{
+ // The given METAR string cannot be effective without disabling
+ // real weather fetching.
+ fgSetBool("/environment/realwx/enabled", false);
+ // The user-supplied METAR string
+ fgSetString("/environment/metar/data", arg);
+
+ return FG_OPTIONS_OK;
+}
+
static int
fgOptRandomWind( const char *arg )
{
{
string file = arg;
try {
- readProperties(file, globals->get_props());
+ readProperties(file, globals->get_props());
} catch (const sg_exception &e) {
- string message = "Error loading config file: ";
- message += e.getFormattedMessage() + e.getOrigin();
- SG_LOG(SG_INPUT, SG_ALERT, message);
- exit(2);
+ string message = "Error loading config file: ";
+ message += e.getFormattedMessage() + e.getOrigin();
+ SG_LOG(SG_INPUT, SG_ALERT, message);
+ return FG_OPTIONS_ERROR;
}
return FG_OPTIONS_OK;
}
}
SGPropertyNode_ptr scenario = ai_node->getNode( "scenario", index + 1, true );
scenario->setStringValue( arg );
- ai_node->setBoolValue( "enabled", true );
- return FG_OPTIONS_OK;
-}
-
-static int
-fgOptNoScenarios( const char *arg )
-{
- SGPropertyNode_ptr ai_node = fgGetNode( "/sim/ai", true );
- ai_node->removeChildren("scenario",false);
- ai_node->setBoolValue( "enabled", false );
return FG_OPTIONS_OK;
}
cerr << "Revision: " << REVISION << endl;
cerr << "Build-Id: " << HUDSON_BUILD_ID << endl;
cerr << "FG_ROOT=" << globals->get_fg_root() << endl;
- cerr << "FG_HOME=" << fgGetString("/sim/fg-home") << endl;
+ cerr << "FG_HOME=" << globals->get_fg_home() << endl;
cerr << "FG_SCENERY=";
int didsome = 0;
}
cerr << endl;
cerr << "SimGear version: " << SG_STRINGIZE(SIMGEAR_VERSION) << endl;
+ cerr << "OSG version: " << osgGetVersion() << endl;
cerr << "PLIB version: " << PLIB_VERSION << endl;
return FG_OPTIONS_EXIT;
}
return FG_OPTIONS_OK;
}
+static int
+fgOptIgnoreAutosave(const char* arg)
+{
+ fgSetBool("/sim/startup/ignore-autosave", true);
+ // don't overwrite autosave on exit
+ fgSetBool("/sim/startup/save-on-exit", false);
+ return FG_OPTIONS_OK;
+}
+
+static int
+fgOptEnableFreeze(const char* arg)
+{
+ fgSetBool("/sim/freeze/master", true);
+ fgSetBool("/sim/freeze/clock", true);
+ return FG_OPTIONS_OK;
+}
+
+static int
+fgOptDisableFreeze(const char* arg)
+{
+ fgSetBool("/sim/freeze/master", false);
+ fgSetBool("/sim/freeze/clock", false);
+ return FG_OPTIONS_OK;
+}
// Set a property for the --prop: option. Syntax: --prop:[<type>:]<name>=<value>
// <type> can be "double" etc. but also only the first letter "d".
return ret ? FG_OPTIONS_OK : FG_OPTIONS_ERROR;
}
+static int
+fgOptLoadTape(const char* arg)
+{
+ // load a flight recorder tape but wait until the fdm is initialized
+ class DelayedTapeLoader : SGPropertyChangeListener {
+ public:
+ DelayedTapeLoader( const char * tape ) :
+ _tape(tape)
+ {
+ SGPropertyNode_ptr n = fgGetNode("/sim/signals/fdm-initialized", true);
+ n->addChangeListener( this );
+ }
+
+ virtual ~ DelayedTapeLoader() {}
+
+ virtual void valueChanged(SGPropertyNode * node)
+ {
+ node->removeChangeListener( this );
+
+ // tell the replay subsystem to load the tape
+ FGReplay* replay = (FGReplay*) globals->get_subsystem("replay");
+ SGPropertyNode_ptr arg = new SGPropertyNode();
+ arg->setStringValue("tape", _tape );
+ arg->setBoolValue( "same-aircraft", 0 );
+ replay->loadTape(arg);
+
+ delete this; // commence suicide
+ }
+ private:
+ std::string _tape;
+
+ };
+
+ new DelayedTapeLoader(arg);
+ return FG_OPTIONS_OK;
+}
+
/*
int (*func)( const char * );
} fgOptionArray[] = {
- {"language", true, OPTION_FUNC, "", false, "", fgOptLanguage },
- {"disable-game-mode", false, OPTION_BOOL, "/sim/startup/game-mode", false, "", 0 },
- {"enable-game-mode", false, OPTION_BOOL, "/sim/startup/game-mode", true, "", 0 },
+ {"language", true, OPTION_IGNORE, "", false, "", 0 },
+ {"console", false, OPTION_IGNORE, "", false, "", 0 },
+ {"launcher", false, OPTION_IGNORE, "", false, "", 0 },
+ {"disable-rembrandt", false, OPTION_BOOL, "/sim/rendering/rembrandt/enabled", false, "", 0 },
+ {"enable-rembrandt", false, OPTION_BOOL, "/sim/rendering/rembrandt/enabled", true, "", 0 },
+ {"renderer", true, OPTION_STRING, "/sim/rendering/rembrandt/renderer", false, "", 0 },
{"disable-splash-screen", false, OPTION_BOOL, "/sim/startup/splash-screen", false, "", 0 },
{"enable-splash-screen", false, OPTION_BOOL, "/sim/startup/splash-screen", true, "", 0 },
- {"disable-intro-music", false, OPTION_BOOL, "/sim/startup/intro-music", false, "", 0 },
- {"enable-intro-music", false, OPTION_BOOL, "/sim/startup/intro-music", true, "", 0 },
{"disable-mouse-pointer", false, OPTION_STRING, "/sim/startup/mouse-pointer", false, "disabled", 0 },
{"enable-mouse-pointer", false, OPTION_STRING, "/sim/startup/mouse-pointer", false, "enabled", 0 },
{"disable-random-objects", false, OPTION_BOOL, "/sim/rendering/random-objects", false, "", 0 },
{"enable-random-objects", false, OPTION_BOOL, "/sim/rendering/random-objects", true, "", 0 },
+ {"disable-random-vegetation", false, OPTION_BOOL, "/sim/rendering/random-vegetation", false, "", 0 },
+ {"enable-random-vegetation", false, OPTION_BOOL, "/sim/rendering/random-vegetation", true, "", 0 },
+ {"disable-random-buildings", false, OPTION_BOOL, "/sim/rendering/random-buildings", false, "", 0 },
+ {"enable-random-buildings", false, OPTION_BOOL, "/sim/rendering/random-buildings", true, "", 0 },
{"disable-real-weather-fetch", false, OPTION_BOOL, "/environment/realwx/enabled", false, "", 0 },
{"enable-real-weather-fetch", false, OPTION_BOOL, "/environment/realwx/enabled", true, "", 0 },
- {"metar", true, OPTION_STRING, "/environment/metar/data", false, "", 0 },
+ {"metar", true, OPTION_FUNC, "", false, "", fgOptMetar },
{"disable-ai-models", false, OPTION_BOOL, "/sim/ai/enabled", false, "", 0 },
{"enable-ai-models", false, OPTION_BOOL, "/sim/ai/enabled", true, "", 0 },
{"disable-ai-traffic", false, OPTION_BOOL, "/sim/traffic-manager/enabled", false, "", 0 },
{"enable-ai-traffic", false, OPTION_BOOL, "/sim/traffic-manager/enabled", true, "", 0 },
- {"disable-freeze", false, OPTION_BOOL, "/sim/freeze/master", false, "", 0 },
- {"enable-freeze", false, OPTION_BOOL, "/sim/freeze/master", true, "", 0 },
+ {"disable-freeze", false, OPTION_FUNC, "", false, "", fgOptDisableFreeze },
+ {"enable-freeze", false, OPTION_FUNC, "", true, "", fgOptEnableFreeze },
{"disable-fuel-freeze", false, OPTION_BOOL, "/sim/freeze/fuel", false, "", 0 },
{"enable-fuel-freeze", false, OPTION_BOOL, "/sim/freeze/fuel", true, "", 0 },
{"disable-clock-freeze", false, OPTION_BOOL, "/sim/freeze/clock", false, "", 0 },
{"enable-hud-3d", false, OPTION_BOOL, "/sim/hud/enable3d[1]", true, "", 0 },
{"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, "/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 },
{"aero", true, OPTION_STRING, "/sim/aero", false, "", 0 },
{"aircraft-dir", true, OPTION_IGNORE, "", false, "", 0 },
{"model-hz", true, OPTION_INT, "/sim/model-hz", false, "", 0 },
- {"speed", true, OPTION_INT, "/sim/speed-up", false, "", 0 },
+ {"max-fps", true, OPTION_DOUBLE, "/sim/frame-rate-throttle-hz", false, "", 0 },
+ {"speed", true, OPTION_DOUBLE, "/sim/speed-up", false, "", 0 },
{"trim", false, OPTION_BOOL, "/sim/presets/trim", true, "", 0 },
{"notrim", false, OPTION_BOOL, "/sim/presets/trim", false, "", 0 },
{"on-ground", false, OPTION_BOOL, "/sim/presets/onground", true, "", 0 },
{"enable-fullscreen", false, OPTION_BOOL, "/sim/startup/fullscreen", true, "", 0 },
{"disable-save-on-exit", false, OPTION_BOOL, "/sim/startup/save-on-exit", false, "", 0 },
{"enable-save-on-exit", false, OPTION_BOOL, "/sim/startup/save-on-exit", true, "", 0 },
+ {"read-only", false, OPTION_BOOL, "/sim/fghome-readonly", true, "", 0 },
+ {"ignore-autosave", false, OPTION_FUNC, "", false, "", fgOptIgnoreAutosave },
+ {"restore-defaults", false, OPTION_BOOL, "/sim/startup/restore-defaults", true, "", 0 },
{"shading-flat", false, OPTION_BOOL, "/sim/rendering/shading", false, "", 0 },
{"shading-smooth", false, OPTION_BOOL, "/sim/rendering/shading", true, "", 0 },
- {"disable-skyblend", false, OPTION_BOOL, "/sim/rendering/skyblend", false, "", 0 },
- {"enable-skyblend", false, OPTION_BOOL, "/sim/rendering/skyblend", true, "", 0 },
- {"disable-textures", false, OPTION_BOOL, "/sim/rendering/textures", false, "", 0 },
- {"enable-textures", false, OPTION_BOOL, "/sim/rendering/textures", true, "", 0 },
{"texture-filtering", false, OPTION_INT, "/sim/rendering/filtering", 1, "", 0 },
{"disable-wireframe", false, OPTION_BOOL, "/sim/rendering/wireframe", false, "", 0 },
{"enable-wireframe", false, OPTION_BOOL, "/sim/rendering/wireframe", true, "", 0 },
{"materials-file", true, OPTION_STRING, "/sim/rendering/materials-file", false, "", 0 },
{"disable-terrasync", false, OPTION_BOOL, "/sim/terrasync/enabled", false, "", 0 },
{"enable-terrasync", false, OPTION_BOOL, "/sim/terrasync/enabled", true, "", 0 },
- {"terrasync-dir", true, OPTION_STRING, "/sim/terrasync/scenery-dir", false, "", 0 },
+ {"terrasync-dir", true, OPTION_FUNC, "", false, "", fgOptTerrasyncDir },
+ {"download-dir", true, OPTION_STRING, "/sim/paths/download-dir", false, "", 0 },
{"geometry", true, OPTION_FUNC, "", false, "", fgOptGeometry },
{"bpp", true, OPTION_FUNC, "", false, "", fgOptBpp },
{"units-feet", false, OPTION_STRING, "/sim/startup/units", false, "feet", 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 | OPTION_MULTI, "", false, "", 0 },
- {"httpd", true, OPTION_CHANNEL, "", false, "", 0 },
-#ifdef FG_JPEG_SERVER
- {"jpg-httpd", true, OPTION_CHANNEL, "", false, "", 0 },
-#endif
+ {"httpd", true, OPTION_FUNC , "", false, "", fgOptHttpd },
+ {"jpg-httpd", true, OPTION_FUNC, "", false, "", fgOptJpgHttpd },
{"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 },
{"AV400WSimA", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"AV400WSimB", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"garmin", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
+ {"igc", 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 },
{"proxy", true, OPTION_FUNC, "", false, "", fgSetupProxy },
{"callsign", true, OPTION_FUNC, "", false, "", fgOptCallSign},
{"multiplay", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
-#ifdef FG_HAVE_HLA
+#if FG_HAVE_HLA
{"hla", true, OPTION_CHANNEL, "", false, "", 0 },
+ {"hla-local", true, OPTION_CHANNEL, "", false, "", 0 },
#endif
{"trace-read", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptTraceRead },
{"trace-write", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptTraceWrite },
{"aircraft", true, OPTION_STRING, "/sim/aircraft", false, "", 0 },
{"vehicle", true, OPTION_STRING, "/sim/aircraft", false, "", 0 },
{"failure", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptFailure },
+#ifdef ENABLE_IAX
+ {"enable-fgcom", false, OPTION_BOOL, "/sim/fgcom/enabled", true, "", 0 },
+ {"disable-fgcom", false, OPTION_BOOL, "/sim/fgcom/enabled", false, "", 0 },
+#endif
{"com1", true, OPTION_DOUBLE, "/instrumentation/comm[0]/frequencies/selected-mhz", false, "", 0 },
{"com2", true, OPTION_DOUBLE, "/instrumentation/comm[1]/frequencies/selected-mhz", false, "", 0 },
{"nav1", true, OPTION_FUNC, "", false, "", fgOptNAV1 },
{"min-status", true, OPTION_STRING, "/sim/aircraft-min-status", false, "all", 0 },
{"livery", true, OPTION_FUNC, "", false, "", fgOptLivery },
{"ai-scenario", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptScenario },
- {"disable-ai-scenarios", false, OPTION_FUNC, "", false, "", fgOptNoScenarios},
{"parking-id", true, OPTION_FUNC, "", false, "", fgOptParking },
{"version", false, OPTION_FUNC, "", false, "", fgOptVersion },
{"enable-fpe", false, OPTION_IGNORE, "", false, "", 0},
{"fgviewer", false, OPTION_IGNORE, "", false, "", 0},
+ {"no-default-config", false, OPTION_IGNORE, "", false, "", 0},
{"prop", true, OPTION_FUNC | OPTION_MULTI, "", false, "", fgOptSetProperty},
+ {"load-tape", true, OPTION_FUNC, "", false, "", fgOptLoadTape },
{0}
};
return it; // not found
}
+
+ OptionValueVec::iterator findValue(const string& key)
+ {
+ OptionValueVec::iterator it = values.begin();
+ for (; it != values.end(); ++it) {
+ if (!it->desc) {
+ continue; // ignore markers
+ }
+
+ if (it->desc->option == key) {
+ return it;
+ }
+ } // of set values iteration
+
+ return it; // not found
+ }
OptionDesc* findOption(const string& key) const
{
}
/**
- * given a current iterator into the values, find the preceeding group marker,
+ * given a current iterator into the values, find the preceding group marker,
* or return the beginning of the value vector.
*/
OptionValueVec::const_iterator rfindGroup(OptionValueVec::const_iterator pos) const
bool showHelp,
verbose,
- showAircraft;
-
+ showAircraft,
+ shouldLoadDefaultConfig;
+
OptionDescDict options;
OptionValueVec values;
simgear::PathList propertyFiles;
p->showHelp = false;
p->verbose = false;
p->showAircraft = false;
+ p->shouldLoadDefaultConfig = true;
// build option map
OptionDesc *desc = &fgOptionArray[ 0 ];
void Options::init(int argc, char **argv, const SGPath& appDataPath)
{
- fgSetDefaults();
-
// first, process the command line
bool inOptions = true;
for (int i=1; i<argc; ++i) {
SGPath f(argv[i]);
if (!f.exists()) {
SG_LOG(SG_GENERAL, SG_ALERT, "config file not found:" << f.str());
- return;
+ } else {
+ p->propertyFiles.push_back(f);
}
-
- p->propertyFiles.push_back(f);
}
} // of arguments iteration
p->insertGroupMarker(); // command line is one group
+ // establish log-level before anything else - otherwise it is not possible
+ // to show extra (debug/info/warning) messages for the start-up phase.
+ fgOptLogLevel(valueForOption("log-level", "alert").c_str());
+
+ if (!p->shouldLoadDefaultConfig) {
+ setupRoot(argc, argv);
+ return;
+ }
+
// then config files
SGPath config;
-
- if( homedir && hostname && strlen(hostname) > 0 ) {
+ std::string homedir;
+ if (getenv("HOME")) {
+ homedir = getenv("HOME");
+ }
+
+ if( !homedir.empty() && !hostname.empty() ) {
// Check for ~/.fgfsrc.hostname
config.set(homedir);
config.append(".fgfsrc");
}
// Check for ~/.fgfsrc
- if( homedir ) {
+ if( !homedir.empty() ) {
config.set(homedir);
config.append(".fgfsrc");
readConfig(config);
}
// setup FG_ROOT
- setupRoot();
+ setupRoot(argc, argv);
-// system.fgfsrc handling
- if( hostname && strlen(hostname) > 0 ) {
+// system.fgfsrc is disabled, as we no longer allow anything in fgdata to set
+// fg-root/fg-home/fg-aircraft and hence control what files Nasal can access
+ std::string name_for_error = homedir.empty() ? appDataConfig.str() : config.str();
+ if( ! hostname.empty() ) {
config.set(globals->get_fg_root());
config.append( "system.fgfsrc" );
config.concat( "." );
config.concat( hostname );
- readConfig(config);
+ if (config.exists()) {
+ flightgear::fatalMessageBox("Unsupported configuration",
+ "You have a " + config.str() + " file, which is no longer processed for security reasons",
+ "If you created this file intentionally, please move it to " + name_for_error);
+ }
}
config.set(globals->get_fg_root());
config.append( "system.fgfsrc" );
- readConfig(config);
+ if (config.exists()) {
+ flightgear::fatalMessageBox("Unsupported configuration",
+ "You have a " + config.str() + " file, which is no longer processed for security reasons",
+ "If you created this file intentionally, please move it to " + name_for_error);
+ }
}
-
-void Options::initAircraft()
+
+void Options::initPaths()
{
- BOOST_FOREACH(const string& paths, valuesForOption("fg-aircraft")) {
- globals->append_aircraft_paths(paths);
- }
-
- const char* envp = ::getenv("FG_AIRCRAFT");
- if (envp) {
- globals->append_aircraft_paths(envp);
- }
+ BOOST_FOREACH(const string& paths, valuesForOption("fg-aircraft")) {
+ globals->append_aircraft_paths(paths);
+ }
+
+ const char* envp = ::getenv("FG_AIRCRAFT");
+ if (envp) {
+ globals->append_aircraft_paths(envp);
+ }
+
+}
+void Options::initAircraft()
+{
string aircraft;
if (isOptionSet("aircraft")) {
aircraft = valueForOption("aircraft");
} else {
SG_LOG(SG_INPUT, SG_INFO, "No user specified aircraft, using default" );
}
-
+
if (p->showAircraft) {
+ vector<SGPath> path_list;
+
fgOptLogLevel( "alert" );
- SGPath path( globals->get_fg_root() );
- path.append("Aircraft");
- fgShowAircraft(path);
+
+ // First place to check is the 'Aircraft' sub-directory in $FG_ROOT
+
+ path_list.push_back( SGPath( globals->get_fg_root() ) );
+ path_list.back().append("Aircraft");
+
+ // Additionally, aircraft may also be found in user-defined places
+ // (via $FG_AIRCRAFT or with the '--fg-aircraft' option)
+
+ string_list aircraft_paths = globals->get_aircraft_paths();
+ for (string_list::iterator it = aircraft_paths.begin();
+ it != aircraft_paths.end(); ++it)
+ path_list.push_back( SGPath(*it));
+
+ fgShowAircraft(path_list);
exit(0);
}
if (isOptionSet("aircraft-dir")) {
- // set this now, so it's available in FindAndCacheAircraft
- fgSetString("/sim/aircraft-dir", valueForOption("aircraft-dir"));
+ SGPath aircraftDirPath(valueForOption("aircraft-dir"));
+
+ // Set this now, so it's available in FindAndCacheAircraft. Use realpath()
+ // as in FGGlobals::append_aircraft_path(), otherwise fgValidatePath()
+ // will deny access to resources under this path if one of its components
+ // is a symlink (which is not a problem, since it was given as is by the
+ // user---this is very different from a symlink *under* the aircraft dir
+ // or a scenery dir).
+ fgSetString("/sim/aircraft-dir", aircraftDirPath.realpath().c_str());
}
}
else if (result == FG_OPTIONS_VERBOSE_HELP)
p->verbose = true;
else if (result == FG_OPTIONS_SHOW_AIRCRAFT) {
- p->showAircraft = true;
+ p->showAircraft = true;
+ } else if (result == FG_OPTIONS_NO_DEFAULT_CONFIG) {
+ p->shouldLoadDefaultConfig = false;
} else if (result == FG_OPTIONS_SHOW_SOUND_DEVICES) {
SGSoundMgr smgr;
cout << i << ". \"" << devices[i] << "\"" << endl;
}
devices.clear();
+ smgr.stop();
exit(0);
} else if (result == FG_OPTIONS_EXIT) {
exit(0);
} else if ( (s == "--verbose") || (s == "-v") ) {
// verbose help/usage request
return FG_OPTIONS_VERBOSE_HELP;
+ } else if ((s == "--console") || (s == "-c")) {
+ simgear::requestConsole();
+ return FG_OPTIONS_OK;
} else if (s.find("-psn") == 0) {
// on Mac, when launched from the GUI, we are passed the ProcessSerialNumber
// as an argument (and no others). Silently ignore the argument here.
return(FG_OPTIONS_SHOW_AIRCRAFT);
} else if ( s.find( "--show-sound-devices") == 0) {
return(FG_OPTIONS_SHOW_SOUND_DEVICES);
+ } else if ( s.find( "--no-default-config") == 0) {
+ return FG_OPTIONS_NO_DEFAULT_CONFIG;
} else if ( s.find( "--prop:") == 0) {
// property setting has a slightly different syntax, so fudge things
OptionDesc* desc = p->findOption("prop");
return addOption(key, value);
} else {
- SG_LOG(SG_GENERAL, SG_ALERT, "unknown option:" << s);
+ flightgear::modalMessageBox("Unknown option", "Unknown command-line option: " + s);
return FG_OPTIONS_ERROR;
}
}
{
OptionDesc* desc = p->findOption(key);
if (!desc) {
- SG_LOG(SG_GENERAL, SG_ALERT, "unknown option:" << key);
+ flightgear::modalMessageBox("Unknown option", "Unknown command-line option: " + key);
return FG_OPTIONS_ERROR;
}
if (!(desc->type & OPTION_MULTI)) {
OptionValueVec::const_iterator it = p->findValue(key);
if (it != p->values.end()) {
- SG_LOG(SG_GENERAL, SG_INFO, "multiple values forbidden for option:" << key << ", ignoring:" << value);
+ SG_LOG(SG_GENERAL, SG_WARN, "multiple values forbidden for option:" << key << ", ignoring:" << value);
return FG_OPTIONS_OK;
}
}
p->values.push_back(OptionValue(desc, value));
return FG_OPTIONS_OK;
}
-
+
+int Options::setOption(const string &key, const string &value)
+{
+ OptionDesc* desc = p->findOption(key);
+ if (!desc) {
+ flightgear::modalMessageBox("Unknown option", "Unknown command-line option: " + key);
+ return FG_OPTIONS_ERROR;
+ }
+
+ if (!(desc->type & OPTION_MULTI)) {
+ OptionValueVec::iterator it = p->findValue(key);
+ if (it != p->values.end()) {
+ // remove existing valye
+ p->values.erase(it);
+ }
+ }
+
+ p->values.push_back(OptionValue(desc, value));
+ return FG_OPTIONS_OK;
+}
+
+void Options::clearOption(const std::string& key)
+{
+ OptionValueVec::iterator it = p->findValue(key);
+ for (; it != p->values.end(); it = p->findValue(key)) {
+ p->values.erase(it);
+ }
+}
+
bool Options::isOptionSet(const string &key) const
{
OptionValueVec::const_iterator it = p->findValue(key);
return result;
}
-
-void Options::processOptions()
+
+string defaultDownloadDir()
+{
+#if defined(SG_WINDOWS)
+ SGPath p(SGPath::documents());
+ p.append("FlightGear");
+#else
+ SGPath p(globals->get_fg_home());
+#endif
+ return p.str();
+}
+
+OptionResult Options::processOptions()
{
+ // establish locale before showing help (this selects the default locale,
+ // when no explicit option was set)
+ globals->get_locale()->selectLanguage(valueForOption("language").c_str());
+
// now FG_ROOT is setup, process various command line options that bail us
// out quickly, but rely on aircraft / root settings
if (p->showHelp) {
showUsage();
- exit(0);
+ return FG_OPTIONS_EXIT;
}
// processing order is complicated. We must process groups LIFO, but the
// 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
{
case FG_OPTIONS_ERROR:
showUsage();
- exit(-1); // exit and return an error
+ return FG_OPTIONS_ERROR;
+
case FG_OPTIONS_EXIT:
- exit(0); // clean exit
- break;
+ return FG_OPTIONS_EXIT;
+
default:
break;
}
+ if (it->desc) {
+ SG_LOG(SG_GENERAL, SG_INFO, "\toption:" << it->desc->option << " = " << it->value);
+ }
}
groupEnd = groupBegin;
}
-
+
BOOST_FOREACH(const SGPath& file, p->propertyFiles) {
- if (!file.exists()) {
- SG_LOG(SG_GENERAL, SG_ALERT, "config file not found:" << file.str());
- continue;
- }
-
SG_LOG(SG_GENERAL, SG_INFO,
"Reading command-line property file " << file.str());
readProperties(file.str(), globals->get_props());
// now options are process, do supplemental fixup
const char *envp = ::getenv( "FG_SCENERY" );
if (envp) {
- globals->append_fg_scenery(envp);
+ globals->append_fg_scenery(envp, true);
}
-
+
+// download dir fix-up
+ string downloadDir = simgear::strutils::strip(fgGetString("/sim/paths/download-dir"));
+ if (downloadDir.empty()) {
+ downloadDir = defaultDownloadDir();
+ SG_LOG(SG_GENERAL, SG_INFO, "Using default download dir: " << downloadDir);
+ } else {
+ simgear::Dir d(downloadDir);
+ if (!d.exists()) {
+ SG_LOG(SG_GENERAL, SG_INFO, "Creating requested download dir: " << downloadDir);
+ d.create(0755);
+ }
+ }
+
// terrasync directory fixup
- if (fgGetBool("/sim/terrasync/enabled")) {
- string terrasyncDir = fgGetString("/sim/terrasync/scenery-dir");
- if (terrasyncDir.empty()) {
- SGPath p(fgGetString("/sim/fg-home"));
+ string terrasyncDir = simgear::strutils::strip(fgGetString("/sim/terrasync/scenery-dir"));
+ if (terrasyncDir.empty()) {
+ SGPath p(downloadDir);
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);
- }
-
+
+ simgear::Dir d(terrasyncDir);
+ if (!d.exists()) {
+ d.create(0755);
+ }
+
+ SG_LOG(SG_GENERAL, SG_INFO, "Using default TerraSync: " << terrasyncDir);
+ fgSetString("/sim/terrasync/scenery-dir", p.str());
+ } else {
+ SG_LOG(SG_GENERAL, SG_INFO, "Using explicit TerraSync dir: " << terrasyncDir);
+ }
+
+ // check if we setup a scenery path so far
+ bool addFGDataScenery = globals->get_fg_scenery().empty();
+
+ // always add the terrasync location, regardless of whether terrasync
+ // is enabled or not. This allows us to toggle terrasync on/off at
+ // runtime and have things work as expected
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);
+ // 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
- SGPath root(globals->get_fg_root());
- root.append("Scenery");
- globals->append_fg_scenery(root.str());
- }
+
+ if (addFGDataScenery) {
+ // no scenery paths set at all, use the data in FG_ROOT
+ // ensure this path is added last
+ SGPath root(globals->get_fg_root());
+ root.append("Scenery");
+ globals->append_fg_scenery(root.str());
+ }
+
+ return FG_OPTIONS_OK;
}
void Options::showUsage() const
{
fgOptLogLevel( "alert" );
- SGPropertyNode *locale = globals->get_locale();
+ FGLocale *locale = globals->get_locale();
SGPropertyNode options_root;
- SG_LOG( SG_GENERAL, SG_ALERT, "" ); // To popup the console on Windows
+ simgear::requestConsole(); // ensure console is shown on Windows
cout << endl;
-
+
try {
fgLoadProps("options.xml", &options_root);
} catch (const sg_exception &) {
exit(-1);
}
-
+
SGPropertyNode *options = options_root.getNode("options");
if (!options) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Error reading options.xml: <options> directive not found." );
exit(-1);
}
-
- SGPropertyNode *usage = locale->getNode(options->getStringValue("usage"));
+
+ if (!locale->loadResource("options"))
+ {
+ cout << "Unable to read the language resource." << endl;
+ exit(-1);
+ }
+
+ const char* usage = locale->getLocalizedString(options->getStringValue("usage"), "options");
if (usage) {
- cout << "Usage: " << usage->getStringValue() << endl;
+ cout << usage << endl;
}
vector<SGPropertyNode_ptr>section = options->getChildren("section");
msg += tmp + '\n';
msg.append(32, ' ');
}
- // There may be more than one <description> tag assosiated
+ // There may be more than one <description> tag associated
// with one option
vector<SGPropertyNode_ptr> desc;
desc = option[k]->getChildren("description");
- if (desc.size() > 0) {
+ if (! desc.empty()) {
for ( unsigned int l = 0; l < desc.size(); l++) {
-
- // There may be more than one translation line.
-
string t = desc[l]->getStringValue();
- SGPropertyNode *n = locale->getNode("strings");
- vector<SGPropertyNode_ptr>trans_desc =
- n->getChildren(t.substr(8).c_str());
-
+
+ // There may be more than one translation line.
+ vector<SGPropertyNode_ptr>trans_desc = locale->getLocalizedStrings(t.c_str(),"options");
for ( unsigned int m = 0; m < trans_desc.size(); m++ ) {
string t_str = trans_desc[m]->getStringValue();
}
}
- SGPropertyNode *name;
- name = locale->getNode(section[j]->getStringValue("name"));
-
+ const char* name = locale->getLocalizedString(section[j]->getStringValue("name"),"options");
if (!msg.empty() && name) {
- cout << endl << name->getStringValue() << ":" << endl;
+ cout << endl << name << ":" << endl;
cout << msg;
msg.erase();
}
}
if ( !p->verbose ) {
- cout << endl;
- cout << "For a complete list of options use --help --verbose" << endl;
+ const char* verbose_help = locale->getLocalizedString(options->getStringValue("verbose-help"),"options");
+ if (verbose_help)
+ cout << endl << verbose_help << endl;
}
#ifdef _MSC_VER
std::cout << "Hit a key to continue..." << std::endl;
return "../data";
}
-#elif defined(_WIN32)
+#elif defined(SG_WINDOWS)
string Options::platformDefaultRoot() const
{
return "..\\data";
}
-#elif defined(__APPLE__)
-string Options::platformDefaultRoot() const
-{
- /*
- The following code looks for the base package inside the application
- bundle, in the standard Contents/Resources location.
- */
- CFURLRef resourcesUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
-
- // look for a 'data' subdir
- CFURLRef dataDir = CFURLCreateCopyAppendingPathComponent(NULL, resourcesUrl, CFSTR("data"), true);
-
- // now convert down to a path, and the a c-string
- CFStringRef path = CFURLCopyFileSystemPath(dataDir, kCFURLPOSIXPathStyle);
- string root = CFStringGetCStringPtr(path, CFStringGetSystemEncoding());
-
- CFRelease(resourcesUrl);
- CFRelease(dataDir);
- CFRelease(path);
-
- return root;
-}
+#elif defined(SG_MAC)
+// platformDefaultRoot defined in CocoaHelpers.mm
#else
string Options::platformDefaultRoot() const
{
}
#endif
-void Options::setupRoot()
+void Options::setupRoot(int argc, char **argv)
{
- string root;
+ string root;
+ bool usingDefaultRoot = false;
+
if (isOptionSet("fg-root")) {
root = valueForOption("fg-root"); // easy!
+ SG_LOG(SG_GENERAL, SG_INFO, "set from command-line argument: fg_root = " << root );
} else {
// Next check if fg-root is set as an env variable
char *envp = ::getenv( "FG_ROOT" );
if ( envp != NULL ) {
root = envp;
+ SG_LOG(SG_GENERAL, SG_INFO, "set from FG_ROOT env var: fg_root = " << root );
} else {
- root = platformDefaultRoot();
+#if defined(HAVE_QT)
+ flightgear::initApp(argc, argv);
+ root = SetupRootDialog::restoreUserSelectedRoot();
+#endif
+ if (root.empty()) {
+ usingDefaultRoot = true;
+ root = platformDefaultRoot();
+ SG_LOG(SG_GENERAL, SG_INFO, "platform default fg_root = " << root );
+ } else {
+ SG_LOG(SG_GENERAL, SG_INFO, "Qt launcher set fg_root = " << root );
+ }
}
}
- SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root );
globals->set_fg_root(root);
-
-// validate it
- static char required_version[] = FLIGHTGEAR_VERSION;
- string base_version = fgBasePackageVersion();
- if ( !(base_version == required_version) ) {
- // tell the operator how to use this application
+ static char required_version[] = FLIGHTGEAR_VERSION;
+ string base_version = fgBasePackageVersion(root);
+
+#if defined(HAVE_QT)
+ // note we never end up here if restoring a user selected root via
+ // the Qt GUI, since that code pre-validates the path. But if we're using
+ // a command-line, env-var or default root this check can fail and
+ // we still want to use the GUI in that case
+ if (base_version != required_version) {
+ flightgear::initApp(argc, argv);
+ SetupRootDialog::runDialog(usingDefaultRoot);
+ }
+#else
+ // validate it
+ if (base_version.empty()) {
+ flightgear::fatalMessageBox("Base package not found",
+ "Required data files not found, check your installation.",
+ "Looking for base-package files at: '" + root + "'");
+
+ exit(-1);
+ }
- SG_LOG( SG_GENERAL, SG_ALERT, "" ); // To popup the console on windows
- cerr << endl << "Base package check failed:" << endl \
- << " Version " << base_version << " found at: " \
- << globals->get_fg_root() << endl \
- << " Version " << required_version << " is required." << endl \
- << "Please upgrade/downgrade base package and set the path to your fgdata" << endl \
- << "with --fg-root=path_to_your_fgdata" << endl;
-#ifdef _MSC_VER
- cerr << "Hit a key to continue..." << endl;
- cin.get();
-#endif
+ if (base_version != required_version) {
+ flightgear::fatalMessageBox("Base package version mismatch",
+ "Version check failed: please check your installation.",
+ "Found data files for version '" + base_version +
+ "' at '" + globals->get_fg_root() + "', version '"
+ + required_version + "' is required.");
+
exit(-1);
}
+#endif
}
+bool Options::shouldLoadDefaultConfig() const
+{
+ return p->shouldLoadDefaultConfig;
+}
+
+bool Options::checkForArg(int argc, char* argv[], const char* checkArg)
+{
+ for (int i = 0; i < argc; ++i) {
+ char* arg = argv[i];
+ if (arg == 0) {
+ continue;
+ }
+
+ if (*arg != '-') { // we only care about args with a leading hypen
+ continue;
+ }
+
+ arg++;
+ if (*arg == '-') { // skip double hypens
+ arg++;
+ }
+
+ if (strcmp(arg, checkArg) == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // of namespace flightgear