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