CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cmdline.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
9#include "cmdline.h"
10
11#include <util/edit_distance.h>
13#include <util/invariant.h>
14#include <util/string_utils.h>
15
19
23
25{
26 options.clear();
27 args.clear();
28}
29
30bool cmdlinet::isset(char option) const
31{
32 auto i=getoptnr(option);
33 if(i.has_value())
34 return options[*i].isset;
35 else
36 return false;
37}
38
39bool cmdlinet::isset(const char *option) const
40{
41 auto i=getoptnr(option);
42 if(i.has_value())
43 return options[*i].isset;
44 else
45 return false;
46}
47
48std::string cmdlinet::get_value(char option) const
49{
50 return value_opt(option).value_or("");
51}
52
53std::optional<std::string> cmdlinet::value_opt(char option) const
54{
55 auto i=getoptnr(option);
56
57 if(i.has_value() && !options[*i].values.empty())
58 return options[*i].values.front();
59 else
60 return {};
61}
62
63void cmdlinet::set(const std::string &option, bool value)
64{
65 auto i=getoptnr(option);
66
67 if(i.has_value())
68 options[*i].isset = value;
69 else
70 {
72 "unknown command line option", option);
73 }
75
76void cmdlinet::set(const std::string &option, const std::string &value)
77{
78 auto i=getoptnr(option);
79
80 if(i.has_value())
81 {
82 options[*i].isset=true;
83 options[*i].values.push_back(value);
84 }
85 else
86 {
88 "unknown command line option", option);
89 }
90}
91
92static std::list<std::string> immutable_empty_list;
93
94const std::list<std::string> &cmdlinet::get_values(char option) const
95{
96 auto i=getoptnr(option);
97
98 if(i.has_value())
99 return options[*i].values;
100 else
102}
103
104std::string cmdlinet::get_value(const char *option) const
105{
106 return value_opt(option).value_or("");
107}
108
109std::optional<std::string> cmdlinet::value_opt(const char *option) const
110{
111 auto i=getoptnr(option);
112
113 if(i.has_value() && !options[*i].values.empty())
114 return options[*i].values.front();
115 else
116 return {};
117}
118
119const std::list<std::string> &cmdlinet::get_values(
120 const std::string &option) const
121{
122 auto i=getoptnr(option);
123
124 if(i.has_value())
125 return options[*i].values;
126 else
128}
129
130std::list<std::string>
132{
133 std::list<std::string> separated_values;
134
135 for(const auto &csv : get_values(option))
136 {
137 const auto values = split_string(csv, ',');
138 separated_values.insert(
139 separated_values.end(), values.begin(), values.end());
140 }
141
142 return separated_values;
143}
144
145std::optional<std::size_t> cmdlinet::getoptnr(char option) const
146{
147 for(std::size_t i=0; i<options.size(); i++)
148 if(options[i].optchar==option)
149 return i;
150
151 return std::optional<std::size_t>();
152}
153
154std::optional<std::size_t> cmdlinet::getoptnr(const std::string &option) const
155{
156 for(std::size_t i=0; i<options.size(); i++)
157 if(options[i].optstring==option)
158 return i;
159
160 return std::optional<std::size_t>();
161}
162
163bool cmdlinet::parse(int argc, const char **argv, const char *optstring)
164{
165 clear();
166
167 parse_optstring(optstring);
168 return parse_arguments(argc, argv);
169}
170
175void cmdlinet::parse_optstring(const char *optstring)
176{
177 while(optstring[0] != 0)
178 {
179 optiont option;
180
182 optstring[0] != ':', "cmdlinet::parse: Invalid option string\n");
183
184 if(optstring[0] == '(')
185 {
186 option.islong = true;
187 option.optchar = 0;
188 option.isset = false;
189 option.optstring.clear();
190
191 for(optstring++; optstring[0] != ')' && optstring[0] != 0; optstring++)
192 option.optstring += optstring[0];
193
194 if(optstring[0] == ')')
195 optstring++;
196 }
197 else
198 {
199 option.islong = false;
200 option.optchar = optstring[0];
201 option.optstring.clear();
202 option.isset = false;
203
204 optstring++;
205 }
206
207 if(optstring[0] == ':')
208 {
209 option.hasval = true;
210 optstring++;
211 }
212 else
213 option.hasval = false;
214
215 options.push_back(option);
216 }
217}
218
219std::vector<std::string>
221{
222 struct suggestiont
223 {
224 std::size_t distance;
225 std::string suggestion;
226
227 bool operator<(const suggestiont &other) const
228 {
229 return distance < other.distance;
230 }
231 };
232
233 auto argument_suggestions = std::vector<suggestiont>{};
234 // We allow 3 errors here. This can lead to the output being a bit chatty,
235 // which we mitigate by reducing suggestions to those with the minimum
236 // distance further down below
238 for(const auto &option : options)
239 {
240 if(option.islong)
241 {
242 const auto long_name = "--" + option.optstring;
243 if(auto distance = argument_matcher.get_edit_distance(long_name))
244 {
245 argument_suggestions.push_back({distance.value(), long_name});
246 }
247 }
248 if(!option.islong)
249 {
250 const auto short_name = std::string{"-"} + option.optchar;
251 if(auto distance = argument_matcher.get_edit_distance(short_name))
252 {
253 argument_suggestions.push_back({distance.value(), short_name});
254 }
255 }
256 }
257
258 auto final_suggestions = std::vector<std::string>{};
259 if(!argument_suggestions.empty())
260 {
261 // we only want to keep suggestions with the minimum distance
262 // because otherwise they become quickly too noisy to be useful
263 auto min = std::min_element(
265 INVARIANT(
266 min != argument_suggestions.end(),
267 "there is a minimum because it's not empty");
268 for(auto const &suggestion : argument_suggestions)
269 {
270 if(suggestion.distance == min->distance)
271 {
272 final_suggestions.push_back(suggestion.suggestion);
273 }
274 }
275 }
276 return final_suggestions;
277}
278
279bool cmdlinet::parse_arguments(int argc, const char **argv)
280{
281 for(int i = 1; i < argc; i++)
282 {
283 if(argv[i][0] != '-')
284 args.push_back(argv[i]);
285 else
286 {
287 std::optional<std::size_t> optnr;
288
289 if(argv[i][1] != 0 && argv[i][2] == 0)
290 optnr = getoptnr(argv[i][1]); // single-letter option -X
291 else if(argv[i][1] == '-')
292 optnr = getoptnr(argv[i] + 2); // multi-letter option with --XXX
293 else
294 {
295 // Multi-letter option -XXX, or single-letter with argument -Xval
296 // We first try single-letter.
297 optnr = getoptnr(argv[i][1]);
298
299 if(!optnr.has_value()) // try multi-letter
300 optnr = getoptnr(argv[i] + 1);
301 }
302
303 if(!optnr.has_value())
304 {
305 unknown_arg = argv[i];
306 return true;
307 }
308
309 options[*optnr].isset = true;
310
311 if(options[*optnr].hasval)
312 {
313 if(argv[i][2] == 0 || options[*optnr].islong)
314 {
315 i++;
316 if(i == argc)
317 return true;
318 if(argv[i][0] == '-' && argv[i][1] != 0)
319 return true;
320 options[*optnr].values.push_back(argv[i]);
321 }
322 else
323 options[*optnr].values.push_back(argv[i] + 2);
324 }
325 }
326 }
327 return false;
328}
329
331 const cmdlinet *command_line,
332 std::size_t index)
333 : command_line(command_line), index(index)
334{
336}
337
340{
341 PRECONDITION(command_line != nullptr);
342 ++index;
343 goto_next_valid_index();
344 return *this;
345}
347{
348 PRECONDITION(command_line != nullptr);
349 auto const &options = command_line->options;
350 return index < options.size() && options[index].isset &&
351 options[index].islong;
352}
353
355{
356 PRECONDITION(command_line != nullptr);
357 while(index < command_line->options.size() && !is_valid_index())
358 {
359 ++index;
360 }
361}
362
368
370{
371 PRECONDITION(command_line != nullptr);
372 return command_line->options.at(index).optstring;
373}
374
381
388
393
398
400{
401 return option_names_iteratort(&command_line, command_line.options.size());
402}
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
std::string get_value(char option) const
Definition cmdline.cpp:48
std::string unknown_arg
Definition cmdline.h:155
virtual bool isset(char option) const
Definition cmdline.cpp:30
std::list< std::string > get_comma_separated_values(const char *option) const
Collect all occurrences of option option and split their values on each comma, merging them into a si...
Definition cmdline.cpp:131
std::optional< std::size_t > getoptnr(char option) const
Definition cmdline.cpp:145
argst args
Definition cmdline.h:154
std::optional< std::string > value_opt(char option) const
Definition cmdline.cpp:53
bool parse_arguments(int argc, const char **argv)
Parses a commandline according to a previously parsed optstring and writes the result to cmdlinet::op...
Definition cmdline.cpp:279
std::vector< optiont > options
Definition cmdline.h:193
virtual ~cmdlinet()
Definition cmdline.cpp:20
virtual void set(const std::string &option, bool value=true)
Set option option to value, or true if the value is omitted.
Definition cmdline.cpp:63
virtual bool parse(int argc, const char **argv, const char *optstring)
Parses a commandline according to a specification given in optstring.
Definition cmdline.cpp:163
std::vector< std::string > get_argument_suggestions(const std::string &unknown_argument)
Definition cmdline.cpp:220
void parse_optstring(const char *optstring)
Parses an optstring and writes the result to cmdlinet::options.
Definition cmdline.cpp:175
option_namest option_names() const
Pseudo-object that can be used to iterate over options in this cmdlinet (should not outlive this)
Definition cmdline.cpp:171
virtual void clear()
Definition cmdline.cpp:24
const std::list< std::string > & get_values(const std::string &option) const
Definition cmdline.cpp:119
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
static std::list< std::string > immutable_empty_list
Definition cmdline.cpp:92
bool operator<(const reaching_definitiont &a, const reaching_definitiont &b)
In order to use instances of this structure as keys in ordered containers, such as std::map,...
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
#define PRECONDITION(CONDITION)
Definition invariant.h:463
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition invariant.h:423
void split_string(const std::string &s, char delim, std::vector< std::string > &result, bool strip, bool remove_empty)
bool operator==(const option_names_iteratort &other)
Definition cmdline.cpp:376
bool operator!=(const option_names_iteratort &other)
Definition cmdline.cpp:383
option_names_iteratort end()
Definition cmdline.cpp:399
option_names_iteratort begin()
Definition cmdline.cpp:394
option_namest(const cmdlinet &command_line)
Definition cmdline.cpp:389
const cmdlinet & command_line
Definition cmdline.h:146
std::string optstring
Definition cmdline.h:170
Simple automaton that can detect whether a string can be transformed into another with a limited numb...