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