Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/kyua/utils/cmdline/options.cpp
103316 views
1
// Copyright 2010 The Kyua Authors.
2
// All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or without
5
// modification, are permitted provided that the following conditions are
6
// met:
7
//
8
// * Redistributions of source code must retain the above copyright
9
// notice, this list of conditions and the following disclaimer.
10
// * Redistributions in binary form must reproduce the above copyright
11
// notice, this list of conditions and the following disclaimer in the
12
// documentation and/or other materials provided with the distribution.
13
// * Neither the name of Google Inc. nor the names of its contributors
14
// may be used to endorse or promote products derived from this software
15
// without specific prior written permission.
16
//
17
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29
#include "utils/cmdline/options.hpp"
30
31
#include <stdexcept>
32
#include <vector>
33
34
#include "utils/cmdline/exceptions.hpp"
35
#include "utils/defs.hpp"
36
#include "utils/format/macros.hpp"
37
#include "utils/fs/exceptions.hpp"
38
#include "utils/fs/path.hpp"
39
#include "utils/sanity.hpp"
40
#include "utils/text/operations.ipp"
41
42
namespace cmdline = utils::cmdline;
43
namespace text = utils::text;
44
45
46
/// Constructs a generic option with both a short and a long name.
47
///
48
/// \param short_name_ The short name for the option.
49
/// \param long_name_ The long name for the option.
50
/// \param description_ A user-friendly description for the option.
51
/// \param arg_name_ If not NULL, specifies that the option must receive an
52
/// argument and specifies the name of such argument for documentation
53
/// purposes.
54
/// \param default_value_ If not NULL, specifies that the option has a default
55
/// value for the mandatory argument.
56
/// \param arg_is_optional_ Specifies if a value must be provided or not.
57
cmdline::base_option::base_option(const char short_name_,
58
const char* long_name_,
59
const char* description_,
60
const char* arg_name_,
61
const char* default_value_,
62
bool arg_is_optional_) :
63
_short_name(short_name_),
64
_long_name(long_name_),
65
_description(description_),
66
_arg_name(arg_name_ == NULL ? "" : arg_name_),
67
_arg_is_optional(arg_is_optional_),
68
_has_default_value(default_value_ != NULL),
69
_default_value(default_value_ == NULL ? "" : default_value_)
70
{
71
INV(short_name_ != '\0');
72
}
73
74
75
/// Constructs a generic option with a long name only.
76
///
77
/// \param long_name_ The long name for the option.
78
/// \param description_ A user-friendly description for the option.
79
/// \param arg_name_ If not NULL, specifies that the option must receive an
80
/// argument and specifies the name of such argument for documentation
81
/// purposes.
82
/// \param default_value_ If not NULL, specifies that the option has a default
83
/// value for the mandatory argument.
84
cmdline::base_option::base_option(const char* long_name_,
85
const char* description_,
86
const char* arg_name_,
87
const char* default_value_) :
88
_short_name('\0'),
89
_long_name(long_name_),
90
_description(description_),
91
_arg_name(arg_name_ == NULL ? "" : arg_name_),
92
_has_default_value(default_value_ != NULL),
93
_default_value(default_value_ == NULL ? "" : default_value_)
94
{
95
}
96
97
98
/// Destructor for the option.
99
cmdline::base_option::~base_option(void)
100
{
101
}
102
103
104
/// Checks whether the option has a short name or not.
105
///
106
/// \return True if the option has a short name, false otherwise.
107
bool
108
cmdline::base_option::has_short_name(void) const
109
{
110
return _short_name != '\0';
111
}
112
113
114
/// Returns the short name of the option.
115
///
116
/// \pre has_short_name() must be true.
117
///
118
/// \return The short name.
119
char
120
cmdline::base_option::short_name(void) const
121
{
122
PRE(has_short_name());
123
return _short_name;
124
}
125
126
127
/// Returns the long name of the option.
128
///
129
/// \return The long name.
130
const std::string&
131
cmdline::base_option::long_name(void) const
132
{
133
return _long_name;
134
}
135
136
137
/// Returns the description of the option.
138
///
139
/// \return The description.
140
const std::string&
141
cmdline::base_option::description(void) const
142
{
143
return _description;
144
}
145
146
147
/// Checks whether the option needs an argument or not.
148
///
149
/// \return True if the option needs an argument, false otherwise.
150
bool
151
cmdline::base_option::needs_arg(void) const
152
{
153
return !_arg_name.empty();
154
}
155
156
157
/// Returns the argument name of the option for documentation purposes.
158
///
159
/// \pre needs_arg() must be true.
160
///
161
/// \return The argument name.
162
const std::string&
163
cmdline::base_option::arg_name(void) const
164
{
165
INV(needs_arg());
166
return _arg_name;
167
}
168
169
170
/// Returns optionality of the argument.
171
///
172
/// \return The optionality.
173
bool
174
cmdline::base_option::arg_is_optional(void) const
175
{
176
return _arg_is_optional;
177
}
178
179
180
/// Checks whether the option has a default value for its argument.
181
///
182
/// \pre needs_arg() must be true.
183
///
184
/// \return True if the option has a default value, false otherwise.
185
bool
186
cmdline::base_option::has_default_value(void) const
187
{
188
PRE(needs_arg());
189
return _has_default_value;
190
}
191
192
193
/// Returns the default value for the argument to the option.
194
///
195
/// \pre has_default_value() must be true.
196
///
197
/// \return The default value.
198
const std::string&
199
cmdline::base_option::default_value(void) const
200
{
201
INV(has_default_value());
202
return _default_value;;
203
}
204
205
206
/// Formats the short name of the option for documentation purposes.
207
///
208
/// \return A string describing the option's short name.
209
std::string
210
cmdline::base_option::format_short_name(void) const
211
{
212
PRE(has_short_name());
213
214
if (needs_arg()) {
215
return F("-%s %s") % short_name() % arg_name();
216
} else {
217
return F("-%s") % short_name();
218
}
219
}
220
221
222
/// Formats the long name of the option for documentation purposes.
223
///
224
/// \return A string describing the option's long name.
225
std::string
226
cmdline::base_option::format_long_name(void) const
227
{
228
if (needs_arg()) {
229
return F("--%s=%s") % long_name() % arg_name();
230
} else {
231
return F("--%s") % long_name();
232
}
233
}
234
235
236
237
/// Ensures that an argument passed to the option is valid.
238
///
239
/// This must be reimplemented by subclasses that describe options with
240
/// arguments.
241
///
242
/// \throw cmdline::option_argument_value_error Subclasses must raise this
243
/// exception to indicate the cases in which str is invalid.
244
void
245
cmdline::base_option::validate(const std::string& /* str */) const
246
{
247
UNREACHABLE_MSG("Option does not support an argument");
248
}
249
250
251
/// Constructs a boolean option with both a short and a long name.
252
///
253
/// \param short_name_ The short name for the option.
254
/// \param long_name_ The long name for the option.
255
/// \param description_ A user-friendly description for the option.
256
cmdline::bool_option::bool_option(const char short_name_,
257
const char* long_name_,
258
const char* description_) :
259
base_option(short_name_, long_name_, description_)
260
{
261
}
262
263
264
/// Constructs a boolean option with a long name only.
265
///
266
/// \param long_name_ The long name for the option.
267
/// \param description_ A user-friendly description for the option.
268
cmdline::bool_option::bool_option(const char* long_name_,
269
const char* description_) :
270
base_option(long_name_, description_)
271
{
272
}
273
274
275
/// Constructs an integer option with both a short and a long name.
276
///
277
/// \param short_name_ The short name for the option.
278
/// \param long_name_ The long name for the option.
279
/// \param description_ A user-friendly description for the option.
280
/// \param arg_name_ The name of the mandatory argument, for documentation
281
/// purposes.
282
/// \param default_value_ If not NULL, the default value for the mandatory
283
/// argument.
284
cmdline::int_option::int_option(const char short_name_,
285
const char* long_name_,
286
const char* description_,
287
const char* arg_name_,
288
const char* default_value_) :
289
base_option(short_name_, long_name_, description_, arg_name_,
290
default_value_)
291
{
292
}
293
294
295
/// Constructs an integer option with a long name only.
296
///
297
/// \param long_name_ The long name for the option.
298
/// \param description_ A user-friendly description for the option.
299
/// \param arg_name_ The name of the mandatory argument, for documentation
300
/// purposes.
301
/// \param default_value_ If not NULL, the default value for the mandatory
302
/// argument.
303
cmdline::int_option::int_option(const char* long_name_,
304
const char* description_,
305
const char* arg_name_,
306
const char* default_value_) :
307
base_option(long_name_, description_, arg_name_, default_value_)
308
{
309
}
310
311
312
/// Ensures that an integer argument passed to the int_option is valid.
313
///
314
/// \param raw_value The argument representing an integer as provided by the
315
/// user.
316
///
317
/// \throw cmdline::option_argument_value_error If the integer provided in
318
/// raw_value is invalid.
319
void
320
cmdline::int_option::validate(const std::string& raw_value) const
321
{
322
try {
323
(void)text::to_type< int >(raw_value);
324
} catch (const std::runtime_error& e) {
325
throw cmdline::option_argument_value_error(
326
F("--%s") % long_name(), raw_value, "Not a valid integer");
327
}
328
}
329
330
331
/// Converts an integer argument to a native integer.
332
///
333
/// \param raw_value The argument representing an integer as provided by the
334
/// user.
335
///
336
/// \return The integer.
337
///
338
/// \pre validate(raw_value) must be true.
339
int
340
cmdline::int_option::convert(const std::string& raw_value)
341
{
342
try {
343
return text::to_type< int >(raw_value);
344
} catch (const std::runtime_error& e) {
345
PRE_MSG(false, F("Raw value '%s' for int option not properly "
346
"validated: %s") % raw_value % e.what());
347
}
348
}
349
350
351
/// Constructs a list option with both a short and a long name.
352
///
353
/// \param short_name_ The short name for the option.
354
/// \param long_name_ The long name for the option.
355
/// \param description_ A user-friendly description for the option.
356
/// \param arg_name_ The name of the mandatory argument, for documentation
357
/// purposes.
358
/// \param default_value_ If not NULL, the default value for the mandatory
359
/// argument.
360
cmdline::list_option::list_option(const char short_name_,
361
const char* long_name_,
362
const char* description_,
363
const char* arg_name_,
364
const char* default_value_) :
365
base_option(short_name_, long_name_, description_, arg_name_,
366
default_value_)
367
{
368
}
369
370
371
/// Constructs a list option with a long name only.
372
///
373
/// \param long_name_ The long name for the option.
374
/// \param description_ A user-friendly description for the option.
375
/// \param arg_name_ The name of the mandatory argument, for documentation
376
/// purposes.
377
/// \param default_value_ If not NULL, the default value for the mandatory
378
/// argument.
379
cmdline::list_option::list_option(const char* long_name_,
380
const char* description_,
381
const char* arg_name_,
382
const char* default_value_) :
383
base_option(long_name_, description_, arg_name_, default_value_)
384
{
385
}
386
387
388
/// Ensures that a lisstring argument passed to the list_option is valid.
389
void
390
cmdline::list_option::validate(
391
const std::string& /* raw_value */) const
392
{
393
// Any list is potentially valid; the caller must check for semantics.
394
}
395
396
397
/// Converts a string argument to a vector.
398
///
399
/// \param raw_value The argument representing a list as provided by the user.
400
///
401
/// \return The list.
402
///
403
/// \pre validate(raw_value) must be true.
404
cmdline::list_option::option_type
405
cmdline::list_option::convert(const std::string& raw_value)
406
{
407
try {
408
return text::split(raw_value, ',');
409
} catch (const std::runtime_error& e) {
410
PRE_MSG(false, F("Raw value '%s' for list option not properly "
411
"validated: %s") % raw_value % e.what());
412
}
413
}
414
415
416
/// Constructs a path option with both a short and a long name.
417
///
418
/// \param short_name_ The short name for the option.
419
/// \param long_name_ The long name for the option.
420
/// \param description_ A user-friendly description for the option.
421
/// \param arg_name_ The name of the mandatory argument, for documentation
422
/// purposes.
423
/// \param default_value_ If not NULL, the default value for the mandatory
424
/// argument.
425
cmdline::path_option::path_option(const char short_name_,
426
const char* long_name_,
427
const char* description_,
428
const char* arg_name_,
429
const char* default_value_) :
430
base_option(short_name_, long_name_, description_, arg_name_,
431
default_value_)
432
{
433
}
434
435
436
/// Constructs a path option with a long name only.
437
///
438
/// \param long_name_ The long name for the option.
439
/// \param description_ A user-friendly description for the option.
440
/// \param arg_name_ The name of the mandatory argument, for documentation
441
/// purposes.
442
/// \param default_value_ If not NULL, the default value for the mandatory
443
/// argument.
444
cmdline::path_option::path_option(const char* long_name_,
445
const char* description_,
446
const char* arg_name_,
447
const char* default_value_) :
448
base_option(long_name_, description_, arg_name_, default_value_)
449
{
450
}
451
452
453
/// Ensures that a path argument passed to the path_option is valid.
454
///
455
/// \param raw_value The argument representing a path as provided by the user.
456
///
457
/// \throw cmdline::option_argument_value_error If the path provided in
458
/// raw_value is invalid.
459
void
460
cmdline::path_option::validate(const std::string& raw_value) const
461
{
462
try {
463
(void)utils::fs::path(raw_value);
464
} catch (const utils::fs::error& e) {
465
throw cmdline::option_argument_value_error(F("--%s") % long_name(),
466
raw_value, e.what());
467
}
468
}
469
470
471
/// Converts a path argument to a utils::fs::path.
472
///
473
/// \param raw_value The argument representing a path as provided by the user.
474
///
475
/// \return The path.
476
///
477
/// \pre validate(raw_value) must be true.
478
utils::fs::path
479
cmdline::path_option::convert(const std::string& raw_value)
480
{
481
try {
482
return utils::fs::path(raw_value);
483
} catch (const std::runtime_error& e) {
484
PRE_MSG(false, F("Raw value '%s' for path option not properly "
485
"validated: %s") % raw_value % e.what());
486
}
487
}
488
489
490
/// Constructs a property option with both a short and a long name.
491
///
492
/// \param short_name_ The short name for the option.
493
/// \param long_name_ The long name for the option.
494
/// \param description_ A user-friendly description for the option.
495
/// \param arg_name_ The name of the mandatory argument, for documentation
496
/// purposes. Must include the '=' delimiter.
497
cmdline::property_option::property_option(const char short_name_,
498
const char* long_name_,
499
const char* description_,
500
const char* arg_name_) :
501
base_option(short_name_, long_name_, description_, arg_name_)
502
{
503
PRE(arg_name().find('=') != std::string::npos);
504
}
505
506
507
/// Constructs a property option with a long name only.
508
///
509
/// \param long_name_ The long name for the option.
510
/// \param description_ A user-friendly description for the option.
511
/// \param arg_name_ The name of the mandatory argument, for documentation
512
/// purposes. Must include the '=' delimiter.
513
cmdline::property_option::property_option(const char* long_name_,
514
const char* description_,
515
const char* arg_name_) :
516
base_option(long_name_, description_, arg_name_)
517
{
518
PRE(arg_name().find('=') != std::string::npos);
519
}
520
521
522
/// Validates the argument to a property option.
523
///
524
/// \param raw_value The argument provided by the user.
525
void
526
cmdline::property_option::validate(const std::string& raw_value) const
527
{
528
const std::string::size_type pos = raw_value.find('=');
529
if (pos == std::string::npos)
530
throw cmdline::option_argument_value_error(
531
F("--%s") % long_name(), raw_value,
532
F("Argument does not have the form '%s'") % arg_name());
533
534
const std::string key = raw_value.substr(0, pos);
535
if (key.empty())
536
throw cmdline::option_argument_value_error(
537
F("--%s") % long_name(), raw_value, "Empty property name");
538
539
const std::string value = raw_value.substr(pos + 1);
540
if (value.empty())
541
throw cmdline::option_argument_value_error(
542
F("--%s") % long_name(), raw_value, "Empty value");
543
}
544
545
546
/// Returns the property option in a key/value pair form.
547
///
548
/// \param raw_value The argument provided by the user.
549
///
550
/// \return raw_value The key/value pair representation of the property.
551
///
552
/// \pre validate(raw_value) must be true.
553
cmdline::property_option::option_type
554
cmdline::property_option::convert(const std::string& raw_value)
555
{
556
const std::string::size_type pos = raw_value.find('=');
557
return std::make_pair(raw_value.substr(0, pos), raw_value.substr(pos + 1));
558
}
559
560
561
/// Constructs a string option with both a short and a long name.
562
///
563
/// \param short_name_ The short name for the option.
564
/// \param long_name_ The long name for the option.
565
/// \param description_ A user-friendly description for the option.
566
/// \param arg_name_ The name of the mandatory argument, for documentation
567
/// purposes.
568
/// \param default_value_ If not NULL, the default value for the mandatory
569
/// argument.
570
cmdline::string_option::string_option(const char short_name_,
571
const char* long_name_,
572
const char* description_,
573
const char* arg_name_,
574
const char* default_value_,
575
bool arg_is_optional_) :
576
base_option(short_name_, long_name_, description_, arg_name_,
577
default_value_, arg_is_optional_)
578
{
579
}
580
581
582
/// Constructs a string option with a long name only.
583
///
584
/// \param long_name_ The long name for the option.
585
/// \param description_ A user-friendly description for the option.
586
/// \param arg_name_ The name of the mandatory argument, for documentation
587
/// purposes.
588
/// \param default_value_ If not NULL, the default value for the mandatory
589
/// argument.
590
cmdline::string_option::string_option(const char* long_name_,
591
const char* description_,
592
const char* arg_name_,
593
const char* default_value_) :
594
base_option(long_name_, description_, arg_name_, default_value_)
595
{
596
}
597
598
599
/// Does nothing; all string values are valid arguments to a string_option.
600
void
601
cmdline::string_option::validate(
602
const std::string& /* raw_value */) const
603
{
604
// Nothing to do.
605
}
606
607
608
/// Returns the string unmodified.
609
///
610
/// \param raw_value The argument provided by the user.
611
///
612
/// \return raw_value
613
///
614
/// \pre validate(raw_value) must be true.
615
std::string
616
cmdline::string_option::convert(const std::string& raw_value)
617
{
618
return raw_value;
619
}
620
621