00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00035 #include "OW_config.h"
00036 #include "OW_CmdLineParser.hpp"
00037 #include "OW_Array.hpp"
00038 #include "OW_ExceptionIds.hpp"
00039 #include "OW_StringBuffer.hpp"
00040 #include "OW_Assertion.hpp"
00041 
00042 #include <algorithm>
00043 
00044 
00045 namespace OW_NAMESPACE
00046 {
00047 
00048 OW_DEFINE_EXCEPTION_WITH_ID(CmdLineParser)
00049 
00050 namespace
00051 {
00053    struct longOptIs
00054    {
00055       longOptIs(const String& longOpt) : m_longOpt(longOpt) {}
00056 
00057       bool operator()(const CmdLineParser::Option& x) const
00058       {
00059          if (x.longopt != 0)
00060          {
00061             return m_longOpt.startsWith(x.longopt);
00062          }
00063          return false;
00064       }
00065 
00066       String m_longOpt;
00067    };
00068 
00070    struct shortOptIs
00071    {
00072       shortOptIs(char shortOpt) : m_shortOpt(shortOpt) {}
00073 
00074       bool operator()(const CmdLineParser::Option& x) const
00075       {
00076          return m_shortOpt == x.shortopt;
00077       }
00078 
00079       char m_shortOpt;
00080    };
00081 
00082 }
00083 
00085 CmdLineParser::CmdLineParser(int argc, char const* const* const argv_, const Option* options, EAllowNonOptionArgsFlag allowNonOptionArgs)
00086 {
00087    OW_ASSERT(argc > 0); 
00088    OW_ASSERT(argv_ != 0);
00089    OW_ASSERT(options != 0);
00090    char const* const* argv = argv_;
00091    char const* const* argvEnd = argv + argc;
00092 
00093    
00094    const Option* optionsEnd(options);
00095    while (optionsEnd->shortopt != '\0' || optionsEnd->longopt != 0)
00096    {
00097       ++optionsEnd;
00098    }
00099 
00100    
00101    ++argv;
00102    while (argv != argvEnd)
00103    {
00104       OW_ASSERT(*argv != 0);
00105       String arg(*argv);
00106 
00107       
00108       if ((arg.length() >= 2) && (arg[0] == '-'))
00109       {
00110          const Option* theOpt(0);
00111          bool longOpt = false;
00112          if (arg[1] == '-')
00113          {
00114             
00115             longOpt = true;
00116             arg = arg.substring(2); 
00117             theOpt = std::find_if (options,  optionsEnd, longOptIs(arg));
00118          }
00119          else 
00120          {
00121             longOpt = false;
00122             arg = arg.substring(1); 
00123             theOpt = std::find_if (options,  optionsEnd, shortOptIs(arg[0]));
00124          }
00125 
00126          if (theOpt == optionsEnd)
00127          {
00128             OW_THROW_ERR(CmdLineParserException, arg.c_str(), E_INVALID_OPTION);
00129          }
00130 
00131          if (theOpt->argtype == E_NO_ARG)
00132          {
00133             m_parsedOptions[theOpt->id]; 
00134             ++argv;
00135             continue;
00136          }
00137          
00138          String val;
00139          if ((theOpt->argtype == E_OPTIONAL_ARG) && (theOpt->defaultValue != 0))
00140          {
00141             val = theOpt->defaultValue;
00142          }
00143          
00144          const char* p = ::strchr(arg.c_str(), '=');
00145          if (p)
00146          {
00147             
00148             val = String(p+1);
00149          }
00150          else
00151          {
00152             
00153             if (longOpt == false && arg.length() > 1)
00154             {
00155                val = arg.substring(1);
00156             }
00157             
00158             else if (argv+1 != argvEnd)
00159             {
00160                if (**(argv+1) != '-')
00161                {
00162                   val = *(argv+1);
00163                   ++argv;
00164                }
00165             }
00166          }
00167 
00168          
00169          if (theOpt->argtype == E_REQUIRED_ARG && val.empty())
00170          {
00171             OW_THROW_ERR(CmdLineParserException, arg.c_str(), E_MISSING_ARGUMENT);
00172          }
00173 
00174          m_parsedOptions[theOpt->id].push_back(val);
00175       }
00176       else
00177       {
00178          if (allowNonOptionArgs == E_NON_OPTION_ARGS_INVALID)
00179          {
00180             OW_THROW_ERR(CmdLineParserException, arg.c_str(), E_INVALID_NON_OPTION_ARG);
00181          }
00182          else
00183          {
00184             m_nonOptionArgs.push_back(arg);
00185          }
00186       }
00187       ++argv;
00188    }
00189 }
00190 
00192 
00193 String
00194 CmdLineParser::getUsage(const Option* options, unsigned int maxColumns)
00195 {
00196 
00197 
00198 
00199 
00200 
00201 
00202    const unsigned int NUM_OPTION_COLUMNS = 28;
00203    StringBuffer usage("Options:\n");
00204 
00205    
00206    for (const Option* curOption = options; curOption->shortopt != '\0' || curOption->longopt != 0; ++curOption)
00207    {
00208       StringBuffer curLine;
00209       curLine += "  ";
00210       if (curOption->shortopt != '\0')
00211       {
00212          curLine += '-';
00213          curLine += curOption->shortopt;
00214          if (curOption->longopt != 0)
00215          {
00216             curLine += ", ";
00217          }
00218       }
00219       if (curOption->longopt != 0)
00220       {
00221          curLine += "--";
00222          curLine += curOption->longopt;
00223       }
00224 
00225       if (curOption->argtype == E_REQUIRED_ARG)
00226       {
00227          curLine += " <arg>";
00228       }
00229       else if (curOption->argtype == E_OPTIONAL_ARG)
00230       {
00231          curLine += " [arg]";
00232       }
00233 
00234       size_t bufferlen = (curLine.length() >= NUM_OPTION_COLUMNS-1) ? 1 : (NUM_OPTION_COLUMNS - curLine.length());
00235       for (size_t i = 0; i < bufferlen; ++i)
00236       {
00237          curLine += ' ';
00238       }
00239 
00240       if (curOption->description != 0)
00241       {
00242          curLine += curOption->description;
00243       }
00244 
00245       if (curOption->defaultValue != 0)
00246       {
00247          curLine += " (default is ";
00248          curLine += curOption->defaultValue;
00249          curLine += ')';
00250       }
00251 
00252       
00253       while (curLine.length() > maxColumns || curLine.toString().indexOf('\n') != String::npos)
00254       {
00255          String curLineStr(curLine.toString());
00256          
00257          size_t newlineIdx = curLineStr.indexOf('\n');
00258 
00259          
00260          size_t lastSpaceIdx = curLineStr.lastIndexOf(' ', maxColumns);
00261 
00262          size_t cutIdx = 0;
00263          size_t nextLineBeginIdx = 0;
00264          if (newlineIdx <= maxColumns)
00265          {
00266             cutIdx = newlineIdx;
00267             nextLineBeginIdx = newlineIdx + 1; 
00268          }
00269          else if (lastSpaceIdx > NUM_OPTION_COLUMNS)
00270          {
00271             cutIdx = lastSpaceIdx;
00272             nextLineBeginIdx = lastSpaceIdx + 1; 
00273          }
00274          else
00275          {
00276             
00277             cutIdx = maxColumns;
00278             nextLineBeginIdx = maxColumns;
00279          }
00280 
00281          
00282          usage += curLineStr.substring(0, cutIdx);
00283          usage += '\n';
00284 
00285          
00286          StringBuffer spaces;
00287          for (size_t i = 0; i < NUM_OPTION_COLUMNS; ++i)
00288          {
00289             spaces += ' ';
00290          }
00291          curLine = spaces.releaseString() + curLineStr.substring(nextLineBeginIdx);
00292       }
00293 
00294       curLine += '\n';
00295       usage += curLine;
00296    }
00297    return usage.releaseString();
00298 }
00299 
00301 String
00302 CmdLineParser::getOptionValue(int id, const char* defaultValue) const
00303 {
00304    optionsMap_t::const_iterator ci = m_parsedOptions.find(id);
00305    if (ci != m_parsedOptions.end() && ci->second.size() > 0)
00306    {
00307       
00308       return ci->second[ci->second.size()-1];
00309    }
00310    return defaultValue;
00311 }
00312 
00314 String
00315 CmdLineParser::mustGetOptionValue(int id, const char* exceptionMessage) const
00316 {
00317    optionsMap_t::const_iterator ci = m_parsedOptions.find(id);
00318    if (ci != m_parsedOptions.end() && ci->second.size() > 0)
00319    {
00320       
00321       return ci->second[ci->second.size()-1];
00322    }
00323    OW_THROW_ERR(CmdLineParserException, exceptionMessage, E_MISSING_OPTION);
00324 }
00325 
00327 StringArray
00328 CmdLineParser::getOptionValueList(int id) const
00329 {
00330    StringArray rval;
00331    optionsMap_t::const_iterator ci = m_parsedOptions.find(id);
00332    if (ci != m_parsedOptions.end() && ci->second.size() > 0)
00333    {
00334       rval = ci->second;
00335    }
00336    return rval;
00337 }
00338 
00340 StringArray
00341 CmdLineParser::mustGetOptionValueList(int id, const char* exceptionMessage) const
00342 {
00343    optionsMap_t::const_iterator ci = m_parsedOptions.find(id);
00344    if (ci != m_parsedOptions.end() && ci->second.size() > 0)
00345    {
00346       return ci->second;
00347    }
00348    OW_THROW_ERR(CmdLineParserException, exceptionMessage, E_MISSING_OPTION);
00349 }
00350 
00352 bool
00353 CmdLineParser::isSet(int id) const
00354 {
00355    return m_parsedOptions.count(id) > 0;
00356 }
00357 
00359 size_t
00360 CmdLineParser::getNonOptionCount () const
00361 {
00362    return m_nonOptionArgs.size();
00363 }
00364 
00366 String
00367 CmdLineParser::getNonOptionArg(size_t n) const
00368 {
00369    return m_nonOptionArgs[n];
00370 }
00371 
00373 StringArray
00374 CmdLineParser::getNonOptionArgs() const
00375 {
00376    return m_nonOptionArgs;
00377 }
00378 
00379 
00380 
00381 } 
00382 
00383 
00384