1*02e95f1aSMarcin Radomski /* Optparse --- portable, reentrant, embeddable, getopt-like option parser
2*02e95f1aSMarcin Radomski *
3*02e95f1aSMarcin Radomski * This is free and unencumbered software released into the public domain.
4*02e95f1aSMarcin Radomski *
5*02e95f1aSMarcin Radomski * To get the implementation, define OPTPARSE_IMPLEMENTATION.
6*02e95f1aSMarcin Radomski * Optionally define OPTPARSE_API to control the API's visibility
7*02e95f1aSMarcin Radomski * and/or linkage (static, __attribute__, __declspec).
8*02e95f1aSMarcin Radomski *
9*02e95f1aSMarcin Radomski * The POSIX getopt() option parser has three fatal flaws. These flaws
10*02e95f1aSMarcin Radomski * are solved by Optparse.
11*02e95f1aSMarcin Radomski *
12*02e95f1aSMarcin Radomski * 1) Parser state is stored entirely in global variables, some of
13*02e95f1aSMarcin Radomski * which are static and inaccessible. This means only one thread can
14*02e95f1aSMarcin Radomski * use getopt(). It also means it's not possible to recursively parse
15*02e95f1aSMarcin Radomski * nested sub-arguments while in the middle of argument parsing.
16*02e95f1aSMarcin Radomski * Optparse fixes this by storing all state on a local struct.
17*02e95f1aSMarcin Radomski *
18*02e95f1aSMarcin Radomski * 2) The POSIX standard provides no way to properly reset the parser.
19*02e95f1aSMarcin Radomski * This means for portable code that getopt() is only good for one
20*02e95f1aSMarcin Radomski * run, over one argv with one option string. It also means subcommand
21*02e95f1aSMarcin Radomski * options cannot be processed with getopt(). Most implementations
22*02e95f1aSMarcin Radomski * provide a method to reset the parser, but it's not portable.
23*02e95f1aSMarcin Radomski * Optparse provides an optparse_arg() function for stepping over
24*02e95f1aSMarcin Radomski * subcommands and continuing parsing of options with another option
25*02e95f1aSMarcin Radomski * string. The Optparse struct itself can be passed around to
26*02e95f1aSMarcin Radomski * subcommand handlers for additional subcommand option parsing. A
27*02e95f1aSMarcin Radomski * full reset can be achieved by with an additional optparse_init().
28*02e95f1aSMarcin Radomski *
29*02e95f1aSMarcin Radomski * 3) Error messages are printed to stderr. This can be disabled with
30*02e95f1aSMarcin Radomski * opterr, but the messages themselves are still inaccessible.
31*02e95f1aSMarcin Radomski * Optparse solves this by writing an error message in its errmsg
32*02e95f1aSMarcin Radomski * field. The downside to Optparse is that this error message will
33*02e95f1aSMarcin Radomski * always be in English rather than the current locale.
34*02e95f1aSMarcin Radomski *
35*02e95f1aSMarcin Radomski * Optparse should be familiar with anyone accustomed to getopt(), and
36*02e95f1aSMarcin Radomski * it could be a nearly drop-in replacement. The option string is the
37*02e95f1aSMarcin Radomski * same and the fields have the same names as the getopt() global
38*02e95f1aSMarcin Radomski * variables (optarg, optind, optopt).
39*02e95f1aSMarcin Radomski *
40*02e95f1aSMarcin Radomski * Optparse also supports GNU-style long options with optparse_long().
41*02e95f1aSMarcin Radomski * The interface is slightly different and simpler than getopt_long().
42*02e95f1aSMarcin Radomski *
43*02e95f1aSMarcin Radomski * By default, argv is permuted as it is parsed, moving non-option
44*02e95f1aSMarcin Radomski * arguments to the end. This can be disabled by setting the `permute`
45*02e95f1aSMarcin Radomski * field to 0 after initialization.
46*02e95f1aSMarcin Radomski */
47*02e95f1aSMarcin Radomski #ifndef OPTPARSE_H
48*02e95f1aSMarcin Radomski #define OPTPARSE_H
49*02e95f1aSMarcin Radomski
50*02e95f1aSMarcin Radomski #ifndef OPTPARSE_API
51*02e95f1aSMarcin Radomski # define OPTPARSE_API
52*02e95f1aSMarcin Radomski #endif
53*02e95f1aSMarcin Radomski
54*02e95f1aSMarcin Radomski struct optparse {
55*02e95f1aSMarcin Radomski char **argv;
56*02e95f1aSMarcin Radomski int permute;
57*02e95f1aSMarcin Radomski int optind;
58*02e95f1aSMarcin Radomski int optopt;
59*02e95f1aSMarcin Radomski char *optarg;
60*02e95f1aSMarcin Radomski char errmsg[64];
61*02e95f1aSMarcin Radomski int subopt;
62*02e95f1aSMarcin Radomski };
63*02e95f1aSMarcin Radomski
64*02e95f1aSMarcin Radomski enum optparse_argtype {
65*02e95f1aSMarcin Radomski OPTPARSE_NONE,
66*02e95f1aSMarcin Radomski OPTPARSE_REQUIRED,
67*02e95f1aSMarcin Radomski OPTPARSE_OPTIONAL
68*02e95f1aSMarcin Radomski };
69*02e95f1aSMarcin Radomski
70*02e95f1aSMarcin Radomski struct optparse_long {
71*02e95f1aSMarcin Radomski const char *longname;
72*02e95f1aSMarcin Radomski int shortname;
73*02e95f1aSMarcin Radomski enum optparse_argtype argtype;
74*02e95f1aSMarcin Radomski };
75*02e95f1aSMarcin Radomski
76*02e95f1aSMarcin Radomski /**
77*02e95f1aSMarcin Radomski * Initializes the parser state.
78*02e95f1aSMarcin Radomski */
79*02e95f1aSMarcin Radomski OPTPARSE_API
80*02e95f1aSMarcin Radomski void optparse_init(struct optparse *options, char **argv);
81*02e95f1aSMarcin Radomski
82*02e95f1aSMarcin Radomski /**
83*02e95f1aSMarcin Radomski * Read the next option in the argv array.
84*02e95f1aSMarcin Radomski * @param optstring a getopt()-formatted option string.
85*02e95f1aSMarcin Radomski * @return the next option character, -1 for done, or '?' for error
86*02e95f1aSMarcin Radomski *
87*02e95f1aSMarcin Radomski * Just like getopt(), a character followed by no colons means no
88*02e95f1aSMarcin Radomski * argument. One colon means the option has a required argument. Two
89*02e95f1aSMarcin Radomski * colons means the option takes an optional argument.
90*02e95f1aSMarcin Radomski */
91*02e95f1aSMarcin Radomski OPTPARSE_API
92*02e95f1aSMarcin Radomski int optparse(struct optparse *options, const char *optstring);
93*02e95f1aSMarcin Radomski
94*02e95f1aSMarcin Radomski /**
95*02e95f1aSMarcin Radomski * Handles GNU-style long options in addition to getopt() options.
96*02e95f1aSMarcin Radomski * This works a lot like GNU's getopt_long(). The last option in
97*02e95f1aSMarcin Radomski * longopts must be all zeros, marking the end of the array. The
98*02e95f1aSMarcin Radomski * longindex argument may be NULL.
99*02e95f1aSMarcin Radomski */
100*02e95f1aSMarcin Radomski OPTPARSE_API
101*02e95f1aSMarcin Radomski int optparse_long(struct optparse *options,
102*02e95f1aSMarcin Radomski const struct optparse_long *longopts,
103*02e95f1aSMarcin Radomski int *longindex);
104*02e95f1aSMarcin Radomski
105*02e95f1aSMarcin Radomski /**
106*02e95f1aSMarcin Radomski * Used for stepping over non-option arguments.
107*02e95f1aSMarcin Radomski * @return the next non-option argument, or NULL for no more arguments
108*02e95f1aSMarcin Radomski *
109*02e95f1aSMarcin Radomski * Argument parsing can continue with optparse() after using this
110*02e95f1aSMarcin Radomski * function. That would be used to parse the options for the
111*02e95f1aSMarcin Radomski * subcommand returned by optparse_arg(). This function allows you to
112*02e95f1aSMarcin Radomski * ignore the value of optind.
113*02e95f1aSMarcin Radomski */
114*02e95f1aSMarcin Radomski OPTPARSE_API
115*02e95f1aSMarcin Radomski char *optparse_arg(struct optparse *options);
116*02e95f1aSMarcin Radomski
117*02e95f1aSMarcin Radomski /* Implementation */
118*02e95f1aSMarcin Radomski #ifdef OPTPARSE_IMPLEMENTATION
119*02e95f1aSMarcin Radomski
120*02e95f1aSMarcin Radomski #define OPTPARSE_MSG_INVALID "invalid option"
121*02e95f1aSMarcin Radomski #define OPTPARSE_MSG_MISSING "option requires an argument"
122*02e95f1aSMarcin Radomski #define OPTPARSE_MSG_TOOMANY "option takes no arguments"
123*02e95f1aSMarcin Radomski
124*02e95f1aSMarcin Radomski static int
optparse_error(struct optparse * options,const char * msg,const char * data)125*02e95f1aSMarcin Radomski optparse_error(struct optparse *options, const char *msg, const char *data)
126*02e95f1aSMarcin Radomski {
127*02e95f1aSMarcin Radomski unsigned p = 0;
128*02e95f1aSMarcin Radomski const char *sep = " -- '";
129*02e95f1aSMarcin Radomski while (*msg)
130*02e95f1aSMarcin Radomski options->errmsg[p++] = *msg++;
131*02e95f1aSMarcin Radomski while (*sep)
132*02e95f1aSMarcin Radomski options->errmsg[p++] = *sep++;
133*02e95f1aSMarcin Radomski while (p < sizeof(options->errmsg) - 2 && *data)
134*02e95f1aSMarcin Radomski options->errmsg[p++] = *data++;
135*02e95f1aSMarcin Radomski options->errmsg[p++] = '\'';
136*02e95f1aSMarcin Radomski options->errmsg[p++] = '\0';
137*02e95f1aSMarcin Radomski return '?';
138*02e95f1aSMarcin Radomski }
139*02e95f1aSMarcin Radomski
140*02e95f1aSMarcin Radomski OPTPARSE_API
141*02e95f1aSMarcin Radomski void
optparse_init(struct optparse * options,char ** argv)142*02e95f1aSMarcin Radomski optparse_init(struct optparse *options, char **argv)
143*02e95f1aSMarcin Radomski {
144*02e95f1aSMarcin Radomski options->argv = argv;
145*02e95f1aSMarcin Radomski options->permute = 1;
146*02e95f1aSMarcin Radomski options->optind = 1;
147*02e95f1aSMarcin Radomski options->subopt = 0;
148*02e95f1aSMarcin Radomski options->optarg = 0;
149*02e95f1aSMarcin Radomski options->errmsg[0] = '\0';
150*02e95f1aSMarcin Radomski }
151*02e95f1aSMarcin Radomski
152*02e95f1aSMarcin Radomski static int
optparse_is_dashdash(const char * arg)153*02e95f1aSMarcin Radomski optparse_is_dashdash(const char *arg)
154*02e95f1aSMarcin Radomski {
155*02e95f1aSMarcin Radomski return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
156*02e95f1aSMarcin Radomski }
157*02e95f1aSMarcin Radomski
158*02e95f1aSMarcin Radomski static int
optparse_is_shortopt(const char * arg)159*02e95f1aSMarcin Radomski optparse_is_shortopt(const char *arg)
160*02e95f1aSMarcin Radomski {
161*02e95f1aSMarcin Radomski return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
162*02e95f1aSMarcin Radomski }
163*02e95f1aSMarcin Radomski
164*02e95f1aSMarcin Radomski static int
optparse_is_longopt(const char * arg)165*02e95f1aSMarcin Radomski optparse_is_longopt(const char *arg)
166*02e95f1aSMarcin Radomski {
167*02e95f1aSMarcin Radomski return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
168*02e95f1aSMarcin Radomski }
169*02e95f1aSMarcin Radomski
170*02e95f1aSMarcin Radomski static void
optparse_permute(struct optparse * options,int index)171*02e95f1aSMarcin Radomski optparse_permute(struct optparse *options, int index)
172*02e95f1aSMarcin Radomski {
173*02e95f1aSMarcin Radomski char *nonoption = options->argv[index];
174*02e95f1aSMarcin Radomski int i;
175*02e95f1aSMarcin Radomski for (i = index; i < options->optind - 1; i++)
176*02e95f1aSMarcin Radomski options->argv[i] = options->argv[i + 1];
177*02e95f1aSMarcin Radomski options->argv[options->optind - 1] = nonoption;
178*02e95f1aSMarcin Radomski }
179*02e95f1aSMarcin Radomski
180*02e95f1aSMarcin Radomski static int
optparse_argtype(const char * optstring,char c)181*02e95f1aSMarcin Radomski optparse_argtype(const char *optstring, char c)
182*02e95f1aSMarcin Radomski {
183*02e95f1aSMarcin Radomski int count = OPTPARSE_NONE;
184*02e95f1aSMarcin Radomski if (c == ':')
185*02e95f1aSMarcin Radomski return -1;
186*02e95f1aSMarcin Radomski for (; *optstring && c != *optstring; optstring++);
187*02e95f1aSMarcin Radomski if (!*optstring)
188*02e95f1aSMarcin Radomski return -1;
189*02e95f1aSMarcin Radomski if (optstring[1] == ':')
190*02e95f1aSMarcin Radomski count += optstring[2] == ':' ? 2 : 1;
191*02e95f1aSMarcin Radomski return count;
192*02e95f1aSMarcin Radomski }
193*02e95f1aSMarcin Radomski
194*02e95f1aSMarcin Radomski OPTPARSE_API
195*02e95f1aSMarcin Radomski int
optparse(struct optparse * options,const char * optstring)196*02e95f1aSMarcin Radomski optparse(struct optparse *options, const char *optstring)
197*02e95f1aSMarcin Radomski {
198*02e95f1aSMarcin Radomski int type;
199*02e95f1aSMarcin Radomski char *next;
200*02e95f1aSMarcin Radomski char *option = options->argv[options->optind];
201*02e95f1aSMarcin Radomski options->errmsg[0] = '\0';
202*02e95f1aSMarcin Radomski options->optopt = 0;
203*02e95f1aSMarcin Radomski options->optarg = 0;
204*02e95f1aSMarcin Radomski if (option == 0) {
205*02e95f1aSMarcin Radomski return -1;
206*02e95f1aSMarcin Radomski } else if (optparse_is_dashdash(option)) {
207*02e95f1aSMarcin Radomski options->optind++; /* consume "--" */
208*02e95f1aSMarcin Radomski return -1;
209*02e95f1aSMarcin Radomski } else if (!optparse_is_shortopt(option)) {
210*02e95f1aSMarcin Radomski if (options->permute) {
211*02e95f1aSMarcin Radomski int index = options->optind++;
212*02e95f1aSMarcin Radomski int r = optparse(options, optstring);
213*02e95f1aSMarcin Radomski optparse_permute(options, index);
214*02e95f1aSMarcin Radomski options->optind--;
215*02e95f1aSMarcin Radomski return r;
216*02e95f1aSMarcin Radomski } else {
217*02e95f1aSMarcin Radomski return -1;
218*02e95f1aSMarcin Radomski }
219*02e95f1aSMarcin Radomski }
220*02e95f1aSMarcin Radomski option += options->subopt + 1;
221*02e95f1aSMarcin Radomski options->optopt = option[0];
222*02e95f1aSMarcin Radomski type = optparse_argtype(optstring, option[0]);
223*02e95f1aSMarcin Radomski next = options->argv[options->optind + 1];
224*02e95f1aSMarcin Radomski switch (type) {
225*02e95f1aSMarcin Radomski case -1: {
226*02e95f1aSMarcin Radomski char str[2] = {0, 0};
227*02e95f1aSMarcin Radomski str[0] = option[0];
228*02e95f1aSMarcin Radomski options->optind++;
229*02e95f1aSMarcin Radomski return optparse_error(options, OPTPARSE_MSG_INVALID, str);
230*02e95f1aSMarcin Radomski }
231*02e95f1aSMarcin Radomski case OPTPARSE_NONE:
232*02e95f1aSMarcin Radomski if (option[1]) {
233*02e95f1aSMarcin Radomski options->subopt++;
234*02e95f1aSMarcin Radomski } else {
235*02e95f1aSMarcin Radomski options->subopt = 0;
236*02e95f1aSMarcin Radomski options->optind++;
237*02e95f1aSMarcin Radomski }
238*02e95f1aSMarcin Radomski return option[0];
239*02e95f1aSMarcin Radomski case OPTPARSE_REQUIRED:
240*02e95f1aSMarcin Radomski options->subopt = 0;
241*02e95f1aSMarcin Radomski options->optind++;
242*02e95f1aSMarcin Radomski if (option[1]) {
243*02e95f1aSMarcin Radomski options->optarg = option + 1;
244*02e95f1aSMarcin Radomski } else if (next != 0) {
245*02e95f1aSMarcin Radomski options->optarg = next;
246*02e95f1aSMarcin Radomski options->optind++;
247*02e95f1aSMarcin Radomski } else {
248*02e95f1aSMarcin Radomski char str[2] = {0, 0};
249*02e95f1aSMarcin Radomski str[0] = option[0];
250*02e95f1aSMarcin Radomski options->optarg = 0;
251*02e95f1aSMarcin Radomski return optparse_error(options, OPTPARSE_MSG_MISSING, str);
252*02e95f1aSMarcin Radomski }
253*02e95f1aSMarcin Radomski return option[0];
254*02e95f1aSMarcin Radomski case OPTPARSE_OPTIONAL:
255*02e95f1aSMarcin Radomski options->subopt = 0;
256*02e95f1aSMarcin Radomski options->optind++;
257*02e95f1aSMarcin Radomski if (option[1])
258*02e95f1aSMarcin Radomski options->optarg = option + 1;
259*02e95f1aSMarcin Radomski else
260*02e95f1aSMarcin Radomski options->optarg = 0;
261*02e95f1aSMarcin Radomski return option[0];
262*02e95f1aSMarcin Radomski }
263*02e95f1aSMarcin Radomski return 0;
264*02e95f1aSMarcin Radomski }
265*02e95f1aSMarcin Radomski
266*02e95f1aSMarcin Radomski OPTPARSE_API
267*02e95f1aSMarcin Radomski char *
optparse_arg(struct optparse * options)268*02e95f1aSMarcin Radomski optparse_arg(struct optparse *options)
269*02e95f1aSMarcin Radomski {
270*02e95f1aSMarcin Radomski char *option = options->argv[options->optind];
271*02e95f1aSMarcin Radomski options->subopt = 0;
272*02e95f1aSMarcin Radomski if (option != 0)
273*02e95f1aSMarcin Radomski options->optind++;
274*02e95f1aSMarcin Radomski return option;
275*02e95f1aSMarcin Radomski }
276*02e95f1aSMarcin Radomski
277*02e95f1aSMarcin Radomski static int
optparse_longopts_end(const struct optparse_long * longopts,int i)278*02e95f1aSMarcin Radomski optparse_longopts_end(const struct optparse_long *longopts, int i)
279*02e95f1aSMarcin Radomski {
280*02e95f1aSMarcin Radomski return !longopts[i].longname && !longopts[i].shortname;
281*02e95f1aSMarcin Radomski }
282*02e95f1aSMarcin Radomski
283*02e95f1aSMarcin Radomski static void
optparse_from_long(const struct optparse_long * longopts,char * optstring)284*02e95f1aSMarcin Radomski optparse_from_long(const struct optparse_long *longopts, char *optstring)
285*02e95f1aSMarcin Radomski {
286*02e95f1aSMarcin Radomski char *p = optstring;
287*02e95f1aSMarcin Radomski int i;
288*02e95f1aSMarcin Radomski for (i = 0; !optparse_longopts_end(longopts, i); i++) {
289*02e95f1aSMarcin Radomski if (longopts[i].shortname) {
290*02e95f1aSMarcin Radomski int a;
291*02e95f1aSMarcin Radomski *p++ = longopts[i].shortname;
292*02e95f1aSMarcin Radomski for (a = 0; a < (int)longopts[i].argtype; a++)
293*02e95f1aSMarcin Radomski *p++ = ':';
294*02e95f1aSMarcin Radomski }
295*02e95f1aSMarcin Radomski }
296*02e95f1aSMarcin Radomski *p = '\0';
297*02e95f1aSMarcin Radomski }
298*02e95f1aSMarcin Radomski
299*02e95f1aSMarcin Radomski /* Unlike strcmp(), handles options containing "=". */
300*02e95f1aSMarcin Radomski static int
optparse_longopts_match(const char * longname,const char * option)301*02e95f1aSMarcin Radomski optparse_longopts_match(const char *longname, const char *option)
302*02e95f1aSMarcin Radomski {
303*02e95f1aSMarcin Radomski const char *a = option, *n = longname;
304*02e95f1aSMarcin Radomski if (longname == 0)
305*02e95f1aSMarcin Radomski return 0;
306*02e95f1aSMarcin Radomski for (; *a && *n && *a != '='; a++, n++)
307*02e95f1aSMarcin Radomski if (*a != *n)
308*02e95f1aSMarcin Radomski return 0;
309*02e95f1aSMarcin Radomski return *n == '\0' && (*a == '\0' || *a == '=');
310*02e95f1aSMarcin Radomski }
311*02e95f1aSMarcin Radomski
312*02e95f1aSMarcin Radomski /* Return the part after "=", or NULL. */
313*02e95f1aSMarcin Radomski static char *
optparse_longopts_arg(char * option)314*02e95f1aSMarcin Radomski optparse_longopts_arg(char *option)
315*02e95f1aSMarcin Radomski {
316*02e95f1aSMarcin Radomski for (; *option && *option != '='; option++);
317*02e95f1aSMarcin Radomski if (*option == '=')
318*02e95f1aSMarcin Radomski return option + 1;
319*02e95f1aSMarcin Radomski else
320*02e95f1aSMarcin Radomski return 0;
321*02e95f1aSMarcin Radomski }
322*02e95f1aSMarcin Radomski
323*02e95f1aSMarcin Radomski static int
optparse_long_fallback(struct optparse * options,const struct optparse_long * longopts,int * longindex)324*02e95f1aSMarcin Radomski optparse_long_fallback(struct optparse *options,
325*02e95f1aSMarcin Radomski const struct optparse_long *longopts,
326*02e95f1aSMarcin Radomski int *longindex)
327*02e95f1aSMarcin Radomski {
328*02e95f1aSMarcin Radomski int result;
329*02e95f1aSMarcin Radomski char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */
330*02e95f1aSMarcin Radomski optparse_from_long(longopts, optstring);
331*02e95f1aSMarcin Radomski result = optparse(options, optstring);
332*02e95f1aSMarcin Radomski if (longindex != 0) {
333*02e95f1aSMarcin Radomski *longindex = -1;
334*02e95f1aSMarcin Radomski if (result != -1) {
335*02e95f1aSMarcin Radomski int i;
336*02e95f1aSMarcin Radomski for (i = 0; !optparse_longopts_end(longopts, i); i++)
337*02e95f1aSMarcin Radomski if (longopts[i].shortname == options->optopt)
338*02e95f1aSMarcin Radomski *longindex = i;
339*02e95f1aSMarcin Radomski }
340*02e95f1aSMarcin Radomski }
341*02e95f1aSMarcin Radomski return result;
342*02e95f1aSMarcin Radomski }
343*02e95f1aSMarcin Radomski
344*02e95f1aSMarcin Radomski OPTPARSE_API
345*02e95f1aSMarcin Radomski int
optparse_long(struct optparse * options,const struct optparse_long * longopts,int * longindex)346*02e95f1aSMarcin Radomski optparse_long(struct optparse *options,
347*02e95f1aSMarcin Radomski const struct optparse_long *longopts,
348*02e95f1aSMarcin Radomski int *longindex)
349*02e95f1aSMarcin Radomski {
350*02e95f1aSMarcin Radomski int i;
351*02e95f1aSMarcin Radomski char *option = options->argv[options->optind];
352*02e95f1aSMarcin Radomski if (option == 0) {
353*02e95f1aSMarcin Radomski return -1;
354*02e95f1aSMarcin Radomski } else if (optparse_is_dashdash(option)) {
355*02e95f1aSMarcin Radomski options->optind++; /* consume "--" */
356*02e95f1aSMarcin Radomski return -1;
357*02e95f1aSMarcin Radomski } else if (optparse_is_shortopt(option)) {
358*02e95f1aSMarcin Radomski return optparse_long_fallback(options, longopts, longindex);
359*02e95f1aSMarcin Radomski } else if (!optparse_is_longopt(option)) {
360*02e95f1aSMarcin Radomski if (options->permute) {
361*02e95f1aSMarcin Radomski int index = options->optind++;
362*02e95f1aSMarcin Radomski int r = optparse_long(options, longopts, longindex);
363*02e95f1aSMarcin Radomski optparse_permute(options, index);
364*02e95f1aSMarcin Radomski options->optind--;
365*02e95f1aSMarcin Radomski return r;
366*02e95f1aSMarcin Radomski } else {
367*02e95f1aSMarcin Radomski return -1;
368*02e95f1aSMarcin Radomski }
369*02e95f1aSMarcin Radomski }
370*02e95f1aSMarcin Radomski
371*02e95f1aSMarcin Radomski /* Parse as long option. */
372*02e95f1aSMarcin Radomski options->errmsg[0] = '\0';
373*02e95f1aSMarcin Radomski options->optopt = 0;
374*02e95f1aSMarcin Radomski options->optarg = 0;
375*02e95f1aSMarcin Radomski option += 2; /* skip "--" */
376*02e95f1aSMarcin Radomski options->optind++;
377*02e95f1aSMarcin Radomski for (i = 0; !optparse_longopts_end(longopts, i); i++) {
378*02e95f1aSMarcin Radomski const char *name = longopts[i].longname;
379*02e95f1aSMarcin Radomski if (optparse_longopts_match(name, option)) {
380*02e95f1aSMarcin Radomski char *arg;
381*02e95f1aSMarcin Radomski if (longindex)
382*02e95f1aSMarcin Radomski *longindex = i;
383*02e95f1aSMarcin Radomski options->optopt = longopts[i].shortname;
384*02e95f1aSMarcin Radomski arg = optparse_longopts_arg(option);
385*02e95f1aSMarcin Radomski if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) {
386*02e95f1aSMarcin Radomski return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);
387*02e95f1aSMarcin Radomski } if (arg != 0) {
388*02e95f1aSMarcin Radomski options->optarg = arg;
389*02e95f1aSMarcin Radomski } else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
390*02e95f1aSMarcin Radomski options->optarg = options->argv[options->optind];
391*02e95f1aSMarcin Radomski if (options->optarg == 0)
392*02e95f1aSMarcin Radomski return optparse_error(options, OPTPARSE_MSG_MISSING, name);
393*02e95f1aSMarcin Radomski else
394*02e95f1aSMarcin Radomski options->optind++;
395*02e95f1aSMarcin Radomski }
396*02e95f1aSMarcin Radomski return options->optopt;
397*02e95f1aSMarcin Radomski }
398*02e95f1aSMarcin Radomski }
399*02e95f1aSMarcin Radomski return optparse_error(options, OPTPARSE_MSG_INVALID, option);
400*02e95f1aSMarcin Radomski }
401*02e95f1aSMarcin Radomski
402*02e95f1aSMarcin Radomski #endif /* OPTPARSE_IMPLEMENTATION */
403*02e95f1aSMarcin Radomski #endif /* OPTPARSE_H */
404