From 386d87e098f37a2785b854c0c8b523737e5cab43 Mon Sep 17 00:00:00 2001
From: James Turner <zakalawe@mac.com>
Date: Tue, 15 Oct 2013 22:16:50 +0100
Subject: [PATCH] Cleanup exit handling.

Replace many lingering calls to exit() from the code,
replacing most with exception throws, which can be
caught by the existing mechanisms.

Update the option-parsing code to return an explicit
value indicating what to do (e.g., exit status to return
to the shell).
---
 src/Airports/apt_loader.cxx  |  4 ++--
 src/Airports/runwayprefs.cxx |  3 ++-
 src/Airports/sidstar.cxx     |  1 -
 src/Main/fg_init.cxx         | 14 +++++---------
 src/Main/fg_init.hxx         |  2 +-
 src/Main/main.cxx            | 15 ++++++++-------
 src/Main/options.cxx         | 36 +++++++++++++++---------------------
 src/Main/options.hxx         | 21 ++++++++++++++++++---
 src/Navaids/fixlist.cxx      |  4 ++--
 src/Sound/voiceplayer.cxx    | 12 ++----------
 src/Systems/electrical.cxx   |  8 +-------
 src/Traffic/TrafficMgr.cxx   |  7 +++++--
 src/Viewer/fgviewer.cxx      | 13 +++++++------
 13 files changed, 68 insertions(+), 72 deletions(-)

diff --git a/src/Airports/apt_loader.cxx b/src/Airports/apt_loader.cxx
index 5833c02c3..f2f3b7120 100644
--- a/src/Airports/apt_loader.cxx
+++ b/src/Airports/apt_loader.cxx
@@ -90,7 +90,7 @@ public:
 
     if ( !in.is_open() ) {
         SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << aptdb_file );
-        exit(-1);
+        throw sg_io_exception("cannot open APT file", aptdb_file);
     }
 
     string line;
@@ -186,7 +186,7 @@ public:
       } else {
           SG_LOG( SG_GENERAL, SG_ALERT, 
                   "Unknown line(#" << line_num << ") in apt.dat file: " << line );
-          exit( -1 );
+          throw sg_format_exception("malformed line in apt.dat:", line);
       }
     }
 
diff --git a/src/Airports/runwayprefs.cxx b/src/Airports/runwayprefs.cxx
index 46c9bcb58..e6f1eb68a 100644
--- a/src/Airports/runwayprefs.cxx
+++ b/src/Airports/runwayprefs.cxx
@@ -34,6 +34,7 @@
 #include <simgear/compiler.h>
 #include <simgear/debug/logstream.hxx>
 #include <simgear/misc/strutils.hxx>
+#include <simgear/structure/exception.hxx>
 
 #include <Main/globals.hxx>
 #include <Airports/runways.hxx>
