/* 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 #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 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 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