| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 |
- /*
- * @File: optparse.c
- * @Author: liu2guang
- * @Date: 2018-06-20 14:52:10
- *
- * @LICENSE: MIT
- * https://github.com/liu2guang/optparse/blob/master/LICENSE
- *
- * Change Logs:
- * Date Author Notes
- * 2018-06-20 liu2guang Adapter RT-Thread.
- */
- #include "optparse.h"
- #define OPTPARSE_MSG_INVALID "invalid option"
- #define OPTPARSE_MSG_MISSING "option requires an argument"
- #define OPTPARSE_MSG_TOOMANY "option takes no arguments"
- int optparse_error(struct optparse *options, const char *msg, const char *data)
- {
- unsigned p = 0;
- const char *sep = " -- '";
- while (*msg)
- options->errmsg[p++] = *msg++;
- while (*sep)
- options->errmsg[p++] = *sep++;
- while (p < sizeof(options->errmsg) - 2 && *data)
- options->errmsg[p++] = *data++;
- options->errmsg[p++] = '\'';
- options->errmsg[p++] = '\0';
- return '?';
- }
- static int optparse_is_dashdash(const char *arg)
- {
- return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
- }
- static int optparse_is_shortopt(const char *arg)
- {
- return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
- }
- static int optparse_is_longopt(const char *arg)
- {
- return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
- }
- static void optparse_permute(struct optparse *options, int index)
- {
- char *nonoption = options->argv[index];
- int i;
- for (i = index; i < options->optind - 1; i++)
- options->argv[i] = options->argv[i + 1];
- options->argv[options->optind - 1] = nonoption;
- }
- static int optparse_argtype(const char *optstring, char c)
- {
- int count = OPTPARSE_NONE;
- if (c == ':')
- return -1;
- for (; *optstring && c != *optstring; optstring++);
- if (!*optstring)
- return -1;
- if (optstring[1] == ':')
- count += optstring[2] == ':' ? 2 : 1;
- return count;
- }
- static int optparse_longopts_end(const struct optparse_long *longopts, int i)
- {
- return !longopts[i].longname && !longopts[i].shortname;
- }
- static void optparse_from_long(const struct optparse_long *longopts, char *optstring)
- {
- char *p = optstring;
- int i;
- for (i = 0; !optparse_longopts_end(longopts, i); i++)
- {
- if (longopts[i].shortname && longopts[i].shortname < 127)
- {
- int a;
- *p++ = longopts[i].shortname;
- for (a = 0; a < (int)longopts[i].argtype; a++)
- *p++ = ':';
- }
- }
- *p = '\0';
- }
- /* Unlike strcmp(), handles options containing "=". */
- static int optparse_longopts_match(const char *longname, const char *option)
- {
- const char *a = option, *n = longname;
- if (longname == 0)
- return 0;
- for (; *a && *n && *a != '='; a++, n++)
- if (*a != *n)
- return 0;
- return *n == '\0' && (*a == '\0' || *a == '=');
- }
- /* Return the part after "=", or NULL. */
- static char *optparse_longopts_arg(char *option)
- {
- for (; *option && *option != '='; option++);
- if (*option == '=')
- return option + 1;
- else
- return 0;
- }
- static int optparse_long_fallback(struct optparse *options,
- const struct optparse_long *longopts,
- int *longindex)
- {
- int result;
- char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */
- optparse_from_long(longopts, optstring);
- result = optparse(options, optstring);
- if (longindex != 0)
- {
- *longindex = -1;
- if (result != -1)
- {
- int i;
- for (i = 0; !optparse_longopts_end(longopts, i); i++)
- if (longopts[i].shortname == options->optopt)
- *longindex = i;
- }
- }
- return result;
- }
- void optparse_init(struct optparse *options, int argc, char **argv)
- {
- options->argc = argc;
- options->argv = argv;
- options->permute = 1;
- options->optind = argv[0] != 0;
- options->subopt = 0;
- options->optarg = 0;
- options->errmsg[0] = '\0';
- }
- int optparse(struct optparse *options, const char *optstring)
- {
- int type;
- char *next;
- char *option = options->argv[options->optind];
- options->errmsg[0] = '\0';
- options->optopt = 0;
- options->optarg = 0;
- if ((options->optind>= options->argc) || option == 0)
- {
- return -1;
- }
- else if (optparse_is_dashdash(option))
- {
- options->optind++; /* consume "--" */
- return -1;
- }
- else if (!optparse_is_shortopt(option))
- {
- if (options->permute)
- {
- int index = options->optind++;
- int r = optparse(options, optstring);
- optparse_permute(options, index);
- options->optind--;
- return r;
- }
- else
- {
- return -1;
- }
- }
- option += options->subopt + 1;
- options->optopt = option[0];
- type = optparse_argtype(optstring, option[0]);
- next = options->argv[options->optind + 1];
- switch (type)
- {
- case -1:
- {
- char str[2] = {0, 0};
- str[0] = option[0];
- options->optind++;
- return optparse_error(options, OPTPARSE_MSG_INVALID, str);
- }
- case OPTPARSE_NONE:
- if (option[1])
- {
- options->subopt++;
- }
- else
- {
- options->subopt = 0;
- options->optind++;
- }
- return option[0];
- case OPTPARSE_REQUIRED:
- options->subopt = 0;
- options->optind++;
- if (option[1])
- {
- options->optarg = option + 1;
- }
- else if (next != 0)
- {
- options->optarg = next;
- options->optind++;
- }
- else
- {
- char str[2] = {0, 0};
- str[0] = option[0];
- options->optarg = 0;
- return optparse_error(options, OPTPARSE_MSG_MISSING, str);
- }
- return option[0];
- case OPTPARSE_OPTIONAL:
- options->subopt = 0;
- options->optind++;
- if (option[1])
- options->optarg = option + 1;
- else
- options->optarg = 0;
- return option[0];
- }
- return 0;
- }
- int optparse_long(struct optparse *options, const struct optparse_long *longopts, int *longindex)
- {
- int i;
- char *option = options->argv[options->optind];
- if (option == 0)
- {
- return -1;
- }
- else if (optparse_is_dashdash(option))
- {
- options->optind++; /* consume "--" */
- return -1;
- }
- else if (optparse_is_shortopt(option))
- {
- return optparse_long_fallback(options, longopts, longindex);
- }
- else if (!optparse_is_longopt(option))
- {
- if (options->permute)
- {
- int index = options->optind++;
- int r = optparse_long(options, longopts, longindex);
- optparse_permute(options, index);
- options->optind--;
- return r;
- }
- else
- {
- return -1;
- }
- }
- /* Parse as long option. */
- options->errmsg[0] = '\0';
- options->optopt = 0;
- options->optarg = 0;
- option += 2; /* skip "--" */
- options->optind++;
- for (i = 0; !optparse_longopts_end(longopts, i); i++)
- {
- const char *name = longopts[i].longname;
- if (optparse_longopts_match(name, option))
- {
- char *arg;
- if (longindex)
- *longindex = i;
- options->optopt = longopts[i].shortname;
- arg = optparse_longopts_arg(option);
- if (longopts[i].argtype == OPTPARSE_NONE && arg != 0)
- {
- return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);
- }
- if (arg != 0)
- {
- options->optarg = arg;
- }
- else if (longopts[i].argtype == OPTPARSE_REQUIRED)
- {
- options->optarg = options->argv[options->optind];
- if (options->optarg == 0)
- return optparse_error(options, OPTPARSE_MSG_MISSING, name);
- else
- options->optind++;
- }
- return options->optopt;
- }
- }
- return optparse_error(options, OPTPARSE_MSG_INVALID, option);
- }
- char *optparse_arg(struct optparse *options)
- {
- char *option = options->argv[options->optind];
- options->subopt = 0;
- if (option != 0)
- options->optind++;
- return option;
- }
|