about summary refs log tree commit diff
path: root/src/libmain
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2014-08-13T01·50+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2014-08-13T01·50+0200
commit47e185847e729d49e6aa376e8299fd66ef834a0a (patch)
tree6abfc9e9d5744e78b123c73182c30253c9a39681 /src/libmain
parent5bed74d1b0acd8d8083fb82a31d907ad2348a91b (diff)
Refactor option handling
Diffstat (limited to 'src/libmain')
-rw-r--r--src/libmain/shared.cc82
-rw-r--r--src/libmain/shared.hh35
2 files changed, 52 insertions, 65 deletions
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 467a15e76023..ec05db0a6675 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -100,10 +100,16 @@ string getArg(const string & opt,
 void detectStackOverflow();
 
 
-/* Initialize and reorder arguments, then call the actual argument
-   processor. */
-static void initAndRun(int argc, char * * argv)
+void initNix()
 {
+    /* Turn on buffering for cerr. */
+#if HAVE_PUBSETBUF
+    static char buf[1024];
+    std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
+#endif
+
+    std::ios::sync_with_stdio(false);
+
     settings.processEnvironment();
     settings.loadConfFile();
 
@@ -144,6 +150,14 @@ static void initAndRun(int argc, char * * argv)
     gettimeofday(&tv, 0);
     srandom(tv.tv_usec);
 
+    if (char *pack = getenv("_NIX_OPTIONS"))
+        settings.unpack(pack);
+}
+
+
+void parseCmdLine(int argc, char * * argv,
+    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
+{
     /* Put the arguments in a vector. */
     Strings args, remaining;
     while (argc--) args.push_back(*argv++);
@@ -164,7 +178,6 @@ static void initAndRun(int argc, char * * argv)
         } else remaining.push_back(arg);
     }
     args = remaining;
-    remaining.clear();
 
     /* Process default options. */
     for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
@@ -179,14 +192,6 @@ static void initAndRun(int argc, char * * argv)
             settings.buildVerbosity = lvlVomit;
         else if (arg == "--print-build-trace")
             settings.printBuildTrace = true;
-        else if (arg == "--help") {
-            printHelp();
-            return;
-        }
-        else if (arg == "--version") {
-            std::cout << format("%1% (Nix) %2%") % programId % nixVersion << std::endl;
-            return;
-        }
         else if (arg == "--keep-failed" || arg == "-K")
             settings.keepFailed = true;
         else if (arg == "--keep-going" || arg == "-k")
@@ -216,25 +221,20 @@ static void initAndRun(int argc, char * * argv)
             string value = *i;
             settings.set(name, value);
         }
-        else if (arg == "--arg" || arg == "--argstr") {
-            remaining.push_back(arg);
-            ++i; if (i == args.end()) throw UsageError(format("`%1%' requires two arguments") % arg);
-            remaining.push_back(*i);
-            ++i; if (i == args.end()) throw UsageError(format("`%1%' requires two arguments") % arg);
-            remaining.push_back(*i);
+        else {
+            if (!parseArg(i, args.end()))
+                throw UsageError(format("unrecognised option `%1%'") % *i);
         }
-        else remaining.push_back(arg);
     }
 
-    if (char *pack = getenv("_NIX_OPTIONS"))
-        settings.unpack(pack);
-
     settings.update();
+}
 
-    run(remaining);
 
-    /* Close the Nix database. */
-    store.reset((StoreAPI *) 0);
+void printVersion(const string & programName)
+{
+    std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
+    throw Exit();
 }
 
 
@@ -246,30 +246,11 @@ void showManPage(const string & name)
 }
 
 
-int exitCode = 0;
-char * * argvSaved = 0;
-
-}
-
-
-static char buf[1024];
-
-int main(int argc, char * * argv)
+int handleExceptions(const string & programName, std::function<void()> fun)
 {
-    using namespace nix;
-
-    argvSaved = argv;
-
-    /* Turn on buffering for cerr. */
-#if HAVE_PUBSETBUF
-    std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
-#endif
-
-    std::ios::sync_with_stdio(false);
-
     try {
         try {
-            initAndRun(argc, argv);
+            fun();
         } catch (...) {
             /* Subtle: we have to make sure that any `interrupted'
                condition is discharged before we reach printMsg()
@@ -279,12 +260,14 @@ int main(int argc, char * * argv)
             _isInterrupted = 0;
             throw;
         }
+    } catch (Exit & e) {
+        return e.status;
     } catch (UsageError & e) {
         printMsg(lvlError,
             format(
                 "error: %1%\n"
                 "Try `%2% --help' for more information.")
-            % e.what() % programId);
+            % e.what() % programName);
         return 1;
     } catch (BaseError & e) {
         printMsg(lvlError, format("error: %1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
@@ -299,5 +282,8 @@ int main(int argc, char * * argv)
         return 1;
     }
 
-    return exitCode;
+    return 0;
+}
+
+
 }
diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh
index b29b08bb597e..c74e7cbc197d 100644
--- a/src/libmain/shared.hh
+++ b/src/libmain/shared.hh
@@ -7,25 +7,28 @@
 #include <locale>
 
 
-/* These are not implemented here, but must be implemented by a
-   program linking against libmain. */
+namespace nix {
 
-/* Main program.  Called by main() after the ATerm library has been
-   initialised and some default arguments have been processed (and
-   removed from `args').  main() will catch all exceptions. */
-void run(nix::Strings args);
+MakeError(UsageError, nix::Error);
 
-/* Should print a help message to stdout and return. */
-void printHelp();
+class Exit : public std::exception
+{
+public:
+    int status;
+    Exit() : status(0) { }
+    Exit(int status) : status(status) { }
+};
 
-extern std::string programId;
+class StoreAPI;
 
+int handleExceptions(const string & programName, std::function<void()> fun);
 
-namespace nix {
+void initNix();
 
-MakeError(UsageError, nix::Error);
+void parseCmdLine(int argc, char * * argv,
+    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg);
 
-class StoreAPI;
+void printVersion(const string & programName);
 
 /* Ugh.  No better place to put this. */
 void printGCWarning();
@@ -36,6 +39,9 @@ void printMissing(const PathSet & willBuild,
     const PathSet & willSubstitute, const PathSet & unknown,
     unsigned long long downloadSize, unsigned long long narSize);
 
+string getArg(const string & opt,
+    Strings::iterator & i, const Strings::iterator & end);
+
 template<class N> N getIntArg(const string & opt,
     Strings::iterator & i, const Strings::iterator & end, bool allowUnit)
 {
@@ -65,9 +71,4 @@ void showManPage(const string & name);
 
 extern volatile ::sig_atomic_t blockInt;
 
-/* Exit code of the program. */
-extern int exitCode;
-
-extern char * * argvSaved;
-
 }