Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

Option.cpp

Go to the documentation of this file.
00001 
00002 //
00003 // Copyright (C) 2000
00004 // Ralf Westram
00005 // (Coded@ReallySoft.de)
00006 //
00007 // Permission to use, copy, modify, distribute and sell this software
00008 // and its documentation for any purpose is hereby granted without fee,
00009 // provided that the above copyright notice appear in all copies and
00010 // that both that copyright notice and this permission notice appear
00011 // in supporting documentation.  Ralf Westram makes no
00012 // representations about the suitability of this software for any
00013 // purpose.  It is provided "as is" without express or implied warranty.
00014 //
00015 // This code is part of my library.
00016 // You may find a more recent version at http://www.reallysoft.de/
00017 //
00019 
00020 #include "Option.h"
00021 #include "Tools.h"
00022 #include "Directory.h"
00023 #include "sys_dep.h"
00024 #include "path.h"
00025 
00026 #include <iomanip>
00027 #include <algorithm>
00028 #include <functional>
00029 #include <cstring>
00030 
00031 #if defined(DUMP)
00032 //#define DUMP_PARSE
00033 #endif // DUMP
00034 
00035 #if defined(DEBUG)
00036 // #define PATH_DETECT
00037 #endif // DEBUG
00038 
00039 using namespace std;
00040 using namespace rs;
00041 using namespace rs::cmdline;
00042 using namespace rs::err;
00043 using namespace rs::str;
00044 using namespace rs::file;
00045 using namespace rs::posix;
00046 
00047 typedef list<CmdLineOption*> Options;
00048 typedef list<CmdLineArgument*> Arguments;
00049 typedef list<CmdLineAnnotation*> Annotations;
00050 
00051 static Options *options = 0;
00052 static Arguments *arguments = 0;
00053 static Annotations *annotations = 0;
00054 
00055 static bool initialized = false; // was ProgramInfo::init called ?
00056 static size_t longest_arg_name_length = 6; // 6=length("<opts>")
00057 static size_t longest_optarg_name_length = 0;
00058 
00059 static bool options_are_case_sensitive = false; // will be automatically set to true, if options
00060                                                 // with same letter but different case occur
00061 
00062 static Terminator *there_can_only_be_one = 0; // will install my own terminator function (real_terminate)
00063 
00064 // --------------------------------------------------------------------------------
00065 //     inline void test_initialized(string where_tested)
00066 // --------------------------------------------------------------------------------
00067 inline void test_initialized(string where_tested) {
00068     if (!initialized) {
00069         string msg = "ProgramInfo::init() not called in "+where_tested;
00070         throw InternalError(msg);
00071     }
00072 }
00073 
00074 // --------------------------------------------------------------------------------
00075 //     class InfoError : public Error
00076 // --------------------------------------------------------------------------------
00077 
00079 class InfoError : public Error {
00080     const ProgramInfo& info;
00081 public:
00082     InfoError(const ProgramInfo& info_, bool real_error_ /*= true*/, const string& msg_)
00083         : Error(real_error_, msg_),
00084           info(info_)
00085     {
00086     }
00087     InfoError(const ProgramInfo& info_, const string& msg_)
00088         : Error(true, msg_),
00089           info(info_)
00090     {
00091     }
00092     virtual ~InfoError() throw() {}
00093 
00094     virtual void print(ostream& out) const {
00095         info.infos(out);
00096         Error::print(out);
00097     }
00098 };
00099 
00100 //  -----------------------------------------
00101 //      class StringError : public Error
00102 //  -----------------------------------------
00103 
00105 class StringError : public Error {
00106     string s;
00107 public:
00108     StringError(const string& msg_, const string& extra_message)
00109         : Error(true, msg_)
00110         , s(extra_message)
00111     {
00112     }
00113     virtual ~StringError() throw() {}
00114 
00115     virtual void print(ostream& out) const {
00116         Error::print(out);
00117         out << s;
00118     }
00119 };
00120 
00121 // --------------------------------------------------------------------------------
00122 //     CmdLineOption::CmdLineOption(char optChar_, const char *helptext_)
00123 // --------------------------------------------------------------------------------
00124 CmdLineOption::CmdLineOption(char optChar_, const char *helptext_)
00125     : CmdLineHelpText(helptext_)
00126 {
00127 #if defined(DUMP_PARSE)
00128     cout << "CmdLineOption(" << optChar_ << ", " << helptext_ << ")\n";
00129 #endif // DUMP_PARSE
00130     used = false;
00131     optChar = optChar_;
00132     if (!options) options = new Options();
00133     options->push_back(this);
00134 }
00135 
00136 CmdLineOption::~CmdLineOption() {
00137 }
00138 
00139 void CmdLineOption::print(ostream& out) const {
00140     out << '-' << optChar << string(longest_optarg_name_length+1, ' ');
00141 }
00142 
00143 //  ---------------------------------------------------------------------------------
00144 //      CmdLineAnnotation::CmdLineAnnotation(const char *helptext_, bool spaced_)
00145 //  ---------------------------------------------------------------------------------
00146 CmdLineAnnotation::CmdLineAnnotation(const char *helptext_, bool spaced_)
00147     : CmdLineHelpText(helptext_)
00148 {
00149     print_infrontof_option = options ? options->size() : 0;
00150     if (!annotations) annotations = new Annotations();
00151     annotations->push_back(this);
00152     spaced = spaced_;
00153 }
00154 
00155 // --------------------------------------------------------------------------------
00156 //     CmdLineArgumentOption::CmdLineArgumentOption(char optChar_, const char *name_, const char *helptext_, const char *value_)
00157 // --------------------------------------------------------------------------------
00158 CmdLineArgumentOption::CmdLineArgumentOption(char optChar_, const char *name_, const char *helptext_, const char *value_)
00159     : CmdLineOption(optChar_, helptext_)
00160     , CmdLineArgument(name_, helptext_, value_, false)
00161     , CmdLineHelpText(helptext_)
00162 {
00163 #if defined(DUMP_PARSE)
00164     cout << "CmdLineArgumentOption(" << optChar_ << ", " << name_ << ", " << helptext_ << ", " << value_ << ")\n";
00165 #endif // DUMP_PARSE
00166     if (value_) {
00167         if (value_[0]==0) {
00168             cerr << "Empty default argument for option -" << optChar_ << endl;
00169             throw InternalError("see above");
00170         }
00171         CmdLineOption::set();
00172     }
00173     longest_optarg_name_length = max(get_name().length(), longest_optarg_name_length);
00174 }
00175 
00176 // --------------------------------------------------------------------------------
00177 //     CmdLineArgumentOption::~CmdLineArgumentOption()
00178 // --------------------------------------------------------------------------------
00179 CmdLineArgumentOption::~CmdLineArgumentOption() {
00180 }
00181 
00182 // --------------------------------------------------------------------------------
00183 //     void CmdLineArgumentOption::print(ostream& out) const
00184 // --------------------------------------------------------------------------------
00185 void CmdLineArgumentOption::print(ostream& out) const {
00186     out << '-' << get_optChar() << get_name() << string(longest_optarg_name_length-get_name().length()+1, ' ');
00187 }
00188 
00189 //  ------------------------------------------
00190 //      int CmdLineArgument::getNumeric()
00191 //  ------------------------------------------
00192 int CmdLineArgument::getNumeric() {
00193     string val    = get();
00194     int    digits = 0;
00195     int    xs     = 0;
00196     int    len    = val.length();
00197 
00198     int p;
00199     for (p=0; p<len; ++p) {
00200         char c = val[p];
00201         if (c>='0' && c<='9') {
00202             ++digits;
00203         }
00204         else {
00205             if (c=='x') ++xs;
00206         }
00207     }
00208 
00209     int result = 0;
00210     if (len==digits) { // only digits found
00211         result = atoi(val.c_str());
00212     }
00213     else {
00214         if ((xs+digits)==len && xs==1 && val[0]=='0' && val[p]=='x') { // hex-number
00215             result = strtoul(val.c_str()+2, 0, 16);
00216         }
00217         else {
00218             throw Error(str::strf("Numeric argument awaited in <%s> '%s' (dec or hex '0x..') ",
00219                                   name.c_str(), val.c_str()));
00220         }
00221     }
00222 
00223     return result;
00224 }
00225 
00226 //  --------------------------------------------
00227 //      double CmdLineArgument::getDouble()
00228 //  --------------------------------------------
00229 double CmdLineArgument::getDouble() {
00230     string val    = get();
00231     int    digits = 0;
00232     int    kommas = 0;
00233     int    len    = val.length();
00234 
00235     int p;
00236     for (p=0; p<len; ++p) {
00237         char c = val[p];
00238         if (c>='0' && c<='9') {
00239             ++digits;
00240         }
00241         else {
00242             if (c=='.') ++kommas;
00243             else if (c==',') { ++kommas; val[p] = '.'; }
00244         }
00245     }
00246 
00247     double result = 0;
00248     if (len==digits) { // only digits found
00249         result = atoi(val.c_str());
00250     }
00251     else {
00252         if ((kommas+digits) == len && kommas==1) { // floating point
00253             result = atof(val.c_str());
00254         }
00255         else {
00256             throw Error(str::strf("Floating point argument awaited in <%s> '%s'",
00257                                   name.c_str(), val.c_str()));
00258         }
00259     }
00260 
00261     return result;
00262 }
00263 
00264 // --------------------------------------------------------------------------------
00265 //     CmdLineArgument::CmdLineArgument(const char *name_, const char *helptext_, const char *value_, bool is_real_arg)
00266 // --------------------------------------------------------------------------------
00267 CmdLineArgument::CmdLineArgument(const char *name_, const char *helptext_, const char *value_, bool is_real_arg)
00268     : CmdLineHelpText(helptext_),
00269       name(name_),
00270       value(value_ ? value_ : ""),
00271       has_default_value(false),
00272       really_used(false)
00273 {
00274 #if defined(DUMP_PARSE)
00275     cout << "CmdLineArgument(" << name_ << ", " << helptext_ << ", " << int(is_real_arg) << ")\n";
00276 #endif // DUMP_PARSE
00277     if (is_real_arg) {
00278         if (!arguments) arguments = new Arguments(0);
00279         arguments->push_back(this);
00280         longest_arg_name_length = max(get_name().length(), longest_arg_name_length);
00281     }
00282 }
00283 
00284 namespace rs {
00285     namespace cmdline {
00286         //  ------------------------------------------------------
00287         //      bool acceptAnyArgument(const string */*arg*/)
00288         //  ------------------------------------------------------
00289         bool acceptAnyArgument(const string */*arg*/) {
00290             return true;
00291         }
00292     };
00293 };
00294 
00295 // --------------------------------------------------------------------------------
00296 //     CmdLineArgument::~CmdLineArgument()
00297 // --------------------------------------------------------------------------------
00298 CmdLineArgument::~CmdLineArgument() {
00299 }
00300 
00301 // start of implementation of class RepeatableCmdLineArgument:
00302 
00303 // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
00304 //      RepeatableCmdLineArgument::RepeatableCmdLineArgument(const char *name_, const char *helptext_, int min_occur_, int max_occur_, CmdLineArgumentPredicate isArg_, bool is_real_arg)
00305 // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
00306 RepeatableCmdLineArgument::RepeatableCmdLineArgument(const char *name_, const char *helptext_, int min_occur_, int max_occur_, CmdLineArgumentPredicate isArg_, bool is_real_arg)
00307     : CmdLineArgument(name_, helptext_, 0, is_real_arg)
00308     , CmdLineHelpText(helptext_)
00309 {
00310     min_occur = min_occur_;
00311     max_occur = max_occur_;
00312     isArg = isArg_;
00313     count = 0;
00314 
00315     // do not set longest_arg_name_length here (it's set in cons of CmdLineArgument)
00316     // and we don't want to know the length of '[<arg>]+' but of '<arg>'
00317 
00318     //longest_arg_name_length = max(get_name().length(), longest_arg_name_length);
00319 }
00320 
00321 // -----------------------------------------------------------
00322 //      string RepeatableCmdLineArgument::get_name() const
00323 // -----------------------------------------------------------
00324 string RepeatableCmdLineArgument::get_name() const {
00325     string Name = string("[") + CmdLineArgument::get_name() + "]";
00326 
00327     if (min_occur==0) {
00328         if (max_occur>1) Name = Name+"*";
00329     }
00330     else {
00331         Name = Name+"+";
00332     }
00333     return Name;
00334 }
00335 
00336 // ------------------------------------------------
00337 //      string RepeatableCmdLineArgument::get()
00338 // ------------------------------------------------
00339 string RepeatableCmdLineArgument::get()
00340 {
00341     string result = CmdLineArgument::get();
00342     if (!result.empty()) seen_values.push_back(result); // store as seen
00343     if (repeated_values.empty()) {
00344         CmdLineArgument::set("");
00345     }
00346     else {
00347         CmdLineArgument::set(repeated_values.front());
00348         repeated_values.pop_front();
00349     }
00350     return result;
00351 }
00352 
00353 // ------------------------------------------------
00354 //      void RepeatableCmdLineArgument::reset()
00355 // ------------------------------------------------
00356 void RepeatableCmdLineArgument::reset()
00357 {
00358     while (!get().empty()) ;    // read leftover arguments
00359     repeated_values = seen_values;
00360     seen_values.clear();
00361     get();
00362 }
00363 
00364 // -end- of implementation of class RepeatableCmdLineArgument.
00365 
00366 // --------------------------------------------------------------------------------
00367 //     class HasOptChar : public unary_function<CmdLineOption*, char>
00368 // --------------------------------------------------------------------------------
00370 class HasOptChar : public unary_function<CmdLineOption*, char> {
00371     char optChar;
00372 public:
00373     explicit HasOptChar(char optChar_) :optChar(optChar_) {}
00374     bool operator() (const CmdLineOption* const & opt) const { return optChar==opt->get_optChar(); }
00375 };
00376 
00377 // start of implementation of class RepeatedCmdLineArgumentOption:
00378 
00379 // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
00380 //      RepeatedCmdLineArgumentOption::RepeatedCmdLineArgumentOption(char optChar_, const char *argname_, char separator_, const char *helptext_, const char *value_)
00381 // ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
00382 RepeatedCmdLineArgumentOption::RepeatedCmdLineArgumentOption(char optChar_, const char *argname_, char separator_, const char *helptext_, const char *value_)
00383     : CmdLineOption(optChar_, helptext_)
00384     , RepeatableCmdLineArgument(argname_, helptext_, 1, -1, acceptAnyArgument, false)
00385     , CmdLineHelpText(helptext_)
00386     , separator(separator_)
00387 {
00388     if (value_) set(value_, true);
00389     longest_optarg_name_length = max(get_name().length(), longest_optarg_name_length);
00390 }
00391 
00392 // ----------------------------------------------------------------------------------------
00393 //      void RepeatedCmdLineArgumentOption::set(string value_, bool set_default_value)
00394 // ----------------------------------------------------------------------------------------
00395 void RepeatedCmdLineArgumentOption::set(string value_, bool set_default_value) {
00396     size_t start = 0;
00397     size_t seppos;
00398     string next_arg;
00399 
00400     CmdLineOption::set();
00401     while (string::npos != (seppos = value_.find(separator, start))) {
00402         next_arg = value_.substr(start, seppos-start);
00403         if (!next_arg.empty()) RepeatableCmdLineArgument::set(next_arg, set_default_value);
00404         start    = seppos+1;
00405     }
00406     next_arg = value_.substr(start);
00407     if (!next_arg.empty()) RepeatableCmdLineArgument::set(next_arg, set_default_value);
00408 }
00409 
00410 // ---------------------------------------------------------------
00411 //      string RepeatedCmdLineArgumentOption::get_name() const
00412 // ---------------------------------------------------------------
00413 string RepeatedCmdLineArgumentOption::get_name() const {
00414     const char *Name = CmdLineArgument::get_name().c_str();
00415     return strf("%s[%c%s]*", Name, separator, Name);
00416 }
00417 
00418 // ----------------------------------------------------------------------
00419 //      void RepeatedCmdLineArgumentOption::print(ostream& out) const
00420 // ----------------------------------------------------------------------
00421 void RepeatedCmdLineArgumentOption::print(ostream& out) const
00422 {
00423     string Name   = get_name();
00424     int    spaces = longest_optarg_name_length - Name.length() + 1;
00425     assert(spaces >= 0);
00426     out << '-' << get_optChar() << Name << string(spaces, ' ');
00427 }
00428 
00429 // -end- of implementation of class RepeatedCmdLineArgumentOption.
00430 
00431 // start of implementation of class ProgramInfo:
00432 
00433 //  --------------------------------------------------------------------------------------------------------------------------------------------------------------
00434 //      ProgramInfo::ProgramInfo(const char *program_name_, int main_version_, int sub_version_, const char *program_description_, const char *creation_date_)
00435 //  --------------------------------------------------------------------------------------------------------------------------------------------------------------
00436 ProgramInfo::ProgramInfo(const char *program_name_, int main_version_, int sub_version_, const char *program_description_, const char *creation_date_)
00437     : program_name(program_name_),
00438       main_version(main_version_),
00439       sub_version(sub_version_),
00440       program_description(program_description_),
00441       creation_date(creation_date_),
00442       any_option_given(false)
00443 {
00444     Error::set_module_name(program_name_);
00445 }
00446 
00447 // --------------------------------------------------------------------------------
00448 //      static bool test_existing_path(const string& candidate,string& result)
00449 // --------------------------------------------------------------------------------
00450 static bool test_existing_path(const string& candidate,string& result) {
00451     string canonical;
00452     bool   wrong_path = false;
00453 
00454 #if defined(PATH_DETECT)
00455     cout << "candidate='" << candidate << "'\n";
00456 #endif // PATH_DETECT
00457 
00458     try { canonical = canonicalize(candidate); }
00459     catch (IOError&) { wrong_path = true; }
00460 
00461 #if defined(PATH_DETECT)
00462     if (!canonical.empty()) cout << "canonical='" << canonical << "'\n";
00463 #endif // PATH_DETECT
00464 
00465     if (!wrong_path &&
00466         nonnull(canonical.length()) &&
00467         (fileExists(canonical) || fileExists(canonical+".exe")))
00468     {
00469 #if defined(PATH_DETECT)
00470         cout << canonical << " exists!\n";
00471 #endif // PATH_DETECT
00472         result = extractDirectory(canonical);
00473 #if defined(PATH_DETECT)
00474         cout << "result='" << result << "'\n";
00475 #endif // PATH_DETECT
00476         assert(!result.empty());
00477         return true;
00478     }
00479 
00480 //     if (candidate.find(".exe") == string::npos) {
00481 //         return test_existing_path(candidate+".exe", result);
00482 //     }
00483     return false;
00484 }
00485 
00486 // --------------------------------------------------------------
00487 //      void ProgramInfo::setProgramPaths(const char *argv0)
00488 // --------------------------------------------------------------
00489 void ProgramInfo::setProgramPaths(const char *argv0_) {
00490     call_path        = getcwd();
00491     string argv0     = argv0_;
00492 
00493 #if defined(PATH_DETECT)
00494     cout << "argv0='" << argv0 << "'\n";
00495     cout << "call_path='" << call_path << "'\n";
00496 #endif // PATH_DETECT
00497 
00498     if (!test_existing_path(argv0, program_path) &&
00499         !test_existing_path(string("./")+argv0, program_path))
00500     {
00501         sys_dep::Path path; // reads $PATH from environment
00502         for (vector<string>::const_iterator dir = path.begin(); dir != path.end(); ++dir) {
00503             if (test_existing_path(*dir+'/'+argv0_, program_path)) break;
00504         }
00505     }
00506 
00507     if (program_path.empty()) {
00508         throw Error(strf("Can't detect location of %s.exe -- please call with full pathname", program_name.c_str()));
00509     }
00510 
00511 #if defined(PATH_DETECT)
00512     cout << "program_path='" << program_path << "'\n";
00513 #endif // PATH_DETECT
00514 }
00515 //  ---------------------------------------------------------
00516 //      void ProgramInfo::init(int argc_, char* argv_[])
00517 //  ---------------------------------------------------------
00518 void ProgramInfo::init(int argc_, char* argv_[]) {
00519     // install terminator
00520     if (there_can_only_be_one == 0) there_can_only_be_one = new Terminator();
00521 
00522     // test option integrity:
00523     if (options) {
00524         bool char_used[256];
00525 
00526         for (int i=0; i<256; ++i) char_used[i] = false;
00527 
00528         for (Options::iterator o = options->begin(); o!=options->end(); ++o) {
00529             char c = (*o)->get_optChar();
00530 
00531             if (char_used[c]) {
00532                 throw InternalError(string("Duplicated usage of option character '")+c+"'");
00533             }
00534             char_used[c] = true;
00535             if (!options_are_case_sensitive && isalpha(c)) {
00536                 if (islower(c)) {
00537                     if (char_used[toupper(c)]) options_are_case_sensitive = true;
00538                 }
00539                 else {
00540                     if (char_used[tolower(c)]) options_are_case_sensitive = true;
00541                 }
00542             }
00543         }
00544     }
00545 
00546     // set defaults for options and arguments
00547     if (options) {
00548         for (Options::iterator o=options->begin(); o!=options->end(); ++o) {
00549             CmdLineArgumentOption *arg_opt = dynamic_cast<CmdLineArgumentOption*>(*o);
00550             if (arg_opt) { // is an argument option
00551                 arg_opt->set_has_default();
00552             }
00553         }
00554     }
00555 
00556     if (arguments) {
00557         for (Arguments::iterator a=arguments->begin(); a!=arguments->end(); ++a) {
00558             (*a)->set_has_default();
00559         }
00560     }
00561 
00562     bool allow_multiple_usage = false; // warn if an option is used more than once
00563 
00564     // proceed through command line
00565     Arguments::iterator next_arg;
00566     if (arguments) next_arg = arguments->begin();
00567 
00568 //     setProgramPaths("once");
00569     setProgramPaths(argv_[0]);
00570 
00571     for (int a=1; a<argc_; a++) {
00572         const char *arg = argv_[a];
00573 
00574 #if defined(DUMP_PARSE)
00575         cout << "Parse arg #" << a << ": '" << arg << "'\n";
00576 #endif // DUMP_PARSE
00577 
00578         // test for help-requests
00579         if ((arg[0]=='/' || arg[0]=='-') &&
00580             (arg[1]=='?' || arg[1]=='h' || (arg[1]=='-' && strcmp(arg+2, "help")==0)) )
00581         {
00582             throw InfoError(*this, false, "Help requested");
00583         }
00584 
00585         if (arg[0]=='-') {      // option found
00586             bool internal_option = false;
00587             if (arg[1] == '-') { // maybe an internal option
00588                 const char *longopt = arg+2;
00589                 internal_option     = true;
00590                 if (rs::str::stricmp(longopt, "multi") == 0) {
00591                     allow_multiple_usage = true;
00592                 }
00593                 else if (stricmp(string(longopt), "multi") == 0) {
00594                 }
00595                 else {
00596                     throw StringError(string("Unknown long option '")+arg+"'",
00597                                       "Valid options are:\n"
00598                                       "     --help          show command line help\n"
00599                                       "     --multi         allow to use args multiple (behind this option)\n"
00600                                       );
00601                 }
00602             }
00603 
00604             if (!internal_option) {
00605                 size_t pos        = 1;
00606                 bool   done       = false;
00607                 char   switchChar = arg[0];
00608 
00609                 while (!done) {
00610                     char optChar = arg[pos];
00611                     if (!optChar) {
00612                         if (pos==1) throw InfoError(*this, string("character awaited behind '") + switchChar + '\'');
00613                         break;
00614                     }
00615 
00616                     CmdLineOption *found_option = 0;
00617 
00618                     if (options) {
00619                         Options::iterator found = find_if(options->begin(), options->end(), HasOptChar(optChar));
00620                         if (found!=options->end()) {
00621                             found_option = *found;
00622                         }
00623                     }
00624 
00625                     if (!found_option) {
00626                         throw InfoError(*this, string("Unknown option '") + switchChar + optChar + '\'' );
00627                     }
00628 
00629                     any_option_given = true;
00630                     if (found_option->reallyUsed()) { // option was already set
00631                         if (!allow_multiple_usage) {
00632                             throw InfoError(*this, string("Option '")+switchChar+optChar+"' was already used (preceed with --multi to avoid this warning).");
00633                         }
00634                     }
00635 
00636                     if (found_option->takes_argument()) {
00637                         CmdLineArgumentOption *arg_option = static_cast<CmdLineArgumentOption*>(found_option);
00638                         string arg_value;
00639 
00640                         if (arg[pos+1]==0) { // arg_value is in next argv_
00641                             if (a<(argc_-1)) { // there is another arg
00642                                 arg_value = argv_[++a];
00643                             }
00644                         }
00645                         else { // arg_value appeded to option
00646                             arg_value = string(arg, pos+1, string::npos);
00647                         }
00648 
00649                         if (arg_value.empty()) {
00650                             throw InfoError(*this, string("Option ") + switchChar + optChar + " awaits argument " + arg_option->get_name());
00651                         }
00652                         arg_option->set(arg_value);
00653                         done = true;
00654                     }
00655                     else {
00656                         found_option->set();
00657                     }
00658                     pos++;
00659                 }
00660             }
00661         }
00662         else { // it seems to be an argument
00663             bool arg_handler_found = false; // detected correct arg handler?
00664             bool inc_arg_handler = true; // continue with next arg handler afterwards
00665 
00666             while (!arg_handler_found) {
00667                 if (!arguments || next_arg==arguments->end()) {
00668                     throw InfoError(*this, string("Superfluous argument '")+arg+'\'');
00669                 }
00670 
00671                 RepeatableCmdLineArgument *repeatable = dynamic_cast<RepeatableCmdLineArgument*>(*next_arg);
00672 
00673                 if (repeatable) {
00674                     inc_arg_handler = false;
00675                     if (repeatable->get_count() < repeatable->get_min_occur()) { // if we have not scanned enough of this yet
00676                         arg_handler_found = true; // use it anyway
00677                     }
00678                     else { // we have scanned enough of it
00679                         int max_occur = repeatable->get_max_occur();
00680                         assert(max_occur==-1 || repeatable->get_count()<max_occur); // otherwise next_arg should have been incremented before
00681                         string arg_str(arg);
00682                         if (repeatable->isArg(&arg_str)) { // should be added to repeatable
00683                             arg_handler_found = true;
00684                             if (repeatable->get_count()==(max_occur-1)) {
00685                                 inc_arg_handler = true;
00686                             }
00687                         }
00688                         else {
00689                             ++next_arg; // try next arg
00690                         }
00691                     }
00692                 }
00693                 else {
00694                     arg_handler_found = true;
00695                 }
00696             }
00697 
00698             (*next_arg)->set(arg);
00699             if (inc_arg_handler) ++next_arg;
00700         }
00701     }
00702 
00703     if (arguments) {
00704         if (next_arg!=arguments->end()) {
00705             string err("Missing arguments:");
00706             bool raise_error = false;
00707 
00708             do {
00709                 RepeatableCmdLineArgument *repeated = dynamic_cast<RepeatableCmdLineArgument*>(*next_arg);
00710                 bool is_missing = true;
00711 
00712                 if (repeated) {
00713                     if (repeated->get_count() >= repeated->get_min_occur()) { // may be enough
00714                         if (repeated->isArg(0)) { // argument should be missing
00715                             is_missing = false;
00716                         }
00717                     }
00718                 }
00719 
00720                 if (is_missing) {
00721                     err += ' ';
00722                     err += (*next_arg)->get_name();
00723                     raise_error = true;
00724                 }
00725                 next_arg++;
00726             }
00727             while(next_arg!=arguments->end());
00728 
00729             if (raise_error) throw InfoError(*this, err);
00730         }
00731     }
00732 
00733     initialized = true;
00734 }
00735 
00736 // --------------------------------------------------------------------------------
00737 //     void ProgramInfo::infos(ostream& out) const
00738 // --------------------------------------------------------------------------------
00739 
00742 void ProgramInfo::infos(ostream& out) const {
00743     size_t border    = 1;
00744     size_t tty_width = 80;
00745     size_t width = tty_width-2*border;
00746     string left(border, ' ');
00747     string line  = left+string(width, '-')+'\n';
00748 
00749     out << "\n"
00750         << line
00751         << left << program_name << ' ';
00752     out << int(main_version) << '.' << setw(2) << setfill('0') << int(sub_version);
00753     out << "   ---   (C) " << creation_date << " by " << COPYRIGHT_BY() << "\n";
00754     out << line
00755         << left << "Purpose: "; output::printIndented(out, 9, border, width, program_description);
00756     out << left << "Usage  : " << program_name;
00757 
00758     if (options) out << " <opts>";
00759 
00760     if (arguments) {
00761         for (Arguments::iterator i=arguments->begin(); i!=arguments->end(); i++) {
00762             out << ' ' << (*i)->get_name();
00763         }
00764     }
00765     out << "\n"
00766         << "\n";
00767 
00768     // show detailed info on arguments:
00769     if (arguments) {
00770         for (Arguments::iterator i=arguments->begin(); i!=arguments->end(); i++) {
00771             string arg_left = (*i)->CmdLineArgument::get_name();
00772             unsigned len = arg_left.length();
00773 
00774             if (len<longest_arg_name_length) {
00775                 unsigned spaces = longest_arg_name_length-len;
00776                 arg_left += string(spaces, ' ');
00777                 len += spaces;
00778             }
00779 
00780             arg_left += "::= ";
00781             len += 4;
00782 
00783             out << left << arg_left; output::printIndented(out, len, border, width, (*i)->get_helptext());
00784         }
00785         out << "\n";
00786     }
00787 
00788     // show detailed info on options:
00789     string opt_left = "<opts>";
00790 //  unsigned len1 = opt_left.length();
00791 
00792 //     if (len1<longest_arg_name_length) {
00793 //         unsigned spaces = longest_arg_name_length-len1;
00794 //         opt_left += string(spaces, ' ');
00795 //         len1 += spaces;
00796 //     }
00797 
00798     opt_left += "::= ";
00799     //    len1 += 4;
00800     unsigned len1 = opt_left.length();
00801 
00802     if (!options) options = new Options();
00803     if (!annotations) annotations = new Annotations();
00804 
00805     Options::iterator i = options->begin();
00806     Annotations::iterator j = annotations->begin();
00807     int printed = 0;
00808 
00809     while (i!=options->end()) {
00810         out << left << opt_left;
00811         if (i==options->begin()) {
00812             opt_left = string(len1, ' ');
00813             assert(opt_left.length()==len1);
00814         }
00815 
00816         if (j!=annotations->end()) {
00817             if ((*j)->get_print_infrontof_option()==printed) {
00818                 output::printIndented(out, len1, border, width,
00819                                       (*j)->print_spaced()
00820                                       ? string("\n")+(*j)->get_helptext()+"\n"
00821                                       : (*j)->get_helptext());
00822 
00823                 out << left << opt_left;
00824                 ++j;
00825             }
00826         }
00827 
00828         (*i)->print(out);
00829         output::printIndented(out, len1 + 2 + longest_optarg_name_length + 1, border, width, (*i)->get_helptext());
00830 
00831         ++i;
00832         ++printed;
00833     }
00834 
00835     if (j!=annotations->end()) {
00836         opt_left = string(len1, ' ');
00837         while (j!=annotations->end()) {
00838             output::printIndented(out, printed ? len1 : 0, border, width, string("\n")+(*j)->get_helptext()+"\n");
00839             ++j;
00840         }
00841     }
00842 
00843     out << line
00844         << left << "Contact: " << MAIL_CONTACT(program_name) << "\n"
00845         << line;
00846 }
00847 
00848 // --------------------------------------------------------------------------------
00849 //     static string countOptions(CmdLineOptionArray optList, size_t& used_options, const string& trennwort, bool return_used_options)
00850 // --------------------------------------------------------------------------------
00851 static string countOptions(CmdLineOptionArray optList, size_t& used_options, const string& trennwort, bool return_used_options) {
00852     test_initialized("countOptions");
00853 
00854     used_options = 0;
00855     unsigned i;
00856 
00857     for (i = 0; optList[i]; i++) {
00858         if (optList[i]->reallyUsed()) used_options++;
00859     }
00860 
00861     unsigned size = i;
00862     size_t counter = 0;
00863     string opts;
00864     for (i = 0; optList[i]; i++) {
00865         if (return_used_options==false || optList[i]->reallyUsed()) { // insert option into return-string?
00866             counter++;
00867             bool is_first = counter==1;
00868             bool is_last = return_used_options ? (counter==used_options) : (counter==size);
00869 
00870             if (is_last) {
00871                 opts = opts+' '+trennwort;
00872             }
00873             else if (!is_first) {
00874                 opts += ',';
00875             }
00876             opts = opts+" -" + optList[i]->get_optChar();
00877         }
00878     }
00879 
00880     return opts;
00881 }
00882 
00883 //  --------------------------------------------------------------------------------------------
00884 //      void ProgramInfo::exclude(CmdLineOptionArray optList1, CmdLineOptionArray optList2)
00885 //  --------------------------------------------------------------------------------------------
00886 void ProgramInfo::exclude(CmdLineOptionArray optList1, CmdLineOptionArray optList2) {
00887     test_initialized("exclude");
00888 
00889     for (unsigned i1=0; optList1[i1]; ++i1) {
00890         if (optList1[i1]->reallyUsed()) { // used?
00891             for (unsigned i2=0; optList2[i2]; ++i2) {
00892                 if (optList2[i2]->reallyUsed()) { // used?
00893                     if (optList1[i1]!=optList2[i2]) { // not same option
00894                         throw InfoError(*this, string("Option -")+optList1[i1]->get_optChar()+
00895                                         " can't be used together with -"+optList2[i2]->get_optChar());
00896                     }
00897                 }
00898             }
00899         }
00900     }
00901 }
00902 
00903 // --------------------------------------------------------------------------------
00904 //     void ProgramInfo::needOne(CmdLineOptionArray optList)
00905 // --------------------------------------------------------------------------------
00906 void ProgramInfo::needOne(CmdLineOptionArray optList) {
00907     size_t Count;
00908     string ex_opt = countOptions(optList, Count, "or", false);
00909 #if defined(DEBUG)
00910     cerr << "needOne: '" << ex_opt << "'\n";
00911 #endif // DEBUG
00912     if (Count==0) {
00913         string msg = "You have to specify one of the options"+ex_opt+'.';
00914         throw InfoError(*this, msg);
00915     }
00916 }
00917 
00918 // --------------------------------------------------------------------------------
00919 //     void ProgramInfo::neededBy(const CmdLineOption& drug, const CmdLineOption& addict)
00920 // --------------------------------------------------------------------------------
00921 void ProgramInfo::neededBy(const CmdLineOption& drug, const CmdLineOption& addict) {
00922     if (addict.reallyUsed() && !drug) {
00923         throw InfoError(*this, string("Specifying option -")+addict.get_optChar()+ " does not make sense without option -"+drug.get_optChar());
00924     }
00925 }
00926 //  --------------------------------------------------------------
00927 //      void ProgramInfo::throw_Error(const string& msg) const
00928 //  --------------------------------------------------------------
00929 void ProgramInfo::throw_Error(const string& msg) const {
00930     throw InfoError(*this, msg);
00931 }
00932 
00933 // ----------------------------------------------------
00934 //      const string& ProgramInfo::CallPath() const
00935 // ----------------------------------------------------
00936 const string& ProgramInfo::CallPath() const
00937 {
00938     test_initialized("CallPath");
00939     return call_path;
00940 }
00941 
00942 // -------------------------------------------------------
00943 //      const string& ProgramInfo::ProgramPath() const
00944 // -------------------------------------------------------
00945 const string& ProgramInfo::ProgramPath() const
00946 {
00947     test_initialized("ProgramPath");
00948     return program_path;
00949 }
00950 
00951 // -end- of implementation of class ProgramInfo.
00952 

Contact me in case of errors or questions.
This documentation is powered by Doxygen.
(C) 2000-2002 Doxygen