@@ -100,7 +101,7 @@ std::string ScheduleTime::getName(time_t dayStart)
     if ((start.size() != end.size())
         || (start.size() != scheduleNames.size())) {
         SG_LOG(SG_GENERAL, SG_INFO, "Unable to parse schedule times");
-        exit(1);
+        throw sg_exception("Unable to parse schedule times");
     } else {
         int nrItems = start.size();
         //cerr << "Nr of items to process: " << nrItems << endl;
diff --git a/src/Airports/sidstar.cxx b/src/Airports/sidstar.cxx
index a95119482..ad8d61344 100644
--- a/src/Airports/sidstar.cxx
+++ b/src/Airports/sidstar.cxx
@@ -44,7 +44,6 @@ FGSidStar::FGSidStar(FGAirport *ap) {
 
 FGSidStar::FGSidStar(const FGSidStar &other) {
      cerr << "TODO" << endl;
-     exit(1);
 }
 
 void FGSidStar::load(SGPath filename) {
diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx
index 82bf86f95..07488ac64 100644
--- a/src/Main/fg_init.cxx
+++ b/src/Main/fg_init.cxx
@@ -409,7 +409,7 @@ void fgInitHome()
 }
 
 // Read in configuration (file and command line)
-bool fgInitConfig ( int argc, char **argv )
+int fgInitConfig ( int argc, char **argv )
 {
     SGPath dataPath = globals->get_fg_home();
     
@@ -453,14 +453,12 @@ bool fgInitConfig ( int argc, char **argv )
 
     FindAndCacheAircraft f(globals->get_props());
     if (!f.loadAircraft()) {
-      return false;
+      return flightgear::FG_OPTIONS_ERROR;
     }
 
     // parse options after loading aircraft to ensure any user
     // overrides of defaults are honored.
-    options->processOptions();
-      
-    return true;
+    return options->processOptions();
 }
 
 
@@ -510,7 +508,7 @@ bool fgInitGeneral() {
         SG_LOG( SG_GENERAL, SG_ALERT,
                 "Cannot continue without a path to the base package "
                 << "being defined." );
-        exit(-1);
+        return false;
     }
     SG_LOG( SG_GENERAL, SG_INFO, "FG_ROOT = " << '"' << root << '"' << endl );
 
@@ -599,9 +597,7 @@ void fgCreateSubsystems() {
     mpath.append( fgGetString("/sim/rendering/materials-file") );
     if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
             globals->get_props()) ) {
-        SG_LOG( SG_GENERAL, SG_ALERT,
-                "Error loading materials file " << mpath.str() );
-        exit(-1);
+        throw sg_io_exception("Error loading materials file", mpath);
     }
 
     globals->add_subsystem( "http", new FGHTTPClient );
diff --git a/src/Main/fg_init.hxx b/src/Main/fg_init.hxx
index 2d81cc82b..5329b0381 100644
--- a/src/Main/fg_init.hxx
+++ b/src/Main/fg_init.hxx
@@ -37,7 +37,7 @@ std::string fgBasePackageVersion();
 void fgInitHome();
 
 // Read in configuration (file and command line)
-bool fgInitConfig ( int argc, char **argv );
+int fgInitConfig ( int argc, char **argv );
 
 
 // log various settings / configuration state
diff --git a/src/Main/main.cxx b/src/Main/main.cxx
index 4ca387e21..792362632 100644
--- a/src/Main/main.cxx
+++ b/src/Main/main.cxx
@@ -65,6 +65,7 @@
 #include "fg_props.hxx"
 #include "positioninit.hxx"
 #include "subsystemFactory.hxx"
+#include "options.hxx"
 
 using namespace flightgear;
 
@@ -164,9 +165,7 @@ static void fgIdleFunction ( void ) {
         
         // Do some quick general initializations
         if( !fgInitGeneral()) {
-            SG_LOG( SG_GENERAL, SG_ALERT,
-                "General initialization failed ..." );
-            exit(-1);
+            throw sg_exception("General initialization failed");
         }
 
         ////////////////////////////////////////////////////////////////////
@@ -344,11 +343,13 @@ int fgMainInit( int argc, char **argv ) {
     // Load the configuration parameters.  (Command line options
     // override config file options.  Config file options override
     // defaults.)
-    if ( !fgInitConfig(argc, argv) ) {
-      SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
-      exit(-1);
+    int configResult = fgInitConfig(argc, argv);
+    if (configResult == flightgear::FG_OPTIONS_ERROR) {
+        return EXIT_FAILURE;
+    } else if (configResult == flightgear::FG_OPTIONS_EXIT) {
+        return EXIT_SUCCESS;
     }
-
+    
     // Initialize the Window/Graphics environment.
     fgOSInit(&argc, argv);
     _bootstrap_OSInit++;
diff --git a/src/Main/options.cxx b/src/Main/options.cxx
index 5ec12cdec..261343b13 100644
--- a/src/Main/options.cxx
+++ b/src/Main/options.cxx
@@ -84,19 +84,9 @@ using std::endl;
 using std::vector;
 using std::cin;
 
-#define NEW_DEFAULT_MODEL_HZ 120
+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,
-    FG_OPTIONS_NO_DEFAULT_CONFIG = 7
-};
+#define NEW_DEFAULT_MODEL_HZ 120
 
 static flightgear::Options* shared_instance = NULL;
 
@@ -1016,12 +1006,12 @@ fgOptConfig( 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;
 }
@@ -1988,7 +1978,7 @@ string_list Options::valuesForOption(const std::string& key) const
   return result;
 }
 
-void Options::processOptions()
+OptionResult Options::processOptions()
 {
   // establish locale before showing help (this selects the default locale,
   // when no explicit option was set)
@@ -1998,7 +1988,7 @@ void Options::processOptions()
   // 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
@@ -2018,9 +2008,11 @@ void Options::processOptions()
       {
           case FG_OPTIONS_ERROR:
               showUsage();
-              exit(-1); // exit and return an error
+              return FG_OPTIONS_ERROR;
+              
           case FG_OPTIONS_EXIT:
-              exit(0);  // clean exit
+              return FG_OPTIONS_EXIT;
+              
           default:
               break;
       }
@@ -2085,6 +2077,8 @@ void Options::processOptions()
     root.append("Scenery");
     globals->append_fg_scenery(root.str());
   }
+    
+    return FG_OPTIONS_OK;
 }
   
 void Options::showUsage() const
diff --git a/src/Main/options.hxx b/src/Main/options.hxx
index 082d4a430..7765ecffe 100644
--- a/src/Main/options.hxx
+++ b/src/Main/options.hxx
@@ -34,7 +34,22 @@ class SGPath;
 
 namespace flightgear
 {
-  
+
+/// option processing can have various result values
+/// depending on what the user requested. Note processOptions only
+/// returns a subset of these.
+enum OptionResult
+{
+    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,
+    FG_OPTIONS_NO_DEFAULT_CONFIG = 7
+};
+    
 class Options
 {
 private:
@@ -80,9 +95,9 @@ public:
   
   /**
    * apply option values to the simulation state
-   * (set properties, etc)
+   * (set properties, etc). 
    */
-  void processOptions();
+  OptionResult processOptions();
   
   /**
    * init the aircraft options
diff --git a/src/Navaids/fixlist.cxx b/src/Navaids/fixlist.cxx
index 2dc8806ea..27ece5744 100644
--- a/src/Navaids/fixlist.cxx
+++ b/src/Navaids/fixlist.cxx
@@ -31,6 +31,7 @@
 #include <simgear/misc/sgstream.hxx>
 #include <simgear/misc/sg_path.hxx>
 #include <simgear/math/sg_geodesy.hxx>
+#include <simgear/structure/exception.hxx>
 
 #include "fixlist.hxx"
 #include <Navaids/fix.hxx>
@@ -49,8 +50,7 @@ void loadFixes(const SGPath& path)
 {
   sg_gzifstream in( path.str() );
   if ( !in.is_open() ) {
-    SG_LOG( SG_NAVAID, SG_ALERT, "Cannot open file: " << path.str() );
-    exit(-1);
+      throw sg_io_exception("Cannot open file:", path);
   }
   
   // toss the first two lines of the file
diff --git a/src/Sound/voiceplayer.cxx b/src/Sound/voiceplayer.cxx
index 6e12b083d..583443ded 100644
--- a/src/Sound/voiceplayer.cxx
+++ b/src/Sound/voiceplayer.cxx
@@ -249,16 +249,8 @@ FGVoicePlayer::get_sample (const char *name)
     if (! sample)
     {
         string filename = dir_prefix + string(name) + ".wav";
-        try
-        {
-            sample = new SGSoundSample(filename.c_str(), SGPath());
-        }
-        catch (const sg_exception &e)
-        {
-            SG_LOG(SG_SOUND, SG_ALERT, "Error loading sound sample \"" + filename + "\": " + e.getFormattedMessage());
-            exit(1);
-        }
-
+        sample = new SGSoundSample(filename.c_str(), SGPath());
+        
         _sgr->add(sample, refname);
         samples[refname] = sample;
     }
diff --git a/src/Systems/electrical.cxx b/src/Systems/electrical.cxx
index 947df0aae..ebe684cc9 100644
--- a/src/Systems/electrical.cxx
+++ b/src/Systems/electrical.cxx
@@ -386,13 +386,7 @@ void FGElectricalSystem::init () {
             if ( build(config_props) ) {
                 enabled = true;
             } else {
-                SG_LOG( SG_SYSTEMS, SG_ALERT,
-                        "Detected a logic error in the electrical system ");
-                SG_LOG( SG_SYSTEMS, SG_ALERT,
-                        "specification file.  See earlier errors for " );
-                SG_LOG( SG_SYSTEMS, SG_ALERT,
-                        "details.");
-                exit(-1);
+                throw sg_exception("Logic error in electrical system file.");
             }        
         } catch (const sg_exception&) {
             SG_LOG( SG_SYSTEMS, SG_ALERT,
diff --git a/src/Traffic/TrafficMgr.cxx b/src/Traffic/TrafficMgr.cxx
index 51d7154d7..d36645b46 100644
--- a/src/Traffic/TrafficMgr.cxx
+++ b/src/Traffic/TrafficMgr.cxx
@@ -57,6 +57,8 @@
 #include <simgear/misc/sg_dir.hxx>
 #include <simgear/props/props.hxx>
 #include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/structure/exception.hxx>
+
 #include <simgear/xml/easyxml.hxx>
 #include <simgear/threads/SGThread.hxx>
 #include <simgear/threads/SGGuard.hxx>
@@ -709,9 +711,10 @@ void FGTrafficManager::readTimeTableFromFile(SGPath infileName)
          if (!tokens.empty()) {
              if (tokens[0] == string("AC")) {
                  if (tokens.size() != 13) {
-                     SG_LOG(SG_AI, SG_ALERT, "Error parsing traffic file " << infileName.str() << " at " << buffString);
-                     exit(1);
+                     throw sg_io_exception("Error parsing traffic file @ " + buffString, sg_location(infileName.str()));
                  }
+                 
+                 
                  model          = tokens[12];
                  livery         = tokens[6];
                  homePort       = tokens[1];
diff --git a/src/Viewer/fgviewer.cxx b/src/Viewer/fgviewer.cxx
index 757266926..0e98613dd 100644
--- a/src/Viewer/fgviewer.cxx
+++ b/src/Viewer/fgviewer.cxx
@@ -29,6 +29,7 @@
 #include <simgear/scene/tgdb/userdata.hxx>
 #include <simgear/scene/model/ModelRegistry.hxx>
 #include <simgear/scene/model/modellib.hxx>
+#include <simgear/structure/exception.hxx>
 
 #include <Scenery/scenery.hxx>
 
@@ -170,9 +171,11 @@ fgviewerMain(int argc, char** argv)
 
     globals = new FGGlobals;
 
-    if ( !fgInitConfig(arguments.argc(), arguments.argv()) ) {
-        SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
-        exit(-1);
+    int configResult = fgInitConfig(arguments.argc(), arguments.argv());
+    if (configResult == flightgear::FG_OPTIONS_ERROR) {
+        return EXIT_FAILURE;
+    } else if (configResult == flightgear::FG_OPTIONS_EXIT) {
+        return EXIT_SUCCESS;
     }
 
     osgDB::FilePathList filePathList
@@ -193,9 +196,7 @@ fgviewerMain(int argc, char** argv)
     mpath.append( fgGetString("/sim/rendering/materials-file") );
     if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
             globals->get_props()) ) {
-        SG_LOG( SG_GENERAL, SG_ALERT,
-                "Error loading materials file " << mpath.str() );
-        exit(-1);
+        throw sg_io_exception("Error loading materials file", mpath);
     }
 
     globals->set_scenery( new FGScenery );