1 /* -*- related-file-name: "../include/lcdf/clp.h" -*- */
2 /* clp.c - Complete source code for CLP.
3  * This file is part of CLP, the command line parser package.
4  *
5  * Copyright (c) 1997-2005 Eddie Kohler, kohler@cs.ucla.edu
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, subject to the conditions
10  * listed in the Click LICENSE file, which is available in full at
11  * http://www.pdos.lcs.mit.edu/click/license.html. The conditions include: you
12  * must preserve this copyright notice, and you cannot mention the copyright
13  * holders in advertising related to the Software without their permission.
14  * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
15  * notice is a summary of the Click LICENSE file; the license in that file is
16  * legally binding. */
17 
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <lcdf/clp.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <assert.h>
26 #include <stdarg.h>
27 #include <ctype.h>
28 
29 /* By default, assume we have strtoul. */
30 #if !defined(HAVE_STRTOUL) && !defined(HAVE_CONFIG_H)
31 # define HAVE_STRTOUL 1
32 #endif
33 
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37 
38 /* Option types for Clp_SetOptionChar */
39 #define Clp_DoubledLong		(Clp_LongImplicit * 2)
40 
41 #define Clp_AnyArgument		(Clp_Mandatory | Clp_Optional)
42 
43 #define MAX_AMBIGUOUS_VALUES	4
44 
45 typedef struct {
46     Clp_ArgParseFunc func;
47     int flags;
48     void *thunk;
49 } Clp_ArgType;
50 
51 
52 typedef struct {
53     int pos;
54     int neg;
55 } Clp_LongMinMatch;
56 
57 
58 struct Clp_Internal {
59 
60     Clp_Option *opt;
61     Clp_LongMinMatch *long_min_match;
62     int nopt;
63 
64     Clp_ArgType *argtype;
65     int nargtype;
66 
67     const char * const *argv;
68     int argc;
69 
70     unsigned char option_class[256];
71     int both_short_and_long;
72 
73     char option_chars[3];
74     const char *text;
75 
76     const char *program_name;
77     void (*error_handler)(const char *);
78 
79     int is_short;
80     int whole_negated;		/* true if negated by an option character */
81     int could_be_short;
82 
83     int option_processing;
84 
85     int ambiguous;
86     int ambiguous_values[MAX_AMBIGUOUS_VALUES];
87 
88     Clp_Option *current_option;
89     int current_short;
90     int negated_by_no;
91 
92 };
93 
94 
95 struct Clp_ParserState {
96     const char * const *argv;
97     int argc;
98     char option_chars[3];
99     const char *text;
100     int is_short;
101     int whole_negated;
102 };
103 
104 
105 typedef struct Clp_StringList {
106     Clp_Option *items;
107     Clp_LongMinMatch *long_min_match;
108     int nitems;
109     int allow_int;
110     int nitems_invalid_report;
111 } Clp_StringList;
112 
113 
114 #define TEST(o, f)		(((o)->flags & (f)) != 0)
115 
116 
117 static int calculate_long_min_match(int, Clp_Option *, int, int, int);
118 
119 static int parse_string(Clp_Parser *, const char *, int, void *);
120 static int parse_int(Clp_Parser *, const char *, int, void *);
121 static int parse_bool(Clp_Parser *, const char *, int, void *);
122 static int parse_double(Clp_Parser *, const char *, int, void *);
123 static int parse_string_list(Clp_Parser *, const char *, int, void *);
124 
125 static int ambiguity_error(Clp_Parser *, int, int *, Clp_Option *,
126 			   const char *, const char *, ...);
127 
128 
129 /*******
130  * Clp_NewParser, etc.
131  **/
132 
133 static void
check_duplicated_short_options(Clp_Parser * clp,int nopt,Clp_Option * opt,int negated)134 check_duplicated_short_options(Clp_Parser *clp, int nopt, Clp_Option *opt, int negated)
135 {
136     int i;
137     int check[256];
138 
139     for (i = 0; i < 256; i++)
140 	check[i] = -1;
141 
142     for (i = 0; i < nopt; i++)
143 	if (opt[i].short_name > 0 && opt[i].short_name < 256
144 	    && (negated ? TEST(&opt[i], Clp_Negate)
145 		: !TEST(&opt[i], Clp_OnlyNegated))) {
146 	    int sh = opt[i].short_name;
147 	    if (check[sh] >= 0 && check[sh] != opt[i].option_id)
148 		Clp_OptionError(clp, "CLP internal error: more than 1 option has short name '%c'", sh);
149 	    check[sh] = opt[i].option_id;
150 	}
151 }
152 
153 Clp_Parser *
Clp_NewParser(int argc,const char * const * argv,int nopt,Clp_Option * opt)154 Clp_NewParser(int argc, const char * const *argv, int nopt, Clp_Option *opt)
155      /* Creates and returns a new Clp_Parser using the options in 'opt',
156 	or 0 on memory allocation failure */
157 {
158     int i;
159     Clp_Parser *clp = (Clp_Parser *)malloc(sizeof(Clp_Parser));
160     Clp_Internal *cli = (Clp_Internal *)malloc(sizeof(Clp_Internal));
161     Clp_LongMinMatch *lmm = (Clp_LongMinMatch *)malloc(sizeof(Clp_LongMinMatch) * nopt);
162     if (!clp || !cli || !lmm)
163 	goto failed;
164 
165     clp->internal = cli;
166     cli->long_min_match = lmm;
167 
168     /* Assign arguments (need to do this now so we can call Clp_OptionError) */
169     cli->argc = argc;
170     cli->argv = argv;
171     {
172 	const char *slash = strrchr(argv[0], '/');
173 	cli->program_name = slash ? slash + 1 : argv[0];
174     }
175     cli->error_handler = 0;
176 
177     /* Get rid of negative option_ids, which are internal to CLP */
178     for (i = 0; i < nopt; i++)
179 	if (opt[i].option_id < 0) {
180 	    Clp_OptionError(clp, "CLP internal error: option %d has negative option_id", i);
181 	    opt[i] = opt[nopt - 1];
182 	    nopt--;
183 	    i--;
184 	}
185 
186     /* Massage the options to make them usable */
187     for (i = 0; i < nopt; i++) {
188 	/* Enforce invariants */
189 	if (opt[i].arg_type <= 0)
190 	    opt[i].flags &= ~Clp_AnyArgument;
191 	if (opt[i].arg_type > 0 && !TEST(&opt[i], Clp_Optional))
192 	    opt[i].flags |= Clp_Mandatory;
193 
194 	/* Nonexistent short options have character 256. We know this won't
195 	   equal any character in an argument, even if characters are signed */
196 	if (opt[i].short_name <= 0 || opt[i].short_name > 255)
197 	    opt[i].short_name = 256;
198 
199 	/* Options that start with 'no-' should be changed to OnlyNegated */
200 	if (opt[i].long_name && strncmp(opt[i].long_name, "no-", 3) == 0) {
201 	    opt[i].long_name += 3;
202 	    opt[i].flags |= Clp_Negate | Clp_OnlyNegated;
203 	}
204     }
205 
206     /* Check for duplicated short options */
207     check_duplicated_short_options(clp, nopt, opt, 0);
208     check_duplicated_short_options(clp, nopt, opt, 1);
209 
210     /* Calculate long options' minimum unambiguous length */
211     for (i = 0; i < nopt; i++)
212 	if (opt[i].long_name && !TEST(&opt[i], Clp_OnlyNegated))
213 	    lmm[i].pos = calculate_long_min_match
214 		(nopt, opt, i, Clp_OnlyNegated, 0);
215     for (i = 0; i < nopt; i++)
216 	if (opt[i].long_name && TEST(&opt[i], Clp_Negate))
217 	    lmm[i].neg = calculate_long_min_match
218 		(nopt, opt, i, Clp_Negate, Clp_Negate);
219 
220     /* Set up clp->internal */
221     cli->opt = opt;
222     cli->nopt = nopt;
223 
224     cli->argtype = (Clp_ArgType *)malloc(sizeof(Clp_ArgType) * 5);
225     if (!cli->argtype)
226 	goto failed;
227     cli->nargtype = 5;
228 
229     for (i = 0; i < 256; i++)
230 	cli->option_class[i] = 0;
231     cli->option_class[(unsigned char) '-'] = Clp_Short;
232     cli->both_short_and_long = 0;
233 
234     cli->is_short = 0;
235     cli->whole_negated = 0;
236 
237     cli->option_processing = 1;
238     cli->current_option = 0;
239 
240     /* Add default type parsers */
241     Clp_AddType(clp, Clp_ArgString, 0, parse_string, 0);
242     Clp_AddType(clp, Clp_ArgStringNotOption, Clp_DisallowOptions, parse_string, 0);
243     Clp_AddType(clp, Clp_ArgInt, 0, parse_int, 0);
244     Clp_AddType(clp, Clp_ArgUnsigned, 0, parse_int, (void *)cli);
245     Clp_AddType(clp, Clp_ArgBool, 0, parse_bool, 0);
246     Clp_AddType(clp, Clp_ArgDouble, 0, parse_double, 0);
247     return clp;
248 
249   failed:
250     /* It should be OK to free(0), but on some ancient systems, it isn't */
251     if (cli && cli->argtype)
252 	free(cli->argtype);
253     if (cli)
254 	free(cli);
255     if (clp)
256 	free(clp);
257     if (lmm)
258 	free(lmm);
259     return 0;
260 }
261 
262 void
Clp_DeleteParser(Clp_Parser * clp)263 Clp_DeleteParser(Clp_Parser *clp)
264      /* Destroys the Clp_Parser 'clp' and any associated memory allocated by
265         CLP */
266 {
267     int i;
268     Clp_Internal *cli;
269     if (!clp)
270 	return;
271 
272     cli = clp->internal;
273 
274     /* get rid of any string list types */
275     for (i = 0; i < cli->nargtype; i++)
276 	if (cli->argtype[i].func == parse_string_list) {
277 	    Clp_StringList *clsl = (Clp_StringList *)cli->argtype[i].thunk;
278 	    free(clsl->items);
279 	    free(clsl->long_min_match);
280 	    free(clsl);
281 	}
282 
283     free(cli->argtype);
284     free(cli->long_min_match);
285     free(cli);
286     free(clp);
287 }
288 
289 int
Clp_SetOptionProcessing(Clp_Parser * clp,int option_processing)290 Clp_SetOptionProcessing(Clp_Parser *clp, int option_processing)
291      /* Sets whether command line arguments are parsed (looking for options)
292 	at all. Each parser starts out with OptionProcessing true. Returns old
293 	value. */
294 {
295     Clp_Internal *cli = clp->internal;
296     int old = cli->option_processing;
297     cli->option_processing = option_processing;
298     return old;
299 }
300 
301 Clp_ErrorHandler
Clp_SetErrorHandler(Clp_Parser * clp,void (* error_handler)(const char *))302 Clp_SetErrorHandler(Clp_Parser *clp, void (*error_handler)(const char *))
303      /* Sets a hook function to be called before Clp_OptionError
304 	prints anything. 0 means nothing will be called. */
305 {
306     Clp_Internal *cli = clp->internal;
307     Clp_ErrorHandler old = cli->error_handler;
308     cli->error_handler = error_handler;
309     return old;
310 }
311 
312 int
Clp_SetOptionChar(Clp_Parser * clp,int c,int option_type)313 Clp_SetOptionChar(Clp_Parser *clp, int c, int option_type)
314      /* Determines how clp will deal with short options.
315 	option_type must be a sum of:
316 
317 	0 == Clp_NotOption 'c' isn't an option.
318 	Clp_Short	'c' introduces a list of short options.
319 	Clp_Long	'c' introduces a long option.
320 	Clp_ShortNegated 'c' introduces a negated list of
321 			short options.
322 	Clp_LongNegated 'c' introduces a negated long option.
323 	Clp_LongImplicit 'c' introduces a long option, and *is part
324 			of the long option itself*.
325 
326 	Some values are not allowed (Clp_Long | Clp_LongNegated isn't allowed,
327 	for instance). c=0 means ALL characters are that type. Returns 0 on
328 	failure (you gave an illegal option_type), 1 on success. */
329 {
330     int i;
331     Clp_Internal *cli = clp->internal;
332 
333     if (option_type < 0
334 	|| option_type >= 2*Clp_LongImplicit
335 	|| ((option_type & Clp_Short) && (option_type & Clp_ShortNegated))
336 	|| ((option_type & Clp_Long) && (option_type & Clp_LongNegated))
337 	|| ((option_type & Clp_LongImplicit) && (option_type & (Clp_Short | Clp_ShortNegated | Clp_Long | Clp_LongNegated))))
338 	return 0;
339 
340     if (c == 0)
341 	for (i = 1; i < 256; i++)
342 	    cli->option_class[i] = option_type;
343     else
344 	cli->option_class[(unsigned char) c] = option_type;
345 
346     /* If an option character can introduce either short or long options, then
347        we need to fix up the long_min_match values. We may have set the
348        long_min_match for option 'abcde' to 1, if no other option starts
349        with 'a'. But if '-' can introduce either a short option or a long
350        option, AND a short option '-a' exists, then the long_min_match for
351        'abcde' must be set to 2! */
352     if (!cli->both_short_and_long) {
353 	int either_short = option_type & (Clp_Short | Clp_ShortNegated);
354 	int either_long = option_type & (Clp_Long | Clp_LongNegated);
355 	if (either_short && either_long) {
356 	    unsigned char have_short[257];
357 	    for (i = 0; i < 256; i++)
358 		have_short[i] = 0;
359 	    for (i = 0; i < cli->nopt; i++)
360 		have_short[cli->opt[i].short_name] = 1;
361 	    for (i = 0; i < cli->nopt; i++)
362 		if (cli->opt[i].long_name && cli->long_min_match[i].pos == 1) {
363 		    /* if '--Cxxxx's short name is '-C', keep long_min_match
364 		       == 1 */
365 		    unsigned char first = (unsigned char)cli->opt[i].long_name[0];
366 		    if (have_short[first] && first != cli->opt[i].short_name)
367 			cli->long_min_match[i].pos++;
368 		}
369 	    cli->both_short_and_long = 1;
370 	}
371     }
372 
373     return 1;
374 }
375 
376 const char *
Clp_ProgramName(Clp_Parser * clp)377 Clp_ProgramName(Clp_Parser *clp)
378 {
379     return clp->internal->program_name;
380 }
381 
382 void
Clp_SetProgramName(Clp_Parser * clp,const char * program_name)383 Clp_SetProgramName(Clp_Parser *clp, const char *program_name)
384 {
385     clp->internal->program_name = program_name;
386 }
387 
388 
389 /*******
390  * functions for Clp_Option lists
391  **/
392 
393 static int
min_different_chars(const char * s,const char * t)394 min_different_chars(const char *s, const char *t)
395      /* Returns the minimum number of characters required to distinguish
396 	s from t.
397 	If s is shorter than t, returns strlen(s). */
398 {
399     const char *sfirst = s;
400     while (*s && *t && *s == *t)
401 	s++, t++;
402     if (!*s)
403 	return s - sfirst;
404     else
405 	return s - sfirst + 1;
406 }
407 
408 static int
calculate_long_min_match(int nopt,Clp_Option * opt,int which,int flags,int flags_value)409 calculate_long_min_match(int nopt, Clp_Option *opt, int which,
410 			 int flags, int flags_value)
411 {
412     int j, lmm = 1;
413     int preferred = (opt[which].flags & Clp_PreferredMatch);
414 
415     for (j = 0; j < nopt; j++)
416 	if (opt[j].long_name
417 	    && (opt[j].flags & flags) == flags_value
418 	    && opt[which].option_id != opt[j].option_id
419 	    && strncmp(opt[which].long_name, opt[j].long_name, lmm) == 0
420 	    && (!preferred || strncmp(opt[which].long_name, opt[j].long_name, strlen(opt[which].long_name)) != 0))
421 	    lmm = min_different_chars(opt[which].long_name, opt[j].long_name);
422 
423     return lmm;
424 }
425 
426 /* the ever-glorious argcmp */
427 
428 static int
argcmp(const char * ref,const char * arg,int min_match,int fewer_dashes)429 argcmp(const char *ref, const char *arg, int min_match, int fewer_dashes)
430      /* Returns 0 if ref and arg don't match.
431 	Returns -1 if ref and arg match, but fewer than min_match characters.
432 	Returns len if ref and arg match min_match or more characters;
433 	len is the number of characters that matched in arg.
434 	Allows arg to contain fewer dashes than ref iff fewer_dashes != 0.
435 
436 	Examples:
437 	argcmp("x", "y", 1, 0)	-->  0	/ just plain wrong
438 	argcmp("a", "ax", 1, 0)	-->  0	/ ...even though min_match == 1
439 					and the 1st chars match
440 	argcmp("box", "bo", 3, 0) --> -1	/ ambiguous
441 	argcmp("cat", "c=3", 1, 0) -->  1	/ handles = arguments
442 	*/
443 {
444     const char *refstart = ref;
445     const char *argstart = arg;
446     assert(min_match > 0);
447 
448   compare:
449     while (*ref && *arg && *arg != '=' && *ref == *arg)
450 	ref++, arg++;
451 
452     /* Allow arg to contain fewer dashes than ref */
453     if (fewer_dashes && *ref == '-' && ref[1] && ref[1] == *arg) {
454 	ref++;
455 	goto compare;
456     }
457 
458     if (*arg && *arg != '=')
459 	return 0;
460     else if (ref - refstart < min_match)
461 	return -1;
462     else
463 	return arg - argstart;
464 }
465 
466 static int
find_prefix_opt(const char * arg,int nopt,Clp_Option * opt,Clp_LongMinMatch * lmmvec,int * ambiguous,int * ambiguous_values,int negated)467 find_prefix_opt(const char *arg, int nopt, Clp_Option *opt,
468 		Clp_LongMinMatch *lmmvec,
469 		int *ambiguous, int *ambiguous_values, int negated)
470      /* Looks for an unambiguous match of 'arg' against one of the long
471         options in 'opt'. Returns positive if it finds one; otherwise, returns
472         -1 and possibly changes 'ambiguous' and 'ambiguous_values' to keep
473         track of at most MAX_AMBIGUOUS_VALUES possibilities. */
474 {
475     int i, fewer_dashes = 0, first_ambiguous = *ambiguous;
476 
477   retry:
478     for (i = 0; i < nopt; i++) {
479 	int len, lmm;
480 	if (!opt[i].long_name
481 	    || (negated && !TEST(&opt[i], Clp_Negate))
482 	    || (!negated && TEST(&opt[i], Clp_OnlyNegated)))
483 	    continue;
484 
485 	lmm = (negated ? lmmvec[i].neg : lmmvec[i].pos);
486 	len = argcmp(opt[i].long_name, arg, lmm, fewer_dashes);
487 	if (len > 0)
488 	    return i;
489 	else if (len < 0) {
490 	    if (*ambiguous < MAX_AMBIGUOUS_VALUES)
491 		ambiguous_values[*ambiguous] = i;
492 	    (*ambiguous)++;
493 	}
494     }
495 
496     /* If there were no partial matches, try again with fewer_dashes true */
497     if (*ambiguous == first_ambiguous && !fewer_dashes) {
498 	fewer_dashes = 1;
499 	goto retry;
500     }
501 
502     return -1;
503 }
504 
505 
506 /*****
507  * Argument parsing
508  **/
509 
510 int
Clp_AddType(Clp_Parser * clp,int type_id,int flags,Clp_ArgParseFunc func,void * thunk)511 Clp_AddType(Clp_Parser *clp, int type_id, int flags,
512 	    Clp_ArgParseFunc func, void *thunk)
513      /* Add a argument parser for type_id to the Clp_Parser. When an argument
514 	arg for Clp_Option opt is being processed, the parser routines will
515 	call (*func)(clp, opt, arg, thunk, complain)
516 	where complain is 1 if the routine should report errors, or 0 if it
517 	should fail silently.
518 	Returns 1 on success, 0 if memory allocation fails or the arguments
519 	are bad. */
520 {
521     int i;
522     Clp_Internal *cli = clp->internal;
523     Clp_ArgType *new_argtype;
524     int nargtype = cli->nargtype;
525     assert(nargtype);
526 
527     if (type_id <= 0 || !func)
528 	return 0;
529 
530     while (nargtype <= type_id)
531 	nargtype *= 2;
532     new_argtype = (Clp_ArgType *)
533 	realloc(cli->argtype, sizeof(Clp_ArgType) * nargtype);
534     if (!new_argtype)
535 	return 0;
536     cli->argtype = new_argtype;
537 
538     for (i = cli->nargtype; i < nargtype; i++)
539 	cli->argtype[i].func = 0;
540     cli->nargtype = nargtype;
541 
542     cli->argtype[type_id].func = func;
543     cli->argtype[type_id].flags = flags;
544     cli->argtype[type_id].thunk = thunk;
545     return 1;
546 }
547 
548 
549 /*******
550  * Default argument parsers
551  **/
552 
553 static int
parse_string(Clp_Parser * clp,const char * arg,int complain,void * thunk)554 parse_string(Clp_Parser *clp, const char *arg, int complain, void *thunk)
555 {
556     (void)complain, (void)thunk;
557     clp->val.s = arg;
558     return 1;
559 }
560 
561 static int
parse_int(Clp_Parser * clp,const char * arg,int complain,void * thunk)562 parse_int(Clp_Parser *clp, const char *arg, int complain, void *thunk)
563 {
564     char *val;
565     int base = 10;
566     if (arg[0] == '0' && (arg[1] == 'x' || arg[1] == 'X')) {
567 	base = 16;
568 	arg += 2;
569     }
570 
571     if (thunk != 0) {		/* unsigned */
572 #if HAVE_STRTOUL
573 	clp->val.u = strtoul(arg, &val, base);
574 #else
575 	/* don't bother really trying to do it right */
576 	if (arg[0] == '-')
577 	    val = (char *) arg;
578 	else
579 	    clp->val.u = strtol(arg, &val, base);
580 #endif
581     } else
582 	clp->val.i = strtol(arg, &val, base);
583     if (*arg != 0 && *val == 0)
584 	return 1;
585     else if (complain) {
586 	const char *message = thunk != 0
587 	    ? "'%O' expects a nonnegative integer, not '%s'"
588 	    : "'%O' expects an integer, not '%s'";
589 	if (base == 16) arg -= 2;
590 	return Clp_OptionError(clp, message, arg);
591     } else
592 	return 0;
593 }
594 
595 static int
parse_double(Clp_Parser * clp,const char * arg,int complain,void * thunk)596 parse_double(Clp_Parser *clp, const char *arg, int complain, void *thunk)
597 {
598     char *val;
599     (void)thunk;
600     clp->val.d = strtod(arg, &val);
601     if (*arg != 0 && *val == 0)
602 	return 1;
603     else if (complain)
604 	return Clp_OptionError(clp, "'%O' expects a real number, not '%s'", arg);
605     else
606 	return 0;
607 }
608 
609 static int
parse_bool(Clp_Parser * clp,const char * arg,int complain,void * thunk)610 parse_bool(Clp_Parser *clp, const char *arg, int complain, void *thunk)
611 {
612     int i;
613     char lcarg[6];
614     (void)thunk;
615     if (strlen(arg) > 5 || strchr(arg, '=') != 0)
616 	goto error;
617 
618     for (i = 0; arg[i] != 0; i++)
619 	lcarg[i] = tolower(arg[i]);
620     lcarg[i] = 0;
621 
622     if (argcmp("yes", lcarg, 1, 0) > 0
623 	|| argcmp("true", lcarg, 1, 0) > 0
624 	|| argcmp("1", lcarg, 1, 0) > 0) {
625 	clp->val.i = 1;
626 	return 1;
627     } else if (argcmp("no", lcarg, 1, 0) > 0
628 	       || argcmp("false", lcarg, 1, 0) > 0
629 	       || argcmp("1", lcarg, 1, 0) > 0) {
630 	clp->val.i = 0;
631 	return 1;
632     }
633 
634   error:
635     if (complain)
636 	Clp_OptionError(clp, "'%O' expects a true-or-false value, not '%s'", arg);
637     return 0;
638 }
639 
640 
641 /*****
642  * Clp_AddStringListType
643  **/
644 
645 static int
parse_string_list(Clp_Parser * clp,const char * arg,int complain,void * thunk)646 parse_string_list(Clp_Parser *clp, const char *arg, int complain, void *thunk)
647 {
648     Clp_StringList *sl = (Clp_StringList *)thunk;
649     int idx, ambiguous = 0;
650     int ambiguous_values[MAX_AMBIGUOUS_VALUES + 1];
651 
652     /* actually look for a string value */
653     idx = find_prefix_opt
654 	(arg, sl->nitems, sl->items, sl->long_min_match,
655 	 &ambiguous, ambiguous_values, 0);
656     if (idx >= 0) {
657 	clp->val.i = sl->items[idx].option_id;
658 	return 1;
659     }
660 
661     if (sl->allow_int) {
662 	if (parse_int(clp, arg, 0, 0))
663 	    return 1;
664     }
665 
666     if (complain) {
667 	const char *complaint = (ambiguous ? "an ambiguous" : "not a valid");
668 	if (!ambiguous) {
669 	    ambiguous = sl->nitems_invalid_report;
670 	    for (idx = 0; idx < ambiguous; idx++)
671 		ambiguous_values[idx] = idx;
672 	}
673 	return ambiguity_error
674 	    (clp, ambiguous, ambiguous_values, sl->items, "",
675 	     "'%s' is %s argument to '%O'", arg, complaint);
676     } else
677 	return 0;
678 }
679 
680 
681 int
finish_string_list(Clp_Parser * clp,int type_id,int flags,Clp_Option * items,int nitems,int itemscap)682 finish_string_list(Clp_Parser *clp, int type_id, int flags,
683 		   Clp_Option *items, int nitems, int itemscap)
684 {
685     int i;
686     Clp_StringList *clsl = (Clp_StringList *)malloc(sizeof(Clp_StringList));
687     Clp_LongMinMatch *lmm = (Clp_LongMinMatch *)malloc(sizeof(Clp_LongMinMatch) * nitems);
688     if (!clsl || !lmm)
689 	goto error;
690 
691     clsl->items = items;
692     clsl->long_min_match = lmm;
693     clsl->nitems = nitems;
694     clsl->allow_int = (flags & Clp_AllowNumbers) != 0;
695 
696     if (nitems < MAX_AMBIGUOUS_VALUES && nitems < itemscap && clsl->allow_int) {
697 	items[nitems].long_name = "any integer";
698 	clsl->nitems_invalid_report = nitems + 1;
699     } else if (nitems > MAX_AMBIGUOUS_VALUES + 1)
700 	clsl->nitems_invalid_report = MAX_AMBIGUOUS_VALUES + 1;
701     else
702 	clsl->nitems_invalid_report = nitems;
703 
704     for (i = 0; i < nitems; i++)
705 	lmm[i].pos = calculate_long_min_match(nitems, items, i, 0, 0);
706 
707     if (Clp_AddType(clp, type_id, 0, parse_string_list, clsl))
708 	return 1;
709 
710   error:
711     if (clsl)
712 	free(clsl);
713     if (lmm)
714 	free(lmm);
715     return 0;
716 }
717 
718 int
Clp_AddStringListType(Clp_Parser * clp,int type_id,int flags,...)719 Clp_AddStringListType(Clp_Parser *clp, int type_id, int flags, ...)
720      /* An easy way to add new types to clp.
721 	Call like this:
722 	Clp_AddStringListType
723 	  (clp, type_id, flags,
724 	   char *s_1, int value_1, ..., char *s_n, int value_n, 0);
725 
726         Defines type_id as a type in clp.
727 	This type accepts any of the strings s_1, ..., s_n
728 	(or unambiguous abbreviations thereof);
729 	if argument s_i is given, value_i is stored in clp->val.i.
730 	If Clp_AllowNumbers is set in flags,
731 	explicit integers are also allowed.
732 
733 	Returns 1 on success, 0 on memory allocation errors. */
734 {
735     int nitems = 0;
736     int itemscap = 5;
737     Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap);
738 
739     va_list val;
740     va_start(val, flags);
741 
742     if (!items)
743 	goto error;
744 
745     /* slurp up the arguments */
746     while (1) {
747 	int value;
748 	char *name = va_arg(val, char *);
749 	if (!name)
750 	    break;
751 	value = va_arg(val, int);
752 
753 	if (nitems >= itemscap) {
754 	    Clp_Option *new_items;
755 	    itemscap *= 2;
756 	    new_items = (Clp_Option *)realloc(items, sizeof(Clp_Option) * itemscap);
757 	    if (!new_items)
758 		goto error;
759 	    items = new_items;
760 	}
761 
762 	items[nitems].long_name = name;
763 	items[nitems].option_id = value;
764 	items[nitems].flags = 0;
765 	nitems++;
766     }
767 
768     va_end(val);
769     if (finish_string_list(clp, type_id, flags, items, nitems, itemscap))
770 	return 1;
771 
772   error:
773     va_end(val);
774     if (items)
775 	free(items);
776     return 0;
777 }
778 
779 
780 int
Clp_AddStringListTypeVec(Clp_Parser * clp,int type_id,int flags,int nitems,char ** strings,int * values)781 Clp_AddStringListTypeVec(Clp_Parser *clp, int type_id, int flags,
782 			 int nitems, char **strings, int *values)
783      /* An alternate way to make a string list type. See Clp_AddStringListType
784 	for the basics; this coalesces the strings and values into two arrays,
785 	rather than spreading them out into a variable argument list. */
786 {
787     int i;
788     int itemscap = (nitems < 5 ? 5 : nitems);
789     Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap);
790     if (!items)
791 	return 0;
792 
793     /* copy over items */
794     for (i = 0; i < nitems; i++) {
795 	items[i].long_name = strings[i];
796 	items[i].option_id = values[i];
797 	items[i].flags = 0;
798     }
799 
800     if (finish_string_list(clp, type_id, flags, items, nitems, itemscap))
801 	return 1;
802     else {
803 	free(items);
804 	return 0;
805     }
806 }
807 
808 
809 /*******
810  * Returning information
811  **/
812 
813 Clp_Argv *
Clp_NewArgv(const char * str_in,int len)814 Clp_NewArgv(const char *str_in, int len)
815 {
816     int argcap = 32;
817     Clp_Argv *clp_argv = (Clp_Argv *)malloc(sizeof(Clp_Argv));
818     char *s, *end;
819 
820     if (!clp_argv)
821 	goto failed_all;
822     if (len < 0)
823 	len = strlen(str_in);
824     if (!(clp_argv->argv_buf = (char *)malloc(len + 1)))
825 	goto failed_argv_buf;
826     if (!(clp_argv->argv = (char **)malloc(sizeof(char *) * argcap)))
827 	goto failed_argv;
828     memcpy(clp_argv->argv_buf, str_in, len);
829     end = clp_argv->argv_buf + len;
830     *end = 0;
831 
832     /* Parse arguments */
833     s = clp_argv->argv_buf;
834     clp_argv->argc = 0;
835     while (1) {
836 	char *arg, *sout;
837 	int state;
838 	while (s < end && isspace((unsigned char) *s))
839 	    s++;
840 	if (s >= end)
841 	    break;
842 	/* Parse single argument */
843 	for (arg = sout = s, state = 0; s < end; s++) {
844 	    if (*s == '\'') {
845 		if (state == 0)
846 		    state = '\'';
847 		else if (state == '\'')
848 		    state = 0;
849 		else
850 		    *sout++ = *s;
851 	    } else if (*s == '\"') {
852 		if (state == 0)
853 		    state = '\"';
854 		else if (state == '\"')
855 		    state = 0;
856 		else
857 		    *sout++ = *s;
858 	    } else if (*s == '\\') {
859 		if (state == '\'' || s == end - 1)
860 		    *sout++ = *s;
861 		else
862 		    *sout++ = *++s;
863 	    } else if (isspace((unsigned char) *s)) {
864 		if (state == 0)
865 		    break;
866 		else
867 		    *sout++ = *s;
868 	    } else
869 		*sout++ = *s;
870 	}
871 	*sout = 0;
872 	s++;
873 	/* Store argument */
874 	if (clp_argv->argc < argcap - 2) {
875 	    argcap *= 2;
876 	    if (!(clp_argv->argv = (char **)realloc(clp_argv->argv, sizeof(char *) * argcap)))
877 		goto failed_argv;
878 	}
879 	clp_argv->argv[clp_argv->argc++] = arg;
880     }
881     clp_argv->argv[clp_argv->argc] = 0;	/* know we have space */
882 
883     return clp_argv;
884 
885   failed_argv:
886     free(clp_argv->argv_buf);
887   failed_argv_buf:
888     free(clp_argv);
889   failed_all:
890     return 0;
891 }
892 
893 void
Clp_DeleteArgv(Clp_Argv * clp_argv)894 Clp_DeleteArgv(Clp_Argv *clp_argv)
895 {
896     if (!clp_argv)
897 	return;
898     free(clp_argv->argv);
899     free(clp_argv->argv_buf);
900     free(clp_argv);
901 }
902 
903 
904 /******
905  * Clp_ParserStates
906  **/
907 
908 Clp_ParserState *
Clp_NewParserState(void)909 Clp_NewParserState(void)
910 {
911     return (Clp_ParserState *)malloc(sizeof(Clp_ParserState));
912 }
913 
914 void
Clp_DeleteParserState(Clp_ParserState * save)915 Clp_DeleteParserState(Clp_ParserState *save)
916 {
917     free(save);
918 }
919 
920 
921 void
Clp_SaveParser(Clp_Parser * clp,Clp_ParserState * save)922 Clp_SaveParser(Clp_Parser *clp, Clp_ParserState *save)
923      /* Saves parser position in save */
924 {
925     Clp_Internal *cli = clp->internal;
926     save->argv = cli->argv;
927     save->argc = cli->argc;
928     memcpy(save->option_chars, cli->option_chars, 3);
929     save->text = cli->text;
930     save->is_short = cli->is_short;
931     save->whole_negated = cli->whole_negated;
932 }
933 
934 
935 void
Clp_RestoreParser(Clp_Parser * clp,Clp_ParserState * save)936 Clp_RestoreParser(Clp_Parser *clp, Clp_ParserState *save)
937      /* Restores parser position from save */
938 {
939     Clp_Internal *cli = clp->internal;
940     cli->argv = save->argv;
941     cli->argc = save->argc;
942     memcpy(cli->option_chars, save->option_chars, 3);
943     cli->text = save->text;
944     cli->is_short = save->is_short;
945     cli->whole_negated = save->whole_negated;
946 }
947 
948 
949 /*******
950  * Clp_Next and its helpers
951  **/
952 
953 static void
set_option_text(Clp_Internal * cli,const char * text,int n_option_chars)954 set_option_text(Clp_Internal *cli, const char *text, int n_option_chars)
955 {
956     char *option_chars = cli->option_chars;
957     assert(n_option_chars < 3);
958 
959     while (n_option_chars-- > 0)
960 	*option_chars++ = *text++;
961     *option_chars = 0;
962 
963     cli->text = text;
964 }
965 
966 
967 static int
next_argument(Clp_Parser * clp,int want_argument)968 next_argument(Clp_Parser *clp, int want_argument)
969      /* Moves clp to the next argument.
970 	Returns 1 if it finds another option.
971 	Returns 0 if there aren't any more arguments.
972 	Returns 0, sets clp->have_arg = 1, and sets clp->arg to the argument
973 	if the next argument isn't an option.
974 	If want_argument > 0, it'll look for an argument.
975 	want_argument == 1: Accept arguments that start with Clp_NotOption
976 		or Clp_LongImplicit.
977 	want_argument == 2: Accept ALL arguments.
978 
979 	Where is the option stored when this returns?
980 	Well, cli->argv[0] holds the whole of the next command line argument.
981 	cli->option_chars holds a string: what characters began the option?
982 	It is generally "-" or "--".
983 	cli->text holds the text of the option:
984 	for short options, cli->text[0] is the relevant character;
985 	for long options, cli->text holds the rest of the option. */
986 {
987     Clp_Internal *cli = clp->internal;
988     const char *text;
989     int option_class;
990 
991     /* clear relevant flags */
992     clp->have_arg = 0;
993     clp->arg = 0;
994     cli->could_be_short = 0;
995 
996     /* if we're in a string of short options, move up one char in the string */
997     if (cli->is_short) {
998 	++cli->text;
999 	if (cli->text[0] == 0)
1000 	    cli->is_short = 0;
1001 	else if (want_argument > 0) {
1002 	    /* handle -O[=]argument case */
1003 	    clp->have_arg = 1;
1004 	    if (cli->text[0] == '=')
1005 		clp->arg = cli->text + 1;
1006 	    else
1007 		clp->arg = cli->text;
1008 	    cli->is_short = 0;
1009 	    return 0;
1010 	}
1011     }
1012 
1013     /* if in short options, we're all set */
1014     if (cli->is_short)
1015 	return 1;
1016 
1017     /** if not in short options, move to the next argument **/
1018     cli->whole_negated = 0;
1019     cli->text = 0;
1020 
1021     if (cli->argc <= 1)
1022 	return 0;
1023 
1024     cli->argc--;
1025     cli->argv++;
1026     text = cli->argv[0];
1027 
1028     if (want_argument > 1)
1029 	goto not_option;
1030 
1031     option_class = cli->option_class[(unsigned char)text[0]];
1032     if (text[0] == '-' && text[1] == '-')
1033 	option_class = Clp_DoubledLong;
1034 
1035     /* If this character could introduce either a short or a long option,
1036        try a long option first, but remember that short's a possibility for
1037        later. */
1038     if ((option_class & (Clp_Short | Clp_ShortNegated))
1039 	&& (option_class & (Clp_Long | Clp_LongNegated))) {
1040 	option_class &= ~(Clp_Short | Clp_ShortNegated);
1041 	if (text[1] != 0)
1042 	    cli->could_be_short = 1;
1043     }
1044 
1045     switch (option_class) {
1046 
1047       case Clp_Short:
1048 	cli->is_short = 1;
1049 	goto check_singleton;
1050 
1051       case Clp_ShortNegated:
1052 	cli->is_short = 1;
1053 	cli->whole_negated = 1;
1054 	goto check_singleton;
1055 
1056       case Clp_Long:
1057 	goto check_singleton;
1058 
1059       case Clp_LongNegated:
1060 	cli->whole_negated = 1;
1061 	goto check_singleton;
1062 
1063       check_singleton:
1064 	/* For options introduced with one character, option-char,
1065 	   '[option-char]' alone is NOT an option. */
1066 	if (text[1] == 0)
1067 	    goto not_option;
1068 	set_option_text(cli, text, 1);
1069 	break;
1070 
1071       case Clp_LongImplicit:
1072 	/* LongImplict: option_chars == "" (since all chars are part of the
1073 	   option); restore head -> text of option */
1074 	if (want_argument > 0)
1075 	    goto not_option;
1076 	set_option_text(cli, text, 0);
1077 	break;
1078 
1079       case Clp_DoubledLong:
1080 	set_option_text(cli, text, 2);
1081 	break;
1082 
1083       not_option:
1084       case Clp_NotOption:
1085 	cli->is_short = 0;
1086 	clp->have_arg = 1;
1087 	clp->arg = text;
1088 	return 0;
1089 
1090       default:
1091 	assert(0 /* CLP misconfiguration: bad option type */);
1092 
1093     }
1094 
1095     return 1;
1096 }
1097 
1098 
1099 static void
switch_to_short_argument(Clp_Parser * clp)1100 switch_to_short_argument(Clp_Parser *clp)
1101 {
1102     Clp_Internal *cli = clp->internal;
1103     const char *text = cli->argv[0];
1104     int option_class = cli->option_class[(unsigned char)text[0]];
1105     cli->is_short = 1;
1106     cli->whole_negated = (option_class & Clp_ShortNegated ? 1 : 0);
1107     set_option_text(cli, cli->argv[0], 1);
1108     assert(cli->could_be_short);
1109 }
1110 
1111 
1112 static Clp_Option *
find_long(Clp_Parser * clp,const char * arg)1113 find_long(Clp_Parser *clp, const char *arg)
1114      /* If arg corresponds to one of clp's options, finds that option &
1115 	returns it. If any argument is given after an = sign in arg, sets
1116 	clp->have_arg = 1 and clp->arg to that argument. Sets cli->ambiguous
1117 	to 1 iff there was no match because the argument was ambiguous. */
1118 {
1119     Clp_Internal *cli = clp->internal;
1120     int value, len, min_match;
1121     Clp_Option *opt = cli->opt;
1122     int first_negative_ambiguous;
1123 
1124     /* Look for a normal option. */
1125     value = find_prefix_opt
1126 	(arg, cli->nopt, opt, cli->long_min_match,
1127 	 &cli->ambiguous, cli->ambiguous_values, clp->negated);
1128     if (value >= 0)
1129 	goto worked;
1130 
1131     /* If we can't find it, look for a negated option. */
1132     /* I know this is silly, but it makes me happy to accept
1133        --no-no-option as a double negative synonym for --option. :) */
1134     first_negative_ambiguous = cli->ambiguous;
1135     while (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') {
1136 	arg += 3;
1137 	clp->negated = !clp->negated;
1138 	value = find_prefix_opt
1139 	    (arg, cli->nopt, opt, cli->long_min_match,
1140 	     &cli->ambiguous, cli->ambiguous_values, clp->negated);
1141 	if (value >= 0)
1142 	    goto worked;
1143     }
1144 
1145     /* No valid option was found; return 0. Mark the ambiguous values found
1146        through '--no' by making them negative. */
1147     {
1148 	int i, max = cli->ambiguous;
1149 	if (max > MAX_AMBIGUOUS_VALUES) max = MAX_AMBIGUOUS_VALUES;
1150 	for (i = first_negative_ambiguous; i < max; i++)
1151 	    cli->ambiguous_values[i] = -cli->ambiguous_values[i] - 1;
1152     }
1153     return 0;
1154 
1155   worked:
1156     min_match = (clp->negated ? cli->long_min_match[value].neg : cli->long_min_match[value].pos);
1157     len = argcmp(opt[value].long_name, arg, min_match, 1); /* XXX 1? */
1158     assert(len > 0);
1159     if (arg[len] == '=') {
1160 	clp->have_arg = 1;
1161 	clp->arg = arg + len + 1;
1162     }
1163     return &opt[value];
1164 }
1165 
1166 
1167 static Clp_Option *
find_short(Clp_Parser * clp,int short_name)1168 find_short(Clp_Parser *clp, int short_name)
1169      /* If short_name corresponds to one of clp's options, returns it. */
1170 {
1171     Clp_Internal *cli = clp->internal;
1172     Clp_Option *opt = cli->opt;
1173     int i;
1174 
1175     for (i = 0; i < cli->nopt; i++)
1176 	if (opt[i].short_name == short_name
1177 	    && (clp->negated
1178 		? TEST(&opt[i], Clp_Negate)
1179 		: !TEST(&opt[i], Clp_OnlyNegated)))
1180 	    return &opt[i];
1181 
1182     return 0;
1183 }
1184 
1185 
1186 int
Clp_Next(Clp_Parser * clp)1187 Clp_Next(Clp_Parser *clp)
1188      /* Gets and parses the next argument from the argument list.
1189 
1190         If there are no more arguments, returns Clp_Done.
1191 	If the next argument isn't an option, returns Clp_NotOption;
1192 	the argument is stored in clp->arg.
1193 	If the next argument is an option, returns that option's option_id.
1194 
1195 	If the next argument is an unrecognizable or ambiguous option,
1196 	an error message is given and Clp_BadOption is returned.
1197 
1198 	If an option has an argument, that argument is stored in clp->arg
1199 	and clp->have_arg is set to 1.
1200 	Furthermore, that argument's parsed value (according to its type)
1201 	is stored in the clp->val union.
1202 
1203 	If an option needs an argument but isn't given one;
1204 	if it doesn't need an argument but IS given one;
1205 	or if the argument is the wrong type,
1206 	an error message is given and Clp_BadOption is returned. */
1207 {
1208     Clp_Internal *cli = clp->internal;
1209     Clp_Option *opt;
1210     Clp_ParserState clpsave;
1211     int complain;
1212 
1213     /** Set up clp **/
1214     cli->current_option = 0;
1215     cli->ambiguous = 0;
1216 
1217     /** Get the next argument or option **/
1218     if (!next_argument(clp, cli->option_processing ? 0 : 2))
1219 	return clp->have_arg ? Clp_NotOption : Clp_Done;
1220 
1221     clp->negated = cli->whole_negated;
1222     if (cli->is_short)
1223 	opt = find_short(clp, cli->text[0]);
1224     else
1225 	opt = find_long(clp, cli->text);
1226 
1227     /** If there's ambiguity between long & short options, and we couldn't
1228 	find a long option, look for a short option **/
1229     if (!opt && cli->could_be_short) {
1230 	switch_to_short_argument(clp);
1231 	opt = find_short(clp, cli->text[0]);
1232     }
1233 
1234     /** If we didn't find an option... **/
1235     if (!opt || (clp->negated && !TEST(opt, Clp_Negate))) {
1236 
1237 	/* default processing for the "--" option: turn off option processing
1238 	   and return the next argument */
1239 	if (strcmp(cli->argv[0], "--") == 0) {
1240 	    Clp_SetOptionProcessing(clp, 0);
1241 	    return Clp_Next(clp);
1242 	}
1243 
1244 	/* otherwise, report some error or other */
1245 	if (cli->ambiguous)
1246 	    ambiguity_error(clp, cli->ambiguous, cli->ambiguous_values,
1247 			    cli->opt, cli->option_chars,
1248 			    "option '%s%s' is ambiguous",
1249 			    cli->option_chars, cli->text);
1250 	else if (cli->is_short && !cli->could_be_short)
1251 	    Clp_OptionError(clp, "unrecognized option '%s%c'",
1252 			    cli->option_chars, cli->text[0]);
1253 	else
1254 	    Clp_OptionError(clp, "unrecognized option '%s%s'",
1255 			    cli->option_chars, cli->text);
1256 	return Clp_BadOption;
1257     }
1258 
1259     /** Set the current option **/
1260     cli->current_option = opt;
1261     cli->current_short = cli->is_short;
1262     cli->negated_by_no = clp->negated && !cli->whole_negated;
1263 
1264     /** The no-argument (or should-have-no-argument) case **/
1265     if (clp->negated || !TEST(opt, Clp_AnyArgument)) {
1266 	if (clp->have_arg) {
1267 	    Clp_OptionError(clp, "'%O' can't take an argument");
1268 	    return Clp_BadOption;
1269 	} else
1270 	    return opt->option_id;
1271     }
1272 
1273     /** Get an argument if we need one, or if it's optional **/
1274     /* Sanity-check the argument type. */
1275     if (opt->arg_type <= 0 || opt->arg_type >= cli->nargtype
1276 	|| cli->argtype[ opt->arg_type ].func == 0)
1277 	return Clp_Error;
1278 
1279     /* complain == 1 only if the argument was explicitly given,
1280        or it is mandatory. */
1281     complain = (clp->have_arg != 0) || TEST(opt, Clp_Mandatory);
1282     Clp_SaveParser(clp, &clpsave);
1283 
1284     if (TEST(opt, Clp_Mandatory) && !clp->have_arg) {
1285 	/* Mandatory argument case */
1286 	/* Allow arguments to options to start with a dash, but only if the
1287 	   argument type allows it by not setting Clp_DisallowOptions */
1288 	int disallow = TEST(&cli->argtype[opt->arg_type], Clp_DisallowOptions);
1289 	next_argument(clp, disallow ? 1 : 2);
1290 	if (!clp->have_arg) {
1291 	    int got_option = cli->text != 0;
1292 	    Clp_RestoreParser(clp, &clpsave);
1293 	    if (got_option)
1294 		Clp_OptionError(clp, "'%O' requires a non-option argument");
1295 	    else
1296 		Clp_OptionError(clp, "'%O' requires an argument");
1297 	    return Clp_BadOption;
1298 	}
1299 
1300     } else if (cli->is_short && !clp->have_arg && cli->text[1] != 0)
1301 	/* The -[option]argument case:
1302 	   Assume that the rest of the current string is the argument. */
1303 	next_argument(clp, 1);
1304 
1305     /** Parse the argument **/
1306     if (clp->have_arg) {
1307 	Clp_ArgType *atr = &cli->argtype[ opt->arg_type ];
1308 	if (atr->func(clp, clp->arg, complain, atr->thunk) <= 0) {
1309 	    /* parser failed */
1310 	    clp->have_arg = 0;
1311 	    if (TEST(opt, Clp_Mandatory))
1312 		return Clp_BadOption;
1313 	    else
1314 		Clp_RestoreParser(clp, &clpsave);
1315 	}
1316     }
1317 
1318     return opt->option_id;
1319 }
1320 
1321 
1322 const char *
Clp_Shift(Clp_Parser * clp,int allow_dashes)1323 Clp_Shift(Clp_Parser *clp, int allow_dashes)
1324      /* Returns the next argument from the argument list without parsing it.
1325         If there are no more arguments, returns 0. */
1326 {
1327     Clp_ParserState clpsave;
1328     Clp_SaveParser(clp, &clpsave);
1329     next_argument(clp, allow_dashes ? 2 : 1);
1330     if (!clp->have_arg)
1331 	Clp_RestoreParser(clp, &clpsave);
1332     return clp->arg;
1333 }
1334 
1335 
1336 /*******
1337  * Clp_OptionError
1338  **/
1339 
1340 typedef struct Clp_BuildString {
1341     char *text;
1342     char *pos;
1343     int capacity;
1344     int bad;
1345 } Clp_BuildString;
1346 
1347 static Clp_BuildString *
new_build_string(void)1348 new_build_string(void)
1349 {
1350     Clp_BuildString *bs = (Clp_BuildString *)malloc(sizeof(Clp_BuildString));
1351     if (!bs) goto bad;
1352     bs->text = (char *)malloc(256);
1353     if (!bs->text) goto bad;
1354     bs->pos = bs->text;
1355     bs->capacity = 256;
1356     bs->bad = 0;
1357     return bs;
1358 
1359   bad:
1360     if (bs) free(bs);
1361     return 0;
1362 }
1363 
1364 static void
free_build_string(Clp_BuildString * bs)1365 free_build_string(Clp_BuildString *bs)
1366 {
1367     if (bs) free(bs->text);
1368     free(bs);
1369 }
1370 
1371 static int
grow_build_string(Clp_BuildString * bs,int want)1372 grow_build_string(Clp_BuildString *bs, int want)
1373 {
1374     char *new_text;
1375     int ipos = bs->pos - bs->text;
1376     int new_capacity = bs->capacity;
1377     while (want >= new_capacity)
1378 	new_capacity *= 2;
1379     new_text = (char *)realloc(bs->text, new_capacity);
1380     if (!new_text) {
1381 	bs->bad = 1;
1382 	return 0;
1383     } else {
1384 	bs->text = new_text;
1385 	bs->pos = bs->text + ipos;
1386 	bs->capacity = new_capacity;
1387 	return 1;
1388     }
1389 }
1390 
1391 #define ENSURE_BUILD_STRING(bs, space) \
1392   ((((bs)->pos - (bs)->text) + (space) >= (bs)->capacity)		\
1393    || grow_build_string((bs), ((bs)->pos - (bs)->text) + (space)))
1394 
1395 static void
append_build_string(Clp_BuildString * bs,const char * s,int l)1396 append_build_string(Clp_BuildString *bs, const char *s, int l)
1397 {
1398     if (l < 0)
1399 	l = strlen(s);
1400     if (ENSURE_BUILD_STRING(bs, l)) {
1401 	memcpy(bs->pos, s, l);
1402 	bs->pos += l;
1403     }
1404 }
1405 
1406 
1407 static Clp_BuildString *
Clp_VaOptionError(Clp_Parser * clp,Clp_BuildString * bs,const char * fmt,va_list val)1408 Clp_VaOptionError(Clp_Parser *clp, Clp_BuildString *bs,
1409 		  const char *fmt, va_list val)
1410      /* Reports an error for parser clp. Allowable % format characters are:
1411 
1412 	s	Print a string from the argument list.
1413 	c	Print an int from the argument list as a character.
1414 	d	Print an int from the argument list.
1415 	O	Print the name of the current option;
1416 		take nothing from the argument list.
1417 
1418 	No field specifications or flags are allowed. Always returns 0. */
1419 {
1420     Clp_Internal *cli = clp->internal;
1421     const char *percent;
1422 
1423     if (!bs)
1424 	bs = new_build_string();
1425     if (!bs)
1426 	return 0;
1427     append_build_string(bs, cli->program_name, -1);
1428     append_build_string(bs, ": ", 2);
1429 
1430     for (percent = strchr(fmt, '%'); percent; percent = strchr(fmt, '%')) {
1431 	append_build_string(bs, fmt, percent - fmt);
1432 	switch (*++percent) {
1433 
1434 	  case 's': {
1435 	      char *s = va_arg(val, char *);
1436 	      if (s) append_build_string(bs, s, -1);
1437 	      else append_build_string(bs, "(null)", 6);
1438 	      break;
1439 	  }
1440 
1441 	  case 'c': {
1442 	      int c = va_arg(val, int);
1443 	      if (ENSURE_BUILD_STRING(bs, 4)) {
1444 		  if (c >= 32 && c <= 126)
1445 		      *bs->pos++ = c;
1446 		  else if (c < 32) {
1447 		      *bs->pos++ = '^';
1448 		      *bs->pos++ = c + 64;
1449 		  } else {
1450 		      sprintf(bs->pos, "\\%03o", c);
1451 		      bs->pos += 4;
1452 		  }
1453 	      }
1454 	      break;
1455 	  }
1456 
1457 	  case 'd': {
1458 	      int d = va_arg(val, int);
1459 	      if (ENSURE_BUILD_STRING(bs, 32)) {
1460 		  sprintf(bs->pos, "%d", d);
1461 		  bs->pos = strchr(bs->pos, 0);
1462 	      }
1463 	      break;
1464 	  }
1465 
1466 	  case 'O': {
1467 	      Clp_Option *opt = cli->current_option;
1468 	      if (!opt)
1469 		  append_build_string(bs, "(no current option!)", -1);
1470 	      else if (cli->current_short) {
1471 		  append_build_string(bs, cli->option_chars, -1);
1472 		  if (ENSURE_BUILD_STRING(bs, 1))
1473 		      *bs->pos++ = opt->short_name;
1474 	      } else if (cli->negated_by_no) {
1475 		  append_build_string(bs, cli->option_chars, -1);
1476 		  append_build_string(bs, "no-", 3);
1477 		  append_build_string(bs, opt->long_name, -1);
1478 	      } else {
1479 		  append_build_string(bs, cli->option_chars, -1);
1480 		  append_build_string(bs, opt->long_name, -1);
1481 	      }
1482 	      break;
1483 	  }
1484 
1485 	  case '%':
1486 	    if (ENSURE_BUILD_STRING(bs, 1))
1487 		*bs->pos++ = '%';
1488 	    break;
1489 
1490 	  default:
1491 	    if (ENSURE_BUILD_STRING(bs, 2)) {
1492 		*bs->pos++ = '%';
1493 		*bs->pos++ = *percent;
1494 	    }
1495 	    break;
1496 
1497 	}
1498 	fmt = ++percent;
1499     }
1500 
1501     append_build_string(bs, fmt, -1);
1502     append_build_string(bs, "\n", 1);
1503 
1504     return bs;
1505 }
1506 
1507 static void
do_error(Clp_Parser * clp,Clp_BuildString * bs)1508 do_error(Clp_Parser *clp, Clp_BuildString *bs)
1509 {
1510     const char *text;
1511     if (bs && !bs->bad) {
1512 	*bs->pos = 0;
1513 	text = bs->text;
1514     } else
1515 	text = "out of memory\n";
1516 
1517     if (clp->internal->error_handler != 0)
1518 	(*clp->internal->error_handler)(text);
1519     else
1520 	fputs(text, stderr);
1521 }
1522 
1523 int
Clp_OptionError(Clp_Parser * clp,const char * fmt,...)1524 Clp_OptionError(Clp_Parser *clp, const char *fmt, ...)
1525 {
1526     Clp_BuildString *bs;
1527     va_list val;
1528     va_start(val, fmt);
1529     bs = Clp_VaOptionError(clp, 0, fmt, val);
1530     va_end(val);
1531     do_error(clp, bs);
1532     free_build_string(bs);
1533     return 0;
1534 }
1535 
1536 static int
ambiguity_error(Clp_Parser * clp,int ambiguous,int * ambiguous_values,Clp_Option * opt,const char * prefix,const char * fmt,...)1537 ambiguity_error(Clp_Parser *clp, int ambiguous, int *ambiguous_values,
1538 		Clp_Option *opt, const char *prefix,
1539 		const char *fmt, ...)
1540 {
1541     Clp_BuildString *bs;
1542     int i;
1543     va_list val;
1544     va_start(val, fmt);
1545     bs = Clp_VaOptionError(clp, 0, fmt, val);
1546     if (!bs) goto done;
1547 
1548     append_build_string(bs, clp->internal->program_name, -1);
1549     append_build_string(bs, ": (Possibilities are", -1);
1550 
1551     for (i = 0; i < ambiguous && i < MAX_AMBIGUOUS_VALUES; i++) {
1552 	int value = ambiguous_values[i];
1553 	const char *no_dash = "";
1554 	if (value < 0)
1555 	    value = -(value + 1), no_dash = "no-";
1556 	if (i == 0)
1557 	    append_build_string(bs, " ", 1);
1558 	else if (i == ambiguous - 1)
1559 	    append_build_string(bs, (i == 1 ? " and " : ", and "), -1);
1560 	else
1561 	    append_build_string(bs, ", ", 2);
1562 	append_build_string(bs, prefix, -1);
1563 	append_build_string(bs, no_dash, -1);
1564 	append_build_string(bs, opt[value].long_name, -1);
1565     }
1566 
1567     if (ambiguous > MAX_AMBIGUOUS_VALUES)
1568 	append_build_string(bs, ", and others", -1);
1569     append_build_string(bs, ".)\n", -1);
1570     va_end(val);
1571 
1572   done:
1573     do_error(clp, bs);
1574     free_build_string(bs);
1575     return 0;
1576 }
1577 
1578 static int
copy_string(char * buf,int buflen,int bufpos,const char * what)1579 copy_string(char *buf, int buflen, int bufpos, const char *what)
1580 {
1581     int l = strlen(what);
1582     if (l > buflen - bufpos - 1)
1583 	l = buflen - bufpos - 1;
1584     memcpy(buf + bufpos, what, l);
1585     return l;
1586 }
1587 
1588 int
Clp_CurOptionNameBuf(Clp_Parser * clp,char * buf,int buflen)1589 Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int buflen)
1590 {
1591     Clp_Internal *cli = clp->internal;
1592     Clp_Option *opt = cli->current_option;
1593     int pos = 0;
1594     if (!opt)
1595 	pos += copy_string(buf, buflen, pos, "(no current option!)");
1596     else if (cli->current_short) {
1597 	pos += copy_string(buf, buflen, pos, cli->option_chars);
1598 	if (pos < buflen - 1)
1599 	    buf[pos++] = opt->short_name;
1600     } else if (cli->negated_by_no) {
1601 	pos += copy_string(buf, buflen, pos, cli->option_chars);
1602 	pos += copy_string(buf, buflen, pos, "no-");
1603 	pos += copy_string(buf, buflen, pos, opt->long_name);
1604     } else {
1605 	pos += copy_string(buf, buflen, pos, cli->option_chars);
1606 	pos += copy_string(buf, buflen, pos, opt->long_name);
1607     }
1608     buf[pos] = 0;
1609     return pos;
1610 }
1611 
1612 const char *
Clp_CurOptionName(Clp_Parser * clp)1613 Clp_CurOptionName(Clp_Parser *clp)
1614 {
1615     static char buf[256];
1616     Clp_CurOptionNameBuf(clp, buf, 256);
1617     return buf;
1618 }
1619 
1620 #ifdef __cplusplus
1621 }
1622 #endif
1623