— posted by Thomas Kindler, 2006/05/27 00:31
/* A lightweight command line option parser. Copyright (c)2002 by Thomas Kindler, thomas.kindler@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Read the full License at http://www.gnu.org/copyleft for more details. */ // include files ----- // #include "getopt.h" #include <string.h> #include <stdio.h> /** * Left-rotate [len] array entries by one entry. */ static void rotate(char *array[], int len) { char *old = array[0]; for (int i=0; i<len-1; i++) array[i] = array[i+1]; array[len-1] = old; } /** * Parse argv[] array for command line options. * The array is permuted, so that all recognized options * are moved to the end of the array. This has several * advantages, because it makes the option parsing * totally transparent to the calling program. See the * example for more details. * * \b Example: \code * bool opt_boolflag; * int opt_inttest; * * CmdOpt options[] = { * 'b', "onoff", NULL, &opt_boolflag, "this is an on/off flag", * 'i', "integer", "%d", &opt_test, "integer scan test", * NULL, NULL, NULL, NULL, NULL * }; * * int main(int argc, char* argv[]) * { * if (!(argc = getopt(argc, argv, options))) { * getopt_help(options); * return -1; * } * for (int i=0; i<argc; i++) * printf(" %d: \"%s\"\n", i, argv[i]); * } * \endcode * * \param argc, argv argument count and array of * arguments as given to the main() function. * \param options pointer to options array, the * last entry must have zeros or NULL's in all * fields. * \return number of remaining non-option arguments * or 0 if there was an error. */ int getopt(int argc, char *argv[], const CmdOpt *options) { int current = 1; int todo = argc - 1; while (todo > 0) { const CmdOpt *opt = NULL; if (!strcmp(argv[current], "--")) { // stop option parsing. // rotate(&argv[current], argc - current); todo--; return current+todo; } else if (!strncmp(argv[current], "--", 2)) { // search for long-option match // bool ambiguous = false; int len = strlen(&argv[current][2]); for (const CmdOpt *o = options; o->param; o++) { if (!strcmp(&argv[current][2], o->longopt)) { // We found a direct, unambiguos match. // opt = o; ambiguous = false; break; } if (!strncmp(&argv[current][2], o->longopt, len)) { // We found a partial match. If there's more // than one match, the option is ambiguous. // (unless we also find a direct match). // if (opt == NULL) opt = o; else ambiguous = true; } } if (ambiguous) { fprintf(stderr, "ERROR: ambiguous option \"%s\".\n", argv[current]); return 0; } if (!opt) { fprintf(stderr, "ERROR: unknown option \"%s\".\n", argv[current]); return 0; } } else if (!strncmp(argv[current], "-", 1) || !strncmp(argv[current], "/", 1) ) { // search for short-option match // for (const CmdOpt *o = options; o->param; o++) if (argv[current][1] == o->shortopt && argv[current][2] == 0) opt = o; if (!opt) { fprintf(stderr, "ERROR: unknown option \"%s\".\n", argv[current]); return 0; } } if (opt) { // cool, we found an option. // if (opt->format) { // scan for format string.. // if (current+1 >= argc) { fprintf(stderr, "ERROR: missing parameter for \"%s\".\n", argv[current]); return 0; } if (!sscanf(argv[current+1], opt->format, opt->param)) { fprintf(stderr, "ERROR: invalid parameter \"%s\" for \"%s\".\n", argv[current+1], argv[current]); return 0; } rotate(&argv[current], argc - current); todo--; rotate(&argv[current], argc - current); todo--; } else { // no format string - set boolean value. // if (opt->param) *((bool*)opt->param) = true; rotate(&argv[current], argc - current); todo--; } } else { // skip non-option argument. // current++; todo--; } } return current; } /** * Print option help strings to stdout. The help texts * are generated from the options array. * * \param options pointer to array of CmdOpt options. */ void getopt_help(const CmdOpt *options) { int xpos = printf("Options : "); for (CmdOpt *o=options; o->param; o++) { if (xpos == 0) xpos = printf(" "); if (o->shortopt) xpos += printf("-%c, ", o->shortopt); else xpos += printf(" "); if (o->longopt) xpos += printf("--%s", o->longopt); xpos += printf(" "); while (xpos < 25) { printf(" "); xpos++; } printf("%s\n", o->help); xpos = 0; } }
/* A lightweight command line option parser. Copyright (c)2002 by Thomas Kindler, thomas.kindler@gmx.de This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Read the full License at http://www.gnu.org/copyleft for more details. */ #ifndef GETOPT_H #define GETOPT_H /** * Command line option definition. */ typedef struct { char shortopt; ///< short option string, e.g. 'o' char *longopt; ///< long option string, e.g. "--option" char *format; ///< scanf format string, e.g. "%d" ///< or NULL for boolean on/off switches void *param; ///< where to store the parameter char *help; ///< where to store the parameter } CmdOpt; extern int getopt(int argc, char *argv[], const CmdOpt *options); extern void getopt_help(const CmdOpt *options); #endif