dte test coverage


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

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 10644 static inline CommandArgs cmdargs_new(char **args)
28 {
29 10644 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 15649 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 15649 static_assert(BASE64_INVALID > 63);
40
1/2
✗ Branch 0 (2→3) not taken.
✓ Branch 1 (2→4) taken 15649 times.
15649 unsigned int idx = IS_CT_CONSTANT(c) ? base64_decode_branchy(c) : base64_decode(c);
41 15649 BUG_ON(idx > 61);
42 15649 return idx + 1;
43 }
44
45 15580 static inline CommandFlagSet cmdargs_flagset_bit(unsigned char flag)
46 {
47 15580 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 0 (5→3) taken 681 times.
✓ Branch 1 (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 12213 static inline bool cmdargs_has_flag(const CommandArgs *a, unsigned char flag)
61 {
62 12213 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 0 (2→3) taken 25 times.
✓ Branch 1 (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 0 (9→6) taken 26 times.
✗ Branch 1 (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 0 (7→8) taken 1 times.
✓ Branch 1 (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 22 static inline unsigned int cmdargs_convert_flags (
100 const CommandArgs *a,
101 const FlagMapping *map,
102 size_t map_len
103 ) {
104 22 unsigned int val = 0;
105 UNROLL_LOOP(16)
106
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++) {
107
2/2
✓ Branch 0 (4→5) taken 13 times.
✓ Branch 1 (4→6) taken 73 times.
86 if (cmdargs_has_flag(a, map->ch)) {
108 13 val |= map->val;
109 }
110 }
111 22 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