diff --git a/doc/howto.xml b/doc/howto.xml
index b45b9d2..16b9d7e 100644
--- a/doc/howto.xml
+++ b/doc/howto.xml
@@ -398,13 +398,49 @@ $ export LC_CTYPE=ru_RU.KOI8-R
+
+ Allowing Unknown Options
+
+ Usually, the library throws an exception on unknown option names. This
+ behaviour can be changed. For example, only some part of your application uses
+ Program_options, and you wish to pass unrecognized options to another part of
+ the program, or even to another application.
+
+ To allow unregistered options on the command line, you need to use
+ the &basic_command_line_parser; class for parsing (not &parse_command_line;)
+ and call the allow_unregistered
+ method of that class:
+
+parsed_options parsed =
+ command_line_parser(argv, argc).options(desc).allow_unregistered().run();
+
+
+ For each token that looks like an option, but does not have a known name,
+ an instance of &basic_option; will be added to the result.
+ The string_key and value fields of the instance will contain results
+ of syntactic parsing of the token, the unregistered field will be set to true,
+ and the original_tokens field will contain the token as it appeared on the command line.
+
+
+ If you want to pass the unrecognized options further, the
+ collect_unrecognized function can be used.
+ The function will collect original tokens for all unrecognized values, and optionally, all found positional options.
+ Say, if your code handles a few options, but does not handles positional options at all, you can use the function like this:
+
+vector<string> to_pass_further = collect_arguments(parsed.option, include_positional);
+
+
+
+
+
+
diff --git a/doc/program_options.ent b/doc/program_options.ent
index 4d53cd8..084f605 100644
--- a/doc/program_options.ent
+++ b/doc/program_options.ent
@@ -37,3 +37,10 @@
command_line_parser">
+basic_command_line_parser">
+
+
+basic_option">
+
diff --git a/doc/todo.txt b/doc/todo.txt
index beab9b8..4ee42e1 100644
--- a/doc/todo.txt
+++ b/doc/todo.txt
@@ -1,4 +1,6 @@
+Make parse_config_file("foo.cfg", desc) work.
+
Document handling of positional options which depends on precedding options.
I.e scanning the parsed options and creating new variables_map when we see
a positional option. (Email from Tony).
diff --git a/include/boost/program_options/detail/parsers.hpp b/include/boost/program_options/detail/parsers.hpp
index 0328025..fb97ff6 100644
--- a/include/boost/program_options/detail/parsers.hpp
+++ b/include/boost/program_options/detail/parsers.hpp
@@ -76,6 +76,15 @@ namespace boost { namespace program_options {
return *this;
}
+ template
+ basic_command_line_parser&
+ basic_command_line_parser::allow_unregistered()
+ {
+ detail::cmdline::allow_unregistered();
+ return *this;
+ }
+
+
template
basic_parsed_options
basic_command_line_parser::run()
@@ -101,6 +110,26 @@ namespace boost { namespace program_options {
style(style).extra_parser(ext).run();
}
+ template
+ std::vector< std::basic_string >
+ collect_unrecognized(const std::vector< basic_option >& options,
+ enum collect_unrecognized_mode mode)
+ {
+ std::vector< std::basic_string > result;
+ for(unsigned i = 0; i < options.size(); ++i)
+ {
+ if (options[i].unregistered ||
+ (mode == include_positional && options[i].position_key != -1))
+ {
+ copy(options[i].original_tokens.begin(),
+ options[i].original_tokens.end(),
+ back_inserter(result));
+ }
+ }
+ return result;
+ }
+
+
}}
#endif
diff --git a/include/boost/program_options/option.hpp b/include/boost/program_options/option.hpp
index e5eb0ad..635f708 100644
--- a/include/boost/program_options/option.hpp
+++ b/include/boost/program_options/option.hpp
@@ -41,10 +41,16 @@ namespace boost { namespace program_options {
int position_key;
/** Option's value */
std::vector< std::basic_string > value;
+ /** The original unchanged tokens this option was
+ created from. */
+ std::vector< std::basic_string > original_tokens;
/** True if option was not recognized. In that case,
'string_key' and 'value' are results of purely
- syntactic parsing of source. */
+ syntactic parsing of source. The original tokens can be
+ recovered from the "original_tokens" member.
+ */
bool unregistered;
+
};
typedef basic_option option;
typedef basic_option woption;
diff --git a/include/boost/program_options/parsers.hpp b/include/boost/program_options/parsers.hpp
index e59c18e..10b98a9 100644
--- a/include/boost/program_options/parsers.hpp
+++ b/include/boost/program_options/parsers.hpp
@@ -73,13 +73,16 @@ namespace boost { namespace program_options {
/** Command line parser.
The class allows one to specify all the information needed for parsing
- and to parser the parse the command line. It is primarily needed to
+ and to parse the command line. It is primarily needed to
emulate named function parameters -- a regular function with 5
parameters will be hard to use and creating overloads with a smaller
nuber of parameters will be confusing.
For the most common case, the function parse_command_line is a better
alternative.
+
+ There are two typedefs -- command_line_parser and wcommand_line_parser,
+ for charT == char and charT == wchar_t cases.
*/
template
class basic_command_line_parser : private detail::cmdline {
@@ -90,7 +93,7 @@ namespace boost { namespace program_options {
basic_command_line_parser(const std::vector<
std::basic_string >& args);
/** Creates a command line parser for the specified arguments
- list. The parameter should be the same as passes to 'main'.
+ list. The parameters should be the same as passed to 'main'.
*/
basic_command_line_parser(int argc, charT* argv[]);
@@ -104,8 +107,21 @@ namespace boost { namespace program_options {
basic_command_line_parser& style(int);
/** Sets the extra parsers. */
basic_command_line_parser& extra_parser(ext_parser);
-
+
+ /** Parses the options and returns the result of parsing.
+ Throws on error.
+ */
basic_parsed_options run();
+
+ /** Specifies that unregistered options are allowed and should
+ be passed though. For each command like token that looks
+ like an option but does not contain a recognized name, an
+ instance of basic_option will be added to result,
+ with 'unrecognized' field set to 'true'. It's possible to
+ collect all unrecognized options with the 'collect_unrecognized'
+ funciton.
+ */
+ basic_command_line_parser& allow_unregistered();
private:
const options_description* m_desc;
};
@@ -134,6 +150,22 @@ namespace boost { namespace program_options {
basic_parsed_options
parse_config_file(std::basic_istream&, const options_description&);
+ /** Controls if the 'collect_unregistered' function should
+ include positional options, or not. */
+ enum collect_unrecognized_mode
+ { include_positional, exclude_positional };
+
+ /** Collects the original tokens for all named options with
+ 'unregistered' flag set. If 'mode' is 'include_positional'
+ also collects all positional options.
+ Returns the vector of origianl tokens for all collected
+ options.
+ */
+ template
+ std::vector< std::basic_string >
+ collect_unrecognized(const std::vector< basic_option >& options,
+ enum collect_unrecognized_mode mode);
+
/** Parse environment.
For each environment variable, the 'name_mapper' function is called to
@@ -180,6 +212,7 @@ namespace boost { namespace program_options {
split_winmain(const std::wstring& cmdline);
#endif
#endif
+
}}
diff --git a/src/cmdline.cpp b/src/cmdline.cpp
index 246677c..e4cae7f 100644
--- a/src/cmdline.cpp
+++ b/src/cmdline.cpp
@@ -248,6 +248,7 @@ namespace boost { namespace program_options { namespace detail {
if (!ok) {
option opt;
opt.value.push_back(args[0]);
+ opt.original_tokens.push_back(args[0]);
result.push_back(opt);
args.erase(args.begin());
}
@@ -331,6 +332,7 @@ namespace boost { namespace program_options { namespace detail {
// Everything's OK, move the values to the result.
for(;!other_tokens.empty() && max_tokens--; ) {
opt.value.push_back(other_tokens[0]);
+ opt.original_tokens.push_back(other_tokens[0]);
other_tokens.erase(other_tokens.begin());
}
}
@@ -368,6 +370,7 @@ namespace boost { namespace program_options { namespace detail {
opt.string_key = name;
if (!adjacent.empty())
opt.value.push_back(adjacent);
+ opt.original_tokens.push_back(tok);
result.push_back(opt);
args.erase(args.begin());
}
@@ -416,6 +419,7 @@ namespace boost { namespace program_options { namespace detail {
option opt;
opt.string_key = name;
+ opt.original_tokens.push_back(tok);
if (!adjacent.empty())
opt.value.push_back(adjacent);
result.push_back(opt);
@@ -442,6 +446,7 @@ namespace boost { namespace program_options { namespace detail {
opt.string_key = name;
if (!adjacent.empty())
opt.value.push_back(adjacent);
+ opt.original_tokens.push_back(tok);
result.push_back(opt);
args.erase(args.begin());
}