You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: README.md
+118-37
Original file line number
Diff line number
Diff line change
@@ -136,18 +136,20 @@ There are two kinds of building blocks for command line interfaces: parameters a
136
136
```cpp
137
137
bool a = false, f = false;
138
138
string s; vector<string> vs;
139
-
auto cli = ( // matches required positional repeatable
140
-
command("push"), // exactly yes yes no
141
-
required("-f", "--file").set(f), // exactly yes no no
142
-
option("-a", "--all", "-A").set(a), // exactly no no no
139
+
auto cli = ( // matches required positional repeatable
140
+
command("push"), // exactly yes yes no
141
+
required("-f", "--file").set(f), // exactly yes no no
142
+
option("-a", "--all", "-A").set(a), // exactly no no no
143
143
144
-
value("file", s), // any arg yes yes no
145
-
values("file", vs), // any arg yes yes yes
146
-
opt_value("file", s), // any arg no yes no
147
-
opt_values("file", vs), // any arg no yes yes
144
+
value("file", s), // any arg yes yes no
145
+
values("file", vs), // any arg yes yes yes
146
+
opt_value("file", s), // any arg no yes no
147
+
opt_values("file", vs), // any arg no yes yes
148
148
149
149
//"catch all" parameter - useful for error handling
150
-
any_other(vs) // any arg no no yes
150
+
any_other(vs) // any arg no no yes
151
+
//catches arguments that fulfill a predicate and aren't matched by other parameters
152
+
any(predicate, vs) // predicate no no yes
151
153
);
152
154
```
153
155
The functions above are convenience factories:
@@ -161,10 +163,10 @@ auto r1 = required("-f", "--file").set(f);
161
163
// is equivalent to:
162
164
auto r2 = parameter{"-f", "--file"}.required(true).set(f);
163
165
```
164
-
* a required parameter has to match at least one command line argument
165
-
* a repeatable parameter can match any number of arguments
166
-
* non-positional (=non-blocking) parameters can match arguments in any order
167
-
* a positional (blocking) parameter defines a "stop point", i.e., until it matches all parameters following it are not allowed to match; once it matched, all parameters preceding it (wihtin the current group) will become unreachable
166
+
- a required parameter has to match at least one command line argument
167
+
- a repeatable parameter can match any number of arguments
168
+
- non-positional (=non-blocking) parameters can match arguments in any order
169
+
- a positional (blocking) parameter defines a "stop point", i.e., until it matches all parameters following it are not allowed to match; once it matched, all parameters preceding it (wihtin the current group) will become unreachable
168
170
169
171
##### [Flags + Values](#options-with-values)
170
172
If you want parameters to be matched in sequence, you can tie them together using either ```operator &``` or the grouping function ```in_sequence```:
@@ -189,7 +191,6 @@ auto cli = (
189
191
);
190
192
```
191
193
192
-
193
194
##### [Filtering Value Parameters](#value-filters)
194
195
Value parameters use a filter function to test if they are allowed to match an argument string. The default filter ```match::nonempty``` that is used by ```value```, ```values```, ```opt_value``` and ```opt_values``` will match any non-empty argument string.
195
196
You can either supply other filter functions/function objects as first argument of ```value```, ```values```, etc. or use one of these built-in shorthand factory functions covering the most common cases:
Each parameter can have event handler functions attached to it. These are invoked once for each argument that is mapped to the parameter (or once per missing event):
346
349
```cpp
@@ -368,6 +371,21 @@ auto param = required("-nof").set(file,"") |
368
371
```
369
372
370
373
374
+
#### Special Cases
375
+
If we give ```-f -b``` or ```-b -f -a``` as command line arguments for the following CLI, an error will be reported, since the value after ```-f``` is not optional:
376
+
```cpp
377
+
auto cli = ( option("-a"), option("-f") & value("filename"), option("-b") );
378
+
```
379
+
This behavior is fine for most use cases.
380
+
But what if we want our program to take any string as a filename, because our filenames might also collide with flag names? We can make the value parameter [greedy](#greedy-parameters) with ```operator !```. This way, the next string after ```-f``` will always be matched with highest priority as soon as ```-f``` was given:
381
+
```cpp
382
+
auto cli = ( option("-a"), option("-f") & !value("filename"), option("-b") );
383
+
// ^~~~~~
384
+
```
385
+
Be **very careful** with greedy parameters!
386
+
387
+
388
+
371
389
#### Parsing Result Analysis
372
390
```cpp
373
391
auto cli = ( /* your interface here */ );
@@ -419,10 +437,11 @@ The repository folder "examples" contains code for most of the following example
If a parameter doesn't have flags, i.e. it is a value-parameter, a filter function will be used to test if it matches an argument string. The default filter is ```clipp::match::nonempty``` which will match any non-empty argument string.
1360
1381
If you want more control over what is matched, you can use some other predefined filters or you can write your own ones (see [here](#custom-value-filters)).
@@ -1410,6 +1431,15 @@ auto p = parameter{ match::length{1,5} }
1410
1431
```
1411
1432
There are a couple of predefined filters in ```namespace clipp::match```, but you can of course write your own ones (see [here](#custom-value-filters)).
1412
1433
1434
+
Here is another example that makes sure we don't catch any value starting with "-" as a filename:
By default, the parser tries to identify a command line argument (in that order) as
1494
+
- a single flag
1495
+
- a concatenation of multiple, _joinable_ flags (in any order)
1496
+
- a concatenation of a _joinable_ flag sequence in the order defined in the CLI code
1497
+
- a single value parameter
1498
+
- a concatenation of a _joinable_ flag/value sequence in the order defined in the CLI code
1499
+
- a concatenation of _joinable_ flags & values in no particular order
1500
+
1501
+
If no match was found, the parser tries the same list again without any restrictions imposed by blocking (positional) parameters, conflicting alternatives, etc. If this leads to any match, an error will be reported. This way, _potential_, but illegal matches can be found and, e.g., conflicting alternatives can be reported.
1502
+
1503
+
Consider this CLI:
1504
+
```cpp
1505
+
auto cli = ( option("-a"), option("-f") & value("filename"), option("-b") );
1506
+
```
1507
+
If we give ```-f -b``` or ```-b -f -a``` as command line arguments, an error will be reported, since the value after ```-f``` is not optional.
1508
+
1509
+
This behavior is fine for most use cases.
1510
+
But what if we want our program to take any string as a filename, because our filenames might also collide with flag names? We can make the ```filename``` value parameter greedy, so that the next string after ```-f``` will always be matched with highest priority as soon as ```-f``` was given:
1511
+
```cpp
1512
+
auto cli = ( option("-a"), option("-f") & greedy(value("filename")), option("-b") );
1513
+
```
1514
+
or using ```operator !```:
1515
+
```cpp
1516
+
auto cli = ( option("-a"), option("-f") & !value("filename"), option("-b") );
1517
+
```
1518
+
1519
+
Now, every string coming after an ```-f``` will be used as filename.
1520
+
1521
+
If we don't want just *any* kind of match accepted, but still retain a higher priority for a value parameter, we could use a [value filter](#value-filters):
This way, the command line arguments ```A -f B``` will set the filename to "B" and produce no conflict error between the alternative commands ```A``` and ```B``` but ```A -f -b``` will still give an error.
1534
+
1535
+
Note, that there is an inherent decision problem: either we want the ```filename``` value to match no matter what, or we won't get proper error handling if someone forgets to specify a filename and gives ```A -f -b``` Also, there might be interfaces where we really want to catch something like ```A -f B``` as a command conflict.
1536
+
1537
+
1538
+
1539
+
1461
1540
### Generalized Joinable Parameters
1462
1541
1463
1542
Not only flags, but arbitrary combinations of flags and values can be made joinable. This feature is especially powerful if combined with repeatable groups.
0 commit comments