diff C++/OptionParser.cpp @ 236:ff2db0ed78f1

* Import GoogleTest * Start testing of OptionParser
author David Demelier <markand@malikania.fr>
date Fri, 04 Jul 2014 22:16:04 +0200
parents 96ff112d05cf
children 99e83685d4da
line wrap: on
line diff
--- a/C++/OptionParser.cpp	Thu Jun 26 16:49:00 2014 +0200
+++ b/C++/OptionParser.cpp	Fri Jul 04 22:16:04 2014 +0200
@@ -28,8 +28,8 @@
 Option::Option(const std::string &name, const std::string &help, Type type, int flags)
 	: m_name(name)
 	, m_help(help)
+	, m_flags(flags)
 	, m_type(type)
-	, m_flags(flags)
 {
 }
 
@@ -38,6 +38,11 @@
 	return m_name;
 }
 
+const std::string &Option::token() const
+{
+	return m_token;
+}
+
 const std::string &Option::help() const
 {
 	return m_help;
@@ -137,35 +142,92 @@
  * OptionParser class
  * -------------------------------------------------------- */
 
+OptionParser::Args OptionParser::unpack(const Args &args) const
+{
+	if (m_style != Getopt)
+		return args;
+
+	Args ret;
+
+	for (const auto &s : args) {
+		auto length = s.length();
+
+		if (length < 2 || s[0] != '-' || s[1] == '-') {
+			ret.push_back(s);
+			continue;
+		}
+
+		for (int i = 1; i < (int)length; ++i) {
+			ret.push_back(std::string("-") + std::string(&s[i], 1));
+		}
+	}
+
+	return ret;
+}
+
+OptionParser::OptionParser(Style style)
+	: m_style(style)
+{
+}
+
 void OptionParser::add(Option &&option)
 {
-	const auto &name = option.name();
+	const auto &length = option.m_name.size();
+
+	if (length > m_maxlength)
+		m_maxlength = length;
 
-	if (name.length() > m_maxlength)
-		m_maxlength = name.length();
+	/*
+	 * If style is Getopt, we should use a double dash as the long option
+	 * like --color and a single for short options like -v
+	 */
+	if (m_style == Getopt) {
+		if (length > 1)
+			option.m_token = "--" + option.m_name;
+		else
+			option.m_token = "-" + option.m_name;
+	} else
+		option.m_token = "/" + option.m_name;
 
-	m_options.emplace(std::make_pair(name, std::move(option)));
+	m_options.emplace(std::make_pair(option.m_token, std::move(option)));
 }
 
 void OptionParser::add(const Option &option)
 {
-	add(const_cast<Option &>(option));
+	add(Option(option));
 }
 
-OptionResult OptionParser::parse(int argc, char **argv, int flags)
+OptionResult OptionParser::parse(int argc, const char * const *argv, int flags)
+{
+	Args args;
+
+	for (int i = 0; i < argc; ++i)
+		args.push_back(argv[i]);
+
+	return parse(args, flags);
+}
+
+OptionResult OptionParser::parse(const Args &argslist, int flags)
 {
 	OptionResult result;
 	int i;
+	auto args = unpack(argslist);
+	auto length = args.size();
 
-	for (i = 0; i < argc; ++i) {
+	for (i = 0; i < (int)length; ++i) {
 		/* Not a valid option at all? */
-		if (m_options.count(argv[i]) == 0) {
-			log(argv[i], std::string(argv[i]) + " is not a valid option");
-
+		if (m_options.count(args[i]) == 0) {
+			/* When breaking is enabled we should not emit a warning */
 			if (flags & Strict) {
-				usage();
+				if (!(flags & Silent)) {
+					log(args[i], args[i] + " is not a valid option");
+					usage();
+				}
+
 				break;
-			} else
+			} else if (flags & BreakNonOption)
+				break;
+			else
 				continue;
 		}
 
@@ -173,14 +235,14 @@
 		 * At this step, we have an option name valid, check if it requires
 		 * an argument or not.
 		 */
-		const auto &option = m_options.at(argv[i]);
+		const auto &option = m_options.at(args[i]);
 		const auto &name = option.name();
 		auto type = option.type();
 
 		/*
 		 * Already present and must appears only once?
 		 */
-		if (option.flags() & Option::Single && m_placed.count(name) > 0) {
+		if ((option.flags() & Option::Single) && m_placed.count(name) > 0) {
 			if (!(flags & Silent)) {
 				log(name, "option " + name + " must appear only once");
 
@@ -198,10 +260,10 @@
 		if (type == Option::Type::Switch)
 			result.m_values.push_back(OptionValue(name));
 		else {
-			if (i + 1 >= argc)
+			if (i + 1 >= (int)length)
 				result.m_values.push_back(OptionValue(name, ""));
 			else {
-				result.m_values.push_back(OptionValue(name, argv[i + 1]));
+				result.m_values.push_back(OptionValue(name, args[i + 1]));
 				++ i;
 			}
 		}
@@ -212,14 +274,17 @@
 	result.m_total = i;
 
 	return result;
+
 }
 
 void OptionParser::usage()
 {
 	std::cout << "options available: " << std::endl;
 
-	for (const auto &option : m_options)
-		std::cout << " " << std::setw(m_maxlength) << option.second.name() << "\t" << option.second.help() << std::endl;
+	for (const auto &option : m_options) {
+		std::cout << " " << std::setw(m_maxlength) << option.second.name();
+		std::cout << "\t" << option.second.help() << std::endl;
+	}
 }
 
 void OptionParser::log(const std::string &, const std::string &error)