Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f4edb72

Browse files
authoredJan 18, 2021
Merge pull request #5462 from hannes-steffenhagen-diffblue/refactor/split-up-cmdline-parse
Split up the two parts of cmdlinet::parse into separate functions
2 parents 88d8868 + 86baa33 commit f4edb72

File tree

2 files changed

+139
-68
lines changed

2 files changed

+139
-68
lines changed
 

‎src/util/cmdline.cpp

+75-68
Original file line numberDiff line numberDiff line change
@@ -155,100 +155,56 @@ bool cmdlinet::parse(int argc, const char **argv, const char *optstring)
155155
{
156156
clear();
157157

158-
while(optstring[0]!=0)
158+
parse_optstring(optstring);
159+
return parse_arguments(argc, argv);
160+
}
161+
162+
cmdlinet::option_namest cmdlinet::option_names() const
163+
{
164+
return option_namest{*this};
165+
}
166+
void cmdlinet::parse_optstring(const char *optstring)
167+
{
168+
while(optstring[0] != 0)
159169
{
160170
optiont option;
161171

162172
DATA_INVARIANT(
163173
optstring[0] != ':', "cmdlinet::parse: Invalid option string\n");
164174

165-
if(optstring[0]=='(')
175+
if(optstring[0] == '(')
166176
{
167-
option.islong=true;
168-
option.optchar=0;
169-
option.isset=false;
177+
option.islong = true;
178+
option.optchar = 0;
179+
option.isset = false;
170180
option.optstring.clear();
171181

172-
for(optstring++; optstring[0]!=')' && optstring[0]!=0; optstring++)
173-
option.optstring+=optstring[0];
182+
for(optstring++; optstring[0] != ')' && optstring[0] != 0; optstring++)
183+
option.optstring += optstring[0];
174184

175-
if(optstring[0]==')')
185+
if(optstring[0] == ')')
176186
optstring++;
177187
}
178188
else
179189
{
180-
option.islong=false;
181-
option.optchar=optstring[0];
190+
option.islong = false;
191+
option.optchar = optstring[0];
182192
option.optstring.clear();
183-
option.isset=false;
193+
option.isset = false;
184194

185195
optstring++;
186196
}
187197

188-
if(optstring[0]==':')
198+
if(optstring[0] == ':')
189199
{
190-
option.hasval=true;
200+
option.hasval = true;
191201
optstring++;
192202
}
193203
else
194-
option.hasval=false;
204+
option.hasval = false;
195205

196206
options.push_back(option);
197207
}
198-
199-
for(int i=1; i<argc; i++)
200-
{
201-
if(argv[i][0]!='-')
202-
args.push_back(argv[i]);
203-
else
204-
{
205-
optionalt<std::size_t> optnr;
206-
207-
if(argv[i][1]!=0 && argv[i][2]==0)
208-
optnr=getoptnr(argv[i][1]); // single-letter option -X
209-
else if(argv[i][1]=='-')
210-
optnr=getoptnr(argv[i]+2); // multi-letter option with --XXX
211-
else
212-
{
213-
// Multi-letter option -XXX, or single-letter with argument -Xval
214-
// We first try single-letter.
215-
optnr=getoptnr(argv[i][1]);
216-
217-
if(!optnr.has_value()) // try multi-letter
218-
optnr=getoptnr(argv[i]+1);
219-
}
220-
221-
if(!optnr.has_value())
222-
{
223-
unknown_arg=argv[i];
224-
return true;
225-
}
226-
227-
options[*optnr].isset=true;
228-
229-
if(options[*optnr].hasval)
230-
{
231-
if(argv[i][2]==0 || options[*optnr].islong)
232-
{
233-
i++;
234-
if(i==argc)
235-
return true;
236-
if(argv[i][0]=='-' && argv[i][1]!=0)
237-
return true;
238-
options[*optnr].values.push_back(argv[i]);
239-
}
240-
else
241-
options[*optnr].values.push_back(argv[i]+2);
242-
}
243-
}
244-
}
245-
246-
return false;
247-
}
248-
249-
cmdlinet::option_namest cmdlinet::option_names() const
250-
{
251-
return option_namest{*this};
252208
}
253209

254210
std::vector<std::string>
@@ -311,6 +267,57 @@ cmdlinet::get_argument_suggestions(const std::string &unknown_argument)
311267
return final_suggestions;
312268
}
313269

