"Fossies" - the Fresh Open Source Software Archive

Member "rrdtool-1.7.2/src/optparse.c" (27 May 2019, 7767 Bytes) of package /linux/misc/rrdtool-1.7.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "optparse.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.7.0_vs_1.7.1.

    1 #include <stdio.h>
    2 #ifdef _MSC_VER
    3 #include <stdlib.h>     /* for malloc(), free() */
    4 #endif
    5 #include "optparse.h"
    6 
    7 #define opterror(options, format, ...) \
    8     snprintf(options->errmsg, sizeof(options->errmsg), format, __VA_ARGS__);
    9 
   10 #define options_argv(i) \
   11     ((i) < options->argc ? options->argv[i] : NULL)
   12 
   13 void optparse_init(struct optparse *options, int argc, char **argv)
   14 {
   15     options->argv = argv;
   16     options->argc = argc;
   17     options->permute = 1;
   18     options->optind = 1;
   19     options->subopt = 0;
   20     options->optarg = NULL;
   21     options->errmsg[0] = '\0';
   22 }
   23 
   24 static inline int
   25 is_dashdash(const char *arg)
   26 {
   27     return arg != NULL && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
   28 }
   29 
   30 static inline int
   31 is_shortopt(const char *arg)
   32 {
   33     return arg != NULL && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
   34 }
   35 
   36 static inline int
   37 is_longopt(const char *arg)
   38 {
   39     return arg != NULL && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
   40 }
   41 
   42 static void
   43 permute(struct optparse *options, int index)
   44 {
   45     char *nonoption = options->argv[index];
   46     for (int i = index; i < options->optind - 1; i++)
   47         options->argv[i] = options->argv[i + 1];
   48     options->argv[options->optind - 1] = nonoption;
   49 }
   50 
   51 static enum optparse_argtype
   52 argtype(const char *optstring, char c)
   53 {
   54     if (c == ':')
   55         return -1;
   56     for (; *optstring && c != *optstring; optstring++);
   57     if (!*optstring)
   58         return -1;
   59     enum optparse_argtype count = OPTPARSE_NONE;
   60     if (optstring[1] == ':')
   61         count += optstring[2] == ':' ? 2 : 1;
   62     return count;
   63 }
   64 
   65 int optparse(struct optparse *options, const char *optstring)
   66 {
   67     options->errmsg[0] = '\0';
   68     options->optopt = 0;
   69     options->optarg = NULL;
   70     char *option = options_argv(options->optind);
   71     if (option == NULL) {
   72         return -1;
   73     } else if (is_dashdash(option)) {
   74         options->optind++; // consume "--"
   75         return -1;
   76     } else if (!is_shortopt(option)) {
   77         if (options->permute) {
   78             int index = options->optind;
   79             options->optind++;
   80             int r = optparse(options, optstring);
   81             permute(options, index);
   82             options->optind--;
   83             return r;
   84         } else {
   85             return -1;
   86         }
   87     }
   88     option += options->subopt + 1;
   89     options->optopt = option[0];
   90     int type = argtype(optstring, option[0]);
   91     char *next = options_argv(options->optind + 1);
   92     switch (type) {
   93     case -1:
   94         opterror(options, "invalid option -- '%c'", option[0]);
   95         options->optind++;
   96         return '?';
   97     case OPTPARSE_NONE:
   98         if (option[1]) {
   99             options->subopt++;
  100         } else {
  101             options->subopt = 0;
  102             options->optind++;
  103         }
  104         return option[0];
  105     case OPTPARSE_REQUIRED:
  106         options->subopt = 0;
  107         options->optind++;
  108         if (option[1]) {
  109             options->optarg = option + 1;
  110         } else if (next != NULL) {
  111             options->optarg = next;
  112             options->optind++;
  113         } else {
  114             opterror(options, "option requires an argument -- '%c'", option[0]);
  115             options->optarg = NULL;
  116             return '?';
  117         }
  118         return option[0];
  119     case OPTPARSE_OPTIONAL:
  120         options->subopt = 0;
  121         options->optind++;
  122         if (option[1])
  123             options->optarg = option + 1;
  124         else
  125             options->optarg = NULL;
  126         return option[0];
  127     }
  128     return 0;
  129 }
  130 
  131 char *optparse_arg(struct optparse *options)
  132 {
  133     options->subopt = 0;
  134     char *option = options->argv[options->optind];
  135     if (option != NULL)
  136         options->optind++;
  137     return option;
  138 }
  139 
  140 static inline int
  141 longopts_end(const struct optparse_long *longopts, int i)
  142 {
  143     return !longopts[i].longname && !longopts[i].shortname;
  144 }
  145 
  146 static size_t
  147 optstring_length(const struct optparse_long *longopts)
  148 {
  149     int length = 0;
  150     for (int i = 0; !longopts_end(longopts, i); i++, length++)
  151         length += longopts[i].argtype;
  152     return length + 1;
  153 }
  154 
  155 static void
  156 optstring_from_long(const struct optparse_long *longopts, char *optstring)
  157 {
  158     char *p = optstring;
  159     for (int i = 0; !longopts_end(longopts, i); i++) {
  160         if (longopts[i].shortname) {
  161             *p++ = longopts[i].shortname;
  162             for (unsigned int a = 0; a < longopts[i].argtype; a++)
  163                 *p++ = ':';
  164         }
  165     }
  166     *p = '\0';
  167 }
  168 
  169 /* Unlike strcmp(), handles options containing "=". */
  170 static int
  171 longopts_match(const char *longname, const char *option)
  172 {
  173     if (longname == NULL)
  174         return 0;
  175     const char *a = option, *n = longname;
  176     for (; *a && *n && *a != '='; a++, n++)
  177         if (*a != *n)
  178             return 0;
  179     return *n == '\0' && (*a == '\0' || *a == '=');
  180 }
  181 
  182 /* Return the part after "=", or NULL. */
  183 static const char *
  184 longopts_arg(const char *option)
  185 {
  186     for (; *option && *option != '='; option++);
  187     if (*option == '=')
  188         return option + 1;
  189     else
  190         return NULL;
  191 }
  192 
  193 static int
  194 long_fallback(struct optparse *options,
  195               const struct optparse_long *longopts,
  196               int *longindex)
  197 {
  198 #ifdef _MSC_VER
  199     /* Variable length arrays are not currently supported in Visual Studio */
  200     char *optstring = malloc(optstring_length(longopts));
  201 #else
  202     char optstring[optstring_length(longopts)];
  203 #endif
  204     optstring_from_long(longopts, optstring);
  205     int result = optparse(options, optstring);
  206     if (longindex != NULL) {
  207         *longindex = -1;
  208         if (result != -1)
  209             for (int i = 0; !longopts_end(longopts, i); i++)
  210                 if (longopts[i].shortname == options->optopt)
  211                     *longindex = i;
  212     }
  213 #ifdef _MSC_VER
  214     free(optstring);
  215 #endif
  216     return result;
  217 }
  218 
  219 int
  220 optparse_long(struct optparse *options,
  221               const struct optparse_long *longopts,
  222               int *longindex)
  223 {
  224 //    printf("%i < %i\n",options->optind,options->argc);
  225     char *option = options_argv(options->optind);
  226     if (option == NULL) {
  227         return -1;
  228     } else if (is_dashdash(option)) {
  229         options->optind++; // consume "--"
  230         return -1;
  231     } else if (is_shortopt(option)) {
  232         return long_fallback(options, longopts, longindex);
  233     } else if (!is_longopt(option)) {
  234         if (options->permute) {
  235             int index = options->optind;
  236             options->optind++;
  237             int r = optparse_long(options, longopts, longindex);
  238             permute(options, index);
  239             options->optind--;
  240             return r;
  241         } else {
  242             return -1;
  243         }
  244     }
  245 
  246     /* Parse as long option. */
  247     options->errmsg[0] = '\0';
  248     options->optopt = 0;
  249     options->optarg = NULL;
  250     option += 2; // skip "--"
  251     options->optind++;
  252     for (int i = 0; !longopts_end(longopts, i); i++) {
  253         const char *name = longopts[i].longname;
  254         if (longopts_match(name, option)) {
  255             if (longindex)
  256                 *longindex = i;
  257             options->optopt = longopts[i].shortname;
  258             const char *arg = longopts_arg(option);
  259             if (longopts[i].argtype == OPTPARSE_NONE && arg != NULL) {
  260                 opterror(options, "option takes no arguments -- '%s'", name);
  261                 return '?';
  262             } if (arg != NULL) {
  263                 options->optarg = arg;
  264             } else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
  265                 options->optarg = options_argv(options->optind);
  266                 options->optind++;
  267                 if (options->optarg == NULL) {
  268                     opterror(options, "option requires argument -- '%s'", name);
  269                     return '?';
  270                 }
  271             }
  272             return options->optopt;
  273         }
  274     }
  275     opterror(options, "invalid option -- '%s'", option);
  276     return '?';
  277 }