refactor: replace src/cli with libcli

This commit is contained in:
lohhiiccc 2026-03-29 15:18:44 +02:00
parent 526b452827
commit ab1009a2cb
12 changed files with 19 additions and 210 deletions

View file

@ -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

View file

@ -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( \

View file

@ -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

View file

@ -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,

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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)
{ {

View file

@ -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 */