STXXL  1.4-dev
 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
106  << arg->param_text();
107  output_wrap(os, arg->m_desc, m_linewrap,
108  0, m_param_maxlong + 2, m_param_maxlong + 2, 8);
109  }
110  }
111 
112  if (m_optlist.size())
113  {
114  os << "Options:" << std::endl;
115 
116  for (arglist_type::const_iterator it = m_optlist.begin();
117  it != m_optlist.end(); ++it)
118  {
119  const argument* arg = *it;
120 
121  os << " " << std::setw(m_opt_maxlong) << std::left
122  << arg->option_text();
123  output_wrap(os, arg->m_desc, m_linewrap,
124  0, m_opt_maxlong + 2, m_opt_maxlong + 2, 8);
125  }
126  }
127 
128  os.copyfmt(state);
129 }
130 
131 void cmdline_parser::print_option_error(
132  int argc, const char* const* argv, const argument* arg,
133  std::ostream& os)
134 {
135  os << "Error: Argument ";
136  if (argc != 0)
137  os << '"' << argv[0] << '"';
138 
139  os << " for " << arg->type_name() << " option " << arg->option_text()
140  << (argc == 0 ? " is missing!" : " is invalid!")
141  << std::endl << std::endl;
142 
143  print_usage(os);
144 }
145 
146 void cmdline_parser::print_param_error(int argc, const char* const* argv, const argument* arg,
147  std::ostream& os)
148 {
149  os << "Error: Argument ";
150  if (argc != 0)
151  os << '"' << argv[0] << '"';
152 
153  os << " for " << arg->type_name() << " parameter " << arg->param_text()
154  << (argc == 0 ? " is missing!" : " is invalid!")
155  << std::endl << std::endl;
156 
157  print_usage(os);
158 }
159 
160 bool cmdline_parser::process(int argc, const char* const* argv, std::ostream& os)
161 {
162  m_progname = argv[0];
163  --argc, ++argv;
164 
165  // search for help string and output help
166  for (int i = 0; i < argc; ++i)
167  {
168  if (strcmp(argv[i], "-h") == 0 ||
169  strcmp(argv[i], "--help") == 0)
170  {
171  print_usage(os);
172  return false;
173  }
174  }
175 
176  arglist_type::iterator argi = m_paramlist.begin(); // current argument in m_paramlist
177  bool end_optlist = false;
178 
179  while (argc != 0)
180  {
181  const char* arg = argv[0];
182 
183  if (arg[0] == '-' && !end_optlist)
184  {
185  // option, advance to argument
186  --argc, ++argv;
187  if (arg[1] == '-')
188  {
189  if (arg[2] == '-') {
190  end_optlist = true;
191  }
192  else {
193  // long option
194  arglist_type::const_iterator oi = m_optlist.begin();
195  for ( ; oi != m_optlist.end(); ++oi)
196  {
197  if ((arg + 2) == (*oi)->m_longkey)
198  {
199  if (!(*oi)->process(argc, argv))
200  {
201  print_option_error(argc, argv, *oi, os);
202  return false;
203  }
204  else if (m_verbose_process)
205  {
206  os << "Option " << (*oi)->option_text() << " set to ";
207  (*oi)->print_value(os);
208  os << '.' << std::endl;
209  }
210  break;
211  }
212  }
213  if (oi == m_optlist.end())
214  {
215  os << "Error: Unknown option \"" << arg << "\"." << std::endl << std::endl;
216  print_usage(os);
217  return false;
218  }
219  }
220  }
221  else
222  {
223  // short option
224  if (arg[1] == 0) {
225  os << "Invalid option \"" << arg << '"' << std::endl;
226  }
227  else {
228  arglist_type::const_iterator oi = m_optlist.begin();
229  for ( ; oi != m_optlist.end(); ++oi)
230  {
231  if (arg[1] == (*oi)->m_key)
232  {
233  if (!(*oi)->process(argc, argv))
234  {
235  print_option_error(argc, argv, *oi, os);
236  return false;
237  }
238  else if (m_verbose_process)
239  {
240  os << "Option " << (*oi)->option_text() << " set to ";
241  (*oi)->print_value(os);
242  os << '.' << std::endl;
243  }
244  break;
245  }
246  }
247  if (oi == m_optlist.end())
248  {
249  os << "Error: Unknown option \"" << arg << "\"." << std::endl << std::endl;
250  print_usage(os);
251  return false;
252  }
253  }
254  }
255  }
256  else
257  {
258  if (argi != m_paramlist.end())
259  {
260  if (!(*argi)->process(argc, argv))
261  {
262  print_param_error(argc, argv, *argi, os);
263  return false;
264  }
265  else if (m_verbose_process)
266  {
267  os << "Parameter " << (*argi)->param_text() << " set to ";
268  (*argi)->print_value(os);
269  os << '.' << std::endl;
270  }
271  (*argi)->m_found = true;
272  if (!(*argi)->m_repeated)
273  ++argi;
274  }
275  else
276  {
277  os << "Error: Unexpected extra argument \"" << argv[0] << "\"."
278  << std::endl << std::endl;
279  --argc, ++argv;
280  print_usage(os);
281  return false;
282  }
283  }
284  }
285 
286  bool good = true;
287 
288  for (arglist_type::const_iterator it = m_paramlist.begin();
289  it != m_paramlist.end(); ++it)
290  {
291  if ((*it)->m_required && !(*it)->m_found) {
292  os << "Error: Argument for parameter "
293  << (*it)->m_longkey << " is required!" << std::endl;
294  good = false;
295  }
296  }
297 
298  if (!good) {
299  os << std::endl;
300  print_usage(os);
301  }
302 
303  return good;
304 }
305 
306 void cmdline_parser::print_result(std::ostream& os)
307 {
308  std::ios state(NULL);
309  state.copyfmt(os);
310 
311  int maxlong = STXXL_MAX(m_param_maxlong, m_opt_maxlong);
312 
313  if (m_paramlist.size())
314  {
315  os << "Parameters:" << std::endl;
316 
317  for (arglist_type::const_iterator it = m_paramlist.begin();
318  it != m_paramlist.end(); ++it)
319  {
320  const argument* arg = *it;
321 
322  os << " " << std::setw(maxlong) << std::left << arg->param_text();
323 
324  std::string typestr = "(" + std::string(arg->type_name()) + ")";
325  os << std::setw(m_maxtypename + 4) << typestr;
326 
327  arg->print_value(os);
328 
329  os << std::endl;
330  }
331  }
332 
333  if (m_optlist.size())
334  {
335  os << "Options:" << std::endl;
336 
337  for (arglist_type::const_iterator it = m_optlist.begin();
338  it != m_optlist.end(); ++it)
339  {
340  const argument* arg = *it;
341 
342  os << " " << std::setw(maxlong) << std::left << arg->option_text();
343 
344  std::string typestr = "(" + std::string(arg->type_name()) + ")";
345  os << std::setw(m_maxtypename + 4) << std::left << typestr;
346 
347  arg->print_value(os);
348 
349  os << std::endl;
350  }
351  }
352 
353  os.copyfmt(state);
354 }
355 
bool m_required
required, process() fails if the option/parameter is not found.
Definition: cmdline.h:60
std::string m_longkey
long option key or name for parameters
Definition: cmdline.h:54
virtual const char * type_name() const =0
return formatted type name to user
base class of all options and parameters
Definition: cmdline.h:49
std::string option_text() const
return &#39;-s, –longkey [keytype]&#39;
Definition: cmdline.h:98
const Type & STXXL_MAX(const Type &a, const Type &b)
Definition: utils.h:153
bool m_repeated
repeated argument, i.e. std::vector&lt;std::string&gt;
Definition: cmdline.h:64
#define STXXL_BEGIN_NAMESPACE
Definition: namespace.h:16
std::string param_text() const
return &#39;longkey [keytype]&#39;
Definition: cmdline.h:88
std::string m_desc
longer description, which will be wrapped
Definition: cmdline.h:58
virtual void print_value(std::ostream &os) const =0
format value to ostream
#define STXXL_END_NAMESPACE
Definition: namespace.h:17