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