1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the MIT license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9 
10 #ifndef ISL_ARG_H
11 #define ISL_ARG_H
12 
13 #include <stddef.h>
14 #include <stdlib.h>
15 
16 #if defined(__cplusplus)
17 extern "C" {
18 #endif
19 
20 struct isl_arg_choice {
21 	const char	*name;
22 	unsigned	 value;
23 };
24 
25 struct isl_arg_flags {
26 	const char	*name;
27 	unsigned	 mask;
28 	unsigned	 value;
29 };
30 
31 enum isl_arg_type {
32 	isl_arg_end,
33 	isl_arg_alias,
34 	isl_arg_arg,
35 	isl_arg_bool,
36 	isl_arg_child,
37 	isl_arg_choice,
38 	isl_arg_flags,
39 	isl_arg_footer,
40 	isl_arg_int,
41 	isl_arg_user,
42 	isl_arg_long,
43 	isl_arg_ulong,
44 	isl_arg_str,
45 	isl_arg_str_list,
46 	isl_arg_version
47 };
48 
49 struct isl_args;
50 
51 struct isl_arg {
52 	enum isl_arg_type	 type;
53 	char			 short_name;
54 	const char		*long_name;
55 	const char		*argument_name;
56 #define ISL_ARG_OFFSET_NONE	((size_t) -1)
57 	size_t			 offset;
58 	const char		*help_msg;
59 #define ISL_ARG_SINGLE_DASH	(1 << 0)
60 #define ISL_ARG_BOOL_ARG	(1 << 1)
61 #define ISL_ARG_HIDDEN		(1 << 2)
62 	unsigned		 flags;
63 	union {
64 	struct {
65 		struct isl_arg_choice	*choice;
66 		unsigned	 	 default_value;
67 		unsigned	 	 default_selected;
68 		int (*set)(void *opt, unsigned val);
69 	} choice;
70 	struct {
71 		struct isl_arg_flags	*flags;
72 		unsigned	 	 default_value;
73 	} flags;
74 	struct {
75 		unsigned		 default_value;
76 		int (*set)(void *opt, unsigned val);
77 	} b;
78 	struct {
79 		int			default_value;
80 	} i;
81 	struct {
82 		long		 	default_value;
83 		long		 	default_selected;
84 		int (*set)(void *opt, long val);
85 	} l;
86 	struct {
87 		unsigned long		default_value;
88 	} ul;
89 	struct {
90 		const char		*default_value;
91 	} str;
92 	struct {
93 		size_t			 offset_n;
94 	} str_list;
95 	struct {
96 		struct isl_args		*child;
97 	} child;
98 	struct {
99 		void (*print_version)(void);
100 	} version;
101 	struct {
102 		int (*init)(void*);
103 		void (*clear)(void*);
104 	} user;
105 	} u;
106 };
107 
108 struct isl_args {
109 	size_t			 options_size;
110 	struct isl_arg		*args;
111 };
112 
113 #define ISL_ARGS_START(s,name)						\
114 	struct isl_arg name ## LIST[];					\
115 	struct isl_args name = { sizeof(s), name ## LIST };		\
116 	struct isl_arg name ## LIST[] = {
117 #define ISL_ARGS_END							\
118 	{ isl_arg_end } };
119 
120 #define ISL_ARG_ALIAS(l)	{					\
121 	.type = isl_arg_alias,						\
122 	.long_name = l,							\
123 },
124 #define ISL_ARG_ARG(st,f,a,d)	{					\
125 	.type = isl_arg_arg,						\
126 	.argument_name = a,						\
127 	.offset = offsetof(st, f),					\
128 	.u = { .str = { .default_value = d } }				\
129 },
130 #define ISL_ARG_FOOTER(h)	{					\
131 	.type = isl_arg_footer,						\
132 	.help_msg = h,							\
133 },
134 #define ISL_ARG_CHOICE(st,f,s,l,c,d,h)	{				\
135 	.type = isl_arg_choice,						\
136 	.short_name = s,						\
137 	.long_name = l,							\
138 	.offset = offsetof(st, f),					\
139 	.help_msg = h,							\
140 	.u = { .choice = { .choice = c, .default_value = d,		\
141 			    .default_selected = d, .set = NULL } }	\
142 },
143 #define ISL_ARG_OPT_CHOICE(st,f,s,l,c,d,ds,h)	{			\
144 	.type = isl_arg_choice,						\
145 	.short_name = s,						\
146 	.long_name = l,							\
147 	.offset = offsetof(st, f),					\
148 	.help_msg = h,							\
149 	.u = { .choice = { .choice = c, .default_value = d,		\
150 			    .default_selected = ds, .set = NULL } }	\
151 },
152 #define ISL_ARG_PHANTOM_USER_CHOICE_F(s,l,c,setter,d,h,fl)	{	\
153 	.type = isl_arg_choice,						\
154 	.short_name = s,						\
155 	.long_name = l,							\
156 	.offset = ISL_ARG_OFFSET_NONE,					\
157 	.help_msg = h,							\
158 	.flags = fl,							\
159 	.u = { .choice = { .choice = c, .default_value = d,		\
160 			    .default_selected = d, .set = setter } }	\
161 },
162 #define ISL_ARG_USER_OPT_CHOICE(st,f,s,l,c,setter,d,ds,h)	{	\
163 	.type = isl_arg_choice,						\
164 	.short_name = s,						\
165 	.long_name = l,							\
166 	.offset = offsetof(st, f),					\
167 	.help_msg = h,							\
168 	.u = { .choice = { .choice = c, .default_value = d,		\
169 			    .default_selected = ds, .set = setter } }	\
170 },
171 #define _ISL_ARG_BOOL_F(o,s,l,setter,d,h,fl)	{			\
172 	.type = isl_arg_bool,						\
173 	.short_name = s,						\
174 	.long_name = l,							\
175 	.offset = o,							\
176 	.help_msg = h,							\
177 	.flags = fl,							\
178 	.u = { .b = { .default_value = d, .set = setter } }		\
179 },
180 #define ISL_ARG_BOOL_F(st,f,s,l,d,h,fl)					\
181 	_ISL_ARG_BOOL_F(offsetof(st, f),s,l,NULL,d,h,fl)
182 #define ISL_ARG_BOOL(st,f,s,l,d,h)					\
183 	ISL_ARG_BOOL_F(st,f,s,l,d,h,0)
184 #define ISL_ARG_PHANTOM_BOOL_F(s,l,setter,h,fl)				\
185 	_ISL_ARG_BOOL_F(ISL_ARG_OFFSET_NONE,s,l,setter,0,h,fl)
186 #define ISL_ARG_PHANTOM_BOOL(s,l,setter,h)				\
187 	ISL_ARG_PHANTOM_BOOL_F(s,l,setter,h,0)
188 #define ISL_ARG_INT_F(st,f,s,l,a,d,h,fl)	{			\
189 	.type = isl_arg_int,						\
190 	.short_name = s,						\
191 	.long_name = l,							\
192 	.argument_name = a,						\
193 	.offset = offsetof(st, f),					\
194 	.help_msg = h,							\
195 	.flags = fl,							\
196 	.u = { .i = { .default_value = d } }				\
197 },
198 #define ISL_ARG_INT(st,f,s,l,a,d,h)					\
199 	ISL_ARG_INT_F(st,f,s,l,a,d,h,0)
200 #define ISL_ARG_LONG(st,f,s,lo,d,h)	{				\
201 	.type = isl_arg_long,						\
202 	.short_name = s,						\
203 	.long_name = lo,						\
204 	.offset = offsetof(st, f),					\
205 	.help_msg = h,							\
206 	.u = { .l = { .default_value = d, .default_selected = d,	\
207 		      .set = NULL } }					\
208 },
209 #define ISL_ARG_USER_LONG(st,f,s,lo,setter,d,h)	{			\
210 	.type = isl_arg_long,						\
211 	.short_name = s,						\
212 	.long_name = lo,						\
213 	.offset = offsetof(st, f),					\
214 	.help_msg = h,							\
215 	.u = { .l = { .default_value = d, .default_selected = d,	\
216 		      .set = setter } }					\
217 },
218 #define ISL_ARG_OPT_LONG(st,f,s,lo,d,ds,h)	{			\
219 	.type = isl_arg_long,						\
220 	.short_name = s,						\
221 	.long_name = lo,						\
222 	.offset = offsetof(st, f),					\
223 	.help_msg = h,							\
224 	.u = { .l = { .default_value = d, .default_selected = ds,	\
225 		      .set = NULL } }					\
226 },
227 #define ISL_ARG_ULONG(st,f,s,l,d,h)	{				\
228 	.type = isl_arg_ulong,						\
229 	.short_name = s,						\
230 	.long_name = l,							\
231 	.offset = offsetof(st, f),					\
232 	.help_msg = h,							\
233 	.u = { .ul = { .default_value = d } }				\
234 },
235 #define ISL_ARG_STR_F(st,f,s,l,a,d,h,fl)	{			\
236 	.type = isl_arg_str,						\
237 	.short_name = s,						\
238 	.long_name = l,							\
239 	.argument_name = a,						\
240 	.offset = offsetof(st, f),					\
241 	.help_msg = h,							\
242 	.flags = fl,							\
243 	.u = { .str = { .default_value = d } }				\
244 },
245 #define ISL_ARG_STR(st,f,s,l,a,d,h)					\
246 	ISL_ARG_STR_F(st,f,s,l,a,d,h,0)
247 #define ISL_ARG_STR_LIST(st,f_n,f_l,s,l,a,h)	{			\
248 	.type = isl_arg_str_list,					\
249 	.short_name = s,						\
250 	.long_name = l,							\
251 	.argument_name = a,						\
252 	.offset = offsetof(st, f_l),					\
253 	.help_msg = h,							\
254 	.u = { .str_list = { .offset_n = offsetof(st, f_n) } }		\
255 },
256 #define _ISL_ARG_CHILD(o,l,c,h,fl)	{				\
257 	.type = isl_arg_child,						\
258 	.long_name = l,							\
259 	.offset = o,							\
260 	.help_msg = h,							\
261 	.flags = fl,							\
262 	.u = { .child = { .child = c } }				\
263 },
264 #define ISL_ARG_CHILD(st,f,l,c,h)					\
265 	_ISL_ARG_CHILD(offsetof(st, f),l,c,h,0)
266 #define ISL_ARG_GROUP_F(l,c,h,fl)					\
267 	_ISL_ARG_CHILD(ISL_ARG_OFFSET_NONE,l,c,h,fl)
268 #define ISL_ARG_GROUP(l,c,h)						\
269 	ISL_ARG_GROUP_F(l,c,h,0)
270 #define ISL_ARG_FLAGS(st,f,s,l,c,d,h)	{				\
271 	.type = isl_arg_flags,						\
272 	.short_name = s,						\
273 	.long_name = l,							\
274 	.offset = offsetof(st, f),					\
275 	.help_msg = h,							\
276 	.u = { .flags = { .flags = c, .default_value = d } }		\
277 },
278 #define ISL_ARG_USER(st,f,i,c) {					\
279 	.type = isl_arg_user,						\
280 	.offset = offsetof(st, f),					\
281 	.u = { .user = { .init = i, .clear = c} }			\
282 },
283 #define ISL_ARG_VERSION(print) {					\
284 	.type = isl_arg_version,					\
285 	.u = { .version = { .print_version = print } }			\
286 },
287 
288 #define ISL_ARG_ALL		(1 << 0)
289 #define ISL_ARG_SKIP_HELP	(1 << 1)
290 
291 void isl_args_set_defaults(struct isl_args *args, void *opt);
292 void isl_args_free(struct isl_args *args, void *opt);
293 int isl_args_parse(struct isl_args *args, int argc, char **argv, void *opt,
294 	unsigned flags);
295 
296 #define ISL_ARG_DECL(prefix,st,args)					\
297 extern struct isl_args args;						\
298 st *prefix ## _new_with_defaults(void);					\
299 void prefix ## _free(st *opt);						\
300 int prefix ## _parse(st *opt, int argc, char **argv, unsigned flags);
301 
302 #define ISL_ARG_DEF(prefix,st,args)					\
303 st *prefix ## _new_with_defaults()					\
304 {									\
305 	st *opt = (st *)calloc(1, sizeof(st));				\
306 	if (opt)							\
307 		isl_args_set_defaults(&(args), opt);			\
308 	return opt;							\
309 }									\
310 									\
311 void prefix ## _free(st *opt)						\
312 {									\
313 	isl_args_free(&(args), opt);					\
314 }									\
315 									\
316 int prefix ## _parse(st *opt, int argc, char **argv, unsigned flags)	\
317 {									\
318 	return isl_args_parse(&(args), argc, argv, opt, flags);		\
319 }
320 
321 #if defined(__cplusplus)
322 }
323 #endif
324 
325 #endif
326