xref: /freebsd/contrib/kyua/utils/cmdline/parser.cpp (revision b0d29bc47dba79f6f38e67eabadfb4b32ffd9390)
1*b0d29bc4SBrooks Davis // Copyright 2010 The Kyua Authors.
2*b0d29bc4SBrooks Davis // All rights reserved.
3*b0d29bc4SBrooks Davis //
4*b0d29bc4SBrooks Davis // Redistribution and use in source and binary forms, with or without
5*b0d29bc4SBrooks Davis // modification, are permitted provided that the following conditions are
6*b0d29bc4SBrooks Davis // met:
7*b0d29bc4SBrooks Davis //
8*b0d29bc4SBrooks Davis // * Redistributions of source code must retain the above copyright
9*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer.
10*b0d29bc4SBrooks Davis // * Redistributions in binary form must reproduce the above copyright
11*b0d29bc4SBrooks Davis //   notice, this list of conditions and the following disclaimer in the
12*b0d29bc4SBrooks Davis //   documentation and/or other materials provided with the distribution.
13*b0d29bc4SBrooks Davis // * Neither the name of Google Inc. nor the names of its contributors
14*b0d29bc4SBrooks Davis //   may be used to endorse or promote products derived from this software
15*b0d29bc4SBrooks Davis //   without specific prior written permission.
16*b0d29bc4SBrooks Davis //
17*b0d29bc4SBrooks Davis // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*b0d29bc4SBrooks Davis // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*b0d29bc4SBrooks Davis // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*b0d29bc4SBrooks Davis // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*b0d29bc4SBrooks Davis // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*b0d29bc4SBrooks Davis // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*b0d29bc4SBrooks Davis // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*b0d29bc4SBrooks Davis // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*b0d29bc4SBrooks Davis // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*b0d29bc4SBrooks Davis // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*b0d29bc4SBrooks Davis // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*b0d29bc4SBrooks Davis 
29*b0d29bc4SBrooks Davis #include "utils/cmdline/parser.hpp"
30*b0d29bc4SBrooks Davis 
31*b0d29bc4SBrooks Davis #if defined(HAVE_CONFIG_H)
32*b0d29bc4SBrooks Davis #   include "config.h"
33*b0d29bc4SBrooks Davis #endif
34*b0d29bc4SBrooks Davis 
35*b0d29bc4SBrooks Davis extern "C" {
36*b0d29bc4SBrooks Davis #include <getopt.h>
37*b0d29bc4SBrooks Davis }
38*b0d29bc4SBrooks Davis 
39*b0d29bc4SBrooks Davis #include <cstdlib>
40*b0d29bc4SBrooks Davis #include <cstring>
41*b0d29bc4SBrooks Davis #include <limits>
42*b0d29bc4SBrooks Davis 
43*b0d29bc4SBrooks Davis #include "utils/auto_array.ipp"
44*b0d29bc4SBrooks Davis #include "utils/cmdline/exceptions.hpp"
45*b0d29bc4SBrooks Davis #include "utils/cmdline/options.hpp"
46*b0d29bc4SBrooks Davis #include "utils/format/macros.hpp"
47*b0d29bc4SBrooks Davis #include "utils/noncopyable.hpp"
48*b0d29bc4SBrooks Davis #include "utils/sanity.hpp"
49*b0d29bc4SBrooks Davis 
50*b0d29bc4SBrooks Davis namespace cmdline = utils::cmdline;
51*b0d29bc4SBrooks Davis 
52*b0d29bc4SBrooks Davis namespace {
53*b0d29bc4SBrooks Davis 
54*b0d29bc4SBrooks Davis 
55*b0d29bc4SBrooks Davis /// Auxiliary data to call getopt_long(3).
56*b0d29bc4SBrooks Davis struct getopt_data : utils::noncopyable {
57*b0d29bc4SBrooks Davis     /// Plain-text representation of the short options.
58*b0d29bc4SBrooks Davis     ///
59*b0d29bc4SBrooks Davis     /// This string follows the syntax expected by getopt_long(3) in the
60*b0d29bc4SBrooks Davis     /// argument to describe the short options.
61*b0d29bc4SBrooks Davis     std::string short_options;
62*b0d29bc4SBrooks Davis 
63*b0d29bc4SBrooks Davis     /// Representation of the long options as expected by getopt_long(3).
64*b0d29bc4SBrooks Davis     utils::auto_array< ::option > long_options;
65*b0d29bc4SBrooks Davis 
66*b0d29bc4SBrooks Davis     /// Auto-generated identifiers to be able to parse long options.
67*b0d29bc4SBrooks Davis     std::map< int, const cmdline::base_option* > ids;
68*b0d29bc4SBrooks Davis };
69*b0d29bc4SBrooks Davis 
70*b0d29bc4SBrooks Davis 
71*b0d29bc4SBrooks Davis /// Converts a cmdline::options_vector to a getopt_data.
72*b0d29bc4SBrooks Davis ///
73*b0d29bc4SBrooks Davis /// \param options The high-level definition of the options.
74*b0d29bc4SBrooks Davis /// \param [out] data An object containing the necessary data to call
75*b0d29bc4SBrooks Davis ///     getopt_long(3) and interpret its results.
76*b0d29bc4SBrooks Davis static void
options_to_getopt_data(const cmdline::options_vector & options,getopt_data & data)77*b0d29bc4SBrooks Davis options_to_getopt_data(const cmdline::options_vector& options,
78*b0d29bc4SBrooks Davis                        getopt_data& data)
79*b0d29bc4SBrooks Davis {
80*b0d29bc4SBrooks Davis     data.short_options.clear();
81*b0d29bc4SBrooks Davis     data.long_options.reset(new ::option[options.size() + 1]);
82*b0d29bc4SBrooks Davis 
83*b0d29bc4SBrooks Davis     int cur_id = 512;
84*b0d29bc4SBrooks Davis 
85*b0d29bc4SBrooks Davis     for (cmdline::options_vector::size_type i = 0; i < options.size(); i++) {
86*b0d29bc4SBrooks Davis         const cmdline::base_option* option = options[i];
87*b0d29bc4SBrooks Davis         ::option& long_option = data.long_options[i];
88*b0d29bc4SBrooks Davis 
89*b0d29bc4SBrooks Davis         long_option.name = option->long_name().c_str();
90*b0d29bc4SBrooks Davis         if (option->needs_arg())
91*b0d29bc4SBrooks Davis             long_option.has_arg = required_argument;
92*b0d29bc4SBrooks Davis         else
93*b0d29bc4SBrooks Davis             long_option.has_arg = no_argument;
94*b0d29bc4SBrooks Davis 
95*b0d29bc4SBrooks Davis         int id = -1;
96*b0d29bc4SBrooks Davis         if (option->has_short_name()) {
97*b0d29bc4SBrooks Davis             data.short_options += option->short_name();
98*b0d29bc4SBrooks Davis             if (option->needs_arg())
99*b0d29bc4SBrooks Davis                 data.short_options += ':';
100*b0d29bc4SBrooks Davis             id = option->short_name();
101*b0d29bc4SBrooks Davis         } else {
102*b0d29bc4SBrooks Davis             id = cur_id++;
103*b0d29bc4SBrooks Davis         }
104*b0d29bc4SBrooks Davis         long_option.flag = NULL;
105*b0d29bc4SBrooks Davis         long_option.val = id;
106*b0d29bc4SBrooks Davis         data.ids[id] = option;
107*b0d29bc4SBrooks Davis     }
108*b0d29bc4SBrooks Davis 
109*b0d29bc4SBrooks Davis     ::option& last_long_option = data.long_options[options.size()];
110*b0d29bc4SBrooks Davis     last_long_option.name = NULL;
111*b0d29bc4SBrooks Davis     last_long_option.has_arg = 0;
112*b0d29bc4SBrooks Davis     last_long_option.flag = NULL;
113*b0d29bc4SBrooks Davis     last_long_option.val = 0;
114*b0d29bc4SBrooks Davis }
115*b0d29bc4SBrooks Davis 
116*b0d29bc4SBrooks Davis 
117*b0d29bc4SBrooks Davis /// Converts an argc/argv pair to an args_vector.
118*b0d29bc4SBrooks Davis ///
119*b0d29bc4SBrooks Davis /// \param argc The value of argc as passed to main().
120*b0d29bc4SBrooks Davis /// \param argv The value of argv as passed to main().
121*b0d29bc4SBrooks Davis ///
122*b0d29bc4SBrooks Davis /// \return An args_vector with the same contents of argc/argv.
123*b0d29bc4SBrooks Davis static cmdline::args_vector
argv_to_vector(int argc,const char * const argv[])124*b0d29bc4SBrooks Davis argv_to_vector(int argc, const char* const argv[])
125*b0d29bc4SBrooks Davis {
126*b0d29bc4SBrooks Davis     PRE(argv[argc] == NULL);
127*b0d29bc4SBrooks Davis     cmdline::args_vector args;
128*b0d29bc4SBrooks Davis     for (int i = 0; i < argc; i++)
129*b0d29bc4SBrooks Davis         args.push_back(argv[i]);
130*b0d29bc4SBrooks Davis     return args;
131*b0d29bc4SBrooks Davis }
132*b0d29bc4SBrooks Davis 
133*b0d29bc4SBrooks Davis 
134*b0d29bc4SBrooks Davis /// Creates a mutable version of argv.
135*b0d29bc4SBrooks Davis ///
136*b0d29bc4SBrooks Davis /// \param argc The value of argc as passed to main().
137*b0d29bc4SBrooks Davis /// \param argv The value of argv as passed to main().
138*b0d29bc4SBrooks Davis ///
139*b0d29bc4SBrooks Davis /// \return A new argv, with mutable buffers.  The returned array must be
140*b0d29bc4SBrooks Davis /// released using the free_mutable_argv() function.
141*b0d29bc4SBrooks Davis static char**
make_mutable_argv(const int argc,const char * const * argv)142*b0d29bc4SBrooks Davis make_mutable_argv(const int argc, const char* const* argv)
143*b0d29bc4SBrooks Davis {
144*b0d29bc4SBrooks Davis     char** mutable_argv = new char*[argc + 1];
145*b0d29bc4SBrooks Davis     for (int i = 0; i < argc; i++)
146*b0d29bc4SBrooks Davis         mutable_argv[i] = ::strdup(argv[i]);
147*b0d29bc4SBrooks Davis     mutable_argv[argc] = NULL;
148*b0d29bc4SBrooks Davis     return mutable_argv;
149*b0d29bc4SBrooks Davis }
150*b0d29bc4SBrooks Davis 
151*b0d29bc4SBrooks Davis 
152*b0d29bc4SBrooks Davis /// Releases the object returned by make_mutable_argv().
153*b0d29bc4SBrooks Davis ///
154*b0d29bc4SBrooks Davis /// \param argv A dynamically-allocated argv as returned by make_mutable_argv().
155*b0d29bc4SBrooks Davis static void
free_mutable_argv(char ** argv)156*b0d29bc4SBrooks Davis free_mutable_argv(char** argv)
157*b0d29bc4SBrooks Davis {
158*b0d29bc4SBrooks Davis     char** ptr = argv;
159*b0d29bc4SBrooks Davis     while (*ptr != NULL) {
160*b0d29bc4SBrooks Davis         ::free(*ptr);
161*b0d29bc4SBrooks Davis         ptr++;
162*b0d29bc4SBrooks Davis     }
163*b0d29bc4SBrooks Davis     delete [] argv;
164*b0d29bc4SBrooks Davis }
165*b0d29bc4SBrooks Davis 
166*b0d29bc4SBrooks Davis 
167*b0d29bc4SBrooks Davis /// Finds the name of the offending option after a getopt_long error.
168*b0d29bc4SBrooks Davis ///
169*b0d29bc4SBrooks Davis /// \param data Our internal getopt data used for the call to getopt_long.
170*b0d29bc4SBrooks Davis /// \param getopt_optopt The value of getopt(3)'s optopt after the error.
171*b0d29bc4SBrooks Davis /// \param argv The argv passed to getopt_long.
172*b0d29bc4SBrooks Davis /// \param getopt_optind The value of getopt(3)'s optind after the error.
173*b0d29bc4SBrooks Davis ///
174*b0d29bc4SBrooks Davis /// \return A fully-specified option name (i.e. an option name prefixed by
175*b0d29bc4SBrooks Davis ///     either '-' or '--').
176*b0d29bc4SBrooks Davis static std::string
find_option_name(const getopt_data & data,const int getopt_optopt,char ** argv,const int getopt_optind)177*b0d29bc4SBrooks Davis find_option_name(const getopt_data& data, const int getopt_optopt,
178*b0d29bc4SBrooks Davis                  char** argv, const int getopt_optind)
179*b0d29bc4SBrooks Davis {
180*b0d29bc4SBrooks Davis     PRE(getopt_optopt >= 0);
181*b0d29bc4SBrooks Davis 
182*b0d29bc4SBrooks Davis     if (getopt_optopt == 0) {
183*b0d29bc4SBrooks Davis         return argv[getopt_optind - 1];
184*b0d29bc4SBrooks Davis     } else if (getopt_optopt < std::numeric_limits< char >::max()) {
185*b0d29bc4SBrooks Davis         INV(getopt_optopt > 0);
186*b0d29bc4SBrooks Davis         const char ch = static_cast< char >(getopt_optopt);
187*b0d29bc4SBrooks Davis         return F("-%s") % ch;
188*b0d29bc4SBrooks Davis     } else {
189*b0d29bc4SBrooks Davis         for (const ::option* opt = &data.long_options[0]; opt->name != NULL;
190*b0d29bc4SBrooks Davis              opt++) {
191*b0d29bc4SBrooks Davis             if (opt->val == getopt_optopt)
192*b0d29bc4SBrooks Davis                 return F("--%s") % opt->name;
193*b0d29bc4SBrooks Davis         }
194*b0d29bc4SBrooks Davis         UNREACHABLE;
195*b0d29bc4SBrooks Davis     }
196*b0d29bc4SBrooks Davis }
197*b0d29bc4SBrooks Davis 
198*b0d29bc4SBrooks Davis 
199*b0d29bc4SBrooks Davis }  // anonymous namespace
200*b0d29bc4SBrooks Davis 
201*b0d29bc4SBrooks Davis 
202*b0d29bc4SBrooks Davis /// Constructs a new parsed_cmdline.
203*b0d29bc4SBrooks Davis ///
204*b0d29bc4SBrooks Davis /// Use the cmdline::parse() free functions to construct.
205*b0d29bc4SBrooks Davis ///
206*b0d29bc4SBrooks Davis /// \param option_values_ A mapping of long option names to values.  This
207*b0d29bc4SBrooks Davis ///     contains a representation of the options provided by the user.  Note
208*b0d29bc4SBrooks Davis ///     that each value is actually a collection values: a user may specify a
209*b0d29bc4SBrooks Davis ///     flag multiple times, and depending on the case we want to honor one or
210*b0d29bc4SBrooks Davis ///     the other.  For those options that support no argument, the argument
211*b0d29bc4SBrooks Davis ///     value is the empty string.
212*b0d29bc4SBrooks Davis /// \param arguments_ The list of non-option arguments in the command line.
parsed_cmdline(const std::map<std::string,std::vector<std::string>> & option_values_,const cmdline::args_vector & arguments_)213*b0d29bc4SBrooks Davis cmdline::parsed_cmdline::parsed_cmdline(
214*b0d29bc4SBrooks Davis     const std::map< std::string, std::vector< std::string > >& option_values_,
215*b0d29bc4SBrooks Davis     const cmdline::args_vector& arguments_) :
216*b0d29bc4SBrooks Davis     _option_values(option_values_),
217*b0d29bc4SBrooks Davis     _arguments(arguments_)
218*b0d29bc4SBrooks Davis {
219*b0d29bc4SBrooks Davis }
220*b0d29bc4SBrooks Davis 
221*b0d29bc4SBrooks Davis 
222*b0d29bc4SBrooks Davis /// Checks if the given option has been given in the command line.
223*b0d29bc4SBrooks Davis ///
224*b0d29bc4SBrooks Davis /// \param name The long option name to check for presence.
225*b0d29bc4SBrooks Davis ///
226*b0d29bc4SBrooks Davis /// \return True if the option has been given; false otherwise.
227*b0d29bc4SBrooks Davis bool
has_option(const std::string & name) const228*b0d29bc4SBrooks Davis cmdline::parsed_cmdline::has_option(const std::string& name) const
229*b0d29bc4SBrooks Davis {
230*b0d29bc4SBrooks Davis     return _option_values.find(name) != _option_values.end();
231*b0d29bc4SBrooks Davis }
232*b0d29bc4SBrooks Davis 
233*b0d29bc4SBrooks Davis 
234*b0d29bc4SBrooks Davis /// Gets the raw value of an option.
235*b0d29bc4SBrooks Davis ///
236*b0d29bc4SBrooks Davis /// The raw value of an option is a collection of strings that represent all the
237*b0d29bc4SBrooks Davis /// values passed to the option on the command line.  It is up to the consumer
238*b0d29bc4SBrooks Davis /// if he wants to honor only the last value or all of them.
239*b0d29bc4SBrooks Davis ///
240*b0d29bc4SBrooks Davis /// The caller has to use get_option() instead; this function is internal.
241*b0d29bc4SBrooks Davis ///
242*b0d29bc4SBrooks Davis /// \pre has_option(name) must be true.
243*b0d29bc4SBrooks Davis ///
244*b0d29bc4SBrooks Davis /// \param name The option to query.
245*b0d29bc4SBrooks Davis ///
246*b0d29bc4SBrooks Davis /// \return The value of the option as a plain string.
247*b0d29bc4SBrooks Davis const std::vector< std::string >&
get_option_raw(const std::string & name) const248*b0d29bc4SBrooks Davis cmdline::parsed_cmdline::get_option_raw(const std::string& name) const
249*b0d29bc4SBrooks Davis {
250*b0d29bc4SBrooks Davis     std::map< std::string, std::vector< std::string > >::const_iterator iter =
251*b0d29bc4SBrooks Davis         _option_values.find(name);
252*b0d29bc4SBrooks Davis     INV_MSG(iter != _option_values.end(), F("Undefined option --%s") % name);
253*b0d29bc4SBrooks Davis     return (*iter).second;
254*b0d29bc4SBrooks Davis }
255*b0d29bc4SBrooks Davis 
256*b0d29bc4SBrooks Davis 
257*b0d29bc4SBrooks Davis /// Returns the non-option arguments found in the command line.
258*b0d29bc4SBrooks Davis ///
259*b0d29bc4SBrooks Davis /// \return The arguments, if any.
260*b0d29bc4SBrooks Davis const cmdline::args_vector&
arguments(void) const261*b0d29bc4SBrooks Davis cmdline::parsed_cmdline::arguments(void) const
262*b0d29bc4SBrooks Davis {
263*b0d29bc4SBrooks Davis     return _arguments;
264*b0d29bc4SBrooks Davis }
265*b0d29bc4SBrooks Davis 
266*b0d29bc4SBrooks Davis 
267*b0d29bc4SBrooks Davis /// Parses a command line.
268*b0d29bc4SBrooks Davis ///
269*b0d29bc4SBrooks Davis /// \param args The command line to parse, broken down by words.
270*b0d29bc4SBrooks Davis /// \param options The description of the supported options.
271*b0d29bc4SBrooks Davis ///
272*b0d29bc4SBrooks Davis /// \return The parsed command line.
273*b0d29bc4SBrooks Davis ///
274*b0d29bc4SBrooks Davis /// \pre args[0] must be the program or command name.
275*b0d29bc4SBrooks Davis ///
276*b0d29bc4SBrooks Davis /// \throw cmdline::error See the description of parse(argc, argv, options) for
277*b0d29bc4SBrooks Davis ///     more details on the raised errors.
278*b0d29bc4SBrooks Davis cmdline::parsed_cmdline
parse(const cmdline::args_vector & args,const cmdline::options_vector & options)279*b0d29bc4SBrooks Davis cmdline::parse(const cmdline::args_vector& args,
280*b0d29bc4SBrooks Davis                const cmdline::options_vector& options)
281*b0d29bc4SBrooks Davis {
282*b0d29bc4SBrooks Davis     PRE_MSG(args.size() >= 1, "No progname or command name found");
283*b0d29bc4SBrooks Davis 
284*b0d29bc4SBrooks Davis     utils::auto_array< const char* > argv(new const char*[args.size() + 1]);
285*b0d29bc4SBrooks Davis     for (args_vector::size_type i = 0; i < args.size(); i++)
286*b0d29bc4SBrooks Davis         argv[i] = args[i].c_str();
287*b0d29bc4SBrooks Davis     argv[args.size()] = NULL;
288*b0d29bc4SBrooks Davis     return parse(static_cast< int >(args.size()), argv.get(), options);
289*b0d29bc4SBrooks Davis }
290*b0d29bc4SBrooks Davis 
291*b0d29bc4SBrooks Davis 
292*b0d29bc4SBrooks Davis /// Parses a command line.
293*b0d29bc4SBrooks Davis ///
294*b0d29bc4SBrooks Davis /// \param argc The number of arguments in argv, without counting the
295*b0d29bc4SBrooks Davis ///     terminating NULL.
296*b0d29bc4SBrooks Davis /// \param argv The arguments to parse.  The array is NULL-terminated.
297*b0d29bc4SBrooks Davis /// \param options The description of the supported options.
298*b0d29bc4SBrooks Davis ///
299*b0d29bc4SBrooks Davis /// \return The parsed command line.
300*b0d29bc4SBrooks Davis ///
301*b0d29bc4SBrooks Davis /// \pre args[0] must be the program or command name.
302*b0d29bc4SBrooks Davis ///
303*b0d29bc4SBrooks Davis /// \throw cmdline::missing_option_argument_error If the user specified an
304*b0d29bc4SBrooks Davis ///     option that requires an argument, but no argument was provided.
305*b0d29bc4SBrooks Davis /// \throw cmdline::unknown_option_error If the user specified an unknown
306*b0d29bc4SBrooks Davis ///     option (i.e. an option not defined in options).
307*b0d29bc4SBrooks Davis /// \throw cmdline::option_argument_value_error If the user passed an invalid
308*b0d29bc4SBrooks Davis ///     argument to a supported option.
309*b0d29bc4SBrooks Davis cmdline::parsed_cmdline
parse(const int argc,const char * const * argv,const cmdline::options_vector & options)310*b0d29bc4SBrooks Davis cmdline::parse(const int argc, const char* const* argv,
311*b0d29bc4SBrooks Davis                const cmdline::options_vector& options)
312*b0d29bc4SBrooks Davis {
313*b0d29bc4SBrooks Davis     PRE_MSG(argc >= 1, "No progname or command name found");
314*b0d29bc4SBrooks Davis 
315*b0d29bc4SBrooks Davis     getopt_data data;
316*b0d29bc4SBrooks Davis     options_to_getopt_data(options, data);
317*b0d29bc4SBrooks Davis 
318*b0d29bc4SBrooks Davis     std::map< std::string, std::vector< std::string > > option_values;
319*b0d29bc4SBrooks Davis 
320*b0d29bc4SBrooks Davis     for (cmdline::options_vector::const_iterator iter = options.begin();
321*b0d29bc4SBrooks Davis          iter != options.end(); iter++) {
322*b0d29bc4SBrooks Davis         const cmdline::base_option* option = *iter;
323*b0d29bc4SBrooks Davis         if (option->needs_arg() && option->has_default_value())
324*b0d29bc4SBrooks Davis             option_values[option->long_name()].push_back(
325*b0d29bc4SBrooks Davis                 option->default_value());
326*b0d29bc4SBrooks Davis     }
327*b0d29bc4SBrooks Davis 
328*b0d29bc4SBrooks Davis     args_vector args;
329*b0d29bc4SBrooks Davis 
330*b0d29bc4SBrooks Davis     int mutable_argc = argc;
331*b0d29bc4SBrooks Davis     char** mutable_argv = make_mutable_argv(argc, argv);
332*b0d29bc4SBrooks Davis     const int old_opterr = ::opterr;
333*b0d29bc4SBrooks Davis     try {
334*b0d29bc4SBrooks Davis         int ch;
335*b0d29bc4SBrooks Davis 
336*b0d29bc4SBrooks Davis         ::opterr = 0;
337*b0d29bc4SBrooks Davis 
338*b0d29bc4SBrooks Davis         while ((ch = ::getopt_long(mutable_argc, mutable_argv,
339*b0d29bc4SBrooks Davis                                    ("+:" + data.short_options).c_str(),
340*b0d29bc4SBrooks Davis                                    data.long_options.get(), NULL)) != -1) {
341*b0d29bc4SBrooks Davis             if (ch == ':' ) {
342*b0d29bc4SBrooks Davis                 const std::string name = find_option_name(
343*b0d29bc4SBrooks Davis                     data, ::optopt, mutable_argv, ::optind);
344*b0d29bc4SBrooks Davis                 throw cmdline::missing_option_argument_error(name);
345*b0d29bc4SBrooks Davis             } else if (ch == '?') {
346*b0d29bc4SBrooks Davis                 const std::string name = find_option_name(
347*b0d29bc4SBrooks Davis                     data, ::optopt, mutable_argv, ::optind);
348*b0d29bc4SBrooks Davis                 throw cmdline::unknown_option_error(name);
349*b0d29bc4SBrooks Davis             }
350*b0d29bc4SBrooks Davis 
351*b0d29bc4SBrooks Davis             const std::map< int, const cmdline::base_option* >::const_iterator
352*b0d29bc4SBrooks Davis                 id = data.ids.find(ch);
353*b0d29bc4SBrooks Davis             INV(id != data.ids.end());
354*b0d29bc4SBrooks Davis             const cmdline::base_option* option = (*id).second;
355*b0d29bc4SBrooks Davis 
356*b0d29bc4SBrooks Davis             if (option->needs_arg()) {
357*b0d29bc4SBrooks Davis                 if (::optarg != NULL) {
358*b0d29bc4SBrooks Davis                     option->validate(::optarg);
359*b0d29bc4SBrooks Davis                     option_values[option->long_name()].push_back(::optarg);
360*b0d29bc4SBrooks Davis                 } else
361*b0d29bc4SBrooks Davis                     INV(option->has_default_value());
362*b0d29bc4SBrooks Davis             } else {
363*b0d29bc4SBrooks Davis                 option_values[option->long_name()].push_back("");
364*b0d29bc4SBrooks Davis             }
365*b0d29bc4SBrooks Davis         }
366*b0d29bc4SBrooks Davis         args = argv_to_vector(mutable_argc - optind, mutable_argv + optind);
367*b0d29bc4SBrooks Davis 
368*b0d29bc4SBrooks Davis         ::opterr = old_opterr;
369*b0d29bc4SBrooks Davis         ::optind = GETOPT_OPTIND_RESET_VALUE;
370*b0d29bc4SBrooks Davis #if defined(HAVE_GETOPT_WITH_OPTRESET)
371*b0d29bc4SBrooks Davis         ::optreset = 1;
372*b0d29bc4SBrooks Davis #endif
373*b0d29bc4SBrooks Davis     } catch (...) {
374*b0d29bc4SBrooks Davis         free_mutable_argv(mutable_argv);
375*b0d29bc4SBrooks Davis         ::opterr = old_opterr;
376*b0d29bc4SBrooks Davis         ::optind = GETOPT_OPTIND_RESET_VALUE;
377*b0d29bc4SBrooks Davis #if defined(HAVE_GETOPT_WITH_OPTRESET)
378*b0d29bc4SBrooks Davis         ::optreset = 1;
379*b0d29bc4SBrooks Davis #endif
380*b0d29bc4SBrooks Davis         throw;
381*b0d29bc4SBrooks Davis     }
382*b0d29bc4SBrooks Davis     free_mutable_argv(mutable_argv);
383*b0d29bc4SBrooks Davis 
384*b0d29bc4SBrooks Davis     return parsed_cmdline(option_values, args);
385*b0d29bc4SBrooks Davis }
386