1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
/* 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 <ctype.h>
/**
* 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 */
|