STXXL  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
cmdline.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * lib/common/cmdline.cpp
3  *
4  * Part of the STXXL. See http://stxxl.sourceforge.net
5  *
6  * Copyright (C) 2013 Timo Bingmann <[email protected]>
7  *
8  * Distributed under the Boost Software License, Version 1.0.
9  * (See accompanying file LICENSE_1_0.txt or copy at
10  * http://www.boost.org/LICENSE_1_0.txt)
11  **************************************************************************/
12 
15 #include <stxxl/bits/namespace.h>
16 
17 #include <iomanip>
18 #include <cstring>
19 
21 
22 void cmdline_parser::output_wrap(std::ostream& os, const std::string& text, size_t wraplen,
23  size_t indent_first, size_t indent_rest,
24  size_t current, size_t indent_newline)
25 {
26  std::string::size_type t = 0;
27  size_t indent = indent_first;
28  while (t != text.size())
29  {
30  std::string::size_type to = t, lspace = t;
31 
32  // scan forward in text until we hit a newline or wrap point
33  while (to != text.size() &&
34  to + current + indent < t + wraplen &&
35  text[to] != '\n')
36  {
37  if (text[to] == ' ') lspace = to;
38  ++to;
39  }
40 
41  // go back to last space
42  if (to != text.size() && text[to] != '\n' &&
43  lspace != t) to = lspace + 1;
44 
45  // output line
46  os << std::string(indent, ' ')
47  << text.substr(t, to - t) << std::endl;
48 
49  current = 0;
50  indent = indent_rest;
51 
52  // skip over last newline
53  if (to != text.size() && text[to] == '\n') {
54  indent = indent_newline;
55  ++to;
56  }
57 
58  t = to;
59  }
60 }
61 
62 void cmdline_parser::print_usage(std::ostream& os)
63 {
64  std::ios state(NULL);
65  state.copyfmt(os);
66 
67  os << "Usage: " << m_progname
68  << (m_optlist.size() ? " [options]" : "");
69 
70  for (arglist_type::const_iterator it = m_paramlist.begin();
71  it != m_paramlist.end(); ++it)
72  {
73  const argument* arg = *it;
74 
75  os << (arg->m_required ? " <" : " [")
76  << arg->m_longkey
77  << (arg->m_repeated ? " ..." : "")
78  << (arg->m_required ? '>' : ']');
79  }
80 
81  os << std::endl;
82 
83  if (m_description.size())
84  {
85  os << std::endl;
86  output_wrap(os, m_description, m_linewrap);
87  }
88  if (m_author.size())
89  {
90  os << "Author: " << m_author << std::endl;
91  }
92 
93  if (m_description.size() || m_author.size())
94  os << std::endl;
95 
96  if (m_paramlist.size())
97  {
98  os << "Parameters:" << std::endl;
99 
100  for (arglist_type::const_iterator it = m_paramlist.begin();
101  it != m_paramlist.end(); ++it)
102  {
103  const argument* arg = *it;
104 
105  os << " " << std::setw(m_param_maxlong) << std::left << arg->param_text();
106  output_wrap(os, arg->m_desc, m_linewrap,
107  0, m_param_maxlong + 2, m_param_maxlong + 2, 8);
108  }
109  }
110 
111  if (m_optlist.size())
112  {
113  os << "Options:" << std::endl;
114 
115  for (arglist_type::const_iterator it = m_optlist.begin();
116  it != m_optlist.end(); ++it)
117  {
118  const argument* arg = *it;
119 
120  os << " " << std::setw(m_opt_maxlong) << std::left << arg->option_text();
121  output_wrap(os, arg->m_desc, m_linewrap,
122  0, m_opt_maxlong + 2, m_opt_maxlong + 2, 8);
123  }
124  }
125 
126  os.copyfmt(state);
127 }
128 
129 void cmdline_parser::print_option_error(int argc, const char* const* argv, const argument* arg,
130  std::ostream& os)
131 {
132  os << "Error: Argument ";
133  if (argc != 0)
134  os << '"' << argv[0] << '"';
135 
136  os << " for " << arg->type_name() << " option " << arg->option_text()
137  << (argc == 0 ? " is missing!" : " is invalid!")
138  << std::endl << std::endl;
139 
140  print_usage(os);
141 }
142 
143 void cmdline_parser::print_param_error(int argc, const char* const* argv, const argument* arg,
144  std::ostream& os)
145 {
146  os << "Error: Argument ";
147  if (argc != 0)
148  os << '"' << argv[0] << '"';
149 
150  os << " for " << arg->type_name() << " parameter " << arg->param_text()
151  << (argc == 0 ? " is missing!" : " is invalid!")
152  << std::endl << std::endl;
153 
154  print_usage(os);
155 }
156 
157 bool cmdline_parser::process(int argc, const char* const* argv, std::ostream& os)
158 {
159  m_progname = argv[0];
160  --argc, ++argv;
161 
162  // search for help string and output help
163  for (int i = 0; i < argc; ++i)
164  {
165  if (strcmp(argv[i], "-h") == 0 ||
166  strcmp(argv[i], "--help") == 0)
167  {
168  print_usage(os);
169  return false;
170  }
171  }
172 
173  arglist_type::iterator argi = m_paramlist.begin(); // current argument in m_paramlist
174  bool end_optlist = false;
175 
176  while (argc != 0)
177  {
178  const char* arg = argv[0];
179 
180  if (arg[0] == '-' && !end_optlist)
181  {
182  // option, advance to argument
183  --argc, ++argv;
184  if (arg[1] == '-')
185  {
186  if (arg[2] == '-') {
187  end_optlist = true;
188  }
189  else {
190  // long option
191  arglist_type::const_iterator oi = m_optlist.begin();
192  for ( ; oi != m_optlist.end(); ++oi)
193  {
194  if ((arg + 2) == (*oi)->m_longkey)
195  {
196  if (!(*oi)->process(argc, argv))
197  {
198  print_option_error(argc, argv, *oi, os);
199  return false;
200  }
201  else if (m_verbose_process)
202  {
203  os << "Option " << (*oi)->option_text() << " set to ";
204  (*oi)->print_value(os);
205  os << '.' << std::endl;
206  }
207  break;
208  }
209  }
210  if (oi == m_optlist.end())
211  {
212  os << "Error: Unknown option \"" << arg << "\"." << std::endl << std::endl;
213  print_usage(os);
214  return false;
215  }
216  }
217  }
218  else
219  {
220  // short option
221  if (arg[1] == 0) {
222  os << "Invalid option \"" << arg << '"' << std::endl;
223  }
224  else {
225  arglist_type::const_iterator oi = m_optlist.begin();
226  for ( ; oi != m_optlist.end(); ++oi)
227  {
228  if (arg[1] == (*oi)->m_key)
229  {
230  if (!(*oi)->process(argc, argv))
231  {
232  print_option_error(argc, argv, *oi, os);
233  return false;
234  }
235  else if (m_verbose_process)
236  {
237  os << "Option " << (*oi)->option_text() << " set to ";
238  (*oi)->print_value(os);
239  os << '.' << std::endl;
240  }
241  break;
242  }
243  }
244  if (oi == m_optlist.end())
245  {
246  os << "Error: Unknown option \"" << arg << "\"." << std::endl << std::endl;
247  print_usage(os);
248  return false;
249  }
250  }
251  }
252  }
253  else
254  {
255  if (argi != m_paramlist.end())
256  {
257  if (!(*argi)->process(argc, argv))
258  {
259  print_param_error(argc, argv, *argi, os);
260  return false;
261  }
262  else if (m_verbose_process)
263  {
264  os << "Parameter " << (*argi)->param_text() << " set to ";
265  (*argi)->print_value(os);
266  os << '.' << std::endl;
267  }
268  (*argi)->m_found = true;
269  if (!(*argi)->m_repeated)
270  ++argi;
271  }
272  else
273  {
274  os << "Error: Unexpected extra argument \"" << argv[0] << "\"."
275  << std::endl << std::endl;
276  --argc, ++argv;
277  print_usage(os);
278  return false;
279  }
280  }
281  }
282 
283  bool good = true;
284 
285  for (arglist_type::const_iterator it = m_paramlist.begin();
286  it != m_paramlist.end(); ++it)
287  {
288  if ((*it)->m_required && !(*it)->m_found) {
289  os << "Error: Argument for parameter "
290  << (*it)->m_longkey << " is required!" << std::endl;
291  good = false;
292  }
293  }
294 
295  if (!good) {
296  os << std::endl;
297  print_usage(os);
298  }
299 
300  return good;
301 }
302 
303 void cmdline_parser::print_result(std::ostream& os)
304 {
305  std::ios state(NULL);
306  state.copyfmt(os);
307 
308  size_t maxlong = STXXL_MAX(m_param_maxlong, m_opt_maxlong);
309 
310  if (m_paramlist.size())
311  {
312  os << "Parameters:" << std::endl;
313 
314  for (arglist_type::const_iterator it = m_paramlist.begin();
315  it != m_paramlist.end(); ++it)
316  {
317  const argument* arg = *it;
318 
319  os << " " << std::setw(maxlong) << std::left << arg->param_text();
320 
321  std::string typestr = "(" + std::string(arg->type_name()) + ")";
322  os << std::setw(m_maxtypename + 4) << typestr;
323 
324  arg->print_value(os);
325 
326  os << std::endl;
327  }
328  }
329 
330  if (m_optlist.size())
331  {
332  os << "Options:" << std::endl;
333 
334  for (arglist_type::const_iterator it = m_optlist.begin();
335  it != m_optlist.end(); ++it)
336  {
337  const argument* arg = *it;
338 
339  os << " " << std::setw(maxlong) << std::left << arg->option_text();
340 
341  std::string typestr = "(" + std::string(arg->type_name()) + ")";
342  os << std::setw(m_maxtypename + 4) << std::left << typestr;
343 
344  arg->print_value(os);
345 
346  os << std::endl;
347  }
348  }
349 
350  os.copyfmt(state);
351 }
352 
bool m_required
required, process() fails if the option/parameter is not found.
Definition: cmdline.h:57
std::string m_longkey
long option key or name for parameters
Definition: cmdline.h:51
virtual const char * type_name() const =0
return formatted type name to user
base class of all options and parameters
Definition: cmdline.h:46
std::string option_text() const
return &#39;-s, –longkey [keytype]&#39;
Definition: cmdline.h:93
const Tp & STXXL_MAX(const Tp &a, const Tp &b)
Definition: utils.h:154
bool m_repeated
repeated argument, i.e. std::vector&lt;std::string&gt;
Definition: cmdline.h:61
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
std::string param_text() const
return &#39;longkey [keytype]&#39;
Definition: cmdline.h:83
std::string m_desc
longer description, which will be wrapped
Definition: cmdline.h:55
virtual void print_value(std::ostream &os) const =0
format value to ostream
#define STXXL_END_NAMESPACE
Definition: namespace.h:17