Add argument parsing
Added (IMHO) relatively simple argument parsing function (as well as helper function for printing help information).
This commit is contained in:
@@ -67,6 +67,7 @@ endif(TESTING)
|
|||||||
# Set library code
|
# Set library code
|
||||||
set(BH_SOURCE
|
set(BH_SOURCE
|
||||||
src/Algo.c
|
src/Algo.c
|
||||||
|
src/Args.c
|
||||||
src/Hashmap.c
|
src/Hashmap.c
|
||||||
src/IO.c
|
src/IO.c
|
||||||
src/Math.c
|
src/Math.c
|
||||||
@@ -76,6 +77,7 @@ set(BH_SOURCE
|
|||||||
set(BH_HEADER
|
set(BH_HEADER
|
||||||
include/BH/Common.h
|
include/BH/Common.h
|
||||||
include/BH/Algo.h
|
include/BH/Algo.h
|
||||||
|
include/BH/Args.h
|
||||||
include/BH/Hashmap.h
|
include/BH/Hashmap.h
|
||||||
include/BH/IO.h
|
include/BH/IO.h
|
||||||
include/BH/Math.h
|
include/BH/Math.h
|
||||||
|
|||||||
70
include/BH/Args.h
Normal file
70
include/BH/Args.h
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#ifndef BH_ARGS_H
|
||||||
|
#define BH_ARGS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BH_ARGS_ARGUMENT 0
|
||||||
|
#define BH_ARGS_UNKNOWN -1
|
||||||
|
|
||||||
|
#define BH_ARGS_VALUE 1
|
||||||
|
#define BH_ARGS_OPTIONAL 2
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct BH_ArgsOption
|
||||||
|
{
|
||||||
|
int key;
|
||||||
|
const char *name;
|
||||||
|
int flags;
|
||||||
|
const char *description;
|
||||||
|
} BH_ArgsOption;
|
||||||
|
|
||||||
|
|
||||||
|
typedef int (*BH_ArgsCallback)(int key, char *arg, void *data);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses command line \a options (given by \a argc and \a argv) and calls the
|
||||||
|
* specified \a callback with \a data.
|
||||||
|
*
|
||||||
|
* There are few internal rules:
|
||||||
|
* - If the "--" argument is specified, option parsing stops, and the rest of
|
||||||
|
* the arguments are processed as is.
|
||||||
|
* - If the "-" argument is specified, it is processed as is.
|
||||||
|
* - For long options, if a value is required, the string after the equal sign
|
||||||
|
* or the next argument will be used as the value ("--define=Value" or
|
||||||
|
* "--define Value").
|
||||||
|
* - For short options, if a value is required, the string after the option
|
||||||
|
* letter or the next argument will be used as the value ("-DValue" or
|
||||||
|
* "-D Value").
|
||||||
|
*
|
||||||
|
* Options array should have last element filled with zeros.
|
||||||
|
*
|
||||||
|
* \param argc Arguments count
|
||||||
|
* \param argv Arguments array
|
||||||
|
* \param options Options array pointer
|
||||||
|
* \param callback Callback function
|
||||||
|
* \param data Callback data
|
||||||
|
*
|
||||||
|
* \return On success, returns zero value.
|
||||||
|
* \return On failure, returns error code.
|
||||||
|
*/
|
||||||
|
int BH_ArgsParse(int argc,
|
||||||
|
char **argv,
|
||||||
|
BH_ArgsOption *options,
|
||||||
|
BH_ArgsCallback callback,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints documentation for \a options (with specified \a padding).
|
||||||
|
*
|
||||||
|
* \param options Options array pointer
|
||||||
|
* \param padding Padding
|
||||||
|
*/
|
||||||
|
void BH_ArgsHelp(BH_ArgsOption *options,
|
||||||
|
int padding);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* BH_ARGS_H */
|
||||||
219
src/Args.c
Normal file
219
src/Args.c
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
#include <BH/Args.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int BH_ArgsExtractArg(int argc,
|
||||||
|
char **argv,
|
||||||
|
BH_ArgsOption *option,
|
||||||
|
BH_ArgsCallback callback,
|
||||||
|
void *data,
|
||||||
|
int *i,
|
||||||
|
int isLong,
|
||||||
|
char *next)
|
||||||
|
{
|
||||||
|
if (isLong && *next == '=')
|
||||||
|
return callback(option->key, next + 1, data);
|
||||||
|
|
||||||
|
if (!isLong && *next)
|
||||||
|
return callback(option->key, next, data);
|
||||||
|
|
||||||
|
if ((*i) + 1 < argc && !(argv[(*i) + 1][0] == '-' && argv[(*i) + 1][1]))
|
||||||
|
return callback(option->key, argv[++(*i)], data);
|
||||||
|
|
||||||
|
if (option->flags & BH_ARGS_OPTIONAL)
|
||||||
|
return callback(option->key, NULL, data);
|
||||||
|
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int BH_ArgsParseShort(int argc,
|
||||||
|
char **argv,
|
||||||
|
BH_ArgsOption *options,
|
||||||
|
BH_ArgsCallback callback,
|
||||||
|
void *data,
|
||||||
|
int *i)
|
||||||
|
{
|
||||||
|
char *symbol;
|
||||||
|
BH_ArgsOption *option;
|
||||||
|
|
||||||
|
for (symbol = argv[*i] + 1; *symbol; symbol++)
|
||||||
|
{
|
||||||
|
/* Find and process option */
|
||||||
|
for (option = options; option->key || option->name; option++)
|
||||||
|
{
|
||||||
|
if (option->key > 128 || *symbol != option->key)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (option->flags & BH_ARGS_VALUE)
|
||||||
|
return BH_ArgsExtractArg(argc, argv, option, callback, data, i, 0, symbol + 1);
|
||||||
|
|
||||||
|
if (callback(option->key, NULL, data))
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unknown option */
|
||||||
|
if (!option->key && !option->name)
|
||||||
|
{
|
||||||
|
callback(BH_ARGS_UNKNOWN, argv[*i], data);
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int BH_ArgsParseLong(int argc,
|
||||||
|
char **argv,
|
||||||
|
BH_ArgsOption *options,
|
||||||
|
BH_ArgsCallback callback,
|
||||||
|
void *data,
|
||||||
|
int *i)
|
||||||
|
{
|
||||||
|
char *start, *end;
|
||||||
|
BH_ArgsOption *option;
|
||||||
|
|
||||||
|
/* Extract option name from argv */
|
||||||
|
start = argv[*i] + 2;
|
||||||
|
end = argv[*i] + 2;
|
||||||
|
while (isgraph(*end) && *end != '=')
|
||||||
|
end++;
|
||||||
|
|
||||||
|
if (end == start)
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
/* Find and process option */
|
||||||
|
for (option = options; option->key || option->name; option++)
|
||||||
|
{
|
||||||
|
if (!option->name || strlen(option->name) != (size_t)(end - start))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (memcmp(option->name, start, end - start))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (option->flags & BH_ARGS_VALUE)
|
||||||
|
return BH_ArgsExtractArg(argc, argv, option, callback, data, i, 1, end);
|
||||||
|
|
||||||
|
return callback(option->key, NULL, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unknown long option */
|
||||||
|
callback(BH_ARGS_UNKNOWN, argv[*i], data);
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int BH_ArgsParse(int argc,
|
||||||
|
char **argv,
|
||||||
|
BH_ArgsOption *options,
|
||||||
|
BH_ArgsCallback callback,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
int i, j, ignoreRest, size;
|
||||||
|
char *arg;
|
||||||
|
|
||||||
|
ignoreRest = 0; i = 1; size = argc;
|
||||||
|
while (i < argc)
|
||||||
|
{
|
||||||
|
arg = argv[i];
|
||||||
|
|
||||||
|
if (arg[0] == '-' && arg[1] && !ignoreRest)
|
||||||
|
{
|
||||||
|
/* Parse ingore, short or long option */
|
||||||
|
if (arg[1] == '-')
|
||||||
|
{
|
||||||
|
if (arg[2] && BH_ArgsParseLong(argc, argv, options, callback, data, &i))
|
||||||
|
return BH_ERROR;
|
||||||
|
else if (!arg[2])
|
||||||
|
ignoreRest = 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (arg[1] && BH_ArgsParseShort(argc, argv, options, callback, data, &i))
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Shift arguments */
|
||||||
|
for (j = i; j < size - 1; j++)
|
||||||
|
argv[j] = argv[j + 1];
|
||||||
|
argv[size - 1] = arg;
|
||||||
|
|
||||||
|
if (callback(BH_ARGS_ARGUMENT, arg, data))
|
||||||
|
return BH_ERROR;
|
||||||
|
|
||||||
|
argc--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void BH_ArgsHelp(BH_ArgsOption *options,
|
||||||
|
int padding)
|
||||||
|
{
|
||||||
|
int width = 0;
|
||||||
|
BH_ArgsOption *option;
|
||||||
|
|
||||||
|
if (padding == 0)
|
||||||
|
padding = 30;
|
||||||
|
|
||||||
|
/* Calculate option column width */
|
||||||
|
for (option = options; option->key || option->name; option++)
|
||||||
|
{
|
||||||
|
const char *symbol;
|
||||||
|
width = 5;
|
||||||
|
|
||||||
|
/* Print option column with padding */
|
||||||
|
if (isgraph(option->key))
|
||||||
|
{
|
||||||
|
fputs(" -", stdout);
|
||||||
|
fputc(option->key, stdout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fputs(" ", stdout);
|
||||||
|
|
||||||
|
if (isgraph(option->key) && option->name)
|
||||||
|
fputs(", ", stdout);
|
||||||
|
else
|
||||||
|
fputs(" ", stdout);
|
||||||
|
|
||||||
|
if (option->name)
|
||||||
|
{
|
||||||
|
width += 3 + strlen(option->name);
|
||||||
|
fputs("--", stdout);
|
||||||
|
fputs(option->name, stdout);
|
||||||
|
fputc(' ', stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option->flags & BH_ARGS_VALUE)
|
||||||
|
{
|
||||||
|
width += 8;
|
||||||
|
if (option->flags & BH_ARGS_OPTIONAL)
|
||||||
|
{
|
||||||
|
width += 2;
|
||||||
|
fputs("[<value>] ", stdout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fputs("<value> ", stdout);
|
||||||
|
}
|
||||||
|
for (; width++ < padding; fputc(' ', stdout));
|
||||||
|
|
||||||
|
/* Print description */
|
||||||
|
for (symbol = option->description; symbol && *symbol; symbol++)
|
||||||
|
{
|
||||||
|
fputc(*symbol, stdout);
|
||||||
|
|
||||||
|
if (*symbol == '\n')
|
||||||
|
for (width = 0; width++ < padding; fputc(' ', stdout));
|
||||||
|
}
|
||||||
|
fputc('\n', stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
403
test/src/TestArgs.c
Normal file
403
test/src/TestArgs.c
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
#include <BH/Args.h>
|
||||||
|
#include <BH/Unit.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct DBG_State
|
||||||
|
{
|
||||||
|
int key[128];
|
||||||
|
char *args[128];
|
||||||
|
size_t size;
|
||||||
|
} DBG_State;
|
||||||
|
|
||||||
|
|
||||||
|
static int DBG_Process(int key,
|
||||||
|
char *arg,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
DBG_State *state = (DBG_State *)data;
|
||||||
|
|
||||||
|
state->key[state->size] = key;
|
||||||
|
state->args[state->size] = arg;
|
||||||
|
state->size++;
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int DBG_AlwaysPass(int key,
|
||||||
|
char *arg,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
BH_UNUSED(key);
|
||||||
|
BH_UNUSED(arg);
|
||||||
|
BH_UNUSED(data);
|
||||||
|
|
||||||
|
return BH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int DBG_AlwaysFail(int key,
|
||||||
|
char *arg,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
BH_UNUSED(key);
|
||||||
|
BH_UNUSED(arg);
|
||||||
|
BH_UNUSED(data);
|
||||||
|
|
||||||
|
return BH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BH_UNIT_TEST(Empty)
|
||||||
|
{
|
||||||
|
int argc = 1;
|
||||||
|
|
||||||
|
char *argv[] = {
|
||||||
|
"./app"
|
||||||
|
};
|
||||||
|
|
||||||
|
BH_ArgsOption options[] = {
|
||||||
|
{0, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
DBG_State state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_AlwaysFail, NULL) == BH_OK);
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_AlwaysPass, NULL) == BH_OK);
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_Process, &state) == BH_OK);
|
||||||
|
BH_VERIFY(state.size == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[0], "./app") == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BH_UNIT_TEST(Args)
|
||||||
|
{
|
||||||
|
int argc = 4;
|
||||||
|
|
||||||
|
char *argv[] = {
|
||||||
|
"./app",
|
||||||
|
"a",
|
||||||
|
"b",
|
||||||
|
"c"
|
||||||
|
};
|
||||||
|
|
||||||
|
BH_ArgsOption options[] = {
|
||||||
|
{0, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
DBG_State state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_Process, &state) == BH_OK);
|
||||||
|
BH_VERIFY(state.size == 3);
|
||||||
|
BH_VERIFY(state.key[0] == 0 && strcmp(state.args[0], "a") == 0);
|
||||||
|
BH_VERIFY(state.key[1] == 0 && strcmp(state.args[1], "b") == 0);
|
||||||
|
BH_VERIFY(state.key[2] == 0 && strcmp(state.args[2], "c") == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(strcmp(argv[0], "./app") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[1], "a") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[2], "b") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[3], "c") == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BH_UNIT_TEST(Dash)
|
||||||
|
{
|
||||||
|
int argc = 5;
|
||||||
|
|
||||||
|
char *argv[] = {
|
||||||
|
"./app",
|
||||||
|
"a",
|
||||||
|
"--",
|
||||||
|
"-a",
|
||||||
|
"--b"
|
||||||
|
};
|
||||||
|
|
||||||
|
BH_ArgsOption options[] = {
|
||||||
|
{0, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
DBG_State state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_Process, &state) == BH_OK);
|
||||||
|
|
||||||
|
BH_VERIFY(state.size == 3);
|
||||||
|
BH_VERIFY(state.key[0] == 0 && strcmp(state.args[0], "a") == 0);
|
||||||
|
BH_VERIFY(state.key[1] == 0 && strcmp(state.args[1], "-a") == 0);
|
||||||
|
BH_VERIFY(state.key[2] == 0 && strcmp(state.args[2], "--b") == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(strcmp(argv[0], "./app") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[1], "--") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[2], "a") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[3], "-a") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[4], "--b") == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BH_UNIT_TEST(ShortOption)
|
||||||
|
{
|
||||||
|
int argc = 12;
|
||||||
|
|
||||||
|
char *argv[] = {
|
||||||
|
"./app",
|
||||||
|
"a",
|
||||||
|
"-2",
|
||||||
|
"b",
|
||||||
|
"c",
|
||||||
|
"-2d",
|
||||||
|
"e",
|
||||||
|
"-2",
|
||||||
|
"-",
|
||||||
|
"f",
|
||||||
|
"-113",
|
||||||
|
"-1121",
|
||||||
|
};
|
||||||
|
|
||||||
|
BH_ArgsOption options[] = {
|
||||||
|
{'1', NULL, 0, NULL},
|
||||||
|
{'2', NULL, BH_ARGS_VALUE, NULL},
|
||||||
|
{'3', NULL, BH_ARGS_VALUE | BH_ARGS_OPTIONAL, NULL},
|
||||||
|
{0, NULL, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
DBG_State state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_Process, &state) == BH_OK);
|
||||||
|
BH_VERIFY(state.size == 13);
|
||||||
|
BH_VERIFY(state.key[0] == 0 && strcmp(state.args[0], "a") == 0);
|
||||||
|
BH_VERIFY(state.key[1] == '2' && strcmp(state.args[1], "b") == 0);
|
||||||
|
BH_VERIFY(state.key[2] == 0 && strcmp(state.args[2], "c") == 0);
|
||||||
|
BH_VERIFY(state.key[3] == '2' && strcmp(state.args[3], "d") == 0);
|
||||||
|
BH_VERIFY(state.key[4] == 0 && strcmp(state.args[4], "e") == 0);
|
||||||
|
BH_VERIFY(state.key[5] == '2' && strcmp(state.args[5], "-") == 0);
|
||||||
|
BH_VERIFY(state.key[6] == 0 && strcmp(state.args[6], "f") == 0);
|
||||||
|
BH_VERIFY(state.key[7] == '1' && state.args[7] == NULL);
|
||||||
|
BH_VERIFY(state.key[8] == '1' && state.args[8] == NULL);
|
||||||
|
BH_VERIFY(state.key[9] == '3' && state.args[9] == NULL);
|
||||||
|
BH_VERIFY(state.key[10] == '1' && state.args[10] == NULL);
|
||||||
|
BH_VERIFY(state.key[11] == '1' && state.args[11] == NULL);
|
||||||
|
BH_VERIFY(state.key[12] == '2' && strcmp(state.args[12], "1") == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(strcmp(argv[0], "./app") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[1], "-2") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[2], "b") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[3], "-2d") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[4], "-2") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[5], "-") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[6], "-113") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[7], "-1121") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[8], "a") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[9], "c") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[10], "e") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[11], "f") == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BH_UNIT_TEST(LongOptions)
|
||||||
|
{
|
||||||
|
int argc = 12;
|
||||||
|
|
||||||
|
char *argv[] = {
|
||||||
|
"./app",
|
||||||
|
"a",
|
||||||
|
"--def",
|
||||||
|
"b",
|
||||||
|
"c",
|
||||||
|
"--def=d",
|
||||||
|
"e",
|
||||||
|
"--def",
|
||||||
|
"-",
|
||||||
|
"f",
|
||||||
|
"--ghj",
|
||||||
|
"--abc",
|
||||||
|
};
|
||||||
|
|
||||||
|
BH_ArgsOption options[] = {
|
||||||
|
{1000, "abc", 0, NULL},
|
||||||
|
{1001, "def", BH_ARGS_VALUE, NULL},
|
||||||
|
{1002, "ghj", BH_ARGS_VALUE | BH_ARGS_OPTIONAL, NULL},
|
||||||
|
{0, NULL, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
DBG_State state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_Process, &state) == BH_OK);
|
||||||
|
BH_VERIFY(state.size == 9);
|
||||||
|
BH_VERIFY(state.key[0] == 0 && strcmp(state.args[0], "a") == 0);
|
||||||
|
BH_VERIFY(state.key[1] == 1001 && strcmp(state.args[1], "b") == 0);
|
||||||
|
BH_VERIFY(state.key[2] == 0 && strcmp(state.args[2], "c") == 0);
|
||||||
|
BH_VERIFY(state.key[3] == 1001 && strcmp(state.args[3], "d") == 0);
|
||||||
|
BH_VERIFY(state.key[4] == 0 && strcmp(state.args[4], "e") == 0);
|
||||||
|
BH_VERIFY(state.key[5] == 1001 && strcmp(state.args[5], "-") == 0);
|
||||||
|
BH_VERIFY(state.key[6] == 0 && strcmp(state.args[6], "f") == 0);
|
||||||
|
BH_VERIFY(state.key[7] == 1002 && state.args[7] == NULL);
|
||||||
|
BH_VERIFY(state.key[8] == 1000 && state.args[8] == NULL);
|
||||||
|
|
||||||
|
BH_VERIFY(strcmp(argv[0], "./app") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[1], "--def") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[2], "b") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[3], "--def=d") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[4], "--def") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[5], "-") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[6], "--ghj") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[7], "--abc") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[8], "a") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[9], "c") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[10], "e") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[11], "f") == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BH_UNIT_TEST(Complex)
|
||||||
|
{
|
||||||
|
int argc = 15;
|
||||||
|
|
||||||
|
char *argv[] = {
|
||||||
|
"./app",
|
||||||
|
"a",
|
||||||
|
"-i",
|
||||||
|
"--input",
|
||||||
|
"b",
|
||||||
|
"-i-",
|
||||||
|
"-i",
|
||||||
|
"--input",
|
||||||
|
"-",
|
||||||
|
"--input",
|
||||||
|
"--",
|
||||||
|
"-a",
|
||||||
|
"-i",
|
||||||
|
"--input",
|
||||||
|
"--invalid",
|
||||||
|
};
|
||||||
|
|
||||||
|
BH_ArgsOption options[] = {
|
||||||
|
{'a', "abc", 0, NULL},
|
||||||
|
{'i', "input", BH_ARGS_VALUE | BH_ARGS_OPTIONAL, NULL},
|
||||||
|
{0, NULL, 0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
DBG_State state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_Process, &state) == BH_OK);
|
||||||
|
|
||||||
|
BH_VERIFY(state.size == 11);
|
||||||
|
BH_VERIFY(state.key[0] == 0 && strcmp(state.args[0], "a") == 0);
|
||||||
|
BH_VERIFY(state.key[1] == 'i' && state.args[1] == NULL);
|
||||||
|
BH_VERIFY(state.key[2] == 'i' && strcmp(state.args[2], "b") == 0);
|
||||||
|
BH_VERIFY(state.key[3] == 'i' && strcmp(state.args[3], "-") == 0);
|
||||||
|
BH_VERIFY(state.key[4] == 'i' && state.args[4] == NULL);
|
||||||
|
BH_VERIFY(state.key[5] == 'i' && strcmp(state.args[5], "-") == 0);
|
||||||
|
BH_VERIFY(state.key[6] == 'i' && state.args[6] == NULL);
|
||||||
|
BH_VERIFY(state.key[7] == 0 && strcmp(state.args[7], "-a") == 0);
|
||||||
|
BH_VERIFY(state.key[8] == 0 && strcmp(state.args[8], "-i") == 0);
|
||||||
|
BH_VERIFY(state.key[9] == 0 && strcmp(state.args[9], "--input") == 0);
|
||||||
|
BH_VERIFY(state.key[10] == 0 && strcmp(state.args[10], "--invalid") == 0);
|
||||||
|
|
||||||
|
BH_VERIFY(strcmp(argv[0], "./app") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[1], "-i") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[2], "--input") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[3], "b") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[4], "-i-") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[5], "-i") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[6], "--input") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[7], "-") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[8], "--input") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[9], "--") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[10], "a") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[11], "-a") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[12], "-i") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[13], "--input") == 0);
|
||||||
|
BH_VERIFY(strcmp(argv[14], "--invalid") == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BH_UNIT_TEST(InvalidShort)
|
||||||
|
{
|
||||||
|
int argc = 4;
|
||||||
|
|
||||||
|
char *argv[] = {
|
||||||
|
"./app",
|
||||||
|
"a",
|
||||||
|
"-b",
|
||||||
|
"-c"
|
||||||
|
};
|
||||||
|
|
||||||
|
BH_ArgsOption options[] = {
|
||||||
|
{0, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
DBG_State state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_Process, &state) != BH_OK);
|
||||||
|
|
||||||
|
BH_VERIFY(state.size == 2);
|
||||||
|
BH_VERIFY(state.key[0] == 0 && strcmp(state.args[0], "a") == 0);
|
||||||
|
BH_VERIFY(state.key[1] == BH_ARGS_UNKNOWN && strcmp(state.args[1], "-b") == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BH_UNIT_TEST(InvalidLong)
|
||||||
|
{
|
||||||
|
int argc = 4;
|
||||||
|
|
||||||
|
char *argv[] = {
|
||||||
|
"./app",
|
||||||
|
"a",
|
||||||
|
"--b",
|
||||||
|
"--c"
|
||||||
|
};
|
||||||
|
|
||||||
|
BH_ArgsOption options[] = {
|
||||||
|
{0, NULL, 0, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
DBG_State state;
|
||||||
|
memset(&state, 0, sizeof(state));
|
||||||
|
|
||||||
|
BH_VERIFY(BH_ArgsParse(argc, argv, options, DBG_Process, &state) != BH_OK);
|
||||||
|
|
||||||
|
BH_VERIFY(state.size == 2);
|
||||||
|
BH_VERIFY(state.key[0] == 0 && strcmp(state.args[0], "a") == 0);
|
||||||
|
BH_VERIFY(state.key[1] == BH_ARGS_UNKNOWN && strcmp(state.args[1], "--b") == 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
BH_UNIT_ADD(Empty);
|
||||||
|
BH_UNIT_ADD(Args);
|
||||||
|
BH_UNIT_ADD(Dash);
|
||||||
|
BH_UNIT_ADD(ShortOption);
|
||||||
|
BH_UNIT_ADD(LongOptions);
|
||||||
|
BH_UNIT_ADD(Complex);
|
||||||
|
BH_UNIT_ADD(InvalidShort);
|
||||||
|
BH_UNIT_ADD(InvalidLong);
|
||||||
|
|
||||||
|
return BH_UnitRun();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user