270+
bool cmdlinet::parse_arguments(int argc, const char **argv)
271+
{
272+
for(int i = 1; i < argc; i++)
273+
{
274+
if(argv[i][0] != '-')
275+
args.push_back(argv[i]);
276+
else
277+
{
278+
optionalt<std::size_t> optnr;
279+
280+
if(argv[i][1] != 0 && argv[i][2] == 0)
281+
optnr = getoptnr(argv[i][1]); // single-letter option -X
282+
else if(argv[i][1] == '-')
283+
optnr = getoptnr(argv[i] + 2); // multi-letter option with --XXX
284+
else
285+
{
286+
// Multi-letter option -XXX, or single-letter with argument -Xval
287+
// We first try single-letter.
288+
optnr = getoptnr(argv[i][1]);
289+
290+
if(!optnr.has_value()) // try multi-letter
291+
optnr = getoptnr(argv[i] + 1);
292+
}
293+
294+
if(!optnr.has_value())
295+
{
296+
unknown_arg = argv[i];
297+
return true;
298+
}
299+
300+
options[*optnr].isset = true;
301+
302+
if(options[*optnr].hasval)
303+
{
304+
if(argv[i][2] == 0 || options[*optnr].islong)
305+
{
306+
i++;
307+
if(i == argc)
308+
return true;
309+
if(argv[i][0] == '-' && argv[i][1] != 0)
310+
return true;
311+
options[*optnr].values.push_back(argv[i]);
312+
}
313+
else
314+
options[*optnr].values.push_back(argv[i] + 2);
315+
}
316+
}
317+
}
318+
return false;
319+
}
320+
314321
cmdlinet::option_namest::option_names_iteratort::option_names_iteratort(
315322
const cmdlinet *command_line,
316323
std::size_t index)

‎src/util/cmdline.h

+64
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,58 @@ Author: Daniel Kroening, kroening@kroening.com
2020
class cmdlinet
2121
{
2222
public:
23+
/// Parses a commandline according to a specification given in \p optstring.
24+
/// \param argc How many arguments there are.
25+
/// \param argv An array of C strings.
26+
/// The 0th element is assumed to be the name of the command as
27+
/// it was invoked (e.g. /usr/bin/cmake) and is ignored. It is
28+
/// further assumed the array holds \p argc+1 elements with the C
29+
/// string at index argc being a terminating null pointer.
30+
/// This argument is parsed based on \p optstring.
31+
/// \param optstring A specification of allowed command line options.
32+
/// This is a C string container any number of single
33+
/// characters other than '(', ')' or ':' signifying a
34+
/// "short" option consisting of just that character, or
35+
/// names consisting of any characters other than ')'
36+
/// surrounded by a matching pair of '(' and ')' signifying a
37+
/// "long" option with the name being the string between '('
38+
/// and ')', both of which can be optionally followed by a
39+
/// single ':' indicating that the option takes a argument,
40+
/// if not present it does not. arguments must be in the
41+
/// next array element in \p argv , except for short options
42+
/// whose argument may also be concatenated directly on them.
43+
///
44+
/// Option names in \p argv must start with either '-' or "--",
45+
/// no distinction between long and short options is made
46+
/// here, although it is customary to use only one '-' for
47+
/// short options and "--" for long options.
48+
///
49+
/// All options are optional, if some are required it is up
50+
/// to the user to check that they are present.
51+
///
52+
/// Examples:
53+
///
54+
/// argc = 4
55+
/// argv = `{"name", "-V", "--name", "CProver", nullptr}`
56+
/// opstring = `"V(version)(name):"`
57+
///
58+
/// here the argument to "name" would be "CProver", and
59+
/// "V" is a short option passed without arguments.
60+
///
61+
/// argc = 3
62+
/// argv = `{"other-name", "-fFilename", "--trace", nullptr}`
63+
/// optstring = `"f:(trace)(some-other-option):G"`
64+
///
65+
/// here the argument to option "f" would be "Filename",
66+
/// "trace" is a long option with no argument, and
67+
/// "some-other-option" and "G" are both allowed options that
68+
/// don’t appear on the commandline (with and without
69+
/// argument respectively).
70+
///
71+
/// \return true if there was an error while parsing argv, false otherwise. If
72+
/// this failed due to an unknown option name being in argv, the
73+
/// public variable cmdlinet::unknown_arg will be non-empty and
74+
/// contain the name of that option.
2375
virtual bool parse(int argc, const char **argv, const char *optstring);
2476

2577
std::string get_value(char option) const;
@@ -115,6 +167,18 @@ class cmdlinet
115167
{}
116168
};
117169

170+
/// Parses an optstring and writes the result to cmdlinet::options.
171+
/// It is considered a logic error to pass an invalid option string here.
172+
/// \see cmdlinet::parse(int,const char**,const char*)
173+
/// for details on the format of the optstring
174+
void parse_optstring(const char *optstring);
175+
176+
/// Parses a commandline according to a previously parsed optstring and
177+
/// writes the result to cmdlinet::options.
178+
/// \see cmdlinet::parse(int,const char**,const char*)
179+
/// for details the meaning of argc and argv
180+
bool parse_arguments(int argc, const char **argv);
181+
118182
std::vector<optiont> options;
119183

120184
optionalt<std::size_t> getoptnr(char option) const;

0 commit comments

Comments
 (0)
Please sign in to comment.