Index: boost/program_options/positional_options.hpp =================================================================== --- boost/program_options/positional_options.hpp (revision 73739) +++ boost/program_options/positional_options.hpp (working copy) @@ -45,6 +45,14 @@ positional_options_description& add(const char* name, int max_count); + /** Species that up to 'max_count' next positional options + should be given the 'name'. The value of '-1' means 'unlimited'. + No calls to 'add' can be made after call with 'max_value' equal to + '-1'. + */ + positional_options_description& + add(const std::string& name, int max_count); + /** Returns the maximum number of positional options that can be present. Can return (numeric_limits::max)() to indicate unlimited number. */ Index: boost/program_options/options_description.hpp =================================================================== --- boost/program_options/options_description.hpp (revision 73739) +++ boost/program_options/options_description.hpp (working copy) @@ -76,12 +76,22 @@ option_description(const char* name, const value_semantic* s); + /** Initializes the object with the passed data. */ + option_description(const std::string& name, + const value_semantic* s); + /** Initializes the class with the passed data. */ option_description(const char* name, const value_semantic* s, const char* description); + /** Initializes the object with the passed data. */ + option_description(const std::string& name, + const value_semantic* s, + const std::string& description); + + virtual ~option_description(); enum match_result { no_match, full_match, approximate_match }; @@ -119,7 +129,7 @@ private: - option_description& set_name(const char* name); + option_description& set_name(const std::string& name); std::string m_short_name, m_long_name, m_description; // shared_ptr is needed to simplify memory management in @@ -140,13 +150,27 @@ const char* description); options_description_easy_init& + operator()(const std::string& name, + const std::string& description); + + options_description_easy_init& operator()(const char* name, const value_semantic* s); + + options_description_easy_init& + operator()(const std::string& name, + const value_semantic* s); + options_description_easy_init& operator()(const char* name, const value_semantic* s, const char* description); + + options_description_easy_init& + operator()(const std::string& name, + const value_semantic* s, + const std::string& description); private: options_description* owner; Index: boost/program_options/parsers.hpp =================================================================== --- boost/program_options/parsers.hpp (revision 73739) +++ boost/program_options/parsers.hpp (working copy) @@ -176,6 +176,20 @@ parse_config_file(const char* filename, const options_description&, bool allow_unregistered = false); + /** Parse a config file. + + Read from file with the given name. The character type is + passed to the file stream. + */ + template +#if ! BOOST_WORKAROUND(__ICL, BOOST_TESTED_AT(700)) + BOOST_PROGRAM_OPTIONS_DECL +#endif + basic_parsed_options + parse_config_file(const std::string& filename, const options_description&, + bool allow_unregistered = false); + + /** Controls if the 'collect_unregistered' function should include positional options, or not. */ enum collect_unrecognized_mode Index: libs/program_options/test/positional_options_test.cpp =================================================================== --- libs/program_options/test/positional_options_test.cpp (revision 73739) +++ libs/program_options/test/positional_options_test.cpp (working copy) @@ -16,24 +16,26 @@ #include "minitest.hpp" #include +#include using namespace std; +template void test_positional_options() { positional_options_description p; - p.add("first", 1); + p.add(Str("first"), 1); BOOST_CHECK_EQUAL(p.max_total_count(), 1u); BOOST_CHECK_EQUAL(p.name_for_position(0), "first"); - p.add("second", 2); + p.add(Str("second"), 2); BOOST_CHECK_EQUAL(p.max_total_count(), 3u); BOOST_CHECK_EQUAL(p.name_for_position(0), "first"); BOOST_CHECK_EQUAL(p.name_for_position(1), "second"); BOOST_CHECK_EQUAL(p.name_for_position(2), "second"); - p.add("third", -1); + p.add(Str("third"), -1); BOOST_CHECK_EQUAL(p.max_total_count(), (std::numeric_limits::max)()); BOOST_CHECK_EQUAL(p.name_for_position(0), "first"); @@ -47,14 +49,13 @@ { options_description desc; desc.add_options() - ("first", po::value()) - ("second", po::value()) - ("input-file", po::value< vector >()) - ("some-other", po::value()) - ; + (Str("first"), po::value()) + (Str("second"), po::value()) + (Str("input-file"), po::value< vector >()) + (Str("some-other"), po::value()); positional_options_description p; - p.add("input-file", 2).add("some-other", 1); + p.add(Str("input-file"), 2).add(Str("some-other"), 1); vector args; args.push_back("--first=10"); @@ -84,8 +85,12 @@ int main(int, char* []) { - test_positional_options(); - test_parsing(); + test_positional_options(); + test_parsing(); + + test_positional_options(); + test_parsing(); + return 0; } Index: libs/program_options/test/options_description_test.cpp =================================================================== --- libs/program_options/test/options_description_test.cpp (revision 73739) +++ libs/program_options/test/options_description_test.cpp (working copy) @@ -17,83 +17,82 @@ #include "minitest.hpp" +template void test_type() { options_description desc; desc.add_options() - ("foo", value(), "") - ("bar", value(), "") - ; + (Str("foo"), value(), Str("")) + (Str("bar"), value(), Str("")); const typed_value_base* b = dynamic_cast - (desc.find("foo", false).semantic().get()); + (desc.find(Str("foo"), false).semantic().get()); BOOST_CHECK(b); BOOST_CHECK(b->value_type() == typeid(int)); const typed_value_base* b2 = dynamic_cast - (desc.find("bar", false).semantic().get()); + (desc.find(Str("bar"), false).semantic().get()); BOOST_CHECK(b2); BOOST_CHECK(b2->value_type() == typeid(string)); } +template void test_approximation() { options_description desc; desc.add_options() - ("foo", new untyped_value()) - ("fee", new untyped_value()) - ("baz", new untyped_value()) - ("all-chroots", new untyped_value()) - ("all-sessions", new untyped_value()) - ("all", new untyped_value()) - ; + (Str("foo"), new untyped_value()) + (Str("fee"), new untyped_value()) + (Str("baz"), new untyped_value()) + (Str("all-chroots"), new untyped_value()) + (Str("all-sessions"), new untyped_value()) + (Str("all"), new untyped_value()); - BOOST_CHECK_EQUAL(desc.find("fo", true).long_name(), "foo"); + BOOST_CHECK_EQUAL(desc.find(Str("fo"), true).long_name(), Str("foo")); - BOOST_CHECK_EQUAL(desc.find("all", true).long_name(), "all"); - BOOST_CHECK_EQUAL(desc.find("all-ch", true).long_name(), "all-chroots"); + BOOST_CHECK_EQUAL(desc.find(Str("all"), true).long_name(), Str("all")); + BOOST_CHECK_EQUAL(desc.find(Str("all-ch"), true).long_name(), Str("all-chroots")); options_description desc2; desc2.add_options() - ("help", "display this message") - ("config", value(), "config file name") - ("config-value", value(), "single config value") - ; - - BOOST_CHECK_EQUAL(desc2.find("config", true).long_name(), "config"); - BOOST_CHECK_EQUAL(desc2.find("config-value", true).long_name(), - "config-value"); + (Str("help"), Str("display this message")) + (Str("config"), value(), Str("config file name")) + (Str("config-value"), value(), Str("single config value")); + BOOST_CHECK_EQUAL(desc2.find(Str("config"), true).long_name(), Str("config")); + BOOST_CHECK_EQUAL(desc2.find(Str("config-value"), true).long_name(), + Str("config-value")); -// BOOST_CHECK(desc.count_approx("foo") == 1); -// set a = desc.approximations("f"); + +// BOOST_CHECK(desc.count_approx(Str("foo") == 1); +// set a = desc.approximations(Str("f")); // BOOST_CHECK(a.size() == 2); // BOOST_CHECK(*a.begin() == "fee"); // BOOST_CHECK(*(++a.begin()) == "foo"); } +template void test_formatting() { // Long option descriptions used to crash on MSVC-8.0. options_description desc; desc.add_options()( - "test", new untyped_value(), - "foo foo foo foo foo foo foo foo foo foo foo foo foo foo" - "foo foo foo foo foo foo foo foo foo foo foo foo foo foo" - "foo foo foo foo foo foo foo foo foo foo foo foo foo foo" - "foo foo foo foo foo foo foo foo foo foo foo foo foo foo") - ("list", new untyped_value(), - "a list:\n \t" + Str("test"), new untyped_value(), + Str("foo foo foo foo foo foo foo foo foo foo foo foo foo foo" + "foo foo foo foo foo foo foo foo foo foo foo foo foo foo" + "foo foo foo foo foo foo foo foo foo foo foo foo foo foo" + "foo foo foo foo foo foo foo foo foo foo foo foo foo foo")) + (Str("list"), new untyped_value(), + Str("a list:\n \t" "item1, item2, item3, item4, item5, item6, item7, item8, item9, " - "item10, item11, item12, item13, item14, item15, item16, item17, item18") - ("well_formated", new untyped_value(), - "As you can see this is a very well formatted option description.\n" - "You can do this for example:\n\n" - "Values:\n" - " Value1: \tdoes this and that, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\n" - " Value2: \tdoes something else, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\n\n" - " This paragraph has a first line indent only, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla") - ; + "item10, item11, item12, item13, item14, item15, item16, item17, item18")) + (Str("well_formated"), new untyped_value(), + Str("As you can see this is a very well formatted option description.\n" + "You can do this for example:\n\n" + "Values:\n" + " Value1: \tdoes this and that, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\n" + " Value2: \tdoes something else, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla\n\n" + " This paragraph has a first line indent only, bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla")); stringstream ss; ss << desc; @@ -122,20 +121,21 @@ ); } +template void test_formatting_description_length() { { - options_description desc("", + options_description desc(Str(""), options_description::m_default_line_length, options_description::m_default_line_length / 2U); desc.add_options() - ("an-option-that-sets-the-max", new untyped_value(), // > 40 available for desc - "this description sits on the same line, but wrapping should still work correctly") - ("a-long-option-that-would-leave-very-little-space-for-description", new untyped_value(), - "the description of the long opt, but placed on the next line\n" - " \talso ensure that the tabulation works correctly when a" - " description size has been set"); - + (Str("an-option-that-sets-the-max"), new untyped_value(), // > 40 available for desc + Str("this description sits on the same line, but wrapping should still work correctly")) + (Str("a-long-option-that-would-leave-very-little-space-for-description"), new untyped_value(), + Str("the description of the long opt, but placed on the next line\n" + " \talso ensure that the tabulation works correctly when a" + " description size has been set")); + stringstream ss; ss << desc; BOOST_CHECK_EQUAL(ss.str(), @@ -153,12 +153,12 @@ // the default behaviour reserves 23 (+1 space) characters for the // option column; this shows that the min_description_length does not // breach that. - options_description desc("", + options_description desc(Str(""), options_description::m_default_line_length, options_description::m_default_line_length - 10U); // leaves < 23 (default option space) desc.add_options() - ("an-option-that-encroaches-description", new untyped_value(), - "this description should always be placed on the next line, and wrapping should continue as normal"); + (Str("an-option-that-encroaches-description"), new untyped_value(), + Str("this description should always be placed on the next line, and wrapping should continue as normal")); stringstream ss; ss << desc; @@ -170,14 +170,14 @@ } } +template void test_long_default_value() { options_description desc; desc.add_options() - ("cfgfile,c", - value()->default_value("/usr/local/etc/myprogramXXXXXXXXX/configuration.conf"), - "the configfile") - ; + (Str("cfgfile,c"), + value()->default_value(Str("/usr/local/etc/myprogramXXXXXXXXX/configuration.conf")), + Str("the configfile")); stringstream ss; ss << desc; @@ -187,16 +187,17 @@ ); } +template void test_word_wrapping() { - options_description desc("Supported options"); - desc.add_options() - ("help", "this is a sufficiently long text to require word-wrapping") - ("prefix", value()->default_value("/h/proj/tmp/dispatch"), "root path of the dispatch installation") - ("opt1", "this_is_a_sufficiently_long_text_to_require_word-wrapping_but_cannot_be_wrapped") - ("opt2", "this_is_a_sufficiently long_text_to_require_word-wrapping") - ("opt3", "this_is_a sufficiently_long_text_to_require_word-wrapping_but_will_not_be_wrapped") - ; + options_description desc(Str("Supported options")); + desc.add_options() + (Str("help"), Str("this is a sufficiently long text to require word-wrapping")) + (Str("prefix"), value()->default_value(Str("/h/proj/tmp/dispatch")), Str("root path of the dispatch installation")) + (Str("opt1"), Str("this_is_a_sufficiently_long_text_to_require_word-wrapping_but_cannot_be_wrapped")) + (Str("opt2"), Str("this_is_a_sufficiently long_text_to_require_word-wrapping")) + (Str("opt3"), Str("this_is_a sufficiently_long_text_to_require_word-wrapping_but_will_not_be_wrapped")); + stringstream ss; ss << desc; BOOST_CHECK_EQUAL(ss.str(), @@ -214,12 +215,12 @@ ); } +template void test_default_values() { - options_description desc("Supported options"); - desc.add_options() - ("maxlength", value()->default_value(.1, "0.1"), "Maximum edge length to keep.") - ; + options_description desc(Str("Supported options")); + desc.add_options() + (Str("maxlength"), value()->default_value(.1, Str("0.1")), Str("Maximum edge length to keep.")); stringstream ss; ss << desc; BOOST_CHECK_EQUAL(ss.str(), @@ -231,13 +232,22 @@ int main(int, char* []) { - test_type(); - test_approximation(); - test_formatting(); - test_formatting_description_length(); - test_long_default_value(); - test_word_wrapping(); - test_default_values(); + test_type(); + test_approximation(); + test_formatting(); + test_formatting_description_length(); + test_long_default_value(); + test_word_wrapping(); + test_default_values(); + + test_type(); + test_approximation(); + test_formatting(); + test_formatting_description_length(); + test_long_default_value(); + test_word_wrapping(); + test_default_values(); + return 0; } Index: libs/program_options/doc/rationale.dox =================================================================== --- libs/program_options/doc/rationale.dox (revision 73739) +++ libs/program_options/doc/rationale.dox (working copy) @@ -38,13 +38,14 @@ @section char_vs_string const char* vs. std::string - Most of the interface uses const char* where std::string seems a natural - choice. The reason is that those functions are called many times: for - example to declare all options. They are typically called with string - literals, and implicit conversion to string appears to take a lot of - code space. Providing both std::string and const char* version would - considerably bloat the interface. Since passing std::string is considered - rare, only const char* versions are provided. + Most of the interface provides const char* overloads in addition + to std::string. The reason is that those functions are called many + times: for example to declare all options. They are typically + called with string literals, and implicit conversion to string + appears to take a lot of code space. So, including overloads + which take const char* reduces code size in the common case, while + use cases which favor strings are supported without the need to + call .c_str(). @section init_syntax Initialization syntax Index: libs/program_options/src/options_description.cpp =================================================================== --- libs/program_options/src/options_description.cpp (revision 73739) +++ libs/program_options/src/options_description.cpp (working copy) @@ -55,9 +55,16 @@ { this->set_name(name); } - option_description:: + option_description(const std::string& name, + const value_semantic* s) + : m_value_semantic(s) + { + this->set_name(name); + } + + option_description:: option_description(const char* name, const value_semantic* s, const char* description) @@ -66,6 +73,16 @@ this->set_name(name); } + option_description:: + option_description(const std::string& name, + const value_semantic* s, + const std::string& description) + : m_description(description), m_value_semantic(s) + { + this->set_name(name); + } + + option_description::~option_description() { } @@ -144,9 +161,8 @@ } option_description& - option_description::set_name(const char* _name) + option_description::set_name(const std::string& name) { - std::string name(_name); string::size_type n = name.find(','); if (n != string::npos) { assert(n == name.size()-2); @@ -158,6 +174,7 @@ return *this; } + const std::string& option_description::description() const { @@ -214,6 +231,21 @@ options_description_easy_init& options_description_easy_init:: + operator()(const std::string& name, + const std::string& description) + { + // Create untypes semantic which accepts zero tokens: i.e. + // no value can be specified on command line. + // FIXME: does not look exception-safe + shared_ptr d( + new option_description(name, new untyped_value(true), description)); + + owner->add(d); + return *this; + } + + options_description_easy_init& + options_description_easy_init:: operator()(const char* name, const value_semantic* s) { @@ -224,12 +256,34 @@ options_description_easy_init& options_description_easy_init:: + operator()(const std::string& name, + const value_semantic* s) + { + shared_ptr d(new option_description(name, s)); + owner->add(d); + return *this; + } + + options_description_easy_init& + options_description_easy_init:: operator()(const char* name, const value_semantic* s, const char* description) { shared_ptr d(new option_description(name, s, description)); + owner->add(d); + return *this; + } + + options_description_easy_init& + options_description_easy_init:: + operator()(const std::string& name, + const value_semantic* s, + const std::string& description) + { + shared_ptr d(new option_description(name, s, description)); + owner->add(d); return *this; } Index: libs/program_options/src/parsers.cpp =================================================================== --- libs/program_options/src/parsers.cpp (revision 73739) +++ libs/program_options/src/parsers.cpp (working copy) @@ -168,8 +168,31 @@ bool allow_unregistered); #endif + template + basic_parsed_options + parse_config_file(const std::string& filename, + const options_description& desc, + bool allow_unregistered) + { + return parse_config_file(filename.c_str(), desc, allow_unregistered); + } + + template + BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options + parse_config_file(const std::string& filename, + const options_description& desc, + bool allow_unregistered); + +#ifndef BOOST_NO_STD_WSTRING + template + BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options + parse_config_file(const std::string& filename, + const options_description& desc, + bool allow_unregistered); +#endif + -// This versio, which accepts any options without validation, is disabled, +// This version, which accepts any options without validation, is disabled, // in the hope that nobody will need it and we cant drop it altogether. // Besides, probably the right way to handle all options is the '*' name. #if 0 @@ -241,8 +264,4 @@ { return parse_environment(desc, string(prefix)); } - - - - }} Index: libs/program_options/src/positional_options.cpp =================================================================== --- libs/program_options/src/positional_options.cpp (revision 73739) +++ libs/program_options/src/positional_options.cpp (working copy) @@ -20,6 +20,12 @@ positional_options_description& positional_options_description::add(const char* name, int max_count) { + return add(std::string(name), max_count); + } + + positional_options_description& + positional_options_description::add(const std::string& name, int max_count) + { assert(max_count != -1 || m_trailing.empty()); if (max_count == -1)