CPUnit 0.95 (beta)
The REAL C++ port of JUnit.
/Users/Shared/Development/cpp/sourceforge/cpunit_095/src/cpunit_CmdLineParser.cpp
Go to the documentation of this file.
00001 /*
00002    Copyright (c) 2011 Daniel Bakkelund.
00003    All rights reserved.
00004 
00005    Redistribution and use in source and binary forms, with or without
00006    modification, are permitted provided that the following conditions
00007    are met:
00008     1. Redistributions of source code must retain the above copyright
00009        notice, this list of conditions and the following disclaimer.
00010     2. Redistributions in binary form must reproduce the above copyright
00011        notice, this list of conditions and the following disclaimer in the
00012        documentation and/or other materials provided with the distribution.
00013     3. Neither the name of the copyright holders nor the names of its
00014        contributors may be used to endorse or promote products derived from
00015        this software without specific prior written permission.
00016 
00017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
00027    THE POSSIBILITY OF SUCH DAMAGE.
00028 */
00029 
00030 #include "cpunit_CmdLineParser.hpp"
00031 #include "cpunit_IllegalArgumentException.hpp"
00032 #include <sstream>
00033 #include "cpunit_trace.hpp"
00034 
00035 const std::string 
00036 cpunit::CmdLineParser::BLANKS(" \t\n");
00037 
00038 cpunit::CmdLineParser::CmdLineParser() :
00039   legal_args(),
00040   args(),
00041   input()
00042 {}
00043 
00044 cpunit::CmdLineParser::CmdLineParser(const CmdLineParser &p) :
00045   legal_args(p.legal_args),
00046   args(p.args),
00047   input(p.input)
00048 {}
00049 
00050 cpunit::CmdLineParser::~CmdLineParser() 
00051 {}
00052 
00053 cpunit::CmdLineParser&
00054 cpunit::CmdLineParser::operator = (const CmdLineParser &p) {
00055   if (this != &p) {
00056     legal_args = p.legal_args;
00057     args = p.args;
00058     input = p.input;
00059   }
00060   return *this;
00061 }
00062 
00063 void
00064 cpunit::CmdLineParser::add_legal(const std::string &argnames) {
00065   std::size_t end = 0;
00066   for (std::size_t pos=0; pos<argnames.length(); pos = argnames.find_first_not_of(BLANKS, end)) {
00067     end = argnames.find_first_of(BLANKS, pos);
00068     const std::string s = argnames.substr(pos, end - pos);
00069     if (s.find_first_of(BLANKS) != std::string::npos) {
00070       std::ostringstream oss;
00071       oss<<"Option names cannot contain blank characters, was '"<<s<<'\'';
00072       throw IllegalArgumentException(oss.str());
00073     }
00074     if (s.length() < 2 || s[0] != '-' || (s.length() == 2 && s[1] == '-')) {
00075       std::ostringstream oss;
00076       oss<<"Option names cannot be empty and must be prepended by '-' or '--', was '"<<s<<'\'';
00077       throw IllegalArgumentException(oss.str());
00078     }
00079     if (s[1] != '-' && s.length() > 2) {
00080       std::ostringstream oss;
00081       oss<<"Options prepended by '-' can be single character only. Was '"<<s<<'\'';
00082       throw IllegalArgumentException(oss.str());
00083     }
00084     legal_args.insert(s);
00085   }
00086 }
00087 
00088 void 
00089 cpunit::CmdLineParser::parse(const int argc, const char ** cmdline) {
00090   for (int i=0; i<argc; ++i) {
00091     std::string arg(cmdline[i]);
00092     const std::size_t start = arg.find_first_not_of(BLANKS);
00093     arg = arg.substr(start);
00094     if (arg.length() > 0) {
00095       if (arg[0] == '-') {
00096    if (arg.length() == 1) {
00097      throw IllegalArgumentException("Illegal option: '-'");
00098    }
00099    if (arg[1] != '-') {
00100      parse_short_token(arg);
00101    } else {
00102      parse_long_token(arg);
00103    }
00104       } else {
00105    input.push_back(cmdline[i]);
00106       }
00107     }
00108   }
00109 }
00110 
00111 void
00112 cpunit::CmdLineParser::parse_short_token(const std::string &token) {
00113   const std::size_t end = token.find_first_of(" =");
00114   const std::string name = token.substr(0, end);
00115   std::string arg;
00116   for (std::size_t i=1; i<name.length(); ++i) {
00117     arg = std::string("-") + name[i];
00118     if (legal_args.find(arg) == legal_args.end()) {
00119       std::ostringstream oss;
00120       oss<<"Unknown option '"<<arg<<'\'';
00121       if (token.length() > 2) {
00122    oss<<" (specified in '"<<token<<"')";
00123       }
00124       throw IllegalArgumentException(oss.str());
00125     }
00126     args.insert(std::make_pair(arg, std::string("")));
00127     CPUNIT_ITRACE("CmdLineParser - Registered '"<<arg<<"' --> '' from '"<<token<<'\'');
00128   }
00129   if (end != std::string::npos) {
00130     const std::size_t start = token.find_first_not_of(" =", end);
00131     if (start != std::string::npos) {
00132       const std::string val = token.substr(start);
00133       args.erase(arg);
00134       args.insert(std::make_pair(arg, val));
00135       CPUNIT_ITRACE("CmdLineParser - Re-registered '"<<arg<<"' --> '"<<val<<"' from '"<<token<<'\'');
00136     }
00137   }
00138 }
00139 
00140 void
00141 cpunit::CmdLineParser::parse_long_token(const std::string &token) {
00142   const std::size_t end = token.find_first_of("= ", 0);
00143   const std::size_t arg_start = token.find_first_not_of("= ", end);
00144   const std::string name = token.substr(0, end);
00145 
00146   if (legal_args.find(name) == legal_args.end()) {
00147     CPUNIT_ERRTRACE("CmdLineParser - Unknown option '"<<name<<"' extracted from '"<<token<<'\'');
00148     std::ostringstream oss;
00149     oss<<"Unknown option: '"<<token<<'\'';
00150     throw IllegalArgumentException(oss.str());
00151   }  
00152   std::string value = "";
00153   if (arg_start != std::string::npos) {
00154     value = token.substr(arg_start);
00155   }
00156   args.erase(name);
00157   args.insert(std::make_pair(name, value));
00158   CPUNIT_ITRACE("CmdLineParser - Registered '"<<name<<"' --> '"<<value<<"' from '"<<token<<'\'');
00159 }
00160 
00161 bool
00162 cpunit::CmdLineParser::has(const std::string &arg) const {
00163   CPUNIT_DTRACE("CmdLineParser - CmdLineParser::has("<<arg<<')');
00164   if (legal_args.find(arg) == legal_args.end()) {
00165     std::ostringstream oss;
00166     oss<<"Invalid argument passed to has: '"<<arg<<'\'';
00167     throw IllegalArgumentException(oss.str());
00168   }
00169   return args.find(arg) != args.end();
00170 }
00171 
00172 bool
00173 cpunit::CmdLineParser::has_one_of(const std::string &s) const {
00174   bool result = false;
00175   for (std::size_t pos=s.find_first_not_of(BLANKS, 0); pos<s.length(); pos = s.find_first_not_of(BLANKS, pos)) {
00176     const std::size_t end = s.find_first_of(BLANKS, pos);
00177     const std::string arg = s.substr(pos, end - pos);
00178     if (has(arg)) {
00179       result = true;
00180     }
00181     pos = end;
00182   }
00183   return result;
00184 }
00185 
00186 template<>
00187 std::string 
00188 cpunit::CmdLineParser::value_of<std::string>(const std::string &arg) const {
00189   if (!has(arg)) {
00190     std::ostringstream oss;
00191     oss<<"Unknown argument: '"<<arg<<'\'';
00192     throw IllegalArgumentException(oss.str());
00193   }
00194   return args.find(arg)->second;
00195 }
00196 
00197 const std::vector<std::string>& 
00198 cpunit::CmdLineParser::program_input() const {
00199   return input;
00200 }
00201 
00202 std::string
00203 cpunit::CmdLineParser::to_string() const {
00204   std::ostringstream oss;
00205   std::set<std::string>::const_iterator lit = legal_args.begin();
00206   oss<<"Legal arguments:"<<std::endl;
00207   while (lit != legal_args.end()) {
00208     oss<<'\''<<*lit<<'\''<<std::endl;
00209     ++lit;
00210   }
00211 
00212   std::map<std::string,std::string>::const_iterator ait = args.begin();
00213   oss<<"Arguments:"<<std::endl;
00214   while (ait != args.end()) {
00215     oss<<'\''<<ait->first<<'\''<<" --> "<<'\''<<ait->second<<'\''<<std::endl;
00216     ++ait;
00217   }
00218   return oss.str();
00219 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines