mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-30 12:43:52 +00:00
Ini support for flags
This commit is contained in:
parent
37f17fc19a
commit
ee3f5a73c9
@ -1,5 +1,8 @@
|
|||||||
## Version 0.7 (in progress)
|
## Version 0.7 (in progress)
|
||||||
* Allow comments in ini files (lines starting with `;`)
|
* Allow comments in ini files (lines starting with `;`)
|
||||||
|
* Ini files support flags (only read)
|
||||||
|
* Ini files support subcommands (only read)
|
||||||
|
* Ini files support vectors (only read)
|
||||||
|
|
||||||
## Version 0.6
|
## Version 0.6
|
||||||
|
|
||||||
|
35
README.md
35
README.md
@ -38,7 +38,6 @@ So, this library was designed to provide a great syntax, good compiler compatibi
|
|||||||
This library was built to supply the Application object for the GooFit CUDA/OMP fitting library. Before version 2.0 of GooFit is released, this library will reach version 1.0 status. The current tasks still planned are:
|
This library was built to supply the Application object for the GooFit CUDA/OMP fitting library. Before version 2.0 of GooFit is released, this library will reach version 1.0 status. The current tasks still planned are:
|
||||||
|
|
||||||
* Collect user feedback
|
* Collect user feedback
|
||||||
* Ini configuration support is basic (long options only, no vector support), is more needed? Could it be tied to the subcommand system?
|
|
||||||
* Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object.
|
* Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object.
|
||||||
* Test "adding to cmake" method
|
* Test "adding to cmake" method
|
||||||
|
|
||||||
@ -110,18 +109,11 @@ app.add_set(option_name,
|
|||||||
|
|
||||||
app.add_set_ignore_case(... // String only
|
app.add_set_ignore_case(... // String only
|
||||||
|
|
||||||
app.add_config(option_name,
|
|
||||||
default_file_name="",
|
|
||||||
help_string="Read an ini file",
|
|
||||||
required=false)
|
|
||||||
|
|
||||||
App* subcom = app.add_subcommand(name, discription);
|
App* subcom = app.add_subcommand(name, discription);
|
||||||
```
|
```
|
||||||
|
|
||||||
An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`.
|
An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`.
|
||||||
|
|
||||||
Adding a configuration option is special. If it is present, it will be read along with the normal command line arguments. The file will be read if it exists, and does not throw an error unless required is `true`. Configuration files are in `ini` format, and only support long options. Currently, flags and vector options are not supported.
|
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
* `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--option`
|
* `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--option`
|
||||||
@ -185,6 +177,33 @@ There are several options that are supported on the main app and subcommands. Th
|
|||||||
* `.set_callback(void() function)`: Set the callback that runs at the end of parsing. The options have already run at this point.
|
* `.set_callback(void() function)`: Set the callback that runs at the end of parsing. The options have already run at this point.
|
||||||
* `.allow_extras()`: Do not throw an error if extra arguments are left over (Only useful on the main `App`, as that's the one that throws errors).
|
* `.allow_extras()`: Do not throw an error if extra arguments are left over (Only useful on the main `App`, as that's the one that throws errors).
|
||||||
|
|
||||||
|
## Configuration file
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
app.add_config(option_name,
|
||||||
|
default_file_name="",
|
||||||
|
help_string="Read an ini file",
|
||||||
|
required=false)
|
||||||
|
```
|
||||||
|
|
||||||
|
Adding a configuration option is special. If it is present, it will be read along with the normal command line arguments. The file will be read if it exists, and does not throw an error unless `required` is `true`. Configuration files are in `ini` format. An example of a file:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
; Commments are supported, using a ;
|
||||||
|
; The default section is [default], case insensitive
|
||||||
|
|
||||||
|
value = 1
|
||||||
|
str = "A string"
|
||||||
|
vector = 1 2 3
|
||||||
|
|
||||||
|
; Section map to subcommands
|
||||||
|
[subcommand]
|
||||||
|
in_subcommand = Wow
|
||||||
|
sub.subcommand = true
|
||||||
|
```
|
||||||
|
|
||||||
|
Spaces before and after the name and argument are ignored. Multiple arguments are separated by spaces. One set of quotes will be removed, preserving spaces (the same way the command line works). Boolean options can be `true`, `on`, `1`, `yes`; or `false`, `off`, `0`, `no` (case insensitive). Sections (and `.` separated names) are treated as subcommands (note: this does not mean that subcommand was passed, it just sets the "defaults".
|
||||||
|
|
||||||
|
|
||||||
## Subclassing
|
## Subclassing
|
||||||
|
|
||||||
|
@ -824,11 +824,33 @@ protected:
|
|||||||
if(op_ptr == std::end(options_))
|
if(op_ptr == std::end(options_))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Let's not go crasy with pointer syntax
|
// Let's not go crazy with pointer syntax
|
||||||
Option_p& op = *op_ptr;
|
Option_p& op = *op_ptr;
|
||||||
|
|
||||||
if(op->results_.empty())
|
|
||||||
|
if(op->results_.empty()) {
|
||||||
|
// Flag parsing
|
||||||
|
if(op->get_expected() == 0) {
|
||||||
|
if(current.inputs.size() == 1) {
|
||||||
|
std::string val = current.inputs.at(0);
|
||||||
|
val = detail::to_lower(val);
|
||||||
|
if(val == "true" || val == "on" || val == "yes")
|
||||||
|
op->results_ = {""};
|
||||||
|
else if(val == "false" || val == "off" || val == "no")
|
||||||
|
;
|
||||||
|
else
|
||||||
|
try {
|
||||||
|
size_t ui = std::stoul(val);
|
||||||
|
for (size_t i=0; i<ui; i++)
|
||||||
|
op->results_.push_back("");
|
||||||
|
} catch (const std::invalid_argument &) {
|
||||||
|
throw ConversionError(current.fullname + ": Should be true/false or a number");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
throw ConversionError(current.fullname + ": too many inputs for a flag");
|
||||||
|
} else
|
||||||
op->results_ = current.inputs;
|
op->results_ = current.inputs;
|
||||||
|
}
|
||||||
|
|
||||||
args.pop_back();
|
args.pop_back();
|
||||||
return true;
|
return true;
|
||||||
|
@ -262,6 +262,35 @@ TEST_F(TApp, IniVector) {
|
|||||||
EXPECT_EQ(std::vector<int>({1,2,3}), three);
|
EXPECT_EQ(std::vector<int>({1,2,3}), three);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TApp, IniFlags) {
|
||||||
|
|
||||||
|
TempFile tmpini{"TestIniTmp.ini"};
|
||||||
|
|
||||||
|
app.add_config("--config", tmpini);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::ofstream out{tmpini};
|
||||||
|
out << "[default]" << std::endl;
|
||||||
|
out << "two=2" << std::endl;
|
||||||
|
out << "three=true" << std::endl;
|
||||||
|
out << "four=on" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int two;
|
||||||
|
bool three, four;
|
||||||
|
app.add_flag("--two", two);
|
||||||
|
app.add_flag("--three", three);
|
||||||
|
app.add_flag("--four", four);
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_EQ(2, two);
|
||||||
|
EXPECT_EQ(true, three);
|
||||||
|
EXPECT_EQ(true, four);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TApp, IniOutputSimple) {
|
TEST_F(TApp, IniOutputSimple) {
|
||||||
|
|
||||||
int v;
|
int v;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user