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