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 /* macros */ |
| 95 |
| 96 /* types */ |
| 97 typedef enum GETOPT_ORDERING_T |
| 98 { |
| 99 PERMUTE, |
| 100 RETURN_IN_ORDER, |
| 101 REQUIRE_ORDER |
| 102 } GETOPT_ORDERING_T; |
| 103 |
| 104 /* globally-defined variables */ |
| 105 char *optarg = NULL; |
| 106 int optind = 0; |
| 107 int opterr = 1; |
| 108 int optopt = '?'; |
| 109 |
| 110 /* functions */ |
| 111 |
| 112 /* reverse_argv_elements: reverses num elements starting at argv */ |
| 113 static void |
| 114 reverse_argv_elements (char **argv, int num) |
| 115 { |
| 116 int i; |
| 117 char *tmp; |
| 118 |
| 119 for (i = 0; i < (num >> 1); i++) |
| 120 { |
| 121 tmp = argv[i]; |
| 122 argv[i] = argv[num - i - 1]; |
| 123 argv[num - i - 1] = tmp; |
| 124 } |
| 125 } |
| 126 |
| 127 /* permute: swap two blocks of argv-elements given their lengths */ |
| 128 static void |
| 129 permute (char **argv, int len1, int len2) |
| 130 { |
| 131 reverse_argv_elements (argv, len1); |
| 132 reverse_argv_elements (argv, len1 + len2); |
| 133 reverse_argv_elements (argv, len2); |
| 134 } |
| 135 |
| 136 /* is_option: is this argv-element an option or the end of the option list? */ |
| 137 static int |
| 138 is_option (char *argv_element, int only) |
| 139 { |
| 140 return ((argv_element == NULL) |
| 141 || (argv_element[0] == '-') || (only && argv_element[0] == '+')); |
| 142 } |
| 143 |
| 144 /* getopt_internal: the function that does all the dirty work */ |
| 145 static int |
| 146 getopt_internal (int argc, char **argv, char *shortopts, |
| 147 GETOPT_LONG_OPTION_T * longopts, int *longind, int only) |
| 148 { |
| 149 GETOPT_ORDERING_T ordering = PERMUTE; |
| 150 static size_t optwhere = 0; |
| 151 size_t permute_from = 0; |
| 152 int num_nonopts = 0; |
| 153 int optindex = 0; |
| 154 size_t match_chars = 0; |
| 155 char *possible_arg = NULL; |
| 156 int longopt_match = -1; |
| 157 int has_arg = -1; |
| 158 char *cp = NULL; |
| 159 int arg_next = 0; |
| 160 |
| 161 /* first, deal with silly parameters and easy stuff */ |
| 162 if (argc == 0 || argv == NULL || (shortopts == NULL && longopts == NULL)) |
| 163 return (optopt = '?'); |
| 164 if (optind >= argc || argv[optind] == NULL) |
| 165 return EOF; |
| 166 if (strcmp (argv[optind], "--") == 0) |
| 167 { |
| 168 optind++; |
| 169 return EOF; |
| 170 } |
| 171 /* if this is our first time through */ |
| 172 if (optind == 0) { |
| 173 optind = 1; |
| 174 optwhere = 1; |
| 175 } |
| 176 |
| 177 /* define ordering */ |
| 178 if (shortopts != NULL && (*shortopts == '-' || *shortopts == '+')) |
| 179 { |
| 180 ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER; |
| 181 shortopts++; |
| 182 } |
| 183 else |
| 184 ordering = (getenv ("POSIXLY_CORRECT") != NULL) ? REQUIRE_ORDER : PERMUTE; |
| 185 |
| 186 /* |
| 187 * based on ordering, find our next option, if we're at the beginning of |
| 188 * one |
| 189 */ |
| 190 if (optwhere == 1) |
| 191 { |
| 192 switch (ordering) |
| 193 { |
| 194 case PERMUTE: |
| 195 permute_from = optind; |
| 196 num_nonopts = 0; |
| 197 while (!is_option (argv[optind], only)) |
| 198 { |
| 199 optind++; |
| 200 num_nonopts++; |
| 201 } |
| 202 if (argv[optind] == NULL) |
| 203 { |
| 204 /* no more options */ |
| 205 optind = (int)permute_from; |
| 206 return EOF; |
| 207 } |
| 208 else if (strcmp (argv[optind], "--") == 0) |
| 209 { |
| 210 /* no more options, but have to get `--' out of the way */ |
| 211 permute (argv + permute_from, num_nonopts, 1); |
| 212 optind = (int)(permute_from + 1); |
| 213 return EOF; |
| 214 } |
| 215 break; |
| 216 case RETURN_IN_ORDER: |
| 217 if (!is_option (argv[optind], only)) |
| 218 { |
| 219 optarg = argv[optind++]; |
| 220 return (optopt = 1); |
| 221 } |
| 222 break; |
| 223 case REQUIRE_ORDER: |
| 224 if (!is_option (argv[optind], only)) |
| 225 return EOF; |
| 226 break; |
| 227 } |
| 228 } |
| 229 /* we've got an option, so parse it */ |
| 230 |
| 231 /* first, is it a long option? */ |
| 232 if (longopts != NULL |
| 233 && (memcmp (argv[optind], "--", 2) == 0 |
| 234 || (only && argv[optind][0] == '+')) && optwhere == 1) |
| 235 { |
| 236 /* handle long options */ |
| 237 if (memcmp (argv[optind], "--", 2) == 0) |
| 238 optwhere = 2; |
| 239 longopt_match = -1; |
| 240 possible_arg = strchr (argv[optind] + optwhere, '='); |
| 241 if (possible_arg == NULL) |
| 242 { |
| 243 /* no =, so next argv might be arg */ |
| 244 match_chars = strlen (argv[optind]); |
| 245 possible_arg = argv[optind] + match_chars; |
| 246 match_chars = match_chars - optwhere; |
| 247 } |
| 248 else |
| 249 match_chars = (possible_arg - argv[optind]) - optwhere; |
| 250 for (optindex = 0; longopts[optindex].name != NULL; optindex++) |
| 251 { |
| 252 if (memcmp (argv[optind] + optwhere, |
| 253 longopts[optindex].name, match_chars) == 0) |
| 254 { |
| 255 /* do we have an exact match? */ |
| 256 if (match_chars == strlen (longopts[optindex].name)) |
| 257 { |
| 258 longopt_match = optindex; |
| 259 break; |
| 260 } |
| 261 /* do any characters match? */ |
| 262 else |
| 263 { |
| 264 if (longopt_match < 0) |
| 265 longopt_match = optindex; |
| 266 else |
| 267 { |
| 268 /* we have ambiguous options */ |
| 269 if (opterr) |
| 270 fprintf (stderr, "%s: option `%s' is ambiguous " |
| 271 "(could be `--%s' or `--%s')\n", |
| 272 argv[0], |
| 273 argv[optind], |
| 274 longopts[longopt_match].name, |
| 275 longopts[optindex].name); |
| 276 return (optopt = '?'); |
| 277 } |
| 278 } |
| 279 } |
| 280 } |
| 281 if (longopt_match >= 0) |
| 282 has_arg = longopts[longopt_match].has_arg; |
| 283 } |
| 284 /* if we didn't find a long option, is it a short option? */ |
| 285 if (longopt_match < 0 && shortopts != NULL) |
| 286 { |
| 287 cp = strchr (shortopts, argv[optind][optwhere]); |
| 288 if (cp == NULL) |
| 289 { |
| 290 /* couldn't find option in shortopts */ |
| 291 if (opterr) |
| 292 fprintf (stderr, |
| 293 "%s: invalid option -- `-%c'\n", |
| 294 argv[0], argv[optind][optwhere]); |
| 295 optwhere++; |
| 296 if (argv[optind][optwhere] == '\0') |
| 297 { |
| 298 optind++; |
| 299 optwhere = 1; |
| 300 } |
| 301 return (optopt = '?'); |
| 302 } |
| 303 has_arg = ((cp[1] == ':') |
| 304 ? ((cp[2] == ':') ? OPTIONAL_ARG : required_argument) : no_argu
ment); |
| 305 possible_arg = argv[optind] + optwhere + 1; |
| 306 optopt = *cp; |
| 307 } |
| 308 /* get argument and reset optwhere */ |
| 309 arg_next = 0; |
| 310 switch (has_arg) |
| 311 { |
| 312 case OPTIONAL_ARG: |
| 313 if (*possible_arg == '=') |
| 314 possible_arg++; |
| 315 if (*possible_arg != '\0') |
| 316 { |
| 317 optarg = possible_arg; |
| 318 optwhere = 1; |
| 319 } |
| 320 else |
| 321 optarg = NULL; |
| 322 break; |
| 323 case required_argument: |
| 324 if (*possible_arg == '=') |
| 325 possible_arg++; |
| 326 if (*possible_arg != '\0') |
| 327 { |
| 328 optarg = possible_arg; |
| 329 optwhere = 1; |
| 330 } |
| 331 else if (optind + 1 >= argc) |
| 332 { |
| 333 if (opterr) |
| 334 { |
| 335 fprintf (stderr, "%s: argument required for option `", argv[0]); |
| 336 if (longopt_match >= 0) |
| 337 fprintf (stderr, "--%s'\n", longopts[longopt_match].name); |
| 338 else |
| 339 fprintf (stderr, "-%c'\n", *cp); |
| 340 } |
| 341 optind++; |
| 342 return (optopt = ':'); |
| 343 } |
| 344 else |
| 345 { |
| 346 optarg = argv[optind + 1]; |
| 347 arg_next = 1; |
| 348 optwhere = 1; |
| 349 } |
| 350 break; |
| 351 case no_argument: |
| 352 if (longopt_match < 0) |
| 353 { |
| 354 optwhere++; |
| 355 if (argv[optind][optwhere] == '\0') |
| 356 optwhere = 1; |
| 357 } |
| 358 else |
| 359 optwhere = 1; |
| 360 optarg = NULL; |
| 361 break; |
| 362 } |
| 363 |
| 364 /* do we have to permute or otherwise modify optind? */ |
| 365 if (ordering == PERMUTE && optwhere == 1 && num_nonopts != 0) |
| 366 { |
| 367 permute (argv + permute_from, num_nonopts, 1 + arg_next); |
| 368 optind = (int)(permute_from + 1 + arg_next); |
| 369 } |
| 370 else if (optwhere == 1) |
| 371 optind = optind + 1 + arg_next; |
| 372 |
| 373 /* finally return */ |
| 374 if (longopt_match >= 0) |
| 375 { |
| 376 if (longind != NULL) |
| 377 *longind = longopt_match; |
| 378 if (longopts[longopt_match].flag != NULL) |
| 379 { |
| 380 *(longopts[longopt_match].flag) = longopts[longopt_match].val; |
| 381 return 0; |
| 382 } |
| 383 else |
| 384 return longopts[longopt_match].val; |
| 385 } |
| 386 else |
| 387 return optopt; |
| 388 } |
| 389 |
| 390 int |
| 391 getopt (int argc, char **argv, char *optstring) |
| 392 { |
| 393 return getopt_internal (argc, argv, optstring, NULL, NULL, 0); |
| 394 } |
| 395 |
| 396 int |
| 397 getopt_long (int argc, char **argv, const char *shortopts, |
| 398 const GETOPT_LONG_OPTION_T * longopts, int *longind) |
| 399 { |
| 400 return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)l
ongopts, longind, 0); |
| 401 } |
| 402 |
| 403 int |
| 404 getopt_long_only (int argc, char **argv, const char *shortopts, |
| 405 const GETOPT_LONG_OPTION_T * longopts, int *longind) |
| 406 { |
| 407 return getopt_internal (argc, argv, (char*)shortopts, (GETOPT_LONG_OPTION_T*)l
ongopts, longind, 1); |
| 408 } |
| 409 |
| 410 /* end of file GETOPT.C */ |
OLD | NEW |