Line | Branch | Exec | Source |
---|---|---|---|
1 | #ifndef COMMAND_ARGS_H | ||
2 | #define COMMAND_ARGS_H | ||
3 | |||
4 | #include <stdbool.h> | ||
5 | #include <stddef.h> | ||
6 | #include <stdint.h> | ||
7 | #include "error.h" | ||
8 | #include "run.h" | ||
9 | #include "util/base64.h" | ||
10 | #include "util/debug.h" | ||
11 | #include "util/macros.h" | ||
12 | |||
13 | typedef enum { | ||
14 | ARGERR_NONE, | ||
15 | ARGERR_INVALID_OPTION, | ||
16 | ARGERR_TOO_MANY_OPTIONS, | ||
17 | ARGERR_OPTION_ARGUMENT_MISSING, | ||
18 | ARGERR_OPTION_ARGUMENT_NOT_SEPARATE, | ||
19 | ARGERR_TOO_FEW_ARGUMENTS, | ||
20 | ARGERR_TOO_MANY_ARGUMENTS, | ||
21 | } ArgParseError; | ||
22 | |||
23 | typedef struct { | ||
24 | char ch; | ||
25 | unsigned int val; | ||
26 | } FlagMapping; | ||
27 | |||
28 | 8411 | static inline CommandArgs cmdargs_new(char **args) | |
29 | { | ||
30 | 8411 | return (CommandArgs){.args = args}; | |
31 | } | ||
32 | |||
33 | // Map ASCII alphanumeric characters to values between 1 and 62, | ||
34 | // for use as bitset indices in CommandArgs::flag_set | ||
35 | 11579 | static inline unsigned int cmdargs_flagset_idx(unsigned char c) | |
36 | { | ||
37 | // We use base64_decode() here simply because it does a similar byte | ||
38 | // mapping to the one we want and allows us to share the lookup table. | ||
39 | // There's no "real" base64 encoding involved. | ||
40 | 11579 | static_assert(BASE64_INVALID > 63); | |
41 |
1/2✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 11579 times.
|
11579 | unsigned int idx = IS_CT_CONSTANT(c) ? base64_decode_branchy(c) : base64_decode(c); |
42 | 11579 | BUG_ON(idx > 61); | |
43 | 11579 | return idx + 1; | |
44 | } | ||
45 | |||
46 | 11510 | static inline uint_least64_t cmdargs_flagset_value(unsigned char flag) | |
47 | { | ||
48 | 11510 | return UINT64_C(1) << cmdargs_flagset_idx(flag); | |
49 | } | ||
50 | |||
51 | 9094 | static inline bool cmdargs_has_flag(const CommandArgs *a, unsigned char flag) | |
52 | { | ||
53 | 9094 | uint_least64_t bitmask = cmdargs_flagset_value(flag); | |
54 | 9094 | static_assert_compatible_types(bitmask, a->flag_set); | |
55 | 9094 | return (a->flag_set & bitmask) != 0; | |
56 | } | ||
57 | |||
58 | 61 | static inline char cmdargs_pick_winning_flag_from_set(const CommandArgs *a, uint_least64_t flagset) | |
59 | { | ||
60 |
2/2✓ Branch 0 (2→3) taken 3 times.
✓ Branch 1 (2→10) taken 58 times.
|
61 | if (!(a->flag_set & flagset)) { |
61 | return 0; | ||
62 | } | ||
63 | |||
64 | 3 | BUG_ON(a->nr_flags > ARRAYLEN(a->flags)); | |
65 |
1/2✓ Branch 0 (9→6) taken 3 times.
✗ Branch 1 (9→10) not taken.
|
3 | for (size_t n = a->nr_flags, i = n - 1; i < n; i--) { |
66 | 3 | char flag = a->flags[i]; | |
67 |
1/2✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→10) taken 3 times.
|
3 | if (flagset & cmdargs_flagset_value(flag)) { |
68 | return flag; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | 54 | static inline char cmdargs_pick_winning_flag(const CommandArgs *a, char f1, char f2) | |
76 | { | ||
77 | 54 | uint_least64_t set = cmdargs_flagset_value(f1) | cmdargs_flagset_value(f2); | |
78 | 54 | char flag = cmdargs_pick_winning_flag_from_set(a, set); | |
79 | 54 | BUG_ON(flag && flag != f1 && flag != f2); | |
80 | 54 | return flag; | |
81 | } | ||
82 | |||
83 | // Convert CommandArgs::flag_set to bit flags of a different format, | ||
84 | // by using a set of mappings | ||
85 | 21 | static inline unsigned int cmdargs_convert_flags ( | |
86 | const CommandArgs *a, | ||
87 | const FlagMapping *map, | ||
88 | size_t map_len | ||
89 | ) { | ||
90 | 21 | unsigned int val = 0; | |
91 | UNROLL_LOOP(16) | ||
92 |
2/2✓ Branch 0 (7→3) taken 82 times.
✓ Branch 1 (7→8) taken 21 times.
|
103 | for (size_t i = 0; i < map_len; i++, map++) { |
93 |
2/2✓ Branch 0 (4→5) taken 13 times.
✓ Branch 1 (4→6) taken 69 times.
|
82 | if (cmdargs_has_flag(a, map->ch)) { |
94 | 13 | val |= map->val; | |
95 | } | ||
96 | } | ||
97 | 21 | return val; | |
98 | } | ||
99 | |||
100 | bool parse_args(const Command *cmd, CommandArgs *a, ErrorBuffer *ebuf) NONNULL_ARGS WARN_UNUSED_RESULT; | ||
101 | ArgParseError do_parse_args(const Command *cmd, CommandArgs *a) NONNULL_ARGS WARN_UNUSED_RESULT; | ||
102 | |||
103 | #endif | ||
104 |