1 /* Copyright (C) 2006-2010 G.P. Halkes
2    This program is free software: you can redistribute it and/or modify
3    it under the terms of the GNU General Public License version 3, as
4    published by the Free Software Foundation.
5 
6    This program is distributed in the hope that it will be useful,
7    but WITHOUT ANY WARRANTY; without even the implied warranty of
8    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9    GNU General Public License for more details.
10 
11    You should have received a copy of the GNU General Public License
12    along with this program.  If not, see <http://www.gnu.org/licenses/>.
13 */
14 
15 #ifndef OPTIONMACROS_H
16 #define OPTIONMACROS_H
17 
18 #include <string.h>
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <limits.h>
22 
23 /* INSTRUCTIONS:
24 - A fatal routine should be provided.
25 - If gettext is required, define the _ macro. Otherwise, the empty definition
26   here will be used. However, if the macro USE_GETTEXT is defined, the automatic
27   definition in this file will not be used to make sure a wrong order of
28   definitions is detected.
29 - Option parsing may change the argument vector. If this should not happen,
30   define the macro OPTION_STRDUP such that it allocates a copy of the string
31   passed to it.
32 - Printing options should be done by using the "%.*s" format and
33   "(int) optlength, optcurrent" arguments or even better, the OPTFMT format
34   macor and OPTPRARG arg.
35 
36 A simple example argument parser is shown below:
37 
38 PARSE_FUNCTION(parse_options)
39 	OPTIONS
40 		OPTION('f', "long-f", REQUIRED_ARG)
41 		END_OPTION
42 		DOUBLE_DASH
43 			NO_MORE_OPTIONS;
44 		END_OPTION
45 
46 		printf("Unknown option " OPTFMT "\n", OPTPRARG);
47 	NO_OPTION
48 		printf("Non-option argument: " OPTFMT "\n", OPTPRARG);
49 	END_OPTIONS
50 END_FUNCTION
51 
52 */
53 
54 
55 /* Definitions to make the macro's work regardless of configuration. */
56 #if !defined _ && !defined USE_GETTEXT
57 #define _(_x) (_x)
58 #endif
59 
60 #ifndef OPTION_STRDUP
61 #define OPTION_STRDUP(_x) (_x)
62 #define OPTION_FREE(_x) (void) 0
63 #else
64 #define OPTION_FREE(_x) free(_x)
65 #endif
66 
67 /** Format string for printing options. */
68 #define OPTFMT "%.*s"
69 /** Arguments for printf style functions, to be used in combination with @a OPTFMT. */
70 #define OPTPRARG (int) optlength, optcurrent
71 
72 /** Define an option parsing function.
73 	@param name The name of the function to define.
74 */
75 #define PARSE_FUNCTION(name) void name(int argc, char **argv) {\
76 	char *optArg; \
77 	int optargind; \
78 	int optnomore = 0;
79 
80 /** Declare a chile option parsing function.
81 	@param name The name of the function to define.
82 */
83 #define CHILD_PARSE_FUNCTION_DECL(name) int name(int argc, char **argv, char *optcurrent, char *optArg, size_t optlength, ArgType opttype, int _optargind);
84 
85 /** Define a chile option parsing function.
86 	@param name The name of the function to define.
87 */
88 #define CHILD_PARSE_FUNCTION(name) int name(int argc, char **argv, char *optcurrent, char *optArg, size_t optlength, ArgType opttype, int _optargind) { \
89 	int optargind = _optargind, optcontrol = 0;
90 
91 /** Signal the end of a child option parsing function. */
92 #define END_CHILD_FUNCTION return -1; check_next: if (optargind != _optargind) return 4; return optcontrol; }
93 
94 /** Call a child option parsing function.
95 	@param name The name of the function to call.
96 */
97 #define CALL_CHILD(name) do { int retval = name(argc, argv, optcurrent, optArg, optlength, opttype, optargind); \
98 	if (retval == -1) break; \
99 	else if (retval == 4) optargind++; \
100 	else if (retval == 1) optcontrol++; \
101 	goto check_next; } while (0)
102 
103 /** Indicate the start of option processing.
104 
105 	This is separte from @a PARSE_FUNCTION so that local variables can be
106 	defined.
107 */
108 #define OPTIONS \
109 	for (optargind = 1; optargind < argc; optargind++) { \
110 		char optcontrol = 0; \
111 		char *optcurrent, *optptr; \
112 		optcurrent = argv[optargind]; \
113 		if (optcurrent[0] == '-' && !optnomore) { \
114 			size_t optlength; \
115 			ArgType opttype; \
116 \
117 			if (optcurrent[1] == '-') { \
118 				if ((optArg = strchr(optcurrent, '=')) == NULL) { \
119 					optlength = strlen(optcurrent); \
120 				} else { \
121 					optlength = optArg - optcurrent; \
122 					optArg++; \
123 				} \
124 				opttype = LONG; \
125 			} else { \
126 				optlength = 2; \
127 				if (optcurrent[1] != 0 && optcurrent[2] != 0) \
128 					optArg = optcurrent + 2; \
129 				else \
130 					optArg = NULL; \
131 				opttype = SHORT; \
132 			} \
133 			if (optlength > INT_MAX) optlength = INT_MAX; \
134 			next_opt:
135 /* The last line above is to make sure the cast to int in error messages does
136    not overflow. */
137 
138 /** Signal the start of non-switch option processing. */
139 #define NO_OPTION } else {
140 
141 /** Signal the end of option processing. */
142 #define END_OPTIONS check_next: if (optcontrol == 1 || optcontrol == 3) { \
143 		if (optcontrol == 1) { \
144 			optptr = optcurrent = OPTION_STRDUP(optcurrent); \
145 		} \
146 		optcontrol = 2; \
147 		optcurrent++; \
148 		optcurrent[0] = '-'; \
149 		optArg = optcurrent[2] != 0 ? optcurrent + 2 : NULL; \
150 		goto next_opt; \
151 	} else if (optcontrol == 2) { \
152 		OPTION_FREE(optptr); \
153 	} }} goto stop_opt_parse; stop_opt_parse:;
154 
155 /** Signal the end of the option processing function. */
156 #define END_FUNCTION }
157 
158 /** Internal macro to check whether the requirements regarding option arguments
159 		have been met. */
160 #define CHECK_ARG(argReq) \
161 	switch(argReq) { \
162 		case NO_ARG: \
163 			if (optArg != NULL) { \
164 				if (opttype == SHORT) { \
165 					optcontrol++; \
166 					optArg = NULL; \
167 				} else { \
168 					fatal(_("Option %.*s does not take an argument\n"), OPTPRARG); \
169 				} \
170 			} \
171 			break; \
172 		case REQUIRED_ARG: \
173 			if (optArg == NULL && (optargind+1 >= argc)) { \
174 				fatal(_("Option %.*s requires an argument\n"), OPTPRARG); \
175 			} \
176 			if (optArg == NULL) optArg = argv[++optargind]; \
177 			break; \
178 		default: \
179 			break; \
180 	}
181 
182 /** Check for a short style (-o) option.
183 	@param shortName The name of the short style option.
184 	@param argReq Whether or not an argument is required/allowed. One of NO_ARG,
185 		OPTIONAL_ARG or REQUIRED_ARG.
186 */
187 #define SHORT_OPTION(shortName, argReq) if (opttype == SHORT && optcurrent[1] == shortName) { CHECK_ARG(argReq) {
188 
189 /** Check for a single dash as option.
190 
191 	This is usually used to signal standard input/output.
192 */
193 #define SINGLE_DASH SHORT_OPTION('\0', NO_ARG)
194 
195 /** Check for a double dash as option.
196 
197 	This is usually used to signal the end of options.
198 */
199 #define DOUBLE_DASH LONG_OPTION("", NO_ARG)
200 
201 /** Check for a short style (-o) or long style (--option) option.
202 	@param shortName The name of the short style option.
203 	@param longName The name of the long style option.
204 	@param argReq Whether or not an argument is required/allowed. One of NO_ARG,
205 		OPTIONAL_ARG or REQUIRED_ARG.
206 */
207 #define OPTION(shortName, longName, argReq) if ((opttype == SHORT && optcurrent[1] == shortName) || (opttype == LONG && strlen(longName) == optlength - 2 && strncmp(optcurrent + 2, longName, optlength - 2) == 0)) { CHECK_ARG(argReq) {
208 
209 /** Check for a long style (--option) option.
210 	@param longName The name of the long style option.
211 	@param argReq Whether or not an argument is required/allowed. One of NO_ARG,
212 		OPTIONAL_ARG or REQUIRED_ARG.
213 */
214 #define LONG_OPTION(longName, argReq) if (opttype == LONG && strlen(longName) == optlength - 2 && strncmp(optcurrent + 2, longName, optlength - 2) == 0) { CHECK_ARG(argReq) {
215 
216 /** Signal the end of processing for the previous (SHORT_|LONG_)OPTION. */
217 #define END_OPTION } goto check_next; }
218 
219 /** Check for presence of a short style (-o) option and set the variable if so.
220 	@param shortName The name of the short style option.
221 	@param var The variable to set.
222 */
223 #define BOOLEAN_SHORT_OPTION(shortName, var) SHORT_OPTION(shortName, NO_ARG) var = 1; END_OPTION
224 
225 /** Check for presence of a long style (--option) option and set the variable
226 		if so.
227 	@param longName The name of the long style option.
228 	@param var The variable to set.
229 */
230 #define BOOLEAN_LONG_OPTION(longName, var) LONG_OPTION(longName, NO_ARG) var = 1; END_OPTION
231 
232 /** Check for presence of a short style (-o) or long style (--option) option
233 		and set the variable if so.
234 	@param shortName The name of the short style option.
235 	@param longName The name of the long style option.
236 	@param var The variable to set.
237 */
238 #define BOOLEAN_OPTION(shortName, longName, var) OPTION(shortName, longName, NO_ARG) var = 1; END_OPTION
239 
240 /** Tell option processor that all further arguments are non-option arguments. */
241 #define NO_MORE_OPTIONS do { optnomore = 1; } while(0)
242 
243 /** Tell option processor to jump out of option processing. */
244 #define STOP_OPTION_PROCESSING do { goto stop_opt_parse; } while(0)
245 
246 /** Check an option argument for an integer value.
247 	@param var The variable to store the result in.
248 	@param min The minimum allowable value.
249 	@param max The maximum allowable value.
250 */
251 #define PARSE_INT(var, min, max) do {\
252 	char *endptr; \
253 	long value; \
254 	errno = 0; \
255 	\
256 	value = strtol(optArg, &endptr, 10); \
257 	if (*endptr != 0) { \
258 		fatal(_("Garbage after value for %.*s option\n"), OPTPRARG); \
259 	} \
260 	if (errno != 0 || value < min || value > max) { \
261 		fatal(_("Value for %.*s option (%ld) is out of range\n"), OPTPRARG, value); \
262 	} \
263 	var = (int) value; } while(0)
264 
265 /** Check an option argument for a double value.
266 	@param var The variable to store the result in.
267 	@param min The minimum allowable value.
268 	@param max The maximum allowable value.
269 */
270 /* #define PARSE_DOUBLE(var, min, max) do {\
271 	char *endptr; \
272 	double value; \
273 	errno = 0; \
274 	\
275 	value = strtod(optArg, &endptr); \
276 	if (*endptr != 0) { \
277 		fatal(_("Garbage after value for %.*s option\n"), OPTPRARG); \
278 	} \
279 	if (errno != 0 || value < min || value > max) { \
280 		fatal(_("Value for %.*s option (%f) is out of range\n"), OPTPRARG, value); \
281 	} \
282 	var = value; } while(0) */
283 
284 /** Check an option argument for a boolean value.
285 	@param var The variable to store the result in.
286 */
287 #define PARSE_BOOLEAN(var) do {\
288 	if (optArg == NULL || strcmp(optArg, "true") == 0 || strcmp(optArg, "t") == 0 || strcmp(optArg, "yes") == 0 || \
289 			strcmp(optArg, "y") == 0 || strcmp(optArg, "1") == 0) \
290 		(var) = 1; \
291 	else if (strcmp(optArg, "false") == 0 || strcmp(optArg, "f") == 0 || strcmp(optArg, "no") == 0 || \
292 			strcmp(optArg, "n") == 0 || strcmp(optArg, "0") == 0) \
293 		(var) = 0; \
294 	else \
295 		fatal(_("Value for %.*s option (%s) is not a valid boolean value\n"), OPTPRARG, optArg); \
296 	} while (0)
297 
298 typedef enum {
299 	SHORT,
300 	LONG
301 } ArgType;
302 
303 enum {
304 	NO_ARG,
305 	OPTIONAL_ARG,
306 	REQUIRED_ARG
307 };
308 
309 #endif
310