| 1 |
/* $Id: getopt.c,v 1.2 2007/01/07 23:19:19 mjt Exp $ |
|---|
| 2 |
* Simple getopt() implementation. |
|---|
| 3 |
* |
|---|
| 4 |
* Standard interface: |
|---|
| 5 |
* extern int getopt(int argc, char *const *argv, const char *opts); |
|---|
| 6 |
* extern int optind; current index in argv[] |
|---|
| 7 |
* extern char *optarg; argument for the current option |
|---|
| 8 |
* extern int optopt; the current option |
|---|
| 9 |
* extern int opterr; to control error printing |
|---|
| 10 |
* |
|---|
| 11 |
* Some minor extensions: |
|---|
| 12 |
* ignores leading `+' sign in opts[] (unemplemented GNU extension) |
|---|
| 13 |
* handles optional arguments, in form "x::" in opts[] |
|---|
| 14 |
* if opts[] starts with `:', will return `:' in case of missing required |
|---|
| 15 |
* argument, instead of '?'. |
|---|
| 16 |
* |
|---|
| 17 |
* Compile with -DGETOPT_NO_OPTERR to never print errors internally. |
|---|
| 18 |
* Compile with -DGETOPT_NO_STDIO to use write() calls instead of fprintf() for |
|---|
| 19 |
* error reporting (ignored with -DGETOPT_NO_OPTERR). |
|---|
| 20 |
* Compile with -DGETOPT_CLASS=static to get static linkage. |
|---|
| 21 |
* Compile with -DGETOPT_MY to redefine all visible symbols to be prefixed |
|---|
| 22 |
* with "my_", like my_getopt instead of getopt. |
|---|
| 23 |
* Compile with -DTEST to get a test executable. |
|---|
| 24 |
* |
|---|
| 25 |
* Written by Michael Tokarev. Public domain. |
|---|
| 26 |
*/ |
|---|
| 27 |
|
|---|
| 28 |
#include <string.h> |
|---|
| 29 |
|
|---|
| 30 |
#ifndef GETOPT_CLASS |
|---|
| 31 |
# define GETOPT_CLASS |
|---|
| 32 |
#endif |
|---|
| 33 |
#ifdef GETOPT_MY |
|---|
| 34 |
# define optarg my_optarg |
|---|
| 35 |
# define optind my_optind |
|---|
| 36 |
# define opterr my_opterr |
|---|
| 37 |
# define optopt my_optopt |
|---|
| 38 |
# define getopt my_getopt |
|---|
| 39 |
#endif |
|---|
| 40 |
|
|---|
| 41 |
GETOPT_CLASS char *optarg /* = NULL */; |
|---|
| 42 |
GETOPT_CLASS int optind = 1; |
|---|
| 43 |
GETOPT_CLASS int opterr = 1; |
|---|
| 44 |
GETOPT_CLASS int optopt; |
|---|
| 45 |
|
|---|
| 46 |
static char *nextc /* = NULL */; |
|---|
| 47 |
|
|---|
| 48 |
#if defined(GETOPT_NO_OPTERR) |
|---|
| 49 |
|
|---|
| 50 |
#define printerr(argv, msg) |
|---|
| 51 |
|
|---|
| 52 |
#elif defined(GETOPT_NO_STDIO) |
|---|
| 53 |
|
|---|
| 54 |
extern int write(int, void *, int); |
|---|
| 55 |
|
|---|
| 56 |
static void printerr(char *const *argv, const char *msg) { |
|---|
| 57 |
if (opterr) { |
|---|
| 58 |
char buf[64]; |
|---|
| 59 |
unsigned pl = strlen(argv[0]); |
|---|
| 60 |
unsigned ml = strlen(msg); |
|---|
| 61 |
char *p; |
|---|
| 62 |
if (pl + /*": "*/2 + ml + /*" -- c\n"*/6 > sizeof(buf)) { |
|---|
| 63 |
write(2, argv[0], pl); |
|---|
| 64 |
p = buf; |
|---|
| 65 |
} |
|---|
| 66 |
else { |
|---|
| 67 |
memcpy(buf, argv[0], ml); |
|---|
| 68 |
p = buf + pl; |
|---|
| 69 |
} |
|---|
| 70 |
*p++ = ':'; *p++ = ' '; |
|---|
| 71 |
memcpy(p, msg, ml); p += ml; |
|---|
| 72 |
*p++ = ' '; *p++ = '-'; *p++ = '-'; *p++ = ' '; |
|---|
| 73 |
*p++ = optopt; |
|---|
| 74 |
*p++ = '\n'; |
|---|
| 75 |
write(2, buf, p - buf); |
|---|
| 76 |
} |
|---|
| 77 |
} |
|---|
| 78 |
|
|---|
| 79 |
#else |
|---|
| 80 |
|
|---|
| 81 |
#include <stdio.h> |
|---|
| 82 |
static void printerr(char *const *argv, const char *msg) { |
|---|
| 83 |
if (opterr) |
|---|
| 84 |
fprintf(stderr, "%s: %s -- %c\n", argv[0], msg, optopt); |
|---|
| 85 |
} |
|---|
| 86 |
|
|---|
| 87 |
#endif |
|---|
| 88 |
|
|---|
| 89 |
GETOPT_CLASS int getopt(int argc, char *const *argv, const char *opts) { |
|---|
| 90 |
char *p; |
|---|
| 91 |
|
|---|
| 92 |
optarg = 0; |
|---|
| 93 |
if (*opts == '+') /* GNU extension (permutation) - isn't supported */ |
|---|
| 94 |
++opts; |
|---|
| 95 |
|
|---|
| 96 |
if (!optind) { /* a way to reset things */ |
|---|
| 97 |
nextc = 0; |
|---|
| 98 |
optind = 1; |
|---|
| 99 |
} |
|---|
| 100 |
|
|---|
| 101 |
if (!nextc || !*nextc) { /* advance to the next argv element */ |
|---|
| 102 |
/* done scanning? */ |
|---|
| 103 |
if (optind >= argc) |
|---|
| 104 |
return -1; |
|---|
| 105 |
/* not an optional argument */ |
|---|
| 106 |
if (argv[optind][0] != '-') |
|---|
| 107 |
return -1; |
|---|
| 108 |
/* bare `-' */ |
|---|
| 109 |
if (argv[optind][1] == '\0') |
|---|
| 110 |
return -1; |
|---|
| 111 |
/* special case `--' argument */ |
|---|
| 112 |
if (argv[optind][1] == '-' && argv[optind][2] == '\0') { |
|---|
| 113 |
++optind; |
|---|
| 114 |
return -1; |
|---|
| 115 |
} |
|---|
| 116 |
nextc = argv[optind] + 1; |
|---|
| 117 |
} |
|---|
| 118 |
|
|---|
| 119 |
optopt = *nextc++; |
|---|
| 120 |
if (!*nextc) |
|---|
| 121 |
++optind; |
|---|
| 122 |
p = strchr(opts, optopt); |
|---|
| 123 |
if (!p || optopt == ':') { |
|---|
| 124 |
printerr(argv, "illegal option"); |
|---|
| 125 |
return '?'; |
|---|
| 126 |
} |
|---|
| 127 |
if (p[1] == ':') { |
|---|
| 128 |
if (*nextc) { |
|---|
| 129 |
optarg = nextc; |
|---|
| 130 |
nextc = NULL; |
|---|
| 131 |
++optind; |
|---|
| 132 |
} |
|---|
| 133 |
else if (p[2] != ':') { /* required argument */ |
|---|
| 134 |
if (optind >= argc) { |
|---|
| 135 |
printerr(argv, "option requires an argument"); |
|---|
| 136 |
return *opts == ':' ? ':' : '?'; |
|---|
| 137 |
} |
|---|
| 138 |
else |
|---|
| 139 |
optarg = argv[optind++]; |
|---|
| 140 |
} |
|---|
| 141 |
} |
|---|
| 142 |
return optopt; |
|---|
| 143 |
} |
|---|
| 144 |
|
|---|
| 145 |
#ifdef TEST |
|---|
| 146 |
|
|---|
| 147 |
#include <stdio.h> |
|---|
| 148 |
|
|---|
| 149 |
int main(int argc, char **argv) { |
|---|
| 150 |
int c; |
|---|
| 151 |
while((c = getopt(argc, argv, "ab:c::")) != -1) switch(c) { |
|---|
| 152 |
case 'a': |
|---|
| 153 |
case 'b': |
|---|
| 154 |
case 'c': |
|---|
| 155 |
printf("option %c %s\n", c, optarg ? optarg : "(none)"); |
|---|
| 156 |
break; |
|---|
| 157 |
default: |
|---|
| 158 |
return -1; |
|---|
| 159 |
} |
|---|
| 160 |
for(c = optind; c < argc; ++c) |
|---|
| 161 |
printf("non-opt: %s\n", argv[c]); |
|---|
| 162 |
return 0; |
|---|
| 163 |
} |
|---|
| 164 |
|
|---|
| 165 |
#endif |
|---|