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:
UCLI::Parser parser{}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:
parser.setUnknownArgumentCallback([](const char* name, void* data) -> void {
std::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:
parser.setDelimiter('/');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 /:
parser.setDelimiter('/');
parser.setArgumentStyleWindows(true);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:
parser.setBooleanFlipping(true);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:
UCLI_Parser_Pair pairs[2] =
{
{
.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:
UCLI::Parser::cleanupPairs(pairs, 2);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:
UCLI_Parser_ArrayFlag arrayFlags[4] =
{
{
.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:
parser.setDefaultArray(nullptr, [](UCLI_Parser_ArrayFlag*, char** args, size_t size) -> void
{
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,
UCLI_Parser_ArrayFlag* arrayFlags = nullptr, size_t arrayFlagsSize = 0,
UCLI_Parser_BooleanFlag* booleanFlags = nullptr, size_t booleanFlagsSize = 0,
UCLI_Parser_BooleanFlagWithFunc* booleanFlagsWithFunc = nullptr, size_t booleanFlagsWithFuncSize = 0,
UCLI_Parser_Pair* pairs = nullptr, size_t pairsSize = 0,
UCLI_Parser_PairWithFunc* pairsWithFunc = nullptr, size_t pairsWithFuncSize = 0) noexcept;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:
parser.parse(argc, argv,
arrayFlags, 4,
nullptr, 0,
flags, 6,
pairs, 2,
nullptr, 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;
UCLI_Parser_init(&data);