From: James Turner Date: Sat, 16 Nov 2013 14:22:34 +0000 (+0000) Subject: Refactor aircraft-dir visiting. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=fe357ba2a906644809c1c3630543684a4960c449;p=flightgear.git Refactor aircraft-dir visiting. Cap maximum depth to avoid bug 865 --- diff --git a/src/Main/AircraftDirVisitorBase.hxx b/src/Main/AircraftDirVisitorBase.hxx new file mode 100644 index 000000000..cb216c797 --- /dev/null +++ b/src/Main/AircraftDirVisitorBase.hxx @@ -0,0 +1,115 @@ +// +// AircraftDirVisitorBase.hxx - helper to traverse a heirarchy containing +// aircraft dirs +// +// Written by Curtis Olson, started August 1997. +// +// Copyright (C) 1997 Curtis L. Olson - http://www.flightgear.org/~curt +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// + +#ifndef FG_MAIN_AIRCRAFT_DIR_VISITOR_HXX +#define FG_MAIN_AIRCRAFT_DIR_VISITOR_HXX + +class AircraftDirVistorBase +{ +public: + +protected: + enum VisitResult { + VISIT_CONTINUE = 0, + VISIT_DONE, + VISIT_ERROR + }; + + AircraftDirVistorBase() : + _maxDepth(2) + { + + } + + VisitResult visitAircraftPaths() + { + const string_list& paths(globals->get_aircraft_paths()); + string_list::const_iterator it = paths.begin(); + for (; it != paths.end(); ++it) { + VisitResult vr = visitDir(simgear::Dir(*it), 0); + if (vr != VISIT_CONTINUE) { + return vr; + } + } // of aircraft paths iteration + + // if we reach this point, search the default location (always last) + SGPath rootAircraft(globals->get_fg_root()); + rootAircraft.append("Aircraft"); + return visitDir(rootAircraft, 0); + } + + VisitResult visitPath(const SGPath& path, unsigned int depth) + { + if (!path.exists()) { + return VISIT_ERROR; + } + + return visit(path); + } + + VisitResult visitDir(const simgear::Dir& d, unsigned int depth) + { + if (!d.exists()) { + SG_LOG(SG_GENERAL, SG_WARN, "visitDir: no such path:" << d.path()); + return VISIT_CONTINUE; + } + + if (depth >= _maxDepth) { + return VISIT_CONTINUE; + } + + bool recurse = true; + simgear::PathList setFiles(d.children(simgear::Dir::TYPE_FILE, "-set.xml")); + simgear::PathList::iterator p; + for (p = setFiles.begin(); p != setFiles.end(); ++p) { + + // if we found a -set.xml at this level, don't recurse any deeper + recurse = false; + VisitResult vr = visit(*p); + if (vr != VISIT_CONTINUE) { + return vr; + } + } // of -set.xml iteration + + if (!recurse) { + return VISIT_CONTINUE; + } + + simgear::PathList subdirs(d.children(simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT)); + for (p = subdirs.begin(); p != subdirs.end(); ++p) { + VisitResult vr = visitDir(*p, depth + 1); + if (vr != VISIT_CONTINUE) { + return vr; + } + } + + return VISIT_CONTINUE; + } // of visitDir method + + virtual VisitResult visit(const SGPath& path) = 0; + +private: + unsigned int _maxDepth; +}; + +#endif // of FG_MAIN_AIRCRAFT_DIR_VISITOR_HXX diff --git a/src/Main/CMakeLists.txt b/src/Main/CMakeLists.txt index af70f7846..aeade6aa0 100644 --- a/src/Main/CMakeLists.txt +++ b/src/Main/CMakeLists.txt @@ -36,6 +36,7 @@ set(HEADERS util.hxx positioninit.hxx subsystemFactory.hxx + AircraftDirVisitorBase.hxx ) get_property(FG_SOURCES GLOBAL PROPERTY FG_SOURCES) diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index d1d4d15ca..ef6f637f8 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -123,6 +123,7 @@ #include "main.hxx" #include "positioninit.hxx" #include "util.hxx" +#include "AircraftDirVisitorBase.hxx" #if defined(SG_MAC) #include // for Mac impl of platformDefaultDataPath() @@ -154,68 +155,7 @@ string fgBasePackageVersion() { return version; } - -template -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 false; - } - - bool recurse = true; - simgear::Dir dir(dirPath); - simgear::PathList setFiles(dir.children(simgear::Dir::TYPE_FILE, "-set.xml")); - simgear::PathList::iterator p; - for (p = setFiles.begin(); p != setFiles.end(); ++p) { - // check file name ends with -set.xml - - // if we found a -set.xml at this level, don't recurse any deeper - recurse = false; - - bool done = (obj->*pred)(*p); - if (done) { - return true; - } - } // of -set.xml iteration - - 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 subdirs iteration - - return false; -} - -template -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 +class FindAndCacheAircraft : public AircraftDirVistorBase { public: FindAndCacheAircraft(SGPropertyNode* autoSave) @@ -272,7 +212,7 @@ public: n->setAttribute(SGPropertyNode::USERARCHIVE, true); _cache->removeChildren("aircraft"); - fgFindAircraft(this, &FindAndCacheAircraft::checkAircraft); + visitAircraftPaths(); } if (_foundPath.str().empty()) { @@ -348,7 +288,7 @@ private: return false; } - bool checkAircraft(const SGPath& p) + virtual VisitResult visit(const SGPath& p) { // create cache node int i = 0; @@ -370,10 +310,10 @@ private: if ( boost::equals(fileName, _searchAircraft.c_str(), is_iequal()) ) { _foundPath = p; - return true; + return VISIT_DONE; } - return false; + return VISIT_CONTINUE; } std::string _searchAircraft; @@ -966,120 +906,3 @@ void fgReInitSubsystems() } -/////////////////////////////////////////////////////////////////////////////// -// 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: - ShowAircraft() - { - _minStatus = getNumMaturity(fgGetString("/sim/aircraft-min-status", "all")); - } - - - void show(const SGPath& path) - { - fgFindAircraftInDir(path, this, &ShowAircraft::processAircraft); - - 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: - bool processAircraft(const SGPath& path) - { - SGPropertyNode root; - try { - readProperties(path.str(), &root); - } catch (sg_exception& ) { - return false; - } - - 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) { - return false; - } - - _aircraft.push_back(descStr); - return false; - } - - - 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 - { - 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; -}; - -void fgShowAircraft(const SGPath &path) -{ - ShowAircraft s; - s.show(path); - -#ifdef _MSC_VER - cout << "Hit a key to continue..." << endl; - std::cin.get(); -#endif -} - - diff --git a/src/Main/fg_init.hxx b/src/Main/fg_init.hxx index ffadf6d22..b26af11f2 100644 --- a/src/Main/fg_init.hxx +++ b/src/Main/fg_init.hxx @@ -64,15 +64,6 @@ void fgPostInitSubsystems(); // Reset: this is what the 'reset' command (and hence, GUI) is attached to void fgReInitSubsystems(); -/* - * Search in the current directory, and in on directory deeper - * for -set.xml configuration files and show the aircaft name - * and the contents of the tag in a sorted manner. - * - * @parampath the directory to search for configuration files - */ -void fgShowAircraft(const SGPath &path); - #endif // _FG_INIT_HXX diff --git a/src/Main/options.cxx b/src/Main/options.cxx index 6a5b8bbbe..06e57f36f 100644 --- a/src/Main/options.cxx +++ b/src/Main/options.cxx @@ -65,6 +65,7 @@ #include #include #include +#include "AircraftDirVisitorBase.hxx" #include @@ -241,6 +242,129 @@ void fgSetDefaults () 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 SGPath& path) + { + visitDir(path, 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 + { + 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 -set.xml configuration files and show the aircaft name + * and the contents of the tag in a sorted manner. + * + * @parampath the directory to search for configuration files + */ +void fgShowAircraft(const SGPath &path) +{ + ShowAircraft s; + s.show(path); + +#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)