-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy patharg.h
216 lines (193 loc) · 7.99 KB
/
arg.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
/* ========================================================================= */
/**
* @file arg.h
* Permits to declare commandline flags, define defaults and a constraints,
* and provides parsing functions.
*
* @copyright
* Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __LIBBASE_ARG_H__
#define __LIBBASE_ARG_H__
#include "test.h"
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/** Parsing mode, whether to permit extra args or not. */
typedef enum {
/** Expects that the defined args consume all of argc/argv. */
BS_ARG_MODE_NO_EXTRA,
/** Permits extra values (but nothing with a "--" prefix). */
BS_ARG_MODE_EXTRA_VALUES,
/** Permits any leftovers. */
BS_ARG_MODE_EXTRA_ARGS,
} bs_arg_mode_t;
/** Type to consider for the arg. */
typedef enum {
/** Used for sentinel. */
BS_ARG_TYPE_UNDEFINED = 0,
/** A boolean. */
BS_ARG_TYPE_BOOL,
/** An enum, from a set of strings. */
BS_ARG_TYPE_ENUM,
/** A string value. */
BS_ARG_TYPE_STRING,
/** An unsigned 32-bit value. */
BS_ARG_TYPE_UINT32,
} bs_arg_type_t;
/** Holds the specification for a boolean argument. */
typedef struct {
/** Default value, if not specified on the commandline. */
const bool default_value;
/** Points to the boolean that will hold the value. */
bool *value_ptr;
} bs_arg_bool_t;
/** Lookup table for enum. */
typedef struct {
/** The human-readable string of the enum. */
const char *name_ptr;
/** Correspnding numeric value. */
int value;
} bs_arg_enum_table_t;
/** Holds the specification for a string argument. */
typedef struct {
/** Default value, if not specified on the commandline. */
const char *default_value;
/** Points to the string that will hold the value. */
char **value_ptr;
} bs_arg_string_t;
/** Holds the specification for an unsigned 32-bit argument. */
typedef struct {
/** Default value, if not specified on the commandline. */
const uint32_t default_value;
/** Minimum permitted value. Use 0 to permit all possible values. */
const uint32_t min_value;
/** Maximum permitted value. Use UINT32_MAX to permit everything. */
const uint32_t max_value;
/** Points to the uint32_t that will hold the value. */
uint32_t *value_ptr;
} bs_arg_uint32_t;
/** Holds the specification for an enum. */
typedef struct {
/** Default value, if not specified on the commandline. */
const char *default_name_ptr;
/** Lookup table. */
const bs_arg_enum_table_t *lookup_table;
/** Points to the int that will hold the value. */
int *value_ptr;
} bs_arg_enum_t;
/** Holds specification for one argument. */
typedef struct {
/** Type of the argument. */
bs_arg_type_t type;
/** Name of the argument. */
const char *name_ptr;
/** Description, may be NULL. */
const char *description_ptr;
/** Specification for the type. */
union {
void *v_sentinel;
bs_arg_bool_t v_bool;
bs_arg_enum_t v_enum;
bs_arg_string_t v_string;
bs_arg_uint32_t v_uint32;
} v;
} bs_arg_t ;
/** Defines a boolean argument. */
#define BS_ARG_BOOL(_name, _desc, _default, _value_ptr) { \
.type = BS_ARG_TYPE_BOOL, \
.name_ptr = _name, \
.description_ptr = _desc, \
.v = { .v_bool = { \
.default_value = _default, \
.value_ptr = _value_ptr \
} } \
}
/** Defines an enum argument. */
#define BS_ARG_ENUM(_name, _desc, _default, _lookup_table, _value_ptr) {\
.type = BS_ARG_TYPE_ENUM, \
.name_ptr = _name, \
.description_ptr = _desc, \
.v = { .v_enum = { \
.default_name_ptr = _default, \
.lookup_table = _lookup_table, \
.value_ptr = _value_ptr \
} } \
}
/** Defines a string argument. */
#define BS_ARG_STRING(_name, _desc, _default, _value_ptr) { \
.type = BS_ARG_TYPE_STRING, \
.name_ptr = _name, \
.description_ptr = _desc, \
.v = { .v_string = { \
.default_value = _default, \
.value_ptr = _value_ptr \
} } \
}
/** Defines an unsigned 32-bit integer argument. */
#define BS_ARG_UINT32(_name, _desc, _default, _min, _max, _value_ptr) { \
.type = BS_ARG_TYPE_UINT32, \
.name_ptr = _name, \
.description_ptr = _desc, \
.v = { .v_uint32 = { \
.default_value = _default, \
.min_value = _min, \
.max_value = _max, \
.value_ptr = _value_ptr \
} } \
}
/** Defines a sentinel for the argument list. */
#define BS_ARG_SENTINEL() { \
.type = BS_ARG_TYPE_UNDEFINED, \
.name_ptr = NULL, \
.description_ptr = NULL, \
.v = { .v_sentinel = NULL } \
}
/**
* Parses the commandline.
*
* @param arg_ptr Specifies the array of arguments, ending in a sentinel.
* @param mode How to treat extra arguments.
* @param argc_ptr Pointer to the number of arguments.
* @param argv_ptr Pointer to the list of argument values. It is assumed that
* argv_ptr[0] holds the program's name. It will be skipped for parsing.
*
* @return true if the parsing succeeded.
*/
bool bs_arg_parse(const bs_arg_t *arg_ptr, const bs_arg_mode_t mode,
int *argc_ptr, const char **argv_ptr);
/**
* Cleanup any allocated resources during parsing by |bs_arg_parse|.
*
* @param arg_ptr Specifies the array of arguments, ending in a sentinel.
*/
void bs_arg_cleanup(const bs_arg_t *arg_ptr);
/**
* Prints the arguments.
*
* @param stream_ptr
* @param arg_ptr
*/
int bs_arg_print_usage(FILE *stream_ptr, const bs_arg_t *arg_ptr);
/** Unit tests. */
extern const bs_test_case_t bs_arg_test_cases[];
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif /* __LIBBASE_ARG_H__ */
/* == End of arg.h ========================================================= */