| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 Copyright (C) 1997 Gregory Pietsch | |
| 3 | |
| 4 [These files] are hereby placed in the public domain without restrictions. Just | |
| 5 give the author credit, don't claim you wrote it or prevent anyone else from | |
| 6 using it. | |
| 7 */ | |
| 8 | |
| 9 /**************************************************************************** | |
| 10 | |
| 11 getopt.c - Read command line options | |
| 12 | |
| 13 AUTHOR: Gregory Pietsch | |
| 14 CREATED Fri Jan 10 21:13:05 1997 | |
| 15 | |
| 16 DESCRIPTION: | |
| 17 | |
| 18 The getopt() function parses the command line arguments. Its arguments argc | |
| 19 and argv are the argument count and array as passed to the main() function | |
| 20 on program invocation. The argument optstring is a list of available option | |
| 21 characters. If such a character is followed by a colon (`:'), the option | |
| 22 takes an argument, which is placed in optarg. If such a character is | |
| 23 followed by two colons, the option takes an optional argument, which is | |
| 24 placed in optarg. If the option does not take an argument, optarg is NULL. | |
| 25 | |
| 26 The external variable optind is the index of the next array element of argv | |
| 27 to be processed; it communicates from one call to the next which element to | |
| 28 process. | |
| 29 | |
| 30 The getopt_long() function works like getopt() except that it also accepts | |
| 31 long options started by two dashes `--'. If these take values, it is either | |
| 32 in the form | |
| 33 | |
| 34 --arg=value | |
| 35 | |
| 36 or | |
| 37 | |
| 38 --arg value | |
| 39 | |
| 40 It takes the additional arguments longopts which is a pointer to the first | |
| 41 element of an array of type GETOPT_LONG_OPTION_T. The last element of the | |
| 42 array has to be filled with NULL for the name field. | |
| 43 | |
| 44 The longind pointer points to the index of the current long option relative | |
| 45 to longopts if it is non-NULL. | |
| 46 | |
| 47 The getopt() function returns the option character if the option was found | |
| 48 successfully, `:' if there was a missing parameter for one of the options, | |
| 49 `?' for an unknown option character, and EOF for the end of the option list. | |
| 50 | |
| 51 The getopt_long() function's return value is described in the header file. | |
| 52 | |
| 53 The function getopt_long_only() is identical to getopt_long(), except that a | |
| 54 plus sign `+' can introduce long options as well as `--'. | |
| 55 | |
| 56 The following describes how to deal with options that follow non-option | |
| 57 argv-elements. | |
| 58 | |
| 59 If the caller did not specify anything, the default is REQUIRE_ORDER if the | |
| 60 environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. | |
| 61 | |
| 62 REQUIRE_ORDER means don't recognize them as options; stop option processing | |
| 63 when the first non-option is seen. This is what Unix does. This mode of | |
| 64 operation is selected by either setting the environment variable | |
| 65 POSIXLY_CORRECT, or using `+' as the first character of the optstring | |
| 66 parameter. | |
| 67 | |
| 68 PERMUTE is the default. We permute the contents of ARGV as we scan, so that | |
| 69 eventually all the non-options are at the end. This allows options to be | |
| 70 given in any order, even with programs that were not written to expect this. | |
| 71 | |
| 72 RETURN_IN_ORDER is an option available to programs that were written to | |
| 73 expect options and other argv-elements in any order and that care about the | |
| 74 ordering of the two. We describe each non-option argv-element as if it were | |
| 75 the argument of an option with character code 1. Using `-' as the first | |
| 76 character of the optstring parameter selects this mode of operation. | |
| 77 | |
| 78 The special argument `--' forces an end of option-scanning regardless of the | |
| 79 value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause | |
| 80 getopt() and friends to return EOF with optind != argc. | |
| 81 | |
| 82 COPYRIGHT NOTICE AND DISCLAIMER: | |
| 83 | |
| 84 Copyright (C) 1997 Gregory Pietsch | |
| 85 | |
| 86 This file and the accompanying getopt.h header file are hereby placed in the | |
| 87 public domain without restrictions. Just give the author credit, don't | |
| 88 claim you wrote it or prevent anyone else from using it. | |
| 89 | |
| 90 Gregory Pietsch's current e-mail address: | |
| 91 gpietsch@comcast.net | |
| 92 ****************************************************************************/ | |
| 93 | |
| 94 /* include files */ | |
| 95 #include <stdio.h> | |
| 96 #include <stdlib.h> | |
| 97 #include <string.h> | |
| 98 #ifndef GETOPT_H | |
| 99 #include "getopt.h" | |
| 100 #endif | |
| 101 | |
| 102 /* macros */ | |
| 103 | |
| 104 /* types */ | |
| 105 typedef enum GETOPT_ORDERING_T | |
| 106 { | |
| 107 PERMUTE, | |
| 108 RETURN_IN_ORDER, | |
| 109 REQUIRE_ORDER | |
| 110 } GETOPT_ORDERING_T; | |
| 111 | |
| 112 /* globally-defined variables */ | |
| 113 char *optarg = NULL; | |
| 114 int optind = 0; | |
| 115 int opterr = 1; | |
| 116 int optopt = '?'; | |
| 117 | |
| 118 /* functions */ | |
| 119 | |
| 120 /* reverse_argv_elements: reverses num elements starting at argv */ | |
| 121 static void | |
| 122 reverse_argv_elements (char **argv, int num) | |
| 123 { | |
| 124 int i; | |
| 125 char *tmp; | |
| 126 | |
| 127 for (i = 0; i < (num >> 1); i++) | |
| 128 { | |
| 129 tmp = argv[i]; | |
| 130 argv[i] = argv[num - i - 1]; | |
| 131 argv[num - i - 1] = tmp; | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 /* permute: swap two blocks of argv-elements given their lengths */ | |
| 136 static void | |
| 137 permute (char **argv, int len1, int len2) | |
| 138 { | |
| 139 reverse_argv_elements (argv, len1); | |
| 140 reverse_argv_elements (argv, len1 + len2); | |
| 141 reverse_argv_elements (argv, len2); | |
| 142 } | |
| 143 | |
| 144 /* is_option: is this argv-element an option or the end of the option list? */ | |
| 145 static int | |
| 146 is_option (char *argv_element, int only) | |
| 147 { | |
| 148 return ((argv_element == NULL) | |
| 149 || (argv_element[0] == '-') || (only && argv_element[0] == '+')); | |
| 150 } | |
| 151 | |
| 152 /* getopt_internal: the function that does all the dirty work */ | |
| 153 static int | |
| 154 getopt_internal (int argc, char **argv, char *shortopts, | |
| 155 GETOPT_LONG_OPTION_T * longopts, int *longind, int only) | |
| 156 { | |
| 157 GETOPT_ORDERING_T ordering = PERMUTE; | |
| 158 static size_t optwhere = 0; | |
| 159 size_t permute_from = 0; | |
| 160 int num_nonopts = 0; | |
| 161 int optindex = 0; | |
| 162 size_t match_chars = 0; | |
| 163 char *possible_arg = NULL; | |
| 164 int longopt_match = -1; | |
| 165 int has_arg = -1; | |
| 166 char *cp = NULL; | |
| 167 int arg_next = 0; | |
| 168 | |
| 169 /* first, deal with silly parameters and easy stuff */ | |
| 170 if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL)) | |
| 171 return (optopt = '?'); | |
| 172 if (optind >= argc || argv[optind] == NULL) | |
| 173 return EOF; | |
| 174 if (strcmp (argv[optind], "--") == 0) | |
| 175 { | |
| 176 optind++; | |
| 177 return EOF; | |
| 178 } | |
| 179 /* if this is our first time through */ | |
| 180 if (optind == 0) { | |
| 181 optind = 1; | |
| 182 optwhere = 1; | |
| 183 } | |
| 184 | |
| 185 /* define ordering */ | |
| 186 if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+')) | |
| 187 { | |
| 188 ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER; | |
| 189 shortopts++; | |
| 190 } | |
| 191 else | |
| 192 ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE; | |
| 193 | |
| 194 /* | |
| 195 * based on ordering, find our next option, if we're at the beginning of | |
| 196 * one | |
| 197 */ | |
| 198 if (optwhere == 1) | |
| 199 { | |
| 200 switch (ordering) | |
| 201 { | |
| 202 case PERMUTE: | |
| 203 permute_from = optind; | |
| 204 num_nonopts = 0; | |
| 205 while (!is_option (argv[optind], only)) | |
| 206 { | |
| 207 optind++; | |
| 208 num_nonopts++; | |
| 209 } | |
| 210 if (argv[optind] == NULL) | |
| 211 { | |
| 212 /* no more options */ | |
| 213 optind = (int)permute_from; | |
| 214 return EOF; | |
| 215 } | |
| 216 else if (strcmp (argv[optind], "--") == 0) | |
| 217 { | |
| 218 /* no more options, but have to get `--' out of the way */ | |
| 219 permute (argv + permute_from, num_nonopts, 1); | |
| 220 optind = (int)(permute_from + 1); | |
| 221 return EOF; | |
| 222 } | |
| 223 break; | |
| 224 case RETURN_IN_ORDER: | |
| 225 if (!is_option (argv[optind], only)) | |
| 226 { | |
| 227 optarg = argv[optind++]; | |
| 228 return (optopt = 1); | |
| 229 } | |
| 230 break; | |
| 231 case REQUIRE_ORDER: | |
| 232 if (!is_option (argv[optind], only)) | |
| 233 return EOF; | |
| 234 break; | |
| 235 } | |
| 236 } | |
| 237 /* we've got an option, so parse it */ | |
| 238 | |
| 239 /* first, is it a long option? */ | |
| 240 if (longopts != NULL | |
| 241 && (memcmp (argv[optind], "--", 2) == 0 | |
| 242 || (only && argv[optind][0] == '+')) && optwhere == 1) | |
| 243 { | |
| 244 /* handle long options */ | |
| 245 if (memcmp (argv[optind], "--", 2) == 0) | |
| 246 optwhere = 2; | |
| 247 longopt_match = -1; | |
| 248 possible_arg = strchr (argv[optind] + optwhere, '='); | |
| 249 if (possible_arg == NULL) | |
| 250 { | |
| 251 /* no =, so next argv might be arg */ | |
| 252 match_chars = strlen (argv[optind]); | |
| 253 possible_arg = argv[optind] + match_chars; | |
| 254 match_chars = match_chars - optwhere; | |
| 255 } | |
| 256 else | |
| 257 match_chars = (possible_arg - argv[optind]) - optwhere; | |
| 258 for (optindex = 0; longopts[optindex].name != NULL; optindex++) | |
| 259 { | |
| 260 if (memcmp (argv[optind] + optwhere, | |
| 261 longopts[optindex].name, match_chars) == 0) | |
| 262 { | |
| 263 /* do we have an exact match? */ | |
| 264 if (match_chars == strlen (longopts[optindex].name)) | |
| 265 { | |
| 266 longopt_match = optindex; | |
| 267 break; | |
| 268 } | |
| 269 /* do any characters match? */ | |
| 270 else | |
| 271 { | |
| 272 if (longopt_match < 0) | |
| 273 longopt_match = optindex; | |
| 274 else | |
| 275 { | |
| 276 /* we have ambiguous options */ | |
| 277 if (opterr) | |
| 278 fprintf (stderr, "%s: option `%s' is ambiguous " | |
| 279 "(could be `--%s' or `--%s')\n", | |
| 280 argv[0], | |
| 281 argv[optind], | |
| 282 longopts[longopt_match].name, | |
| 283 longopts[optindex].name); | |
| 284 return (optopt = '?'); | |
| 285 } | |
| 286 } | |
| 287 } | |
| 288 } | |
| 289 if (longopt_match >= 0) | |
| 290 has_arg = longopts[longopt_match].has_arg; | |
| 291 } | |
| 292 /* if we didn't find a long option, is it a short option? */ | |
| 293 if (longopt_match < 0 && shortopts != NULL) | |
| 294 { | |
| 295 cp = strchr (shortopts, argv[optind][optwhere]); | |
| 296 if (cp == NULL) | |
| 297 { | |
| 298 /* couldn't find option in shortopts */ | |
| 299 if (opterr) | |
| 300 fprintf (stderr, | |
| 301 "%s: invalid option -- `-%c'\n", | |
| 302 argv[0], argv[optind][optwhere]); | |
| 303 optwhere++; | |
| 304 if (argv[optind][optwhere] == '\0') | |
| 305 { | |
| 306 optind++; | |
| 307 optwhere = 1; | |
| 308 } | |
| 309 return (optopt = '?'); | |
| 310 } | |
| 311 has_arg = ((cp[1] == ':') | |
| 312 ? ((cp[2] == ':') ? OPTIONAL_ARG : required_argument) : no_argu
ment); | |
| 313 possible_arg = argv[optind] + optwhere + 1; | |
| 314 optopt = *cp; | |
| 315 } | |
| 316 /* get argument and reset optwhere */ | |
| 317 arg_next = 0; | |
| 318 switch (has_arg) | |
| 319 { | |
| 320 case OPTIONAL_ARG: | |
| 321 if (*possible_arg == '=') | |
| 322 possible_arg++; | |
| 323 if (*possible_arg != '\0') | |
| 324 { | |
| 325 optarg = possible_arg; | |
| 326 optwhere = 1; | |
| 327 } | |
| 328 else | |
| 329 optarg = NULL; | |
| 330 break; | |
| 331 case required_argument: | |
| 332 if (*possible_arg == '=') | |
| 333 possible_arg++; | |
| 334 if (*possible_arg != '\0') | |
| 335 { | |
| 336 optarg = possible_arg; | |
| 337 optwhere = 1; | |
| 338 } | |
| 339 else if (optind + 1 >= argc) | |
| 340 { | |
| 341 if (opterr) | |
| 342 { | |
| 343 fprintf (stderr, "%s: argument required for option `", argv[0]); | |
| 344 if (longopt_match >= 0) | |
| 345 fprintf (stderr, "--%s'\n", longopts[longopt_match].name); | |
| 346 else | |
| 347 fprintf (stderr, "-%c'\n", *cp); | |
| 348 } | |
| 349 optind++; | |
| 350 return (optopt = ':'); | |
| 351 } | |
| 352 else | |
| 353 { | |
| 354 optarg = argv[optind + 1]; | |
| 355 arg_next = 1; | |
| 356 optwhere = 1; | |
| 357 } | |
| 358 break; | |
| 359 case no_argument: | |
| 360 if (longopt_match < 0) | |
| 361 { | |
| 362 optwhere++; | |
| 363 if (argv[optind][optwhere] == '\0') | |
| 364 optwhere = 1; | |
| 365 } | |
| 366 else | |
| 367 optwhere = 1; | |
| 368 optarg = NULL; | |
| 369 break; | |
| 370 } | |
| 371 | |
| 372 /* do we have to permute or otherwise modify optind? */ | |
| 373 if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0) | |
| 374 { | |
| 375 permute (argv + permute_from, num_nonopts, 1 + arg_next); | |
| 376 optind = (int)(permute_from + 1 + arg_next); | |
| 377 } | |
| 378 else if (optwhere == 1) | |
| 379 optind = optind + 1 + arg_next; | |
| 380 | |
| 381 /* finally return */ | |
| 382 if (longopt_match >= 0) | |
| 383 { | |
| 384 if (longind != NULL) | |
| 385 *longind = longopt_match; | |
| 386 if (longopts[longopt_match].flag != NULL) | |
| 387 { | |
| 388 *(longopts[longopt_match].flag) = longopts[longopt_match].val; | |
| 389 return 0; | |
| 390 } | |
| 391 else | |
| 392 return longopts[longopt_match].val; | |
| 393 } | |
| 394 else | |
| 395 return optopt; | |
| 396 } | |
| 397 | |
| 398 int | |
| 399 getopt (int argc, char **argv, char *optstring) | |
| 400 { | |
| 401 return getopt_internal (argc, argv, optstring, NULL, NULL, 0); | |
| 402 } | |
| 403 | |
| 404 int | |
| 405 getopt_long (int argc, char **argv, const char *shortopts, | |
| 406 const GETOPT_LONG_OPTION_T * longopts, int *longind) | |
| 407 { | |
| 408 return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)l
ongopts, longind, 0); | |
| 409 } | |
| 410 | |
| 411 int | |
| 412 getopt_long_only (int argc, char **argv, const char *shortopts, | |
| 413 const GETOPT_LONG_OPTION_T * longopts, int *longind) | |
| 414 { | |
| 415 return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)l
ongopts, longind, 1); | |
| 416 } | |
| 417 | |
| 418 /* end of file GETOPT.C */ | |
| OLD | NEW |