dte test coverage


Directory: ./
File: src/command/args.h
Date: 2025-12-03 13:13:24
Coverage Exec Excl Total
Lines: 100.0% 33 0 33
Functions: 100.0% 9 0 9
Branches: 85.7% 12 0 14

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