refactor: replace src/cli with libcli
This commit is contained in:
parent
526b452827
commit
ab1009a2cb
12 changed files with 19 additions and 210 deletions
|
|
@ -1,40 +0,0 @@
|
||||||
#ifndef CLI_H
|
|
||||||
#define CLI_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
enum cli_code {
|
|
||||||
CLI_EXIT_SUCCESS = -1,
|
|
||||||
CLI_SUCCESS = 0,
|
|
||||||
CLI_ERROR = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef int (*t_option_handler)(const char *arg, void *config);
|
|
||||||
|
|
||||||
enum option_arg_type
|
|
||||||
{
|
|
||||||
OPT_ARG_NONE = 0,
|
|
||||||
OPT_ARG_INT,
|
|
||||||
OPT_ARG_UINT,
|
|
||||||
OPT_ARG_SECONDS,
|
|
||||||
OPT_ARG_BYTES,
|
|
||||||
OPT_ARG_TTL,
|
|
||||||
OPT_ARG_STRING
|
|
||||||
};
|
|
||||||
|
|
||||||
struct option_descriptor
|
|
||||||
{
|
|
||||||
char short_opt;
|
|
||||||
const char *long_opt;
|
|
||||||
int has_arg;
|
|
||||||
t_option_handler handler;
|
|
||||||
enum option_arg_type arg_type;
|
|
||||||
const char *description;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum cli_code cli_parse(int argc, char **argv, void *config,
|
|
||||||
const struct option_descriptor *opts, size_t nb_opts,
|
|
||||||
char *opt_str, struct option *long_opts);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -2,6 +2,14 @@
|
||||||
#define PING_CLI_OPT_H
|
#define PING_CLI_OPT_H
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
#include "cli.h"
|
||||||
|
|
||||||
|
/* Ping-specific arg types, extending libcli's base enum */
|
||||||
|
enum {
|
||||||
|
OPT_ARG_SECONDS = OPT_ARG_STRING + 1,
|
||||||
|
OPT_ARG_BYTES,
|
||||||
|
OPT_ARG_TTL,
|
||||||
|
};
|
||||||
|
|
||||||
#define PING_OPTIONS_LIST \
|
#define PING_OPTIONS_LIST \
|
||||||
X( \
|
X( \
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,6 @@
|
||||||
|
|
||||||
int cli_parse_uint64(const char *s, uint64_t *out);
|
int cli_parse_uint64(const char *s, uint64_t *out);
|
||||||
int cli_parse_float(const char *s, float *out);
|
int cli_parse_float(const char *s, float *out);
|
||||||
|
int cli_parse_ufloat(const char *s, float *out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#ifndef PING_CLI_H
|
#ifndef PING_CLI_H
|
||||||
#define PING_CLI_H
|
#define PING_CLI_H
|
||||||
|
|
||||||
#include "../cli.h"
|
#include <cli.h>
|
||||||
#include "ping/ping.h"
|
#include "ping/ping.h"
|
||||||
|
|
||||||
enum cli_code cli_parse_arguments(int argc, char **argv,
|
enum cli_code cli_parse_arguments(int argc, char **argv,
|
||||||
|
|
|
||||||
119
src/cli/parse.c
119
src/cli/parse.c
|
|
@ -1,119 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include "internal/cli/messages.h"
|
|
||||||
#include "ping/ft_ping_flags.h"
|
|
||||||
|
|
||||||
/* Map -? to -h to support help shortcut */
|
|
||||||
#define HANDLE_QUESTION_MARK(opt) \
|
|
||||||
do { \
|
|
||||||
if (opt == '?' && (optopt) == '?') \
|
|
||||||
opt = 'h'; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Forward declarations */
|
|
||||||
static void build_long_options(struct option *long_opts, size_t nb_opts,
|
|
||||||
const struct option_descriptor *src);
|
|
||||||
static void build_optstr(char *dest, const struct option_descriptor *opts,
|
|
||||||
size_t nb_opts);
|
|
||||||
static const struct option_descriptor *find_option_handler(int opt,
|
|
||||||
const struct option_descriptor *opts, size_t nb_opts);
|
|
||||||
static int handle_one_option(int opt, char **argv, void *config,
|
|
||||||
uint64_t *opt_tracker,
|
|
||||||
const struct option_descriptor *opts, size_t nb_opts);
|
|
||||||
/* ------------------- */
|
|
||||||
|
|
||||||
enum cli_code
|
|
||||||
cli_parse(int argc, char **argv, void *config,
|
|
||||||
const struct option_descriptor *opts, size_t nb_opts,
|
|
||||||
char *opt_str, struct option *long_opts)
|
|
||||||
{
|
|
||||||
uint64_t tracker = 0;
|
|
||||||
int opt;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
build_optstr(opt_str, opts, nb_opts);
|
|
||||||
build_long_options(long_opts, nb_opts, opts);
|
|
||||||
while (-1 != (opt = getopt_long(argc, argv, opt_str, long_opts, NULL)))
|
|
||||||
{
|
|
||||||
HANDLE_QUESTION_MARK(opt);
|
|
||||||
res = handle_one_option(opt, argv, config, &tracker, opts, nb_opts);
|
|
||||||
if (CLI_SUCCESS != res)
|
|
||||||
return (enum cli_code)res;
|
|
||||||
}
|
|
||||||
return CLI_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
build_optstr(char *dest, const struct option_descriptor *opts, size_t nb_opts)
|
|
||||||
{
|
|
||||||
size_t str_i = 1;
|
|
||||||
|
|
||||||
/* Mute default error messages */
|
|
||||||
dest[0] = ':';
|
|
||||||
|
|
||||||
for (size_t opt_i = 0; opt_i < nb_opts; ++opt_i)
|
|
||||||
{
|
|
||||||
dest[str_i++] = opts[opt_i].short_opt;
|
|
||||||
switch (opts[opt_i].has_arg)
|
|
||||||
{
|
|
||||||
case optional_argument: dest[str_i++] = ':'; /* fall through */
|
|
||||||
case required_argument: dest[str_i++] = ':'; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dest[str_i] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
handle_one_option(int opt, char **argv, void *config,
|
|
||||||
uint64_t *opt_tracker,
|
|
||||||
const struct option_descriptor *opts, size_t nb_opts)
|
|
||||||
{
|
|
||||||
const char *current_opt = argv[optind - 1];
|
|
||||||
const struct option_descriptor *desc;
|
|
||||||
size_t bitmask_index;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
if ('?' == opt)
|
|
||||||
return error_unknown_opt(current_opt);
|
|
||||||
else if (':' == opt)
|
|
||||||
return error_invalid_opt(current_opt);
|
|
||||||
|
|
||||||
desc = find_option_handler(opt, opts, nb_opts);
|
|
||||||
bitmask_index = (size_t)(desc - opts);
|
|
||||||
if (HAS_FLAG(*opt_tracker, (1ULL << bitmask_index)))
|
|
||||||
return error_duplicate_opt(current_opt);
|
|
||||||
|
|
||||||
SET_FLAG(*opt_tracker, (1ULL << bitmask_index));
|
|
||||||
res = desc->handler(optarg, config);
|
|
||||||
if (CLI_ERROR == res)
|
|
||||||
return error_invalid_opt(current_opt);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
build_long_options(struct option *long_opts, size_t nb_opts,
|
|
||||||
const struct option_descriptor *src)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < nb_opts; ++i)
|
|
||||||
{
|
|
||||||
long_opts[i].name = src[i].long_opt;
|
|
||||||
long_opts[i].has_arg = src[i].has_arg;
|
|
||||||
long_opts[i].flag = NULL;
|
|
||||||
long_opts[i].val = src[i].short_opt;
|
|
||||||
}
|
|
||||||
long_opts[nb_opts] = (struct option){0};
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct option_descriptor *
|
|
||||||
find_option_handler(int opt, const struct option_descriptor *opts,
|
|
||||||
size_t nb_opts)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < nb_opts; ++i)
|
|
||||||
{
|
|
||||||
if (opts[i].short_opt == opt)
|
|
||||||
return &opts[i];
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
#include <errno.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
cli_parse_float(const char *s, float *out)
|
|
||||||
{
|
|
||||||
char *end;
|
|
||||||
|
|
||||||
if (NULL == s || '\0' == *s || '-' == *s)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
float v = strtof(s, &end);
|
|
||||||
|
|
||||||
if (s == end || ERANGE == errno || '\0' != *end || 0 == isfinite(v))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
*out = v;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
#include <errno.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
int
|
|
||||||
cli_parse_uint64(const char *s, uint64_t *out)
|
|
||||||
{
|
|
||||||
char *end;
|
|
||||||
|
|
||||||
if ( NULL == s || '\0' == *s || '-' == *s)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
const uintmax_t v = (uintmax_t)strtoumax(s, &end, 10);
|
|
||||||
|
|
||||||
if (s == end || ERANGE == errno || '\0' != *end || v > UINT64_MAX)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
*out = (uint64_t)v;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
@ -7,7 +7,7 @@ cli_handle_deadline(const char *arg, void *config_void)
|
||||||
struct ping_config *config = (struct ping_config *)config_void;
|
struct ping_config *config = (struct ping_config *)config_void;
|
||||||
float deadline;
|
float deadline;
|
||||||
|
|
||||||
if (0 != cli_parse_float(arg, &deadline))
|
if (0 != cli_parse_ufloat(arg, &deadline))
|
||||||
return CLI_ERROR;
|
return CLI_ERROR;
|
||||||
config->deadline = deadline;
|
config->deadline = deadline;
|
||||||
return CLI_SUCCESS;
|
return CLI_SUCCESS;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cli_handle_interval(const char *arg, void *config_void)
|
||||||
struct ping_config *config = (struct ping_config *)config_void;
|
struct ping_config *config = (struct ping_config *)config_void;
|
||||||
float interval;
|
float interval;
|
||||||
|
|
||||||
if (0 != cli_parse_float(arg, &interval))
|
if (0 != cli_parse_ufloat(arg, &interval))
|
||||||
return CLI_ERROR;
|
return CLI_ERROR;
|
||||||
|
|
||||||
config->interval = interval;
|
config->interval = interval;
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ cli_handle_timeout(const char *arg, void *config_void)
|
||||||
struct ping_config *config = (struct ping_config *)config_void;
|
struct ping_config *config = (struct ping_config *)config_void;
|
||||||
float TO;
|
float TO;
|
||||||
|
|
||||||
if (0 != cli_parse_float(arg, &TO))
|
if (0 != cli_parse_ufloat(arg, &TO))
|
||||||
return CLI_ERROR;
|
return CLI_ERROR;
|
||||||
|
|
||||||
config->timeout = TO;
|
config->timeout = TO;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include "internal/cli/options.h"
|
#include "internal/cli/options.h"
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static inline const char * option_arg_type_to_str(enum option_arg_type type);
|
static inline const char * option_arg_type_to_str(int type);
|
||||||
/* -------------------- */
|
/* -------------------- */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -29,7 +29,7 @@ print_help(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const char *
|
static inline const char *
|
||||||
option_arg_type_to_str(enum option_arg_type type)
|
option_arg_type_to_str(int type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -39,13 +39,14 @@ Test(parse_float, empty_string)
|
||||||
cr_assert_eq(ret, 1);
|
cr_assert_eq(ret, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test 5: Negative number */
|
/* Test 5: Negative number (cli_parse_float accepts negatives; use cli_parse_ufloat to reject) */
|
||||||
Test(parse_float, negative_number)
|
Test(parse_float, negative_number)
|
||||||
{
|
{
|
||||||
float result;
|
float result;
|
||||||
int ret = cli_parse_float("-42", &result);
|
int ret = cli_parse_float("-42", &result);
|
||||||
|
|
||||||
cr_assert_eq(ret, 1);
|
cr_assert_eq(ret, 0);
|
||||||
|
cr_assert_float_eq(result, -42.0f, 0.001f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test 6: Invalid characters */
|
/* Test 6: Invalid characters */
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue