|
|
/* getopt.c
* Simple getopt() implementation. * * Standard interface: * extern int getopt(int argc, char *const *argv, const char *opts); * extern int optind; current index in argv[] * extern char *optarg; argument for the current option * extern int optopt; the current option * extern int opterr; to control error printing * * Some minor extensions: * ignores leading `+' sign in opts[] (unemplemented GNU extension) * handles optional arguments, in form "x::" in opts[] * if opts[] starts with `:', will return `:' in case of missing required * argument, instead of '?'. * * Compile with -DGETOPT_NO_OPTERR to never print errors internally. * Compile with -DGETOPT_NO_STDIO to use write() calls instead of fprintf() for * error reporting (ignored with -DGETOPT_NO_OPTERR). * Compile with -DGETOPT_CLASS=static to get static linkage. * Compile with -DGETOPT_MY to redefine all visible symbols to be prefixed * with "my_", like my_getopt instead of getopt. * Compile with -DTEST to get a test executable. * * Written by Michael Tokarev. Public domain. */
#include <string.h>
#ifndef GETOPT_CLASS
# define GETOPT_CLASS
#endif
#ifdef GETOPT_MY
# define optarg my_optarg
# define optind my_optind
# define opterr my_opterr
# define optopt my_optopt
# define getopt my_getopt
#endif
GETOPT_CLASS char *optarg /* = NULL */; GETOPT_CLASS int optind = 1; GETOPT_CLASS int opterr = 1; GETOPT_CLASS int optopt;
static char *nextc /* = NULL */;
#if defined(GETOPT_NO_OPTERR)
#define printerr(argv, msg)
#elif defined(GETOPT_NO_STDIO)
extern int write(int, void *, int);
static void printerr(char *const *argv, const char *msg) { if (opterr) { char buf[64]; unsigned pl = strlen(argv[0]); unsigned ml = strlen(msg); char *p; if (pl + /*": "*/2 + ml + /*" -- c\n"*/6 > sizeof(buf)) { write(2, argv[0], pl); p = buf; } else { memcpy(buf, argv[0], ml); p = buf + pl; } *p++ = ':'; *p++ = ' '; memcpy(p, msg, ml); p += ml; *p++ = ' '; *p++ = '-'; *p++ = '-'; *p++ = ' '; *p++ = optopt; *p++ = '\n'; write(2, buf, p - buf); } }
#else
#include <stdio.h>
static void printerr(char *const *argv, const char *msg) { if (opterr) fprintf(stderr, "%s: %s -- %c\n", argv[0], msg, optopt); }
#endif
GETOPT_CLASS int getopt(int argc, char *const *argv, const char *opts) { char *p;
optarg = 0; if (*opts == '+') /* GNU extension (permutation) - isn't supported */ ++opts;
if (!optind) { /* a way to reset things */ nextc = 0; optind = 1; }
if (!nextc || !*nextc) { /* advance to the next argv element */ /* done scanning? */ if (optind >= argc) return -1; /* not an optional argument */ if (argv[optind][0] != '-') return -1; /* bare `-' */ if (argv[optind][1] == '\0') return -1; /* special case `--' argument */ if (argv[optind][1] == '-' && argv[optind][2] == '\0') { ++optind; return -1; } nextc = argv[optind] + 1; }
optopt = *nextc++; if (!*nextc) ++optind; p = strchr(opts, optopt); if (!p || optopt == ':') { printerr(argv, "illegal option"); return '?'; } if (p[1] == ':') { if (*nextc) { optarg = nextc; nextc = NULL; ++optind; } else if (p[2] != ':') { /* required argument */ if (optind >= argc) { printerr(argv, "option requires an argument"); return *opts == ':' ? ':' : '?'; } else optarg = argv[optind++]; } } return optopt; }
#ifdef TEST
#include <stdio.h>
int main(int argc, char **argv) { int c; while((c = getopt(argc, argv, "ab:c::")) != -1) switch(c) { case 'a': case 'b': case 'c': printf("option %c %s\n", c, optarg ? optarg : "(none)"); break; default: return -1; } for(c = optind; c < argc; ++c) printf("non-opt: %s\n", argv[c]); return 0; }
#endif
|