Add helper to look for an aircraft branch path in multiple candidate locations.
Update the main subsystems to use the helper, and hence load from any aircraft dir.
continue;
}
- SGPath config( globals->get_fg_root() );
- config.append( pathNode->getStringValue() );
+ SGPath config = globals->resolve_aircraft_path(pathNode->getStringValue());
SG_LOG( SG_ALL, SG_INFO, "Reading autopilot configuration from " << config.str() );
FGPanel *
fgReadPanel (const string &relative_path)
{
- SGPath path(globals->get_fg_root());
- path.append(relative_path);
+ SGPath path = globals->resolve_aircraft_path(relative_path);
SGPropertyNode root;
-
+
try {
readProperties(path.str(), &root);
} catch (const sg_exception &e) {
SGPropertyNode *path_n = fgGetNode("/sim/instrumentation/path");
if (path_n) {
- SGPath config( globals->get_fg_root() );
- config.append( path_n->getStringValue() );
-
+ SGPath config = globals->resolve_aircraft_path(path_n->getStringValue());
+
SG_LOG( SG_ALL, SG_INFO, "Reading instruments from "
<< config.str() );
try {
// Read in configuration (files and command line options) but only set
-// fg_root
+// fg_root and aircraft_paths, which are needed *before* do_options() is called
+// in fgInitConfig
+
bool fgInitFGRoot ( int argc, char **argv ) {
string root;
SG_LOG(SG_INPUT, SG_INFO, "fg_root = " << root );
globals->set_fg_root(root);
-
+
return true;
}
// Read in configuration (files and command line options) but only set
// aircraft
bool fgInitFGAircraft ( int argc, char **argv ) {
+
+ string aircraftDir = fgScanForOption("--fg-aircraft=", argc, argv);
+ if (aircraftDir.empty()) {
+ aircraftDir = fgScanForOption("--fg-aircraft=");
+ }
+
+ const char* envp = ::getenv("FG_AIRCRAFT");
+ if (aircraftDir.empty() && envp) {
+ globals->append_aircraft_paths(envp);
+ }
+
+ if (!aircraftDir.empty()) {
+ globals->append_aircraft_paths(aircraftDir);
+ }
+
string aircraft;
// First parse command line options looking for --aircraft=, this
}
template <class T>
-void fgFindAircraftInDir(const SGPath& dirPath, T* obj, bool (T::*pred)(const SGPath& p))
+bool fgFindAircraftInDir(const SGPath& dirPath, T* obj, bool (T::*pred)(const SGPath& p))
{
if (!dirPath.exists()) {
SG_LOG(SG_GENERAL, SG_WARN, "fgFindAircraftInDir: no such path:" << dirPath.str());
- return;
+ return false;
}
-
+
bool recurse = true;
simgear::Dir dir(dirPath);
simgear::PathList setFiles(dir.children(simgear::Dir::TYPE_FILE, "-set.xml"));
bool done = (obj->*pred)(*p);
if (done) {
- return;
+ return true;
}
} // of -set.xml iteration
- if (recurse) {
- simgear::PathList subdirs(dir.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT));
- for (p = subdirs.begin(); p != subdirs.end(); ++p) {
- if (p->file() == "CVS") {
- continue;
- }
-
- fgFindAircraftInDir(*p, obj, pred);
+ if (!recurse) {
+ return false;
+ }
+
+ simgear::PathList subdirs(dir.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT));
+ for (p = subdirs.begin(); p != subdirs.end(); ++p) {
+ if (p->file() == "CVS") {
+ continue;
+ }
+
+ if (fgFindAircraftInDir(*p, obj, pred)) {
+ return true;
}
- } // of recursive case
+ } // of subdirs iteration
+
+ return false;
+}
+
+template <class T>
+void fgFindAircraft(T* obj, bool (T::*pred)(const SGPath& p))
+{
+ const string_list& paths(globals->get_aircraft_paths());
+ string_list::const_iterator it = paths.begin();
+ for (; it != paths.end(); ++it) {
+ bool done = fgFindAircraftInDir(SGPath(*it), obj, pred);
+ if (done) {
+ return;
+ }
+ } // of aircraft paths iteration
+
+ // if we reach this point, search the default location (always last)
+ SGPath rootAircraft(globals->get_fg_root());
+ rootAircraft.append("Aircraft");
+ fgFindAircraftInDir(rootAircraft, obj, pred);
}
class FindAndCacheAircraft
n->setStringValue(globals->get_fg_root().c_str());
n->setAttribute(SGPropertyNode::USERARCHIVE, true);
_cache->removeChildren("aircraft");
-
- SGPath aircraftDir(globals->get_fg_root());
- aircraftDir.append("Aircraft");
-
- fgFindAircraftInDir(aircraftDir, this, &FindAndCacheAircraft::checkAircraft);
+
+ fgFindAircraft(this, &FindAndCacheAircraft::checkAircraft);
}
if (_foundPath.str().empty()) {
} // of path list iteration
}
+void FGGlobals::append_aircraft_path(const std::string& path)
+{
+ SGPath dirPath(path);
+ if (!dirPath.exists()) {
+ SG_LOG(SG_GENERAL, SG_WARN, "aircraft path not found:" << path);
+ return;
+ }
+
+ fg_aircraft_dirs.push_back(path);
+}
+
+void FGGlobals::append_aircraft_paths(const std::string& path)
+{
+ string_list paths = sgPathSplit(path);
+ for (unsigned int p = 0; p<paths.size(); ++p) {
+ append_aircraft_path(paths[p]);
+ }
+}
+
+SGPath FGGlobals::resolve_aircraft_path(const std::string& branch) const
+{
+ string_list pieces(sgPathBranchSplit(branch));
+ if ((pieces.size() < 3) || (pieces.front() != "Aircraft")) {
+ SG_LOG(SG_AIRCRAFT, SG_ALERT, "resolve_aircraft_path: bad path:" << branch);
+ return SGPath();
+ }
+
+// check current aircraft dir first (takes precedence, allows Generics to be
+// over-riden
+ const char* aircraftDir = fgGetString("/sim/aircraft-dir");
+ string_list aircraftDirPieces(sgPathBranchSplit(aircraftDir));
+ if (!aircraftDirPieces.empty() && (aircraftDirPieces.back() == pieces[1])) {
+ SGPath r(aircraftDir);
+
+ for (unsigned int i=2; i<pieces.size(); ++i) {
+ r.append(pieces[i]);
+ }
+
+ if (r.exists()) {
+ std::cout << "using aircraft-dir for:" << r.str() << std::endl;
+ return r;
+ }
+ } // of using aircraft-dir case
+
+// try each fg_aircraft_dirs in turn
+ for (unsigned int p=0; p<fg_aircraft_dirs.size(); ++p) {
+ SGPath r(fg_aircraft_dirs[p]);
+ r.append(branch);
+ if (r.exists()) {
+ std::cout << "using aircraft directory for:" << r.str() << std::endl;
+ return r;
+ }
+ } // of fg_aircraft_dirs iteration
+
+// finally, try fg_root
+ SGPath r(fg_root);
+ r.append(branch);
+ if (r.exists()) {
+ std::cout << "using FG_ROOT for:" << r.str() << std::endl;
+ return r;
+ }
+
+ SG_LOG(SG_AIRCRAFT, SG_ALERT, "resolve_aircraft_path: failed to resolve:" << branch);
+ return SGPath();
+}
+
+SGPath FGGlobals::resolve_maybe_aircraft_path(const std::string& branch) const
+{
+ if (branch.find("Aircraft/") == 0) {
+ return resolve_aircraft_path(branch);
+ } else {
+ SGPath r(fg_root);
+ r.append(branch);
+ return r;
+ }
+}
FGRenderer *
FGGlobals::get_renderer () const
#include <simgear/compiler.h>
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/misc/sg_path.hxx>
#include <vector>
#include <string>
//Mulitplayer managers
FGMultiplayMgr *multiplayer_mgr;
+ /// roots of Aircraft trees
+ string_list fg_aircraft_dirs;
public:
FGGlobals();
inline const string_list &get_fg_scenery () const { return fg_scenery; }
void set_fg_scenery (const std::string &scenery);
+ const string_list& get_aircraft_paths() const { return fg_aircraft_dirs; }
+ void append_aircraft_path(const std::string& path);
+ void append_aircraft_paths(const std::string& path);
+
+ /**
+ * Given a path to an aircraft-related resource file, resolve it
+ * against the appropriate root. This means looking at the location
+ * defined by /sim/aircraft-dir, and then aircraft_path in turn,
+ * finishing with fg_root/Aircraft.
+ *
+ * if the path could not be resolved, an empty path is returned.
+ */
+ SGPath resolve_aircraft_path(const std::string& branch) const;
+
+ /**
+ * Same as above, but test for non 'Aircraft/' branch paths, and
+ * always resolve them against fg_root.
+ */
+ SGPath resolve_maybe_aircraft_path(const std::string& branch) const;
+
inline const std::string &get_browser () const { return browser; }
void set_browser (const std::string &b) { browser = b; }
// Otherwise, default to Scenery being in $FG_ROOT/Scenery
globals->set_fg_scenery("");
}
+
// Position (deliberately out of range)
fgSetDouble("/position/longitude-deg", 9999.0);
fgSetDouble("/position/latitude-deg", 9999.0);
static int
fgOptFgRoot( const char *arg )
{
- globals->set_fg_root(arg);
+ // this option is dealt with by fgInitFGRoot
return FG_OPTIONS_OK;
}
return FG_OPTIONS_OK;
}
+static int
+fgOptFgAircraft(const char* arg)
+{
+ // this option is dealt with by fgInitFGAircraft
+ return FG_OPTIONS_OK;
+}
+
static int
fgOptFov( const char *arg )
{
{"roc", true, OPTION_FUNC, "", false, "", fgOptRoc },
{"fg-root", true, OPTION_FUNC, "", false, "", fgOptFgRoot },
{"fg-scenery", true, OPTION_FUNC, "", false, "", fgOptFgScenery },
+ {"fg-aircraft", true, OPTION_FUNC, "", false, "", fgOptFgAircraft },
{"fdm", true, OPTION_STRING, "/sim/flight-model", false, "", 0 },
{"aero", true, OPTION_STRING, "/sim/aero", false, "", 0 },
{"aircraft-dir", true, OPTION_STRING, "/sim/aircraft-dir", false, "", 0 },
bool verbose = false;
bool help = false;
- SG_LOG(SG_GENERAL, SG_INFO, "Processing command line arguments");
+ SG_LOG(SG_GENERAL, SG_ALERT, "Processing command line arguments");
for (int i = 1; i < argc; i++) {
string arg = argv[i];
tpath.append( "Textures/Splash" );
tpath.concat( num_str );
tpath.concat( ".png" );
- } else
- tpath.append( splash_texture );
-
+ } else {
+ tpath = globals->resolve_maybe_aircraft_path(splash_texture);
+ }
+
osg::Texture2D* splashTexture = new osg::Texture2D;
splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
while((fn = n->getChild("file", j)) != NULL) {
file_specified = true;
const char* file = fn->getStringValue();
- SGPath p(globals->get_fg_root());
- p.append(file);
+ SGPath p = globals->resolve_maybe_aircraft_path(file);
loadModule(p, module);
j++;
}
SGPropertyNode *node = fgGetNode("/sim/sound", true);
string path_str = node->getStringValue("path");
- SGPath path( globals->get_fg_root() );
if (path_str.empty()) {
SG_LOG(SG_GENERAL, SG_ALERT, "No path in /sim/sound/path");
return;
}
-
- path.append(path_str.c_str());
+
+ SGPath path = globals->resolve_aircraft_path(path_str);
SG_LOG(SG_GENERAL, SG_INFO, "Reading sound " << node->getName()
<< " from " << path.str());
SGPropertyNode *path_n = fgGetNode("/sim/systems/path");
if (path_n) {
- SGPath config( globals->get_fg_root() );
- config.append( path_n->getStringValue() );
+ SGPath config = globals->resolve_aircraft_path(path_n->getStringValue());
SG_LOG( SG_ALL, SG_INFO, "Reading systems from "
<< config.str() );