application.cpp
Go to the documentation of this file.
00001 //
00002 //  Copyright (c) Benjamin Kaufmann 2004
00003 //
00004 //  This is free software; you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation; either version 2 of the License, or
00007 //  (at your option) any later version. 
00008 // 
00009 //  This file is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this file; if not, write to the Free Software
00016 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 //
00018 //
00019 // NOTE: ProgramOptions is inspired by Boost.Program_options
00020 //       see: www.boost.org/libs/program_options
00021 //
00022 #include <program_opts/application.h>
00023 #include <program_opts/typed_value.h>
00024 #include <program_opts/detail/alarm.h>
00025 #include <cctype>
00026 #include <limits.h>
00027 #include <cstring>
00028 #ifdef _MSC_VER
00029 #pragma warning (disable : 4996)
00030 #endif
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #if !defined(_WIN32)
00034 #include <unistd.h> // for _exit
00035 #endif
00036 
00037 using namespace ProgramOptions;
00038 using namespace std;
00039 namespace ProgramOptions {
00041 // Application
00043 Application* Application::instance_s = 0;
00044 Application::Application() : exitCode_(EXIT_FAILURE), timeout_(0), verbose_(0), fastExit_(false), blocked_(0), pending_(0) {}
00045 Application::~Application() { 
00046         if (instance_s == this) { instance_s = 0; resetMainThread(); }
00047 }
00048 // Application entry point.
00049 int Application::main(int argc, char** argv) {
00050         instance_s = this; // singleton instance used for signal handling
00051         initMainThread();
00052         exitCode_  = EXIT_FAILURE;
00053         blocked_   = pending_ = 0;
00054         if (getOptions(argc, argv)) {
00055                 // install signal handlers
00056                 for (const int* sig = getSignals(); sig && *sig; ++sig) {
00057                         if (signal(*sig, &Application::sigHandler) == SIG_IGN) {
00058                                 signal(*sig, SIG_IGN);
00059                         }
00060                 }
00061                 if (timeout_) {
00062                         setAlarmHandler(&Application::sigHandler);
00063                         if (setAlarm(timeout_) == 0) { warn("Could not set time limit!"); }
00064                 }
00065                 exitCode_ = EXIT_SUCCESS;
00066                 try         { setup(); run(); shutdown(false); }
00067                 catch (...) { shutdown(true); }
00068         }
00069         if (fastExit_) { exit(exitCode_); }
00070         fflush(stdout); 
00071         fflush(stderr);
00072         return exitCode_;
00073 }
00074 
00075 Application* Application::getInstance() {
00076         return instance_s;
00077 }
00078 
00079 void Application::onUnhandledException() {
00080         try { throw; }
00081         catch (const std::exception& e) { error(e.what()); }
00082         catch (...)                     { error("Unknown exception"); }
00083         exit(EXIT_FAILURE);
00084 }
00085 
00086 void Application::setExitCode(int n) {
00087         exitCode_ = n;
00088 }
00089 
00090 int Application::getExitCode() const {
00091         return exitCode_;
00092 }
00093 
00094 // Called on application shutdown
00095 void Application::shutdown(bool hasError) {
00096         // ignore signals/alarms during shutdown
00097         ++blocked_;
00098         killAlarm();
00099         if (hasError) { onUnhandledException(); }
00100         shutdown();
00101 }
00102 
00103 void Application::shutdown() {}
00104 
00105 // Force exit without calling destructors.
00106 void Application::exit(int status) const {
00107         fflush(stdout);
00108         fflush(stderr);
00109         _exit(status);
00110 }
00111 
00112 // Temporarily disable delivery of signals.
00113 int Application::blockSignals() {
00114         lockAlarm();
00115         int x = blocked_++;
00116         return x;
00117 }
00118 
00119 // Re-enable signal handling and deliver any pending signal.
00120 void Application::unblockSignals(bool deliverPending) {
00121         int x = --blocked_;
00122         unlockAlarm();
00123         if (x == 0) {
00124                 int pend = pending_;
00125                 pending_ = 0;
00126                 // directly deliver any pending signal to our sig handler
00127                 if (pend && deliverPending) { processSignal(pend); }
00128         }
00129 }
00130 
00131 void Application::sigHandler(int sig) {
00132         if (sig != SIGALRM) {
00133                 // reset handler because on Windows and original Unix, a handler once invoked is set to SIG_DFL
00134                 signal(sig, sigHandler);
00135                 struct Protect {
00136                         Protect() { protectMainThread(true);  }
00137                         ~Protect(){ protectMainThread(false); }
00138                         void process(int sig) { Application::instance_s->processSignal(sig); }
00139                 };
00140                 Protect().process(sig);
00141         }
00142         else { Application::instance_s->processSignal(sig); }
00143 }
00144 
00145 // Called on timeout or signal.
00146 void Application::processSignal(int sig) {
00147         int block = blocked_++;
00148         if (block == 0) {
00149                 blocked_ += (onSignal(sig) == false);
00150         }
00151         else if (pending_ == 0) { // signals are currently blocked because output is active
00152                 info("Queueing signal...");
00153                 pending_ = sig;
00154         }
00155         --blocked_;
00156 }
00157 
00158 bool Application::onSignal(int x) {
00159         info("INTERRUPTED by signal!");
00160         exit(EXIT_FAILURE | (128+x));
00161         return false;
00162 }
00163 
00164 // Kill any pending alarm.
00165 void Application::killAlarm() {
00166         if (timeout_ > 0) { setAlarm(0); }
00167 }
00168 
00169 namespace {
00170         struct HelpParser {
00171                 static unsigned maxValue_s;
00172                 static bool parse(const std::string& v, unsigned& out) {
00173                         return string_cast(v, out) && out > 0 && out <= maxValue_s;
00174                 }
00175         };
00176         unsigned HelpParser::maxValue_s = 0;
00177 }
00178 
00179 // Process command-line options.
00180 bool Application::getOptions(int argc, char** argv) {
00181         using namespace ProgramOptions;
00182         unsigned help = 0;
00183         bool version  = false;
00184         try {
00185                 ParsedOptions parsed; // options found in command-line
00186                 OptionContext allOpts(std::string("<").append(getName()).append(">"));
00187                 HelpOpt helpO = getHelpOption();
00188                 if (helpO.second == 0) { error("Invalid help option!"); exit(EXIT_FAILURE); }
00189                 OptionGroup basic("Basic Options");
00190                 HelpParser::maxValue_s = helpO.second;
00191                 Value* hv = helpO.second == 1 ? storeTo(help)->flag() : storeTo(help, &HelpParser::parse)->arg("<n>")->implicit("1");
00192                 basic.addOptions()
00193                         ("help,h"      , hv                               , helpO.first)
00194                         ("version,v"   , flag(version)                    , "Print version information and exit")
00195                         ("verbose,V"   , storeTo(verbose_ = 0)->implicit("-1")->arg("<n>"), "Set verbosity level to %A")
00196                         ("time-limit"  , storeTo(timeout_ = 0)->arg("<n>"), "Set time limit to %A seconds (0=no limit)")
00197                         ("fast-exit,@1", flag(fastExit_   = false)        , "Force fast exit (do not call dtors)")
00198                 ;
00199                 allOpts.add(basic);
00200                 initOptions(allOpts);
00201                 ParsedValues values = parseCommandLine(argc, argv, allOpts, false, getPositional());
00202                 parsed.assign(values);
00203                 allOpts.assignDefaults(parsed);
00204                 if (help || version) {
00205                         exitCode_ = EXIT_SUCCESS;
00206                         if (help) {
00207                                 DescriptionLevel x = (DescriptionLevel)(help-1);
00208                                 allOpts.setActiveDescLevel(x);
00209                                 printHelp(allOpts);
00210                         }
00211                         else {
00212                                 printVersion();
00213                         }
00214                         return false;
00215                 }
00216                 validateOptions(allOpts, parsed, values);
00217         }
00218         catch(const std::exception& e) {
00219                 error(e.what());
00220                 info("Try '--help' for usage information");
00221                 return false;
00222         }
00223         return true;
00224 }
00225 
00226 void Application::printHelp(const OptionContext& root) {
00227         printf("%s version %s\n", getName(), getVersion());
00228         printUsage();
00229         ProgramOptions::FileOut out(stdout);
00230         root.description(out);
00231         printf("\n");
00232         printUsage();
00233         printf("Default command-line:\n%s %s\n", getName(), root.defaults(strlen(getName())+1).c_str());
00234         fflush(stdout);
00235 }
00236 void Application::printVersion() {
00237         printf("%s version %s\n", getName(), getVersion());
00238         printf("Address model: %d-bit\n", (int)(sizeof(void*)*CHAR_BIT));       
00239         fflush(stdout);
00240 }
00241 
00242 void Application::printUsage() {
00243         printf("usage: %s %s\n", getName(), getUsage());
00244 }
00245 
00246 unsigned Application::verbose() const {
00247         return verbose_;
00248 }
00249 void Application::setVerbose(unsigned v) {
00250         verbose_ = v;
00251 }
00252 
00253 }


clasp
Author(s): Benjamin Kaufmann
autogenerated on Thu Aug 27 2015 12:41:38