/* SPDX-License-Identifier: LGPL-2.1 */ /** * cli-opts.h - Extra cli_opt implementations for cli.h * * Copyright (c) 2025 - Yaroslav de la Peña Smirnov */ #ifndef CLI_OPTS_H #define CLI_OPTS_H #include "cli.h" #include /** * struct cli_opt_data_size - an option that represents data size in bytes. * @opt: parent class. * @bytes: the amount given by the user in bytes. * * This CLI option can parse units in bytes, KiB, MiB, GiB, TiB. By giving the * number a suffix, it multiplies the number by the equivalent in bytes. E.g. * `1K` == `1024`. */ struct cli_opt_data_size { struct cli_opt opt; uint64_t bytes; }; #define CLI_OPT_DATA_SIZE(name, sh, ln, dsc) \ struct cli_opt_data_size name = { \ .opt = \ { \ .type = CLI_OT_VALUE, \ .shor = sh, \ .lon = ln, \ .desc = dsc, \ .set = cli_opt_data_size_set, \ }, \ } int cli_opt_data_size_set(struct cli_opt *self, const char *val) { struct cli_opt_data_size *opt = container_of(self, struct cli_opt_data_size, opt); char *endptr = NULL; errno = 0; unsigned long long num = strtoull(val, &endptr, 10); if (errno != 0) goto invalid; if (endptr && *endptr != '\0') { switch (toupper(*endptr)) { case 'K': opt->bytes = num <<= 10; break; case 'M': opt->bytes = num <<= 20; break; case 'G': opt->bytes = num <<= 30; break; case 'T': opt->bytes = num <<= 40; break; default: goto invalid; } } else { opt->bytes = num; } return CLI_RC_OK; invalid: fprintf(stderr, "invalid value \"%s\", expected a number optionally followed " "by a multiplicative suffix (K, M, G, T).", val); return CLI_RC_ERR; } #endif /* CLI_OPTS_H */