C++ API
To use the C++ API, include the CLIParser.hpp
header.
This will include the entire library, except for the C API.
Setting up and configuring the parser
The Parser
class is placed under the UCLI
namespace. First, create an instance and initialise it like this:
::Parser parser{} UCLI
You can also call the init
member function to initialise
it.
Unknown arguments
You can provide a callback, that will be called when an unknown
argument is found. To do this, call the
setUnknownArgumentCallback
function like this:
.setUnknownArgumentCallback([](const char* name, void* data) -> void {
parserstd::cout << "Unknown argument: "<< name << std::endl;
}, nullptr);
The name
parameter is the name of the argument, while
the data
argument is a void*
, that's passed to
the function via the last argument of
setUnknownArgumentCallback
.
Changing the delimiter
In most cases, the delimiter for arguments is -
,
however, you can change it by calling the setDelimiter
function like this:
.setDelimiter('/'); parser
Setting to Windows mode
Some applications use Windows style arguments, which use
/
as the delimiter. Windows mode doesn't support bundling
of short arguments like this -abCDef
, however. To use
Windows mode call the setArgumentStyleWindows
function and
set the delimiter to /
:
.setDelimiter('/');
parser.setArgumentStyleWindows(true); parser
Boolean flipping
By default, all boolean arguments are set to true, when the argument
is encountered, you can change this behaviour to flip the boolean
instead, using the setBooleanFlipping
function, like
this:
.setBooleanFlipping(true); parser
Providing data to the parser
Boolean flag
To add a boolean flag to the parser, create an array of type
UCLI_Parser_BooleanFlag
, then fill the array with your
data. The struct looks like this:
struct UCLI_Parser_BooleanFlag
{
const char* longType;
const char* shortType;
bool* flag;
};
longType
- The long name of the argument i.e.--{longType}
shortType
- The short name of the argument i.e.-{shortType}
.flag
- A boolean pointer that points to the boolean which will be set when this argument is encountered. Depending on the bool flipping setting, it may flip the bool, which might introduce strange behaviour, if the same argument is encountered 2 times in a command
Using this code, we can create a couple of boolean arguments:
bool a = false;
bool b = false;
bool c = false;
[] =
UCLI_Parser_BooleanFlag booleanFlags{
{
.longType = "letter-c",
.shortType = "c",
.flag = &c
},
{
.longType = "letter-b",
.shortType = "b",
.flag = &b
},
{
.longType = "letter-a",
.shortType = "a",
.flag = &a
},
};
Scroll down to the "Parsing" section, to learn how you can pass this to the parser.
Boolean flag with function
You can also enable boolean flags with a function. These flags should
be stored in an array of type
UCLI_Parser_BooleanFlagWithFunc
, like this:
[] =
UCLI_Parser_BooleanFlagWithFunc flags{
{
.longType = "test6",
.shortType = "",
.func = t,
},
{
.longType = "test5",
.shortType = "test5",
.func = t,
},
{
.longType = "test6",
.shortType = "test6",
.func = t,
},
};
where the function t
looks something like this:
std::map<std::string, bool> map;
void t(UCLI_Parser_BooleanFlagWithFunc* arg)
{
auto& tmp = map[arg->shortType];
= !tmp;
tmp }
The UCLI_Parser_BooleanFlagWithFunc
struct looks like
this:
struct UCLI_Parser_BooleanFlagWithFunc
{
const char* longType;
const char* shortType;
void* additionalData;
void(*func)(struct UCLI_Parser_BooleanFlagWithFunc*);
};
The first 2 arguments are the regular short and long names.
additionalData
is a void*
pointing to
additional data you want your function to have access to(this can be
null).
Finally, the func
function pointer is the function
that's going to be called and has the following signature
void(UCLI_Parser_BooleanFlagWithFunc*)
Pair
A pair is an argument like this: --this=SomeDataHere
The parser can also parse pairs like this. To do this, simply create
an array of type UCLI_Parser_Pair
and initialise it like
this:
[2] =
UCLI_Parser_Pair pairs{
{
.longType = "arg3",
},
{
.longType = "arg4",
}
};
The UCLI_Parser_Pair
struct looks like this:
struct UCLI_Parser_Pair
{
const char* longType;
// This is internal and should always be set to false
bool InternalbFound;
// Do not touch this, we will copy the data into here
const char* data;
};
You should, however, only use the longType
variable, as
the other 2 are internal data and should ideally only be read.
When the argument is encountered, we will allocate memory for the
string in the data
field, you can then use the
data
string. Once you're done using the string, you should
deallocate it using the cleanupPairs
function like
this:
::Parser::cleanupPairs(pairs, 2); UCLI
Pairs with function
To use pairs with functions, create an array of type
UCLI_Parser_PairWithFunc
like this:
struct UCLI_Parser_PairWithFunc
{
const char* longType;
void* additionalData;
void(*func)(struct UCLI_Parser_PairWithFunc*, const char*);
};
The additionalData
field is a void*
, which
points to any additional data you want the function to have access
to(can be null)
The func
field is a function pointer with the following
signature: void(UCLI_Parser_PairWithFunc*, const char*)
where the first argument is the struct containing the function pointer,
and the second the value of the pair
Array flags
Finally, the library also provides support for array flags i.e. flags
like these --arr a b c d e f
, where a
to
f
are part of an array. To create flags like this, create
an array of type UCLI_Parser_ArrayFlag
like this:
[4] =
UCLI_Parser_ArrayFlag arrayFlags{
{
.longType = "arr",
.shortType = "",
.func = [](UCLI_Parser_ArrayFlag*, char** args, size_t size) -> void
{
for (size_t i = 0; i < size; i++)
std::cout << args[i] << std::endl;
},
},
{
.longType = "arg1",
.shortType = "",
.func = [](UCLI_Parser_ArrayFlag*, char** args, size_t size) -> void
{
for (size_t i = 0; i < size; i++)
std::cout << args[i] << std::endl;
},
},
{
.longType = "arg2",
.shortType = "",
.func = [](UCLI_Parser_ArrayFlag*, char** args, size_t size) -> void
{
for (size_t i = 0; i < size; i++)
std::cout << args[i] << std::endl;
},
},
{
.longType = "",
.shortType = "Z",
.func = [](UCLI_Parser_ArrayFlag*, char** args, size_t size) -> void
{
for (size_t i = 0; i < size; i++)
std::cout << args[i] << std::endl;
},
}
};
The UCLI_Parser_ArrayFlag
struct looks like this:
struct UCLI_Parser_ArrayFlag
{
const char* longType;
const char* shortType;
void* additionalData;
;
UCLI_Parser_ArrayFlagFunc func};
The first 2 fields are the standard argument names, the 3rd is a
void*
pointing to additional data for the function.
The 4th argument is the function of type
UCLI_Parser_ArrayFlagFunc
, which evaluates to a function
with the following signature
void(UCLI_Parser_ArrayFlag*, char**, size_t)
, where the
first argument is the struct containing the function, the second is the
array of strings and the third, the size of the array
Setting the default array
By default, an application will have a default array, already set up
that will do nothing. This is there in cases like this:
https://madladsquad.com/app a b c d e f
. You can change this by calling the
setDefaultArray
function, like this:
.setDefaultArray(nullptr, [](UCLI_Parser_ArrayFlag*, char** args, size_t size) -> void
parser{
for (size_t i = 0; i < size; i++)
std::cout << "Default array: " << args[i] << std::endl;
});
where the first argument of the function is the void*
,
and the second the function, part of the
UCLI_Parser_ArrayFlag
struct type
Parsing the args
To parse the args call the parse
function, that looks
like this:
void parse(int argc, char** argv,
* arrayFlags = nullptr, size_t arrayFlagsSize = 0,
UCLI_Parser_ArrayFlag* booleanFlags = nullptr, size_t booleanFlagsSize = 0,
UCLI_Parser_BooleanFlag* booleanFlagsWithFunc = nullptr, size_t booleanFlagsWithFuncSize = 0,
UCLI_Parser_BooleanFlagWithFunc* pairs = nullptr, size_t pairsSize = 0,
UCLI_Parser_Pair* pairsWithFunc = nullptr, size_t pairsWithFuncSize = 0) noexcept; UCLI_Parser_PairWithFunc
The first 2 arguments are the int argc
and
char** argv
that are already passed to the main function of
your C/C++ application. After that, we have pairs of array and size
ordered like this:
UCLI_Parser_ArrayFlag, size
UCLI_Parser_BooleanFlag, size
UCLI_Parser_BooleanFlagWithFunc, size
UCLI_Parser_Pair, size
UCLI_Parser_PairWithFunc, size
Now you can pass all the arrays we created before. It can look something like this:
.parse(argc, argv,
parser, 4,
arrayFlagsnullptr, 0,
, 6,
flags, 2,
pairsnullptr, 0);
You can also use the overload of parse
that takes
std::vector
that looks like this:
void parse(int argc, char** argv,
const std::vector<ArrayFlag>& arrayFlags = {},
const std::vector<BooleanFlag>& booleanFlags = {},
const std::vector<BooleanFlagWithFunc>& booleanFlagsWithFunc = {},
const std::vector<Pair>& pairs = {},
const std::vector<PairWithFunc>& pairsWithFunc = {}) noexcept;
C API
The C API is basically the same as the C++ API, except that it doesn't use a class to handle functions. It looks like this:
void UCLI_Parser_init(struct UCLI_Parser_Data* data);
void UCLI_Parser_setDelimiter(struct UCLI_Parser_Data* data, char del);
void UCLI_Parser_setArgumentStyleWindows(struct UCLI_Parser_Data* data, bool bWindows);
void UCLI_Parser_setUnknownArgumentCallback(struct UCLI_Parser_Data* data, UCLI_Parser_UnknownArgumentsCallback func, void* callbackData);
void UCLI_Parser_setDefaultArray(struct UCLI_Parser_Data* data, void* additionalData, UCLI_Parser_ArrayFlagFunc func);
void UCLI_Parser_setBooleanFlipping(struct UCLI_Parser_Data* data, bool bFlip);
void UCLI_Parser_parse(struct UCLI_Parser_Data* data, int argc, char** argv,
struct UCLI_Parser_ArrayFlag* arrayFlags, size_t arrayFlagsSize,
struct UCLI_Parser_BooleanFlag* booleanFlags, size_t booleanFlagsSize,
struct UCLI_Parser_BooleanFlagWithFunc* booleanFlagsWithFunc, size_t booleanFlagsWithFuncSize,
struct UCLI_Parser_Pair* pairs, size_t pairsSize,
struct UCLI_Parser_PairWithFunc* pairsWithFunc, size_t pairsWithFuncSize);
void UCLI_Parser_cleanupPairs(struct UCLI_Parser_Pair* pairs, size_t pairsSize);
as you can see the functions are the same, except that their first
argument is a pointer to a struct of type UCLI_Parser_Data
.
This struct is used to store the data of the parser and members should
not be accessed.
The only actual difference between the C and C++ API is initializing
the parser. To initialise the parser in the C API, simply create a new
variable of type UCLI_Parser_Data
and call
UCLI_Parser_init
on it, like this:
struct UCLI_Parser_Data data;
(&data); UCLI_Parser_init