1 // Copyright Vladimir Prus 2002-2004.
2 // Copyright Bertolt Mildner 2004.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 
8 #ifndef BOOST_OPTION_DESCRIPTION_VP_2003_05_19
9 #define BOOST_OPTION_DESCRIPTION_VP_2003_05_19
10 
11 #include <boost/program_options/config.hpp>
12 #include <boost/program_options/errors.hpp>
13 #include <boost/program_options/value_semantic.hpp>
14 
15 #include <boost/function.hpp>
16 #include <boost/shared_ptr.hpp>
17 #include <boost/detail/workaround.hpp>
18 #include <boost/any.hpp>
19 
20 #include <string>
21 #include <vector>
22 #include <set>
23 #include <map>
24 #include <stdexcept>
25 #include <utility>
26 
27 #include <iosfwd>
28 
29 #if defined(BOOST_MSVC)
30 #   pragma warning (push)
31 #   pragma warning (disable:4251) // class 'boost::shared_ptr<T>' needs to have dll-interface to be used by clients of class 'boost::program_options::option_description'
32 #endif
33 
34 
35 /** Boost namespace */
36 namespace boost {
37 /** Namespace for the library. */
38 namespace program_options {
39 
40     /** Describes one possible command line/config file option. There are two
41         kinds of properties of an option. First describe it syntactically and
42         are used only to validate input. Second affect interpretation of the
43         option, for example default value for it or function that should be
44         called  when the value is finally known. Routines which perform parsing
45         never use second kind of properties \-- they are side effect free.
46         @sa options_description
47     */
48     class BOOST_PROGRAM_OPTIONS_DECL option_description {
49     public:
50 
51         option_description();
52 
53         /** Initializes the object with the passed data.
54 
55             Note: it would be nice to make the second parameter auto_ptr,
56             to explicitly pass ownership. Unfortunately, it's often needed to
57             create objects of types derived from 'value_semantic':
58                options_description d;
59                d.add_options()("a", parameter<int>("n")->default_value(1));
60             Here, the static type returned by 'parameter' should be derived
61             from value_semantic.
62 
63             Alas, derived->base conversion for auto_ptr does not really work,
64             see
65             http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
66             http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84
67 
68             So, we have to use plain old pointers. Besides, users are not
69             expected to use the constructor directly.
70 
71 
72             The 'name' parameter is interpreted by the following rules:
73             - if there's no "," character in 'name', it specifies long name
74             - otherwise, the part before "," specifies long name and the part
75             after \-- short name.
76         */
77         option_description(const char* name,
78                            const value_semantic* s);
79 
80         /** Initializes the class with the passed data.
81          */
82         option_description(const char* name,
83                            const value_semantic* s,
84                            const char* description);
85 
86         virtual ~option_description();
87 
88         enum match_result { no_match, full_match, approximate_match };
89 
90         /** Given 'option', specified in the input source,
91             returns 'true' if 'option' specifies *this.
92         */
93         match_result match(const std::string& option, bool approx,
94                            bool long_ignore_case, bool short_ignore_case) const;
95 
96         /** Returns the key that should identify the option, in
97             particular in the variables_map class.
98             The 'option' parameter is the option spelling from the
99             input source.
100             If option name contains '*', returns 'option'.
101             If long name was specified, it's the long name, otherwise
102             it's a short name with prepended '-'.
103         */
104         const std::string& key(const std::string& option) const;
105 
106 
107         /** Returns the canonical name for the option description to enable the user to
108             recognised a matching option.
109             1) For short options ('-', '/'), returns the short name prefixed.
110             2) For long options ('--' / '-') returns the first long name prefixed
111             3) All other cases, returns the first long name (if present) or the short
112                name, unprefixed.
113         */
114         std::string canonical_display_name(int canonical_option_style = 0) const;
115 
116         const std::string& long_name() const;
117 
118         const std::pair<const std::string*, std::size_t> long_names() const;
119 
120         /// Explanation of this option
121         const std::string& description() const;
122 
123         /// Semantic of option's value
124         shared_ptr<const value_semantic> semantic() const;
125 
126         /// Returns the option name, formatted suitably for usage message.
127         std::string format_name() const;
128 
129         /** Returns the parameter name and properties, formatted suitably for
130             usage message. */
131         std::string format_parameter() const;
132 
133     private:
134 
135         option_description& set_names(const char* name);
136 
137         /**
138          * a one-character "switch" name - with its prefix,
139          * so that this is either empty or has length 2 (e.g. "-c"
140          */
141         std::string m_short_name;
142 
143         /**
144          *  one or more names by which this option may be specified
145          *  on a command-line or in a config file, which are not
146          *  a single-letter switch. The names here are _without_
147          * any prefix.
148          */
149         std::vector<std::string> m_long_names;
150 
151         std::string m_description;
152 
153         // shared_ptr is needed to simplify memory management in
154         // copy ctor and destructor.
155         shared_ptr<const value_semantic> m_value_semantic;
156     };
157 
158     class options_description;
159 
160     /** Class which provides convenient creation syntax to option_description.
161      */
162     class BOOST_PROGRAM_OPTIONS_DECL options_description_easy_init {
163     public:
164         options_description_easy_init(options_description* owner);
165 
166         options_description_easy_init&
167         operator()(const char* name,
168                    const char* description);
169 
170         options_description_easy_init&
171         operator()(const char* name,
172                    const value_semantic* s);
173 
174         options_description_easy_init&
175         operator()(const char* name,
176                    const value_semantic* s,
177                    const char* description);
178 
179     private:
180         options_description* owner;
181     };
182 
183 
184     /** A set of option descriptions. This provides convenient interface for
185         adding new option (the add_options) method, and facilities to search
186         for options by name.
187 
188         See @ref a_adding_options "here" for option adding interface discussion.
189         @sa option_description
190     */
191     class BOOST_PROGRAM_OPTIONS_DECL options_description {
192     public:
193         static const unsigned m_default_line_length;
194 
195         /** Creates the instance. */
196         options_description(unsigned line_length = m_default_line_length,
197                             unsigned min_description_length = m_default_line_length / 2);
198         /** Creates the instance. The 'caption' parameter gives the name of
199             this 'options_description' instance. Primarily useful for output.
200             The 'description_length' specifies the number of columns that
201             should be reserved for the description text; if the option text
202             encroaches into this, then the description will start on the next
203             line.
204         */
205         options_description(const std::string& caption,
206                             unsigned line_length = m_default_line_length,
207                             unsigned min_description_length = m_default_line_length / 2);
208         /** Adds new variable description. Throws duplicate_variable_error if
209             either short or long name matches that of already present one.
210         */
211         void add(shared_ptr<option_description> desc);
212         /** Adds a group of option description. This has the same
213             effect as adding all option_descriptions in 'desc'
214             individually, except that output operator will show
215             a separate group.
216             Returns *this.
217         */
218         options_description& add(const options_description& desc);
219 
220         /** Find the maximum width of the option column, including options
221             in groups. */
222         unsigned get_option_column_width() const;
223 
224     public:
225         /** Returns an object of implementation-defined type suitable for adding
226             options to options_description. The returned object will
227             have overloaded operator() with parameter type matching
228             'option_description' constructors. Calling the operator will create
229             new option_description instance and add it.
230         */
231         options_description_easy_init add_options();
232 
233         const option_description& find(const std::string& name,
234                                        bool approx,
235                                        bool long_ignore_case = false,
236                                        bool short_ignore_case = false) const;
237 
238         const option_description* find_nothrow(const std::string& name,
239                                                bool approx,
240                                                bool long_ignore_case = false,
241                                                bool short_ignore_case = false) const;
242 
243 
244         const std::vector< shared_ptr<option_description> >& options() const;
245 
246         /** Produces a human readable output of 'desc', listing options,
247             their descriptions and allowed parameters. Other options_description
248             instances previously passed to add will be output separately. */
249         friend BOOST_PROGRAM_OPTIONS_DECL std::ostream& operator<<(std::ostream& os,
250                                              const options_description& desc);
251 
252         /** Outputs 'desc' to the specified stream, calling 'f' to output each
253             option_description element. */
254         void print(std::ostream& os, unsigned width = 0) const;
255 
256     private:
257 #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1800))
258         // prevent warning C4512: assignment operator could not be generated
259         options_description& operator=(const options_description&);
260 #endif
261 
262         typedef std::map<std::string, int>::const_iterator name2index_iterator;
263         typedef std::pair<name2index_iterator, name2index_iterator>
264             approximation_range;
265 
266         //approximation_range find_approximation(const std::string& prefix) const;
267 
268         std::string m_caption;
269         const unsigned m_line_length;
270         const unsigned m_min_description_length;
271 
272         // Data organization is chosen because:
273         // - there could be two names for one option
274         // - option_add_proxy needs to know the last added option
275         std::vector< shared_ptr<option_description> > m_options;
276 
277         // Whether the option comes from one of declared groups.
278 #if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, BOOST_TESTED_AT(313))
279         // vector<bool> is buggy there, see
280         // http://support.microsoft.com/default.aspx?scid=kb;en-us;837698
281         std::vector<char> belong_to_group;
282 #else
283         std::vector<bool> belong_to_group;
284 #endif
285 
286         std::vector< shared_ptr<options_description> > groups;
287 
288     };
289 
290     /** Class thrown when duplicate option description is found. */
291     class BOOST_PROGRAM_OPTIONS_DECL duplicate_option_error : public error {
292     public:
duplicate_option_error(const std::string & xwhat)293         duplicate_option_error(const std::string& xwhat) : error(xwhat) {}
294     };
295 }}
296 
297 #if defined(BOOST_MSVC)
298 #   pragma warning (pop)
299 #endif
300 
301 #endif
302