Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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>
00035 #endif
00036
00037 using namespace ProgramOptions;
00038 using namespace std;
00039 namespace ProgramOptions {
00041
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
00049 int Application::main(int argc, char** argv) {
00050 instance_s = this;
00051 initMainThread();
00052 exitCode_ = EXIT_FAILURE;
00053 blocked_ = pending_ = 0;
00054 if (getOptions(argc, argv)) {
00055
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
00095 void Application::shutdown(bool hasError) {
00096
00097 ++blocked_;
00098 killAlarm();
00099 if (hasError) { onUnhandledException(); }
00100 shutdown();
00101 }
00102
00103 void Application::shutdown() {}
00104
00105
00106 void Application::exit(int status) const {
00107 fflush(stdout);
00108 fflush(stderr);
00109 _exit(status);
00110 }
00111
00112
00113 int Application::blockSignals() {
00114 lockAlarm();
00115 int x = blocked_++;
00116 return x;
00117 }
00118
00119
00120 void Application::unblockSignals(bool deliverPending) {
00121 int x = --blocked_;
00122 unlockAlarm();
00123 if (x == 0) {
00124 int pend = pending_;
00125 pending_ = 0;
00126
00127 if (pend && deliverPending) { processSignal(pend); }
00128 }
00129 }
00130
00131 void Application::sigHandler(int sig) {
00132 if (sig != SIGALRM) {
00133
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
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) {
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
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
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;
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 }