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