Back to index

nordugrid-arc-nox  1.1.0~rc6
OptionParser.cpp
Go to the documentation of this file.
00001 // -*- indent-tabs-mode: nil -*-
00002 
00003 #ifdef HAVE_CONFIG_H
00004 #include <config.h>
00005 #endif
00006 
00007 #include <cstdlib>
00008 #include <iostream>
00009 
00010 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00011 #include <glibmm/optioncontext.h>
00012 #else
00013 #include <getopt.h>
00014 #include <arc/IString.h>
00015 #include <arc/StringConv.h>
00016 #endif
00017 
00018 #include <arc/OptionParser.h>
00019 
00020 namespace Arc {
00021 
00022 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00023   class OptionBase {
00024   public:
00025     OptionBase(char shortOpt, const std::string& longOpt,
00026                const std::string& optDesc, const std::string& argDesc) {
00027       entry.set_short_name(shortOpt);
00028       entry.set_long_name(longOpt);
00029       entry.set_description(optDesc);
00030       if (!argDesc.empty())
00031         entry.set_arg_description(argDesc);
00032     }
00033     virtual ~OptionBase() {}
00034     virtual void AddEntry(Glib::OptionGroup& grp) = 0;
00035     virtual void Result() {}
00036 
00037   protected:
00038     Glib::OptionEntry entry;
00039   };
00040 #else
00041   class OptionBase {
00042   public:
00043     OptionBase(char shortOpt, const std::string& longOpt,
00044                const std::string& optDesc, const std::string& argDesc)
00045       : shortOpt(shortOpt),
00046         longOpt(longOpt),
00047         optDesc(optDesc),
00048         argDesc(argDesc) {}
00049     virtual ~OptionBase() {}
00050     virtual bool Set(const std::string& val) = 0;
00051 
00052   protected:
00053     char shortOpt;
00054     std::string longOpt;
00055     std::string optDesc;
00056     std::string argDesc;
00057 
00058     friend class OptionParser;
00059   };
00060 #endif
00061 
00062 
00063   class BoolOption
00064     : public OptionBase {
00065   public:
00066     BoolOption(char shortOpt, std::string longOpt,
00067                std::string optDesc, std::string argDesc,
00068                bool& value)
00069       : OptionBase(shortOpt, longOpt, optDesc, argDesc),
00070         value(value) {}
00071     ~BoolOption() {}
00072 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00073     void AddEntry(Glib::OptionGroup& grp) {
00074       grp.add_entry(entry, value);
00075     }
00076 #else
00077     bool Set(const std::string&) {
00078       value = true;
00079       return true;
00080     }
00081 #endif
00082 
00083   private:
00084     bool& value;
00085   };
00086 
00087   struct IntOption
00088     : public OptionBase {
00089   public:
00090     IntOption(char shortOpt, std::string longOpt,
00091               std::string optDesc, std::string argDesc,
00092               int& value)
00093       : OptionBase(shortOpt, longOpt, optDesc, argDesc),
00094         value(value) {}
00095     ~IntOption() {}
00096 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00097     void AddEntry(Glib::OptionGroup& grp) {
00098       grp.add_entry(entry, value);
00099     }
00100 #else
00101     bool Set(const std::string& val) {
00102       bool ok = stringto(val, value);
00103       if (!ok)
00104         std::cout << IString("Cannot parse integer value '%s' for -%c",
00105                              val, shortOpt) << std::endl;
00106       return ok;
00107     }
00108 #endif
00109 
00110   private:
00111     int& value;
00112   };
00113 
00114   struct StringOption
00115     : public OptionBase {
00116   public:
00117     StringOption(char shortOpt, std::string longOpt,
00118                  std::string optDesc, std::string argDesc,
00119                  std::string& value)
00120       : OptionBase(shortOpt, longOpt, optDesc, argDesc),
00121         value(value) {}
00122     ~StringOption() {}
00123 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00124     void AddEntry(Glib::OptionGroup& grp) {
00125       grp.add_entry(entry, gvalue);
00126     }
00127     void Result() {
00128       if (!gvalue.empty())
00129         value = gvalue;
00130     }
00131 #else
00132     bool Set(const std::string& val) {
00133       value = val;
00134       return true;
00135     }
00136 #endif
00137 
00138   private:
00139     std::string& value;
00140 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00141     Glib::ustring gvalue;
00142 #endif
00143   };
00144 
00145   struct StringListOption
00146     : public OptionBase {
00147   public:
00148     StringListOption(char shortOpt, std::string longOpt,
00149                      std::string optDesc, std::string argDesc,
00150                      std::list<std::string>& value)
00151       : OptionBase(shortOpt, longOpt, optDesc, argDesc),
00152         value(value) {}
00153     ~StringListOption() {}
00154 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00155     void AddEntry(Glib::OptionGroup& grp) {
00156       grp.add_entry(entry, gvalue);
00157     }
00158     void Result() {
00159       value.insert(value.end(), gvalue.begin(), gvalue.end());
00160     }
00161 #else
00162     bool Set(const std::string& val) {
00163       value.push_back(val);
00164       return true;
00165     }
00166 #endif
00167 
00168   private:
00169     std::list<std::string>& value;
00170 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00171     Glib::OptionGroup::vecustrings gvalue;
00172 #endif
00173   };
00174 
00175   OptionParser::OptionParser(const std::string& arguments,
00176                              const std::string& summary,
00177                              const std::string& description)
00178     : arguments(arguments),
00179       summary(summary),
00180       description(description) {}
00181 
00182   OptionParser::~OptionParser() {
00183     for (std::list<OptionBase*>::iterator it = options.begin();
00184          it != options.end(); it++)
00185       delete *it;
00186   }
00187 
00188   void OptionParser::AddOption(const char shortOpt,
00189                                const std::string& longOpt,
00190                                const std::string& optDesc,
00191                                bool& value) {
00192     options.push_back(new BoolOption(shortOpt, longOpt,
00193                                      optDesc, "", value));
00194   }
00195 
00196   void OptionParser::AddOption(const char shortOpt,
00197                                const std::string& longOpt,
00198                                const std::string& optDesc,
00199                                const std::string& argDesc,
00200                                int& value) {
00201     options.push_back(new IntOption(shortOpt, longOpt,
00202                                     optDesc, argDesc, value));
00203   }
00204 
00205   void OptionParser::AddOption(const char shortOpt,
00206                                const std::string& longOpt,
00207                                const std::string& optDesc,
00208                                const std::string& argDesc,
00209                                std::string& value) {
00210     options.push_back(new StringOption(shortOpt, longOpt,
00211                                        optDesc, argDesc, value));
00212   }
00213 
00214   void OptionParser::AddOption(const char shortOpt,
00215                                const std::string& longOpt,
00216                                const std::string& optDesc,
00217                                const std::string& argDesc,
00218                                std::list<std::string>& value) {
00219     options.push_back(new StringListOption(shortOpt, longOpt,
00220                                            optDesc, argDesc, value));
00221   }
00222 
00223 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_SET_SUMMARY
00224   std::list<std::string> OptionParser::Parse(int argc, char **argv) {
00225 
00226     Glib::OptionContext ctx(arguments);
00227     if (!summary.empty())
00228       ctx.set_summary(summary);
00229     if (!description.empty())
00230       ctx.set_description(description);
00231     ctx.set_translation_domain(PACKAGE);
00232     Glib::OptionGroup grp("main", "Main Group");
00233     grp.set_translation_domain(PACKAGE);
00234 
00235     bool h_value = false;
00236     BoolOption h_entry('h', "help", "Show help options", "", h_value);
00237     h_entry.AddEntry(grp);
00238 
00239     for (std::list<OptionBase*>::iterator it = options.begin();
00240          it != options.end(); it++)
00241       (*it)->AddEntry(grp);
00242 
00243     ctx.set_main_group(grp);
00244 
00245     try {
00246       ctx.parse(argc, argv);
00247     } catch (Glib::OptionError err) {
00248       std::cout << err.what() << std::endl;
00249       exit(1);
00250     }
00251     if(h_value) {
00252 #ifdef HAVE_GLIBMM_OPTIONCONTEXT_GET_HELP
00253       std::cout << ctx.get_help() << std::endl;
00254 #else
00255       std::cout << "Use -? to get usage description" << std::endl;
00256 #endif
00257       exit(0);
00258     }
00259 
00260     for (std::list<OptionBase*>::iterator it = options.begin();
00261          it != options.end(); it++)
00262       (*it)->Result();
00263 
00264     std::list<std::string> params;
00265     for (int i = 1; i < argc; i++)
00266       params.push_back(argv[i]);
00267     return params;
00268   }
00269 #else
00270   static inline void setopt(struct option& opt,
00271                             const char *name,
00272                             int has_arg,
00273                             int *flag,
00274                             int val) {
00275     opt.name = name;
00276     opt.has_arg = has_arg;
00277     opt.flag = flag;
00278     opt.val = val;
00279   }
00280 
00281   std::list<std::string> OptionParser::Parse(int argc, char **argv) {
00282 
00283     struct option *longoptions = new struct option[options.size() + 3];
00284     int i = 0;
00285     std::string optstring;
00286     for (std::list<OptionBase*>::iterator it = options.begin();
00287          it != options.end(); it++) {
00288       setopt(longoptions[i++], (*it)->longOpt.c_str(),
00289              (*it)->argDesc.empty() ? no_argument : required_argument,
00290              NULL, (*it)->shortOpt);
00291       optstring += (*it)->shortOpt;
00292       if (!(*it)->argDesc.empty())
00293         optstring += ':';
00294     }
00295     setopt(longoptions[i++], "help", no_argument, NULL, 'h');
00296     optstring += 'h';
00297     setopt(longoptions[i++], "help", no_argument, NULL, '?');
00298     optstring += '?';
00299     setopt(longoptions[i++], NULL, no_argument, NULL, '\0');
00300 
00301     char *argv0save = argv[0];
00302     argv[0] = strrchr(argv[0], '/');
00303     if (argv[0])
00304       argv[0]++;
00305     else
00306       argv[0] = argv0save;
00307 
00308     int opt = 0;
00309     while (opt != -1) {
00310 #ifdef HAVE_GETOPT_LONG_ONLY
00311       opt = getopt_long_only(argc, argv, optstring.c_str(), longoptions, NULL);
00312 #else
00313       opt = getopt_long(argc, argv, optstring.c_str(), longoptions, NULL);
00314 #endif
00315 
00316       if (opt == -1)
00317         continue;
00318       if ((opt == '?') || (opt == ':') || (opt == 'h')) {
00319         if (optopt) {
00320           delete longoptions;
00321           exit(1);
00322         }
00323         std::cout << IString("Usage:") << std::endl;
00324         std::cout << "  " << argv[0];
00325         if (!options.empty())
00326           std::cout << " [" << IString("OPTION...") << "]";
00327         if (!arguments.empty())
00328           std::cout << " " << IString(arguments);
00329         std::cout << std::endl << std::endl;
00330         if (!summary.empty())
00331           std::cout << IString(summary) << std::endl << std::endl;
00332         std::cout << IString("Help Options:") << std::endl;
00333         std::cout << "  -h, -?, --help    " << IString("Show help options")
00334                   << std::endl << std::endl;
00335         std::cout << IString("Application Options:") << std::endl;
00336         for (std::list<OptionBase*>::iterator it = options.begin();
00337              it != options.end(); it++) {
00338           std::cout << "  -" << (*it)->shortOpt << ", --" << (*it)->longOpt;
00339           if (!(*it)->argDesc.empty())
00340             std::cout << "=" << IString((*it)->argDesc);
00341           std::cout << "    " << IString((*it)->optDesc) << std::endl;
00342         }
00343         std::cout << std::endl;
00344         if (!description.empty())
00345           std::cout << IString(description) << std::endl;
00346         delete longoptions;
00347         exit(0);
00348       }
00349       for (std::list<OptionBase*>::iterator it = options.begin();
00350            it != options.end(); it++)
00351         if (opt == (*it)->shortOpt) {
00352           if (!(*it)->Set(optarg ? optarg : "")) {
00353             delete longoptions;
00354             exit(1);
00355           }
00356           break;
00357         }
00358     }
00359 
00360     delete[] longoptions;
00361     argv[0] = argv0save;
00362 
00363     std::list<std::string> params;
00364     while (argc > optind)
00365       params.push_back(argv[optind++]);
00366     return params;
00367   }
00368 #endif
00369 
00370 } // namespace Arc