dte test coverage


Directory: ./
File: src/command/args.h
Date: 2025-05-08 15:05:54
Exec Total Coverage
Lines: 33 33 100.0%
Functions: 8 8 100.0%
Branches: 11 14 78.6%

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 8999 static inline CommandArgs cmdargs_new(char **args)
29 {
30 8999 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 12647 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 12647 static_assert(BASE64_INVALID > 63);
41
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 12647 times.
12647 unsigned int idx = IS_CT_CONSTANT(c) ? base64_decode_branchy(c) : base64_decode(c);
42 12647 BUG_ON(idx > 61);
43 12647 return idx + 1;
44 }
45
46 12578 static inline CommandFlagSet cmdargs_flagset_bit(unsigned char flag)
47 {
48 12578 return UINT64_C(1) << cmdargs_flagset_idx(flag);
49 }
50
51 254 static inline CommandFlagSet cmdargs_flagset_from_str(const char *flags)
52 {
53 254 CommandFlagSet set = 0;
54 UNROLL_LOOP(16)
55
2/2
✓ Branch 0 (5→3) taken 706 times.
✓ Branch 1 (5→6) taken 254 times.
960 for (size_t i = 0, n = strlen(flags); i < n; i++) {
56 706 set |= cmdargs_flagset_bit(flags[i]);
57 }
58 254 return set;
59 }
60
61 9750 static inline bool cmdargs_has_flag(const CommandArgs *a, unsigned char flag)
62 {
63 9750 CommandFlagSet bitmask = cmdargs_flagset_bit(flag);
64 9750 static_assert_compatible_types(bitmask, a->flag_set);
65 9750 return (a->flag_set & bitmask) != 0;
66 }
67
68 // Return the rightmost flag in CommandArgs::flags[] that is also a member of
69 // `flagset`, or 0 if no such flags are present. CommandFunc handlers can use
70 // this to accept multiple, mutually exclusive flags and ignore all except the
71 // last. For example, `exec -s -t -s` is equivalent to `exec -s`.
72 77 static inline char cmdargs_pick_winning_flag_from_set(const CommandArgs *a, CommandFlagSet flagset)
73 {
74
2/2
✓ Branch 0 (2→3) taken 3 times.
✓ Branch 1 (2→10) taken 74 times.
77 if (!(a->flag_set & flagset)) {
75 return 0;
76 }
77
78 3 BUG_ON(a->nr_flags > ARRAYLEN(a->flags));
79
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--) {
80 3 char flag = a->flags[i];
81
1/2
✗ Branch 0 (7→8) not taken.
✓ Branch 1 (7→10) taken 3 times.
3 if (flagset & cmdargs_flagset_bit(flag)) {
82 return flag;
83 }
84 }
85
86 return 0;
87 }
88
89 77 static inline char cmdargs_pick_winning_flag(const CommandArgs *a, const char *flagstr)
90 {
91 77 CommandFlagSet set = cmdargs_flagset_from_str(flagstr);
92 77 return cmdargs_pick_winning_flag_from_set(a, set);
93 }
94
95 // Convert CommandArgs::flag_set to bit flags of a different format,
96 // by using a set of mappings
97 22 static inline unsigned int cmdargs_convert_flags (
98 const CommandArgs *a,
99 const FlagMapping *map,
100 size_t map_len
101 ) {
102 22 unsigned int val = 0;
103 UNROLL_LOOP(16)
104
2/2
✓ Branch 0 (7→3) taken 86 times.
✓ Branch 1 (7→8) taken 22 times.
108 for (size_t i = 0; i < map_len; i++, map++) {
105
2/2
✓ Branch 0 (4→5) taken 13 times.
✓ Branch 1 (4→6) taken 73 times.
86 if (cmdargs_has_flag(a, map->ch)) {
106 13 val |= map->val;
107 }
108 }
109 22 return val;
110 }
111
112 bool parse_args(const Command *cmd, CommandArgs *a, ErrorBuffer *ebuf) NONNULL_ARGS WARN_UNUSED_RESULT;
113 ArgParseError do_parse_args(const Command *cmd, CommandArgs *a) NONNULL_ARGS WARN_UNUSED_RESULT;
114
115 #endif
116