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)
8 #define BOOST_PROGRAM_OPTIONS_SOURCE
9 #include <boost/program_options/config.hpp>
10 #include <boost/program_options/options_description.hpp>
11 // FIXME: this is only to get multiple_occurrences class
12 // should move that to a separate headers.
13 #include <boost/program_options/parsers.hpp>
16 #include <boost/lexical_cast.hpp>
17 #include <boost/tokenizer.hpp>
18 #include <boost/detail/workaround.hpp>
19 #include <boost/throw_exception.hpp>
29 namespace boost
{ namespace program_options
{
33 template< class charT
>
34 std::basic_string
< charT
> tolower_(const std::basic_string
< charT
>& str
)
36 std::basic_string
< charT
> result
;
37 for (typename
std::basic_string
< charT
>::size_type i
= 0; i
< str
.size(); ++i
)
39 result
.append(1, static_cast< charT
>(std::tolower(str
[i
])));
44 } // unnamed namespace
47 option_description::option_description()
52 option_description(const char* name
,
53 const value_semantic
* s
)
61 option_description(const char* name
,
62 const value_semantic
* s
,
63 const char* description
)
64 : m_description(description
), m_value_semantic(s
)
69 option_description::~option_description()
73 option_description::match_result
74 option_description::match(const std::string
& option
,
76 bool long_ignore_case
,
77 bool short_ignore_case
) const
79 match_result result
= no_match
;
81 std::string
local_long_name((long_ignore_case
? tolower_(m_long_name
) : m_long_name
));
83 if (!local_long_name
.empty()) {
85 std::string local_option
= (long_ignore_case
? tolower_(option
) : option
);
87 if (*local_long_name
.rbegin() == '*')
89 // The name ends with '*'. Any specified name with the given
91 if (local_option
.find(local_long_name
.substr(0, local_long_name
.length()-1))
93 result
= approximate_match
;
96 if (local_long_name
== local_option
)
102 if (local_long_name
.find(local_option
) == 0)
104 result
= approximate_match
;
109 if (result
!= full_match
)
111 std::string
local_option(short_ignore_case
? tolower_(option
) : option
);
112 std::string
local_short_name(short_ignore_case
? tolower_(m_short_name
) : m_short_name
);
114 if (local_short_name
== local_option
)
124 option_description::key(const std::string
& option
) const
126 if (!m_long_name
.empty())
127 if (m_long_name
.find('*') != string::npos
)
128 // The '*' character means we're long_name
129 // matches only part of the input. So, returning
130 // long name will remove some of the information,
131 // and we have to return the option as specified
141 option_description::canonical_display_name(int prefix_style
) const
143 if (!m_long_name
.empty())
145 if (prefix_style
== command_line_style::allow_long
)
146 return "--" + m_long_name
;
147 if (prefix_style
== command_line_style::allow_long_disguise
)
148 return "-" + m_long_name
;
150 // sanity check: m_short_name[0] should be '-' or '/'
151 if (m_short_name
.length() == 2)
153 if (prefix_style
== command_line_style::allow_slash_for_short
)
154 return string("/") + m_short_name
[1];
155 if (prefix_style
== command_line_style::allow_dash_for_short
)
156 return string("-") + m_short_name
[1];
158 if (!m_long_name
.empty())
166 option_description::long_name() const
172 option_description::set_name(const char* _name
)
174 std::string
name(_name
);
175 string::size_type n
= name
.find(',');
176 if (n
!= string::npos
) {
177 assert(n
== name
.size()-2);
178 m_long_name
= name
.substr(0, n
);
179 m_short_name
= '-' + name
.substr(n
+1,1);
187 option_description::description() const
189 return m_description
;
192 shared_ptr
<const value_semantic
>
193 option_description::semantic() const
195 return m_value_semantic
;
199 option_description::format_name() const
201 if (!m_short_name
.empty())
203 return m_long_name
.empty()
205 : string(m_short_name
).append(" [ --").
206 append(m_long_name
).append(" ]");
208 return string("--").append(m_long_name
);
212 option_description::format_parameter() const
214 if (m_value_semantic
->max_tokens() != 0)
215 return m_value_semantic
->name();
220 options_description_easy_init::
221 options_description_easy_init(options_description
* owner
)
225 options_description_easy_init
&
226 options_description_easy_init::
227 operator()(const char* name
,
228 const char* description
)
230 // Create untypes semantic which accepts zero tokens: i.e.
231 // no value can be specified on command line.
232 // FIXME: does not look exception-safe
233 shared_ptr
<option_description
> d(
234 new option_description(name
, new untyped_value(true), description
));
240 options_description_easy_init
&
241 options_description_easy_init::
242 operator()(const char* name
,
243 const value_semantic
* s
)
245 shared_ptr
<option_description
> d(new option_description(name
, s
));
250 options_description_easy_init
&
251 options_description_easy_init::
252 operator()(const char* name
,
253 const value_semantic
* s
,
254 const char* description
)
256 shared_ptr
<option_description
> d(new option_description(name
, s
, description
));
262 const unsigned options_description::m_default_line_length
= 80;
264 options_description::options_description(unsigned line_length
,
265 unsigned min_description_length
)
266 : m_line_length(line_length
)
267 , m_min_description_length(min_description_length
)
269 // we require a space between the option and description parts, so add 1.
270 assert(m_min_description_length
< m_line_length
- 1);
273 options_description::options_description(const std::string
& caption
,
274 unsigned line_length
,
275 unsigned min_description_length
)
277 , m_line_length(line_length
)
278 , m_min_description_length(min_description_length
)
280 // we require a space between the option and description parts, so add 1.
281 assert(m_min_description_length
< m_line_length
- 1);
285 options_description::add(shared_ptr
<option_description
> desc
)
287 m_options
.push_back(desc
);
288 belong_to_group
.push_back(false);
292 options_description::add(const options_description
& desc
)
294 shared_ptr
<options_description
> d(new options_description(desc
));
297 for (size_t i
= 0; i
< desc
.m_options
.size(); ++i
) {
298 add(desc
.m_options
[i
]);
299 belong_to_group
.back() = true;
305 options_description_easy_init
306 options_description::add_options()
308 return options_description_easy_init(this);
311 const option_description
&
312 options_description::find(const std::string
& name
,
314 bool long_ignore_case
,
315 bool short_ignore_case
) const
317 const option_description
* d
= find_nothrow(name
, approx
,
318 long_ignore_case
, short_ignore_case
);
320 boost::throw_exception(unknown_option());
324 const std::vector
< shared_ptr
<option_description
> >&
325 options_description::options() const
330 const option_description
*
331 options_description::find_nothrow(const std::string
& name
,
333 bool long_ignore_case
,
334 bool short_ignore_case
) const
336 shared_ptr
<option_description
> found
;
337 bool had_full_match
= false;
338 vector
<string
> approximate_matches
;
339 vector
<string
> full_matches
;
341 // We use linear search because matching specified option
342 // name with the declared option name need to take care about
343 // case sensitivity and trailing '*' and so we can't use simple map.
344 for(unsigned i
= 0; i
< m_options
.size(); ++i
)
346 option_description::match_result r
=
347 m_options
[i
]->match(name
, approx
, long_ignore_case
, short_ignore_case
);
349 if (r
== option_description::no_match
)
352 if (r
== option_description::full_match
)
354 full_matches
.push_back(m_options
[i
]->key(name
));
355 found
= m_options
[i
];
356 had_full_match
= true;
360 // FIXME: the use of 'key' here might not
361 // be the best approach.
362 approximate_matches
.push_back(m_options
[i
]->key(name
));
364 found
= m_options
[i
];
367 if (full_matches
.size() > 1)
368 boost::throw_exception(ambiguous_option(full_matches
));
370 // If we have a full match, and an approximate match,
371 // ignore approximate match instead of reporting error.
372 // Say, if we have options "all" and "all-chroots", then
373 // "--all" on the command line should select the first one,
374 // without ambiguity.
375 if (full_matches
.empty() && approximate_matches
.size() > 1)
376 boost::throw_exception(ambiguous_option(approximate_matches
));
381 BOOST_PROGRAM_OPTIONS_DECL
382 std::ostream
& operator<<(std::ostream
& os
, const options_description
& desc
)
390 /* Given a string 'par', that contains no newline characters
391 outputs it to 'os' with wordwrapping, that is, as several
394 Each output line starts with 'indent' space characters,
395 following by characters from 'par'. The total length of
396 line is no longer than 'line_length'.
399 void format_paragraph(std::ostream
& os
,
402 unsigned line_length
)
404 // Through reminder of this function, 'line_length' will
405 // be the length available for characters, not including
407 assert(indent
< line_length
);
408 line_length
-= indent
;
410 // index of tab (if present) is used as additional indent relative
411 // to first_column_width if paragrapth is spanned over multiple
412 // lines if tab is not on first line it is ignored
413 string::size_type par_indent
= par
.find('\t');
415 if (par_indent
== string::npos
)
421 // only one tab per paragraph allowed
422 if (count(par
.begin(), par
.end(), '\t') > 1)
424 boost::throw_exception(program_options::error(
425 "Only one tab per paragraph is allowed in the options description"));
428 // erase tab from string
429 par
.erase(par_indent
, 1);
431 // this assert may fail due to user error or
432 // environment conditions!
433 assert(par_indent
< line_length
);
435 // ignore tab if not on first line
436 if (par_indent
>= line_length
)
442 if (par
.size() < line_length
)
448 string::const_iterator line_begin
= par
.begin();
449 const string::const_iterator par_end
= par
.end();
451 bool first_line
= true; // of current paragraph!
453 while (line_begin
< par_end
) // paragraph lines
457 // If line starts with space, but second character
458 // is not space, remove the leading space.
459 // We don't remove double spaces because those
460 // might be intentianal.
461 if ((*line_begin
== ' ') &&
462 ((line_begin
+ 1 < par_end
) &&
463 (*(line_begin
+ 1) != ' ')))
465 line_begin
+= 1; // line_begin != line_end
469 // Take care to never increment the iterator past
470 // the end, since MSVC 8.0 (brokenly), assumes that
471 // doing that, even if no access happens, is a bug.
472 unsigned remaining
= static_cast<unsigned>(std::distance(line_begin
, par_end
));
473 string::const_iterator line_end
= line_begin
+
474 ((remaining
< line_length
) ? remaining
: line_length
);
476 // prevent chopped words
477 // Is line_end between two non-space characters?
478 if ((*(line_end
- 1) != ' ') &&
479 ((line_end
< par_end
) && (*line_end
!= ' ')))
481 // find last ' ' in the second half of the current paragraph line
482 string::const_iterator last_space
=
483 find(reverse_iterator
<string::const_iterator
>(line_end
),
484 reverse_iterator
<string::const_iterator
>(line_begin
),
488 if (last_space
!= line_begin
)
490 // is last_space within the second half ot the
492 if (static_cast<unsigned>(std::distance(last_space
, line_end
)) <
495 line_end
= last_space
;
498 } // prevent chopped words
500 // write line to stream
501 copy(line_begin
, line_end
, ostream_iterator
<char>(os
));
505 indent
+= static_cast<unsigned>(par_indent
);
506 line_length
-= static_cast<unsigned>(par_indent
); // there's less to work with now
510 // more lines to follow?
511 if (line_end
!= par_end
)
515 for(unsigned pad
= indent
; pad
> 0; --pad
)
521 // next line starts after of this line
522 line_begin
= line_end
;
527 void format_description(std::ostream
& os
,
528 const std::string
& desc
,
529 unsigned first_column_width
,
530 unsigned line_length
)
532 // we need to use one char less per line to work correctly if actual
533 // console has longer lines
534 assert(line_length
> 1);
540 // line_length must be larger than first_column_width
541 // this assert may fail due to user error or environment conditions!
542 assert(line_length
> first_column_width
);
544 // Note: can't use 'tokenizer' as name of typedef -- borland
545 // will consider uses of 'tokenizer' below as uses of
546 // boost::tokenizer, not typedef.
547 typedef boost::tokenizer
<boost::char_separator
<char> > tok
;
551 char_separator
<char>("\n", "", boost::keep_empty_tokens
));
553 tok::const_iterator par_iter
= paragraphs
.begin();
554 const tok::const_iterator par_end
= paragraphs
.end();
556 while (par_iter
!= par_end
) // paragraphs
558 format_paragraph(os
, *par_iter
, first_column_width
,
563 // prepair next line if any
564 if (par_iter
!= par_end
)
568 for(unsigned pad
= first_column_width
; pad
> 0; --pad
)
576 void format_one(std::ostream
& os
, const option_description
& opt
,
577 unsigned first_column_width
, unsigned line_length
)
580 ss
<< " " << opt
.format_name() << ' ' << opt
.format_parameter();
582 // Don't use ss.rdbuf() since g++ 2.96 is buggy on it.
585 if (!opt
.description().empty())
587 if (ss
.str().size() >= first_column_width
)
589 os
.put('\n'); // first column is too long, lets put description in new line
590 for (unsigned pad
= first_column_width
; pad
> 0; --pad
)
595 for(unsigned pad
= first_column_width
- static_cast<unsigned>(ss
.str().size()); pad
> 0; --pad
)
601 format_description(os
, opt
.description(),
602 first_column_width
, line_length
);
608 options_description::get_option_column_width() const
610 /* Find the maximum width of the option column */
612 unsigned i
; // vc6 has broken for loop scoping
613 for (i
= 0; i
< m_options
.size(); ++i
)
615 const option_description
& opt
= *m_options
[i
];
617 ss
<< " " << opt
.format_name() << ' ' << opt
.format_parameter();
618 width
= (max
)(width
, static_cast<unsigned>(ss
.str().size()));
621 /* Get width of groups as well*/
622 for (unsigned j
= 0; j
< groups
.size(); ++j
)
623 width
= max(width
, groups
[j
]->get_option_column_width());
625 /* this is the column were description should start, if first
626 column is longer, we go to a new line */
627 const unsigned start_of_description_column
= m_line_length
- m_min_description_length
;
629 width
= (min
)(width
, start_of_description_column
-1);
631 /* add an additional space to improve readability */
637 options_description::print(std::ostream
& os
, unsigned width
) const
639 if (!m_caption
.empty())
640 os
<< m_caption
<< ":\n";
643 width
= get_option_column_width();
645 /* The options formatting style is stolen from Subversion. */
646 for (unsigned i
= 0; i
< m_options
.size(); ++i
)
648 if (belong_to_group
[i
])
651 const option_description
& opt
= *m_options
[i
];
653 format_one(os
, opt
, width
, m_line_length
);
658 for (unsigned j
= 0; j
< groups
.size(); ++j
) {
660 groups
[j
]->print(os
, width
);