#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 "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
+#include <Include/version.h>
+#include <simgear/version.h>
using std::string;
using std::sort;
// 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);
fgSetString("/sim/logging/priority", "alert");
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 );
}
- void show(const SGPath& path)
+ void show(const vector<SGPath> & path_list)
{
- visitDir(path, 0);
+ 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
*
* @parampath the directory to search for configuration files
*/
-void fgShowAircraft(const SGPath &path)
+void fgShowAircraft(const vector<SGPath> &path_list)
{
ShowAircraft s;
- s.show(path);
+ s.show(path_list);
#ifdef _MSC_VER
cout << "Hit a key to continue..." << endl;
static int
fgOptFgScenery( const char *arg )
{
- globals->append_fg_scenery(arg);
+ globals->append_fg_scenery(arg, true);
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 )
{
}
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
+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".
// Examples: --prop:alpha=1 --prop:bool:beta=true --prop:d:gamma=0.123
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;
+}
+
/*
{"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 },
{"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 },
{"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 },
+ {"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 },
{"atcsim", true, OPTION_CHANNEL, "", false, "dummy", 0 },
{"atlas", true, OPTION_CHANNEL | OPTION_MULTI, "", false, "", 0 },
{"httpd", true, OPTION_FUNC , "", false, "", fgOptHttpd },
- {"jpg-httpd", true, OPTION_CHANNEL, "", false, "", 0 },
+ {"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 },
{"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}
};
}
/**
- * 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
fgOptLogLevel(valueForOption("log-level", "alert").c_str());
if (!p->shouldLoadDefaultConfig) {
- setupRoot();
+ setupRoot(argc, argv);
return;
}
}
// setup FG_ROOT
- setupRoot();
+ setupRoot(argc, argv);
-// system.fgfsrc handling
+// 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");
}
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());
}
}
return result;
}
-
-static string defaultTerrasyncDir()
+string defaultDownloadDir()
{
#if defined(SG_WINDOWS)
- SGPath p(SGPath::documents());
- p.append("FlightGear");
+ SGPath p(SGPath::documents());
+ p.append("FlightGear");
#else
SGPath p(globals->get_fg_home());
#endif
- p.append("TerraSync");
- return p.str();
+ return p.str();
}
-
OptionResult Options::processOptions()
{
// establish locale before showing help (this selects the default locale,
// 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
- string terrasyncDir = fgGetString("/sim/terrasync/scenery-dir");
+ string terrasyncDir = simgear::strutils::strip(fgGetString("/sim/terrasync/scenery-dir"));
if (terrasyncDir.empty()) {
- terrasyncDir = defaultTerrasyncDir();
- // auto-save it for next time
-
- SG_LOG(SG_GENERAL, SG_INFO,
- "Using default TerraSync: " << terrasyncDir);
- fgSetString("/sim/terrasync/scenery-dir", terrasyncDir);
- }
+ SGPath p(downloadDir);
+ p.append("TerraSync");
+ terrasyncDir = p.str();
- SGPath p(terrasyncDir);
+ simgear::Dir d(terrasyncDir);
+ if (!d.exists()) {
+ d.create(0755);
+ }
- // following is necessary to ensure NavDataCache sees stable scenery paths from
- // terrasync. Ensure the Terrain and Objects subdirs exist immediately, rather
- // than waiting for the first tiles to be scheduled.
- simgear::Dir terrainDir(SGPath(p, "Terrain")),
- objectsDir(SGPath(p, "Objects"));
- if (!terrainDir.exists()) {
- terrainDir.create(0755);
- }
-
- if (!objectsDir.exists()) {
- objectsDir.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);
}
- if (fgGetBool("/sim/terrasync/enabled")) {
+
+ // 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;
}
}
#endif
-void Options::setupRoot()
+void Options::setupRoot(int argc, char **argv)
{
string root;
+ bool usingDefaultRoot = false;
+
if (isOptionSet("fg-root")) {
root = valueForOption("fg-root"); // easy!
} else {
if ( envp != NULL ) {
root = envp;
} else {
+ usingDefaultRoot = true;
root = platformDefaultRoot();
}
}
- SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root );
+ SG_LOG(SG_GENERAL, SG_INFO, "fg_root = " << root );
globals->set_fg_root(root);
-
-// validate it
- static char required_version[] = FLIGHTGEAR_VERSION;
- string base_version = fgBasePackageVersion();
+ static char required_version[] = FLIGHTGEAR_VERSION;
+ string base_version = fgBasePackageVersion(root);
+
+#if defined(HAVE_QT)
+ if (base_version != required_version) {
+ flightgear::initApp(argc, argv);
+ if (SetupRootDialog::restoreUserSelectedRoot()) {
+ SG_LOG(SG_GENERAL, SG_INFO, "restored user selected fg_root = " << globals->get_fg_root() );
+ return;
+ }
+
+ SetupRootDialog dlg(usingDefaultRoot);
+ dlg.exec();
+ if (dlg.result() != QDialog::Accepted) {
+ exit(-1);
+ }
+ }
+#else
+ // validate it
if (base_version.empty()) {
flightgear::fatalMessageBox("Base package not found",
"Required data files not found, check your installation.",
exit(-1);
}
- if (base_version != required_version) {
- // tell the operator how to use this application
-
+ 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 +
exit(-1);
}
+#endif
}
bool Options::shouldLoadDefaultConfig() const