summaryrefslogtreecommitdiff
path: root/Build/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c')
-rw-r--r--Build/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c2359
1 files changed, 0 insertions, 2359 deletions
diff --git a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c b/Build/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c
deleted file mode 100644
index 1555f2298d4..00000000000
--- a/Build/source/texk/lcdf-typetools/lcdf-typetools-src/liblcdf/clp.c
+++ /dev/null
@@ -1,2359 +0,0 @@
-/* -*- related-file-name: "../include/lcdf/clp.h" -*- */
-/* clp.c - Complete source code for CLP.
- * This file is part of CLP, the command line parser package.
- *
- * Copyright (c) 1997-2019 Eddie Kohler, ekohler@gmail.com
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, subject to the conditions
- * listed in the Click LICENSE file, which is available in full at
- * http://www.pdos.lcs.mit.edu/click/license.html. The conditions include: you
- * must preserve this copyright notice, and you cannot mention the copyright
- * holders in advertising related to the Software without their permission.
- * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
- * notice is a summary of the Click LICENSE file; the license in that file is
- * legally binding. */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-#include <lcdf/clp.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <assert.h>
-#include <stdarg.h>
-#include <ctype.h>
-
-/* By default, assume we have strtoul. */
-#if !defined(HAVE_STRTOUL) && !defined(HAVE_CONFIG_H)
-# define HAVE_STRTOUL 1
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/** @file clp.h
- * @brief Functions for parsing command line options.
- *
- * The CLP functions are used to parse command line arugments into options.
- * It automatically handles value parsing, error messages, long options with
- * minimum prefix matching, short options, and negated options.
- *
- * The CLP model works like this.
- *
- * <ol>
- * <li>The user declares an array of Clp_Option structures that define the
- * options their program accepts.</li>
- * <li>The user creates a Clp_Parser object using Clp_NewParser(), passing in
- * the command line arguments to parse and the Clp_Option structures.</li>
- * <li>A loop repeatedly calls Clp_Next() to parse the arguments.</li>
- * </ol>
- *
- * Unlike many command line parsing libraries, CLP steps through all arguments
- * one at a time, rather than slurping up all options at once. This makes it
- * meaningful to give an option more than once.
- *
- * Here's an example.
- *
- * @code
- * #define ANIMAL_OPT 1
- * #define VEGETABLE_OPT 2
- * #define MINERALS_OPT 3
- * #define USAGE_OPT 4
- *
- * static const Clp_Option options[] = {
- * { "animal", 'a', ANIMAL_OPT, Clp_ValString, 0 },
- * { "vegetable", 'v', VEGETABLE_OPT, Clp_ValString, Clp_Negate | Clp_Optional },
- * { "minerals", 'm', MINERALS_OPT, Clp_ValInt, 0 },
- * { "usage", 0, USAGE_OPT, 0, 0 }
- * };
- *
- * int main(int argc, char *argv[]) {
- * Clp_Parser *clp = Clp_NewParser(argc, argv,
- * sizeof(options) / sizeof(options[0]), options);
- * int opt;
- * while ((opt = Clp_Next(clp)) != Clp_Done)
- * switch (opt) {
- * case ANIMAL_OPT:
- * fprintf(stderr, "animal is %s\n", clp->val.s);
- * break;
- * case VEGETABLE_OPT:
- * if (clp->negated)
- * fprintf(stderr, "no vegetables!\n");
- * else if (clp->have_val)
- * fprintf(stderr, "vegetable is %s\n", clp->val.s);
- * else
- * fprintf(stderr, "vegetables OK\n");
- * break;
- * case MINERALS_OPT:
- * fprintf(stderr, "%d minerals\n", clp->val.i);
- * break;
- * case USAGE_OPT:
- * fprintf(stderr, "Usage: 20q [--animal=ANIMAL] [--vegetable[=VEGETABLE]] [--minerals=N]\n");
- * break;
- * case Clp_NotOption:
- * fprintf(stderr, "non-option %s\n", clp->vstr);
- * break;
- * }
- * }
- * }
- * @endcode
- *
- * Here are a couple of executions.
- *
- * <pre>
- * % ./20q --animal=cat
- * animal is cat
- * % ./20q --animal=cat -a dog -afish --animal bird --an=snake
- * animal is cat
- * animal is dog
- * animal is fish
- * animal is bird
- * animal is snake
- * % ./20q --no-vegetables
- * no vegetables!
- * % ./20q -v
- * vegetables OK
- * % ./20q -vkale
- * vegetable is kale
- * % ./20q -m10
- * 10 minerals
- * % ./20q -m foo
- * '-m' expects an integer, not 'foo'
- * </pre>
- */
-
-
-/* Option types for Clp_SetOptionChar */
-#define Clp_DoubledLong (Clp_LongImplicit * 2)
-
-#define Clp_InitialValType 8
-#define MAX_AMBIGUOUS_VALUES 4
-
-typedef struct {
- int val_type;
- Clp_ValParseFunc func;
- int flags;
- void *user_data;
-} Clp_ValType;
-
-typedef struct {
- unsigned ilong : 1;
- unsigned ishort : 1;
- unsigned imandatory : 1;
- unsigned ioptional : 1;
- unsigned ipos : 1;
- unsigned ineg : 1;
- unsigned iprefmatch : 1;
- unsigned lmmpos_short : 1;
- unsigned lmmneg_short : 1;
- unsigned char ilongoff;
- int lmmpos;
- int lmmneg;
-} Clp_InternOption;
-
-
-#define Clp_OptionCharsSize 5
-
-typedef struct {
- int c;
- int type;
-} Clp_Oclass;
-#define Clp_OclassSize 10
-
-typedef struct Clp_Internal {
- const Clp_Option *opt;
- Clp_InternOption *iopt;
- int nopt;
- unsigned opt_generation;
-
- Clp_ValType *valtype;
- int nvaltype;
-
- const char * const *argv;
- int argc;
-
- Clp_Oclass oclass[Clp_OclassSize];
- int noclass;
- int long1pos;
- int long1neg;
- int utf8;
-
- char option_chars[Clp_OptionCharsSize];
- const char *xtext;
-
- const char *program_name;
- void (*error_handler)(Clp_Parser *, const char *);
-
- int option_processing;
- int current_option;
-
- unsigned char is_short;
- unsigned char whole_negated; /* true if negated by an option character */
- unsigned char could_be_short;
- unsigned char current_short;
- unsigned char negated_by_no;
-
- int ambiguous;
- int ambiguous_values[MAX_AMBIGUOUS_VALUES];
-} Clp_Internal;
-
-
-struct Clp_ParserState {
- const char * const *argv;
- int argc;
-
- char option_chars[Clp_OptionCharsSize];
- const char *xtext;
-
- int option_processing;
-
- unsigned opt_generation;
- int current_option;
- unsigned char is_short;
- unsigned char whole_negated;
- unsigned char current_short;
- unsigned char negated_by_no;
-};
-
-
-typedef struct Clp_StringList {
-
- Clp_Option *items;
- Clp_InternOption *iopt;
- int nitems;
-
- int allow_int;
- int nitems_invalid_report;
-
-} Clp_StringList;
-
-
-static const Clp_Option clp_option_sentinel[] = {
- {"", 0, Clp_NotOption, 0, 0},
- {"", 0, Clp_Done, 0, 0},
- {"", 0, Clp_BadOption, 0, 0},
- {"", 0, Clp_Error, 0, 0}
-};
-
-
-static int parse_string(Clp_Parser *, const char *, int, void *);
-static int parse_int(Clp_Parser *, const char *, int, void *);
-static int parse_bool(Clp_Parser *, const char *, int, void *);
-static int parse_double(Clp_Parser *, const char *, int, void *);
-static int parse_string_list(Clp_Parser *, const char *, int, void *);
-
-static int ambiguity_error(Clp_Parser *, int, int *, const Clp_Option *,
- const Clp_InternOption *, const char *, const char *,
- ...);
-
-
-/*******
- * utf8
- **/
-
-#define U_REPLACEMENT 0xFFFD
-
-static char *
-encode_utf8(char *s, int n, int c)
-{
- if (c < 0 || c >= 0x110000 || (c >= 0xD800 && c <= 0xDFFF))
- c = U_REPLACEMENT;
- if (c <= 0x7F && n >= 1)
- *s++ = c;
- else if (c <= 0x7FF && n >= 2) {
- *s++ = 0xC0 | (c >> 6);
- goto char1;
- } else if (c <= 0xFFFF && n >= 3) {
- *s++ = 0xE0 | (c >> 12);
- goto char2;
- } else if (n >= 4) {
- *s++ = 0xF0 | (c >> 18);
- *s++ = 0x80 | ((c >> 12) & 0x3F);
- char2:
- *s++ = 0x80 | ((c >> 6) & 0x3F);
- char1:
- *s++ = 0x80 | (c & 0x3F);
- }
- return s;
-}
-
-static int
-decode_utf8(const char *s, const char **cp)
-{
- int c;
- if ((unsigned char) *s <= 0x7F) /* 1 byte: 0x000000-0x00007F */
- c = *s++;
- else if ((unsigned char) *s <= 0xC1) /* bad/overlong encoding */
- goto replacement;
- else if ((unsigned char) *s <= 0xDF) { /* 2 bytes: 0x000080-0x0007FF */
- if ((s[1] & 0xC0) != 0x80) /* bad encoding */
- goto replacement;
- c = (*s++ & 0x1F) << 6;
- goto char1;
- } else if ((unsigned char) *s <= 0xEF) { /* 3 bytes: 0x000800-0x00FFFF */
- if ((s[1] & 0xC0) != 0x80 /* bad encoding */
- || (s[2] & 0xC0) != 0x80 /* bad encoding */
- || ((unsigned char) *s == 0xE0 /* overlong encoding */
- && (s[1] & 0xE0) == 0x80)
- || ((unsigned char) *s == 0xED /* encoded surrogate */
- && (s[1] & 0xE0) == 0xA0))
- goto replacement;
- c = (*s++ & 0x0F) << 12;
- goto char2;
- } else if ((unsigned char) *s <= 0xF4) { /* 4 bytes: 0x010000-0x10FFFF */
- if ((s[1] & 0xC0) != 0x80 /* bad encoding */
- || (s[2] & 0xC0) != 0x80 /* bad encoding */
- || (s[3] & 0xC0) != 0x80 /* bad encoding */
- || ((unsigned char) *s == 0xF0 /* overlong encoding */
- && (s[1] & 0xF0) == 0x80)
- || ((unsigned char) *s == 0xF4 /* encoded value > 0x10FFFF */
- && (unsigned char) s[1] >= 0x90))
- goto replacement;
- c = (*s++ & 0x07) << 18;
- c += (*s++ & 0x3F) << 12;
- char2:
- c += (*s++ & 0x3F) << 6;
- char1:
- c += (*s++ & 0x3F);
- } else {
- replacement:
- c = U_REPLACEMENT;
- for (s++; (*s & 0xC0) == 0x80; s++)
- /* nothing */;
- }
- if (cp)
- *cp = s;
- return c;
-}
-
-static int
-utf8_charlen(const char *s)
-{
- const char *sout;
- (void) decode_utf8(s, &sout);
- return sout - s;
-}
-
-static int
-clp_utf8_charlen(const Clp_Internal *cli, const char *s)
-{
- return (cli->utf8 ? utf8_charlen(s) : 1);
-}
-
-
-/*******
- * Clp_NewParser, etc.
- **/
-
-static int
-min_different_chars(const char *s, const char *t)
- /* Returns the minimum number of bytes required to distinguish
- s from t.
- If s is shorter than t, returns strlen(s). */
-{
- const char *sfirst = s;
- while (*s && *t && *s == *t)
- s++, t++;
- if (!*s)
- return s - sfirst;
- else
- return s - sfirst + 1;
-}
-
-static int
-long_as_short(const Clp_Internal *cli, const Clp_Option *o,
- Clp_InternOption *io, int failure)
-{
- if ((cli->long1pos || cli->long1neg) && io->ilong) {
- const char *name = o->long_name + io->ilongoff;
- if (cli->utf8) {
- int c = decode_utf8(name, &name);
- if (!*name && c && c != U_REPLACEMENT)
- return c;
- } else if (name[0] && !name[1])
- return (unsigned char) name[0];
- }
- return failure;
-}
-
-static void
-compare_options(Clp_Parser *clp, const Clp_Option *o1, Clp_InternOption *io1,
- const Clp_Option *o2, Clp_InternOption *io2)
-{
- Clp_Internal *cli = clp->internal;
- int short1, shortx1;
-
- /* ignore meaningless combinations */
- if ((!io1->ishort && !io1->ilong) || (!io2->ishort && !io2->ilong)
- || !((io1->ipos && io2->ipos) || (io1->ineg && io2->ineg))
- || o1->option_id == o2->option_id)
- return;
-
- /* look for duplication of short options */
- short1 = (io1->ishort ? o1->short_name : -1);
- shortx1 = long_as_short(cli, o1, io1, -2);
- if (short1 >= 0 || shortx1 >= 0) {
- int short2 = (io2->ishort ? o2->short_name : -3);
- int shortx2 = long_as_short(cli, o2, io2, -4);
- if (short1 == short2)
- Clp_OptionError(clp, "CLP internal error: more than 1 option has short name %<%c%>", short1);
- else if ((short1 == shortx2 || shortx1 == short2 || shortx1 == shortx2)
- && ((io1->ipos && io2->ipos && cli->long1pos)
- || (io1->ineg && io2->ineg && cli->long1neg)))
- Clp_OptionError(clp, "CLP internal error: 1-char long name conflicts with short name %<%c%>", (short1 == shortx2 ? shortx2 : shortx1));
- }
-
- /* analyze longest minimum match */
- if (io1->ilong) {
- const char *name1 = o1->long_name + io1->ilongoff;
-
- /* long name's first character matches short name */
- if (io2->ishort && !io1->iprefmatch) {
- int name1char = (cli->utf8 ? decode_utf8(name1, 0) : (unsigned char) *name1);
- if (name1char == o2->short_name) {
- if (io1->ipos && io2->ipos)
- io1->lmmpos_short = 1;
- if (io1->ineg && io2->ineg)
- io1->lmmneg_short = 1;
- }
- }
-
- /* match long name to long name */
- if (io2->ilong) {
- const char *name2 = o2->long_name + io2->ilongoff;
- if (strcmp(name1, name2) == 0)
- Clp_OptionError(clp, "CLP internal error: duplicate long name %<%s%>", name1);
- if (io1->ipos && io2->ipos && !strncmp(name1, name2, io1->lmmpos)
- && (!io1->iprefmatch || strncmp(name1, name2, strlen(name1))))
- io1->lmmpos = min_different_chars(name1, name2);
- if (io1->ineg && io2->ineg && !strncmp(name1, name2, io1->lmmneg)
- && (!io1->iprefmatch || strncmp(name1, name2, strlen(name1))))
- io1->lmmneg = min_different_chars(name1, name2);
- }
- }
-}
-
-static void
-calculate_lmm(Clp_Parser *clp, const Clp_Option *opt, Clp_InternOption *iopt, int nopt)
-{
- int i, j;
- for (i = 0; i < nopt; ++i) {
- iopt[i].lmmpos = iopt[i].lmmneg = 1;
- iopt[i].lmmpos_short = iopt[i].lmmneg_short = 0;
- for (j = 0; j < nopt; ++j)
- compare_options(clp, &opt[i], &iopt[i], &opt[j], &iopt[j]);
- }
-}
-
-/** @param argc number of arguments
- * @param argv argument array
- * @param nopt number of option definitions
- * @param opt option definition array
- * @return the parser
- *
- * The new Clp_Parser that will parse the arguments in @a argv according to
- * the option definitions in @a opt.
- *
- * The Clp_Parser is created with the following characteristics:
- *
- * <ul>
- * <li>The "-" character introduces short options (<tt>Clp_SetOptionChar(clp,
- * '-', Clp_Short)</tt>).</li>
- * <li>Clp_ProgramName is set from the first argument in @a argv, if any. The
- * first argument returned by Clp_Next() will be the second argument in @a
- * argv. Note that this behavior differs from Clp_SetArguments.</li>
- * <li>UTF-8 support is on iff the <tt>LANG</tt> environment variable contains
- * one of the substrings "UTF-8", "UTF8", or "utf8". Override this with
- * Clp_SetUTF8().</li>
- * <li>The Clp_ValString, Clp_ValStringNotOption, Clp_ValInt, Clp_ValUnsigned,
- * Clp_ValBool, and Clp_ValDouble types are installed.</li>
- * <li>Errors are reported to standard error.</li>
- * </ul>
- *
- * You may also create a Clp_Parser with no arguments or options
- * (<tt>Clp_NewParser(0, 0, 0, 0)</tt>) and set the arguments and options
- * later.
- *
- * Returns NULL if there isn't enough memory to construct the parser.
- *
- * @note The CLP library will not modify the contents of @a argv or @a opt.
- * The calling program must not modify @a opt. It may modify @a argv in
- * limited cases.
- */
-Clp_Parser *
-Clp_NewParser(int argc, const char * const *argv, int nopt, const Clp_Option *opt)
-{
- Clp_Parser *clp = (Clp_Parser *)malloc(sizeof(Clp_Parser));
- Clp_Internal *cli = (Clp_Internal *)malloc(sizeof(Clp_Internal));
- Clp_InternOption *iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nopt);
- if (cli)
- cli->valtype = (Clp_ValType *)malloc(sizeof(Clp_ValType) * Clp_InitialValType);
- if (!clp || !cli || !iopt || !cli->valtype)
- goto failed;
-
- clp->option = &clp_option_sentinel[-Clp_Done];
- clp->negated = 0;
- clp->have_val = 0;
- clp->vstr = 0;
- clp->user_data = 0;
- clp->internal = cli;
-
- cli->opt = opt;
- cli->nopt = nopt;
- cli->iopt = iopt;
- cli->opt_generation = 0;
- cli->error_handler = 0;
-
- /* Assign program name (now so we can call Clp_OptionError) */
- if (argc > 0) {
- const char *slash = strrchr(argv[0], '/');
- cli->program_name = slash ? slash + 1 : argv[0];
- } else
- cli->program_name = 0;
-
- /* Assign arguments, skipping program name */
- Clp_SetArguments(clp, argc - 1, argv + 1);
-
- /* Initialize UTF-8 status and option classes */
- {
- char *s = getenv("LANG");
- cli->utf8 = (s && (strstr(s, "UTF-8") != 0 || strstr(s, "UTF8") != 0
- || strstr(s, "utf8") != 0));
- }
- cli->oclass[0].c = '-';
- cli->oclass[0].type = Clp_Short;
- cli->noclass = 1;
- cli->long1pos = cli->long1neg = 0;
-
- /* Add default type parsers */
- cli->nvaltype = 0;
- Clp_AddType(clp, Clp_ValString, 0, parse_string, 0);
- Clp_AddType(clp, Clp_ValStringNotOption, Clp_DisallowOptions, parse_string, 0);
- Clp_AddType(clp, Clp_ValInt, 0, parse_int, 0);
- Clp_AddType(clp, Clp_ValUnsigned, 0, parse_int, (void *)cli);
- Clp_AddType(clp, Clp_ValBool, 0, parse_bool, 0);
- Clp_AddType(clp, Clp_ValDouble, 0, parse_double, 0);
-
- /* Set options */
- Clp_SetOptions(clp, nopt, opt);
-
- return clp;
-
- failed:
- if (cli && cli->valtype)
- free(cli->valtype);
- if (cli)
- free(cli);
- if (clp)
- free(clp);
- if (iopt)
- free(iopt);
- return 0;
-}
-
-/** @param clp the parser
- *
- * All memory associated with @a clp is freed. */
-void
-Clp_DeleteParser(Clp_Parser *clp)
-{
- int i;
- Clp_Internal *cli;
- if (!clp)
- return;
-
- cli = clp->internal;
-
- /* get rid of any string list types */
- for (i = 0; i < cli->nvaltype; i++)
- if (cli->valtype[i].func == parse_string_list) {
- Clp_StringList *clsl = (Clp_StringList *)cli->valtype[i].user_data;
- free(clsl->items);
- free(clsl->iopt);
- free(clsl);
- }
-
- free(cli->valtype);
- free(cli->iopt);
- free(cli);
- free(clp);
-}
-
-
-/** @param clp the parser
- * @param errh error handler function
- * @return previous error handler function
- *
- * The error handler function is called when CLP encounters an error while
- * parsing the command line. It is called with the arguments "<tt>(*errh)(@a
- * clp, s)</tt>", where <tt>s</tt> is a description of the error terminated by
- * a newline. The <tt>s</tt> descriptions produced by CLP itself are prefixed
- * by the program name, if any. */
-Clp_ErrorHandler
-Clp_SetErrorHandler(Clp_Parser *clp, void (*errh)(Clp_Parser *, const char *))
-{
- Clp_Internal *cli = clp->internal;
- Clp_ErrorHandler old = cli->error_handler;
- cli->error_handler = errh;
- return old;
-}
-
-/** @param clp the parser
- * @param utf8 does the parser support UTF-8?
- * @return previous UTF-8 mode
- *
- * In UTF-8 mode, all input strings (arguments and long names for options) are
- * assumed to be encoded via UTF-8, and all character names
- * (Clp_SetOptionChar() and short names for options) may cover the whole
- * Unicode range. Out of UTF-8 mode, all input strings are treated as binary,
- * and all character names must be unsigned char values.
- *
- * Furthermore, error messages in UTF-8 mode may contain Unicode quote
- * characters. */
-int
-Clp_SetUTF8(Clp_Parser *clp, int utf8)
-{
- Clp_Internal *cli = clp->internal;
- int old_utf8 = cli->utf8;
- cli->utf8 = utf8;
- calculate_lmm(clp, cli->opt, cli->iopt, cli->nopt);
- return old_utf8;
-}
-
-/** @param clp the parser
- * @param c character
- * @return option character treatment
- *
- * Returns an integer specifying how CLP treats arguments that begin
- * with character @a c. See Clp_SetOptionChar for possibilities.
- */
-int
-Clp_OptionChar(Clp_Parser *clp, int c)
-{
- Clp_Internal *cli = clp->internal;
- int i, oclass = 0;
- if (cli->noclass > 0 && cli->oclass[0].c == 0)
- oclass = cli->oclass[0].type;
- for (i = 0; i < cli->noclass; ++i)
- if (cli->oclass[i].c == c)
- oclass = cli->oclass[i].type;
- return oclass;
-}
-
-/** @param clp the parser
- * @param c character
- * @param type option character treatment
- * @return previous option character treatment, or -1 on error
- *
- * @a type specifies how CLP treats arguments that begin with character @a c.
- * Possibilities are:
- *
- * <dl>
- * <dt>Clp_NotOption (or 0)</dt>
- * <dd>The argument cannot be an option.</dd>
- * <dt>Clp_Long</dt>
- * <dd>The argument is a long option.</dd>
- * <dt>Clp_Short</dt>
- * <dd>The argument is a set of short options.</dd>
- * <dt>Clp_Short|Clp_Long</dt>
- * <dd>The argument is either a long option or, if no matching long option is
- * found, a set of short options.</dd>
- * <dt>Clp_LongNegated</dt>
- * <dd>The argument is a negated long option. For example, after
- * Clp_SetOptionChar(@a clp, '^', Clp_LongNegated), the argument "^foo" is
- * equivalent to "--no-foo".</dd>
- * <dt>Clp_ShortNegated</dt>
- * <dd>The argument is a set of negated short options.</dd>
- * <dt>Clp_ShortNegated|Clp_LongNegated</dt>
- * <dd>The argument is either a negated long option or, if no matching long
- * option is found, a set of negated short options.</dd>
- * <dt>Clp_LongImplicit</dt>
- * <dd>The argument may be a long option, where the character @a c is actually
- * part of the long option name. For example, after Clp_SetOptionChar(@a clp,
- * 'f', Clp_LongImplicit), the argument "foo" may be equivalent to
- * "--foo".</dd>
- * </dl>
- *
- * In UTF-8 mode, @a c may be any Unicode character. Otherwise, @a c must be
- * an unsigned char value. The special character 0 assigns @a type to @em
- * every character.
- *
- * It is an error if @a c is out of range, @a type is illegal, or there are
- * too many character definitions stored in @a clp already. The function
- * returns -1 on error.
- *
- * A double hyphen "--" always introduces a long option. This behavior cannot
- * currently be changed with Clp_SetOptionChar().
- */
-int
-Clp_SetOptionChar(Clp_Parser *clp, int c, int type)
-{
- int i, long1pos, long1neg;
- int old = Clp_OptionChar(clp, c);
- Clp_Internal *cli = clp->internal;
-
- if (type != Clp_NotOption && type != Clp_Short && type != Clp_Long
- && type != Clp_ShortNegated && type != Clp_LongNegated
- && type != Clp_LongImplicit && type != (Clp_Short | Clp_Long)
- && type != (Clp_ShortNegated | Clp_LongNegated))
- return -1;
- if (c < 0 || c >= (cli->utf8 ? 0x110000 : 256))
- return -1;
-
- if (c == 0)
- cli->noclass = 0;
- for (i = 0; i < cli->noclass; ++i)
- if (cli->oclass[i].c == c)
- break;
- if (i == Clp_OclassSize)
- return -1;
-
- cli->oclass[i].c = c;
- cli->oclass[i].type = type;
- if (cli->noclass == i)
- cli->noclass = i + 1;
-
- long1pos = long1neg = 0;
- for (i = 0; i < cli->noclass; ++i) {
- if ((cli->oclass[i].type & Clp_Short)
- && (cli->oclass[i].type & Clp_Long))
- long1pos = 1;
- if ((cli->oclass[i].type & Clp_ShortNegated)
- && (cli->oclass[i].type & Clp_LongNegated))
- long1neg = 1;
- }
-
- if (long1pos != cli->long1pos || long1neg != cli->long1neg) {
- /* Must recheck option set */
- cli->long1pos = long1pos;
- cli->long1neg = long1neg;
- calculate_lmm(clp, cli->opt, cli->iopt, cli->nopt);
- }
-
- return old;
-}
-
-/** @param clp the parser
- * @param nopt number of option definitions
- * @param opt option definition array
- * @return 0 on success, -1 on failure
- *
- * Installs the option definitions in @a opt. Future option parsing will
- * use @a opt to search for options.
- *
- * Also checks @a opt's option definitions for validity. "CLP internal
- * errors" are reported via Clp_OptionError() if:
- *
- * <ul>
- * <li>An option has a negative ID.</li>
- * <li>Two different short options have the same name.</li>
- * <li>Two different long options have the same name.</li>
- * <li>A short and a long option are ambiguous, in that some option character
- * might introduce either a short or a long option (e.g., Clp_SetOptionChar(@a
- * clp, '-', Clp_Long|Clp_Short)), and a short name equals a long name.</li>
- * </ul>
- *
- * If necessary memory cannot be allocated, this function returns -1 without
- * modifying the parser.
- *
- * @note The CLP library will not modify the contents of @a argv or @a opt.
- * The calling program must not modify @a opt either until another call to
- * Clp_SetOptions() or the parser is destroyed.
- */
-int
-Clp_SetOptions(Clp_Parser *clp, int nopt, const Clp_Option *opt)
-{
- Clp_Internal *cli = clp->internal;
- Clp_InternOption *iopt;
- int i;
- static unsigned opt_generation = 0;
-
- if (nopt > cli->nopt) {
- iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nopt);
- if (!iopt)
- return -1;
- free(cli->iopt);
- cli->iopt = iopt;
- }
-
- cli->opt = opt;
- cli->nopt = nopt;
- cli->opt_generation = ++opt_generation;
- iopt = cli->iopt;
- cli->current_option = -1;
-
- /* Massage the options to make them usable */
- for (i = 0; i < nopt; i++) {
- /* Ignore negative option_ids, which are internal to CLP */
- if (opt[i].option_id < 0) {
- Clp_OptionError(clp, "CLP internal error: option %d has negative option_id", i);
- iopt[i].ilong = iopt[i].ishort = iopt[i].ipos = iopt[i].ineg = 0;
- continue;
- }
-
- /* Set flags based on input flags */
- iopt[i].ilong = (opt[i].long_name != 0 && opt[i].long_name[0] != 0);
- iopt[i].ishort = (opt[i].short_name > 0
- && opt[i].short_name < (cli->utf8 ? 0x110000 : 256));
- iopt[i].ipos = 1;
- iopt[i].ineg = (opt[i].flags & Clp_Negate) != 0;
- iopt[i].imandatory = (opt[i].flags & Clp_Mandatory) != 0;
- iopt[i].ioptional = (opt[i].flags & Clp_Optional) != 0;
- iopt[i].iprefmatch = (opt[i].flags & Clp_PreferredMatch) != 0;
- iopt[i].ilongoff = 0;
-
- /* Enforce invariants */
- if (opt[i].val_type <= 0)
- iopt[i].imandatory = iopt[i].ioptional = 0;
- if (opt[i].val_type > 0 && !iopt[i].ioptional)
- iopt[i].imandatory = 1;
-
- /* Options that start with 'no-' should be changed to OnlyNegated */
- if (iopt[i].ilong && strncmp(opt[i].long_name, "no-", 3) == 0) {
- iopt[i].ipos = 0;
- iopt[i].ineg = 1;
- iopt[i].ilongoff = 3;
- if (strncmp(opt[i].long_name + 3, "no-", 3) == 0)
- Clp_OptionError(clp, "CLP internal error: option %d begins with \"no-no-\"", i);
- } else if (opt[i].flags & Clp_OnlyNegated) {
- iopt[i].ipos = 0;
- iopt[i].ineg = 1;
- }
- }
-
- /* Check option set */
- calculate_lmm(clp, opt, iopt, nopt);
-
- return 0;
-}
-
-/** @param clp the parser
- * @param argc number of arguments
- * @param argv argument array
- *
- * Installs the arguments in @a argv for parsing. Future option parsing will
- * analyze @a argv.
- *
- * Unlike Clp_NewParser(), this function does not treat @a argv[0] specially.
- * The first subsequent call to Clp_Next() will analyze @a argv[0].
- *
- * This function also sets option processing to on, as by
- * Clp_SetOptionProcessing(@a clp, 1).
- *
- * @note The CLP library will not modify the contents of @a argv. The calling
- * program should not generally modify the element of @a argv that CLP is
- * currently analyzing.
- */
-void
-Clp_SetArguments(Clp_Parser *clp, int argc, const char * const *argv)
-{
- Clp_Internal *cli = clp->internal;
-
- cli->argc = argc + 1;
- cli->argv = argv - 1;
-
- cli->is_short = 0;
- cli->whole_negated = 0;
- cli->option_processing = 1;
- cli->current_option = -1;
-}
-
-
-/** @param clp the parser
- * @param on whether to search for options
- * @return previous option processing setting
- *
- * When option processing is off, every call to Clp_Next() returns
- * Clp_NotOption. By default the option <tt>"--"</tt> turns off option
- * processing and is otherwise ignored.
- */
-int
-Clp_SetOptionProcessing(Clp_Parser *clp, int on)
-{
- Clp_Internal *cli = clp->internal;
- int old = cli->option_processing;
- cli->option_processing = on;
- return old;
-}
-
-
-/*******
- * functions for Clp_Option lists
- **/
-
-/* the ever-glorious argcmp */
-
-static int
-argcmp(const char *ref, const char *arg, int min_match, int fewer_dashes)
- /* Returns 0 if ref and arg don't match.
- Returns -1 if ref and arg match, but fewer than min_match characters.
- Returns len if ref and arg match min_match or more characters;
- len is the number of characters that matched in arg.
- Allows arg to contain fewer dashes than ref iff fewer_dashes != 0.
-
- Examples:
- argcmp("x", "y", 1, 0) --> 0 / just plain wrong
- argcmp("a", "ax", 1, 0) --> 0 / ...even though min_match == 1
- and the 1st chars match
- argcmp("box", "bo", 3, 0) --> -1 / ambiguous
- argcmp("cat", "c=3", 1, 0) --> 1 / handles = arguments
- */
-{
- const char *refstart = ref;
- const char *argstart = arg;
- assert(min_match > 0);
-
- compare:
- while (*ref && *arg && *arg != '=' && *ref == *arg)
- ref++, arg++;
-
- /* Allow arg to contain fewer dashes than ref */
- if (fewer_dashes && *ref == '-' && ref[1] && ref[1] == *arg) {
- ref++;
- goto compare;
- }
-
- if (*arg && *arg != '=')
- return 0;
- else if (ref - refstart < min_match)
- return -1;
- else
- return arg - argstart;
-}
-
-static int
-find_prefix_opt(Clp_Parser *clp, const char *arg,
- int nopt, const Clp_Option *opt,
- const Clp_InternOption *iopt,
- int *ambiguous, int *ambiguous_values)
- /* Looks for an unambiguous match of 'arg' against one of the long
- options in 'opt'. Returns positive if it finds one; otherwise, returns
- -1 and possibly changes 'ambiguous' and 'ambiguous_values' to keep
- track of at most MAX_AMBIGUOUS_VALUES possibilities. */
-{
- int i, fewer_dashes = 0, first_ambiguous = *ambiguous;
- int negated = clp && clp->negated;
- int first_charlen = (clp ? clp_utf8_charlen(clp->internal, arg) : 1);
-
- retry:
- for (i = 0; i < nopt; i++) {
- int len, lmm;
- if (!iopt[i].ilong || (negated ? !iopt[i].ineg : !iopt[i].ipos))
- continue;
-
- lmm = (negated ? iopt[i].lmmneg : iopt[i].lmmpos);
- if (clp && clp->internal->could_be_short
- && (negated ? iopt[i].lmmneg_short : iopt[i].lmmpos_short))
- lmm = (first_charlen >= lmm ? first_charlen + 1 : lmm);
- len = argcmp(opt[i].long_name + iopt[i].ilongoff, arg, lmm, fewer_dashes);
- if (len > 0)
- return i;
- else if (len < 0) {
- if (*ambiguous < MAX_AMBIGUOUS_VALUES)
- ambiguous_values[*ambiguous] = i;
- (*ambiguous)++;
- }
- }
-
- /* If there were no partial matches, try again with fewer_dashes true */
- if (*ambiguous == first_ambiguous && !fewer_dashes) {
- fewer_dashes = 1;
- goto retry;
- }
-
- return -1;
-}
-
-
-/*****
- * Argument parsing
- **/
-
-static int
-val_type_binsearch(Clp_Internal *cli, int val_type)
-{
- unsigned l = 0, r = cli->nvaltype;
- while (l < r) {
- unsigned m = l + (r - l) / 2;
- if (cli->valtype[m].val_type == val_type)
- return m;
- else if (cli->valtype[m].val_type < val_type)
- l = m + 1;
- else
- r = m;
- }
- return l;
-}
-
-/** @param clp the parser
- * @param val_type value type ID
- * @param flags value type flags
- * @param parser parser function
- * @param user_data user data for @a parser function
- * @return 0 on success, -1 on failure
- *
- * Defines argument type @a val_type in parser @a clp. The parsing function
- * @a parser will be passed argument values for type @a val_type. It should
- * parse the argument into values (usually in @a clp->val, but sometimes
- * elsewhere), report errors if necessary, and return whether the parse was
- * successful.
- *
- * Any prior argument parser match @a val_type is removed. @a val_type must
- * be greater than zero.
- *
- * @a flags specifies additional parsing flags. At the moment the only
- * relevant flag is Clp_DisallowOptions, which means that separated values
- * must not look like options. For example, assume argument
- * <tt>--a</tt>/<tt>-a</tt> has mandatory value type Clp_ValStringNotOption
- * (which has Clp_DisallowOptions). Then:
- *
- * <ul>
- * <li><tt>--a=--b</tt> will parse with value <tt>--b</tt>.</li>
- * <li><tt>-a--b</tt> will parse with value <tt>--b</tt>.</li>
- * <li><tt>--a --b</tt> will not parse, since the mandatory value looks like
- * an option.</li>
- * <li><tt>-a --b</tt> will not parse, since the mandatory value looks like
- * an option.</li>
- * </ul>
- */
-int
-Clp_AddType(Clp_Parser *clp, int val_type, int flags,
- Clp_ValParseFunc parser, void *user_data)
-{
- Clp_Internal *cli = clp->internal;
- int vtpos;
-
- if (val_type <= 0 || !parser)
- return -1;
-
- vtpos = val_type_binsearch(cli, val_type);
-
- if (vtpos == cli->nvaltype || cli->valtype[vtpos].val_type != val_type) {
- if (cli->nvaltype != 0 && (cli->nvaltype % Clp_InitialValType) == 0) {
- Clp_ValType *new_valtype =
- (Clp_ValType *) realloc(cli->valtype, sizeof(Clp_ValType) * (cli->nvaltype + Clp_InitialValType));
- if (!new_valtype)
- return -1;
- cli->valtype = new_valtype;
- }
- memmove(&cli->valtype[vtpos + 1], &cli->valtype[vtpos],
- sizeof(Clp_ValType) * (cli->nvaltype - vtpos));
- cli->nvaltype++;
- cli->valtype[vtpos].func = 0;
- }
-
- if (cli->valtype[vtpos].func == parse_string_list) {
- Clp_StringList *clsl = (Clp_StringList *) cli->valtype[vtpos].user_data;
- free(clsl->items);
- free(clsl->iopt);
- free(clsl);
- }
-
- cli->valtype[vtpos].val_type = val_type;
- cli->valtype[vtpos].func = parser;
- cli->valtype[vtpos].flags = flags;
- cli->valtype[vtpos].user_data = user_data;
- return 0;
-}
-
-
-/*******
- * Default argument parsers
- **/
-
-static int
-parse_string(Clp_Parser *clp, const char *arg, int complain, void *user_data)
-{
- (void)complain, (void)user_data;
- clp->val.s = arg;
- return 1;
-}
-
-static int
-parse_int(Clp_Parser *clp, const char *arg, int complain, void *user_data)
-{
- const char *val;
- if (*arg == 0 || isspace((unsigned char) *arg)
- || (user_data != 0 && *arg == '-'))
- val = arg;
- else if (user_data != 0) { /* unsigned */
-#if HAVE_STRTOUL
- clp->val.u = strtoul(arg, (char **) &val, 0);
-#else
- /* don't bother really trying to do it right */
- if (arg[0] == '-')
- val = arg;
- else
- clp->val.u = strtol(arg, (char **) &val, 0);
-#endif
- } else
- clp->val.i = strtol(arg, (char **) &val, 0);
- if (*arg != 0 && *val == 0)
- return 1;
- else if (complain) {
- const char *message = user_data != 0
- ? "%<%O%> expects a nonnegative integer, not %<%s%>"
- : "%<%O%> expects an integer, not %<%s%>";
- return Clp_OptionError(clp, message, arg);
- } else
- return 0;
-}
-
-static int
-parse_double(Clp_Parser *clp, const char *arg, int complain, void *user_data)
-{
- const char *val;
- (void)user_data;
- if (*arg == 0 || isspace((unsigned char) *arg))
- val = arg;
- else
- clp->val.d = strtod(arg, (char **) &val);
- if (*arg != 0 && *val == 0)
- return 1;
- else if (complain)
- return Clp_OptionError(clp, "%<%O%> expects a real number, not %<%s%>", arg);
- else
- return 0;
-}
-
-static int
-parse_bool(Clp_Parser *clp, const char *arg, int complain, void *user_data)
-{
- int i;
- char lcarg[6];
- (void)user_data;
- if (strlen(arg) > 5 || strchr(arg, '=') != 0)
- goto error;
-
- for (i = 0; arg[i] != 0; i++)
- lcarg[i] = tolower((unsigned char) arg[i]);
- lcarg[i] = 0;
-
- if (argcmp("yes", lcarg, 1, 0) > 0
- || argcmp("true", lcarg, 1, 0) > 0
- || argcmp("1", lcarg, 1, 0) > 0) {
- clp->val.i = 1;
- return 1;
- } else if (argcmp("no", lcarg, 1, 0) > 0
- || argcmp("false", lcarg, 1, 0) > 0
- || argcmp("1", lcarg, 1, 0) > 0) {
- clp->val.i = 0;
- return 1;
- }
-
- error:
- if (complain)
- Clp_OptionError(clp, "%<%O%> expects a true-or-false value, not %<%s%>", arg);
- return 0;
-}
-
-
-/*****
- * Clp_AddStringListType
- **/
-
-static int
-parse_string_list(Clp_Parser *clp, const char *arg, int complain, void *user_data)
-{
- Clp_StringList *sl = (Clp_StringList *)user_data;
- int idx, ambiguous = 0;
- int ambiguous_values[MAX_AMBIGUOUS_VALUES + 1];
-
- /* actually look for a string value */
- idx = find_prefix_opt
- (0, arg, sl->nitems, sl->items, sl->iopt,
- &ambiguous, ambiguous_values);
- if (idx >= 0) {
- clp->val.i = sl->items[idx].option_id;
- return 1;
- }
-
- if (sl->allow_int) {
- if (parse_int(clp, arg, 0, 0))
- return 1;
- }
-
- if (complain) {
- const char *complaint = (ambiguous ? "ambiguous" : "invalid");
- if (!ambiguous) {
- ambiguous = sl->nitems_invalid_report;
- for (idx = 0; idx < ambiguous; idx++)
- ambiguous_values[idx] = idx;
- }
- return ambiguity_error
- (clp, ambiguous, ambiguous_values, sl->items, sl->iopt,
- "", "option %<%O%> value %<%s%> is %s", arg, complaint);
- } else
- return 0;
-}
-
-
-static int
-finish_string_list(Clp_Parser *clp, int val_type, int flags,
- Clp_Option *items, int nitems, int itemscap)
-{
- int i;
- Clp_StringList *clsl = (Clp_StringList *)malloc(sizeof(Clp_StringList));
- Clp_InternOption *iopt = (Clp_InternOption *)malloc(sizeof(Clp_InternOption) * nitems);
- if (!clsl || !iopt)
- goto error;
-
- clsl->items = items;
- clsl->iopt = iopt;
- clsl->nitems = nitems;
- clsl->allow_int = (flags & Clp_AllowNumbers) != 0;
-
- if (nitems < MAX_AMBIGUOUS_VALUES && nitems < itemscap && clsl->allow_int) {
- items[nitems].long_name = "any integer";
- clsl->nitems_invalid_report = nitems + 1;
- } else if (nitems > MAX_AMBIGUOUS_VALUES + 1)
- clsl->nitems_invalid_report = MAX_AMBIGUOUS_VALUES + 1;
- else
- clsl->nitems_invalid_report = nitems;
-
- for (i = 0; i < nitems; i++) {
- iopt[i].ilong = iopt[i].ipos = 1;
- iopt[i].ishort = iopt[i].ineg = iopt[i].ilongoff = iopt[i].iprefmatch = 0;
- }
- calculate_lmm(clp, items, iopt, nitems);
-
- if (Clp_AddType(clp, val_type, 0, parse_string_list, clsl) >= 0)
- return 0;
-
- error:
- if (clsl)
- free(clsl);
- if (iopt)
- free(iopt);
- return -1;
-}
-
-/** @param clp the parser
- * @param val_type value type ID
- * @param flags string list flags
- * @return 0 on success, -1 on failure
- *
- * Defines argument type @a val_type in parser @a clp. The parsing function
- * sets @a clp->val.i to an integer. The value string is matched against
- * strings provided in the ellipsis arguments. For example, the
- * Clp_AddStringListType() call below has the same effect as the
- * Clp_AddStringListTypeVec() call:
- *
- * For example:
- * @code
- * Clp_AddStringListType(clp, 100, Clp_AllowNumbers, "cat", 1,
- * "cattle", 2, "dog", 3, (const char *) NULL);
- *
- * const char * const strs[] = { "cat", "cattle", "dog" };
- * const int vals[] = { 1, 2, 3 };
- * Clp_AddStringListTypeVec(clp, 100, Clp_AllowNumbers, 3, strs, vals);
- * @endcode
- *
- * @note The CLP library will not modify any of the passed-in strings. The
- * calling program must not modify or free them either until the parser is
- * destroyed.
- */
-int
-Clp_AddStringListType(Clp_Parser *clp, int val_type, int flags, ...)
-{
- int nitems = 0;
- int itemscap = 5;
- Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap);
-
- va_list val;
- va_start(val, flags);
-
- if (!items)
- goto error;
-
- /* slurp up the arguments */
- while (1) {
- int value;
- char *name = va_arg(val, char *);
- if (!name)
- break;
- value = va_arg(val, int);
-
- if (nitems >= itemscap) {
- Clp_Option *new_items;
- itemscap *= 2;
- new_items = (Clp_Option *)realloc(items, sizeof(Clp_Option) * itemscap);
- if (!new_items)
- goto error;
- items = new_items;
- }
-
- items[nitems].long_name = name;
- items[nitems].option_id = value;
- items[nitems].flags = 0;
- nitems++;
- }
-
- va_end(val);
- if (finish_string_list(clp, val_type, flags, items, nitems, itemscap) >= 0)
- return 0;
-
- error:
- va_end(val);
- if (items)
- free(items);
- return -1;
-}
-
-/** @param clp the parser
- * @param val_type value type ID
- * @param flags string list flags
- * @param nstrs number of strings in list
- * @param strs array of strings
- * @param vals array of values
- * @return 0 on success, -1 on failure
- *
- * Defines argument type @a val_type in parser @a clp. The parsing function
- * sets @a clp->val.i to an integer. The value string is matched against the
- * @a strs. If there's a unique match, the corresponding entry from @a vals
- * is returned. Unique prefix matches also work. Finally, if @a flags
- * contains the Clp_AllowNumbers flag, then integers are also accepted.
- *
- * For example:
- * @code
- * const char * const strs[] = { "cat", "cattle", "dog" };
- * const int vals[] = { 1, 2, 3 };
- * Clp_AddStringListTypeVec(clp, 100, Clp_AllowNumbers, 3, strs, vals);
- * @endcode
- *
- * Say that option <tt>--animal</tt> takes value type 100. Then:
- *
- * <ul>
- * <li><tt>--animal=cat</tt> will succeed and set @a clp->val.i = 1.</li>
- * <li><tt>--animal=cattle</tt> will succeed and set @a clp->val.i = 2.</li>
- * <li><tt>--animal=dog</tt> will succeed and set @a clp->val.i = 3.</li>
- * <li><tt>--animal=d</tt> will succeed and set @a clp->val.i = 3.</li>
- * <li><tt>--animal=c</tt> will fail, since <tt>c</tt> is ambiguous.</li>
- * <li><tt>--animal=4</tt> will succeed and set @a clp->val.i = 4.</li>
- * </ul>
- *
- * @note The CLP library will not modify the contents of @a strs or @a vals.
- * The calling program can modify the @a strs array, but the actual strings
- * (for instance, @a strs[0] and @a strs[1]) must not be modified or freed
- * until the parser is destroyed.
- */
-int
-Clp_AddStringListTypeVec(Clp_Parser *clp, int val_type, int flags,
- int nstrs, const char * const *strs,
- const int *vals)
- /* An alternate way to make a string list type. See Clp_AddStringListType
- for the basics; this coalesces the strings and values into two arrays,
- rather than spreading them out into a variable argument list. */
-{
- int i;
- int itemscap = (nstrs < 5 ? 5 : nstrs);
- Clp_Option *items = (Clp_Option *)malloc(sizeof(Clp_Option) * itemscap);
- if (!items)
- return -1;
-
- /* copy over items */
- for (i = 0; i < nstrs; i++) {
- items[i].long_name = strs[i];
- items[i].option_id = vals[i];
- items[i].flags = 0;
- }
-
- if (finish_string_list(clp, val_type, flags, items, nstrs, itemscap) >= 0)
- return 0;
- else {
- free(items);
- return -1;
- }
-}
-
-
-/*******
- * Returning information
- **/
-
-const char *
-Clp_ProgramName(Clp_Parser *clp)
-{
- return clp->internal->program_name;
-}
-
-/** @param clp the parser
- * @param name new program name
- * @return previous program name
- *
- * The calling program should not modify or free @a name until @a clp itself
- * is destroyed. */
-const char *
-Clp_SetProgramName(Clp_Parser *clp, const char *name)
-{
- const char *old = clp->internal->program_name;
- clp->internal->program_name = name;
- return old;
-}
-
-
-/******
- * Clp_ParserStates
- **/
-
-/** @return the parser state
- *
- * A Clp_ParserState object can store a parsing state of a Clp_Parser object.
- * This state specifies exactly how far the Clp_Parser has gotten in parsing
- * an argument list. The Clp_SaveParser() and Clp_RestoreParser() functions
- * can be used to save this state and then restore it later, allowing a
- * Clp_Parser to switch among argument lists.
- *
- * The initial state is empty, in that after Clp_RestoreParser(clp, state),
- * Clp_Next(clp) would return Clp_Done.
- *
- * Parser states can be saved and restored among different parser objects.
- *
- * @sa Clp_DeleteParserState, Clp_SaveParser, Clp_RestoreParser
- */
-Clp_ParserState *
-Clp_NewParserState(void)
-{
- Clp_ParserState *state = (Clp_ParserState *)malloc(sizeof(Clp_ParserState));
- if (state) {
- state->argv = 0;
- state->argc = 0;
- state->option_chars[0] = 0;
- state->xtext = 0;
- state->option_processing = 0;
- state->opt_generation = 0;
- state->current_option = -1;
- state->is_short = 0;
- state->whole_negated = 0;
- state->current_short = 0;
- state->negated_by_no = 0;
- }
- return state;
-}
-
-/** @param state parser state
- *
- * The memory associated with @a state is freed.
- */
-void
-Clp_DeleteParserState(Clp_ParserState *state)
-{
- free(state);
-}
-
-/** @param clp the parser
- * @param state parser state
- * @sa Clp_NewParserState, Clp_RestoreParser
- */
-void
-Clp_SaveParser(const Clp_Parser *clp, Clp_ParserState *state)
-{
- Clp_Internal *cli = clp->internal;
- state->argv = cli->argv;
- state->argc = cli->argc;
- memcpy(state->option_chars, cli->option_chars, Clp_OptionCharsSize);
- state->xtext = cli->xtext;
-
- state->option_processing = cli->option_processing;
- state->opt_generation = cli->opt_generation;
- state->current_option = cli->current_option;
- state->is_short = cli->is_short;
- state->whole_negated = cli->whole_negated;
- state->current_short = cli->current_short;
- state->negated_by_no = cli->negated_by_no;
-}
-
-
-/** @param clp the parser
- * @param state parser state
- *
- * The parser state in @a state is restored into @a clp. The next call to
- * Clp_Next() will return the same result as it would have at the time @a
- * state was saved (probably by Clp_SaveParser(@a clp, @a state)).
- *
- * A parser state contains information about arguments (argc and argv; see
- * Clp_SetArguments()) and option processing (Clp_SetOptionProcessing()), but
- * not about options (Clp_SetOptions()). Changes to options and value types
- * are preserved across Clp_RestoreParser().
- *
- * @sa Clp_NewParserState, Clp_SaveParser
- */
-void
-Clp_RestoreParser(Clp_Parser *clp, const Clp_ParserState *state)
-{
- Clp_Internal *cli = clp->internal;
- cli->argv = state->argv;
- cli->argc = state->argc;
- memcpy(cli->option_chars, state->option_chars, Clp_OptionCharsSize);
- cli->xtext = state->xtext;
- cli->option_processing = state->option_processing;
- cli->is_short = state->is_short;
- cli->whole_negated = state->whole_negated;
- cli->current_short = state->current_short;
- cli->negated_by_no = state->negated_by_no;
- if (cli->opt_generation == state->opt_generation)
- cli->current_option = state->current_option;
- else
- cli->current_option = -1;
-}
-
-
-/*******
- * Clp_Next and its helpers
- **/
-
-static void
-set_option_text(Clp_Internal *cli, const char *text, int n_option_chars)
-{
- assert(n_option_chars < Clp_OptionCharsSize);
- memcpy(cli->option_chars, text, n_option_chars);
- cli->option_chars[n_option_chars] = 0;
- cli->xtext = text + n_option_chars;
-}
-
-static int
-get_oclass(Clp_Parser *clp, const char *text, int *ocharskip)
-{
- int c;
- if (clp->internal->utf8) {
- const char *s;
- c = decode_utf8(text, &s);
- *ocharskip = s - text;
- } else {
- c = (unsigned char) text[0];
- *ocharskip = 1;
- }
- return Clp_OptionChar(clp, c);
-}
-
-static int
-next_argument(Clp_Parser *clp, int want_argument)
- /* Moves clp to the next argument.
- Returns 1 if it finds another option.
- Returns 0 if there aren't any more arguments.
- Returns 0, sets clp->have_val = 1, and sets clp->vstr to the argument
- if the next argument isn't an option.
- If want_argument > 0, it'll look for an argument.
- want_argument == 1: Accept arguments that start with Clp_NotOption
- or Clp_LongImplicit.
- want_argument == 2: Accept ALL arguments.
-
- Where is the option stored when this returns?
- Well, cli->argv[0] holds the whole of the next command line argument.
- cli->option_chars holds a string: what characters began the option?
- It is generally "-" or "--".
- cli->text holds the text of the option:
- for short options, cli->text[0] is the relevant character;
- for long options, cli->text holds the rest of the option. */
-{
- Clp_Internal *cli = clp->internal;
- const char *text;
- int oclass, ocharskip;
-
- /* clear relevant flags */
- clp->have_val = 0;
- clp->vstr = 0;
- cli->could_be_short = 0;
-
- /* if we're in a string of short options, move up one char in the string */
- if (cli->is_short) {
- cli->xtext += clp_utf8_charlen(cli, cli->xtext);
- if (cli->xtext[0] == 0)
- cli->is_short = 0;
- else if (want_argument > 0) {
- /* handle -O[=]argument case */
- clp->have_val = 1;
- if (cli->xtext[0] == '=')
- clp->vstr = cli->xtext + 1;
- else
- clp->vstr = cli->xtext;
- cli->is_short = 0;
- return 0;
- }
- }
-
- /* if in short options, we're all set */
- if (cli->is_short)
- return 1;
-
- /** if not in short options, move to the next argument **/
- cli->whole_negated = 0;
- cli->xtext = 0;
-
- if (cli->argc <= 1)
- return 0;
-
- cli->argc--;
- cli->argv++;
- text = cli->argv[0];
-
- if (want_argument > 1)
- goto not_option;
-
- if (text[0] == '-' && text[1] == '-') {
- oclass = Clp_DoubledLong;
- ocharskip = 2;
- } else
- oclass = get_oclass(clp, text, &ocharskip);
-
- /* If this character could introduce either a short or a long option,
- try a long option first, but remember that short's a possibility for
- later. */
- if ((oclass & (Clp_Short | Clp_ShortNegated))
- && (oclass & (Clp_Long | Clp_LongNegated))) {
- oclass &= ~(Clp_Short | Clp_ShortNegated);
- if (text[ocharskip])
- cli->could_be_short = 1;
- }
-
- switch (oclass) {
-
- case Clp_Short:
- cli->is_short = 1;
- goto check_singleton;
-
- case Clp_ShortNegated:
- cli->is_short = 1;
- cli->whole_negated = 1;
- goto check_singleton;
-
- case Clp_Long:
- goto check_singleton;
-
- case Clp_LongNegated:
- cli->whole_negated = 1;
- goto check_singleton;
-
- check_singleton:
- /* For options introduced with one character, option-char,
- '[option-char]' alone is NOT an option. */
- if (!text[ocharskip])
- goto not_option;
- set_option_text(cli, text, ocharskip);
- break;
-
- case Clp_LongImplicit:
- /* LongImplict: option_chars == "" (since all chars are part of the
- option); restore head -> text of option */
- if (want_argument > 0)
- goto not_option;
- set_option_text(cli, text, 0);
- break;
-
- case Clp_DoubledLong:
- set_option_text(cli, text, ocharskip);
- break;
-
- not_option:
- case Clp_NotOption:
- cli->is_short = 0;
- clp->have_val = 1;
- clp->vstr = text;
- return 0;
-
- default:
- assert(0 /* CLP misconfiguration: bad option type */);
-
- }
-
- return 1;
-}
-
-
-static void
-switch_to_short_argument(Clp_Parser *clp)
-{
- Clp_Internal *cli = clp->internal;
- const char *text = cli->argv[0];
- int ocharskip, oclass = get_oclass(clp, text, &ocharskip);
- assert(cli->could_be_short);
- cli->is_short = 1;
- cli->whole_negated = (oclass & Clp_ShortNegated ? 1 : 0);
- set_option_text(cli, cli->argv[0], ocharskip);
-}
-
-
-static int
-find_long(Clp_Parser *clp, const char *arg)
- /* If arg corresponds to one of clp's options, finds that option &
- returns it. If any argument is given after an = sign in arg, sets
- clp->have_val = 1 and clp->vstr to that argument. Sets cli->ambiguous
- to 1 iff there was no match because the argument was ambiguous. */
-{
- Clp_Internal *cli = clp->internal;
- int optno, len, lmm;
- const Clp_Option *opt = cli->opt;
- const Clp_InternOption *iopt;
- int first_negative_ambiguous;
-
- /* Look for a normal option. */
- optno = find_prefix_opt
- (clp, arg, cli->nopt, opt, cli->iopt,
- &cli->ambiguous, cli->ambiguous_values);
- if (optno >= 0)
- goto worked;
-
- /* If we can't find it, look for a negated option. */
- /* I know this is silly, but it makes me happy to accept
- --no-no-option as a double negative synonym for --option. :) */
- first_negative_ambiguous = cli->ambiguous;
- while (arg[0] == 'n' && arg[1] == 'o' && arg[2] == '-') {
- arg += 3;
- clp->negated = !clp->negated;
- optno = find_prefix_opt
- (clp, arg, cli->nopt, opt, cli->iopt,
- &cli->ambiguous, cli->ambiguous_values);
- if (optno >= 0)
- goto worked;
- }
-
- /* No valid option was found; return 0. Mark the ambiguous values found
- through '--no' by making them negative. */
- {
- int i, max = cli->ambiguous;
- if (max > MAX_AMBIGUOUS_VALUES) max = MAX_AMBIGUOUS_VALUES;
- for (i = first_negative_ambiguous; i < max; i++)
- cli->ambiguous_values[i] = -cli->ambiguous_values[i] - 1;
- }
- return -1;
-
- worked:
- iopt = &cli->iopt[optno];
- lmm = (clp->negated ? iopt->lmmneg : iopt->lmmpos);
- if (cli->could_be_short
- && (clp->negated ? iopt->lmmneg_short : iopt->lmmpos_short)) {
- int first_charlen = clp_utf8_charlen(cli, arg);
- lmm = (first_charlen >= lmm ? first_charlen + 1 : lmm);
- }
- len = argcmp(opt[optno].long_name + iopt->ilongoff, arg, lmm, 1);
- assert(len > 0);
- if (arg[len] == '=') {
- clp->have_val = 1;
- clp->vstr = arg + len + 1;
- }
- return optno;
-}
-
-
-static int
-find_short(Clp_Parser *clp, const char *text)
- /* If short_name corresponds to one of clp's options, returns it. */
-{
- Clp_Internal *cli = clp->internal;
- const Clp_Option *opt = cli->opt;
- const Clp_InternOption *iopt = cli->iopt;
- int i, c;
- if (clp->internal->utf8)
- c = decode_utf8(text, 0);
- else
- c = (unsigned char) *text;
-
- for (i = 0; i < cli->nopt; i++)
- if (iopt[i].ishort && opt[i].short_name == c
- && (!clp->negated || iopt[i].ineg)) {
- clp->negated = clp->negated || !iopt[i].ipos;
- return i;
- }
-
- return -1;
-}
-
-
-/** @param clp the parser
- * @return option ID of next option
- *
- * Parse the next argument from the argument list, store information about
- * that argument in the fields of @a clp, and return the option's ID.
- *
- * If an argument was successfully parsed, that option's ID is returned.
- * Other possible return values are:
- *
- * <dl>
- * <dt>Clp_Done</dt>
- * <dd>There are no more arguments.</dd>
- * <dt>Clp_NotOption</dt>
- * <dd>The next argument was not an option. The argument's text is @a
- * clp->vstr (and @a clp->val.s).</dd>
- * <dt>Clp_BadOption</dt>
- * <dd>The next argument was a bad option: either an option that wasn't
- * understood, or an option lacking a required value, or an option whose value
- * couldn't be parsed. The option has been skipped.</dd>
- * <dt>Clp_Error</dt>
- * <dd>There was an internal error. This should never occur unless a user
- * messes with, for example, a Clp_Option array.</dd>
- * </dl>
- *
- * The fields of @a clp are set as follows.
- *
- * <dl>
- * <dt><tt>negated</tt></dt>
- * <dd>1 if the option was negated, 0 if it wasn't.</dd>
- * <dt><tt>have_val</tt></dt>
- * <dd>1 if the option had a value, 0 if it didn't. Note that negated options
- * are not allowed to have values.</dd>
- * <dt><tt>vstr</tt></dt>
- * <dd>The value string, if any. NULL if there was no value.</dd>
- * <dt><tt>val</tt></dt>
- * <dd>An option's value type will parse the value string into this
- * union.</dd>
- * </dl>
- *
- * The parsed argument is shifted off the argument list, so that sequential
- * calls to Clp_Next() step through the arugment list.
- */
-int
-Clp_Next(Clp_Parser *clp)
-{
- Clp_Internal *cli = clp->internal;
- int optno;
- const Clp_Option *opt;
- Clp_ParserState clpsave;
- int vtpos, complain;
-
- /* Set up clp */
- cli->current_option = -1;
- cli->ambiguous = 0;
-
- /* Get the next argument or option */
- if (!next_argument(clp, cli->option_processing ? 0 : 2)) {
- clp->val.s = clp->vstr;
- optno = clp->have_val ? Clp_NotOption : Clp_Done;
- clp->option = &clp_option_sentinel[-optno];
- return optno;
- }
-
- clp->negated = cli->whole_negated;
- if (cli->is_short)
- optno = find_short(clp, cli->xtext);
- else
- optno = find_long(clp, cli->xtext);
-
- /* If there's ambiguity between long & short options, and we couldn't
- find a long option, look for a short option */
- if (optno < 0 && cli->could_be_short) {
- switch_to_short_argument(clp);
- optno = find_short(clp, cli->xtext);
- }
-
- /* If we didn't find an option... */
- if (optno < 0 || (clp->negated && !cli->iopt[optno].ineg)) {
- /* default processing for the "--" option: turn off option processing
- and return the next argument */
- if (strcmp(cli->argv[0], "--") == 0) {
- Clp_SetOptionProcessing(clp, 0);
- return Clp_Next(clp);
- }
-
- /* otherwise, report some error or other */
- if (cli->ambiguous)
- ambiguity_error(clp, cli->ambiguous, cli->ambiguous_values,
- cli->opt, cli->iopt, cli->option_chars,
- "option %<%s%s%> is ambiguous",
- cli->option_chars, cli->xtext);
- else if (cli->is_short && !cli->could_be_short)
- Clp_OptionError(clp, "unrecognized option %<%s%C%>",
- cli->option_chars, cli->xtext);
- else
- Clp_OptionError(clp, "unrecognized option %<%s%s%>",
- cli->option_chars, cli->xtext);
-
- clp->option = &clp_option_sentinel[-Clp_BadOption];
- return Clp_BadOption;
- }
-
- /* Set the current option */
- cli->current_option = optno;
- cli->current_short = cli->is_short;
- cli->negated_by_no = clp->negated && !cli->whole_negated;
-
- /* The no-argument (or should-have-no-argument) case */
- if (clp->negated
- || (!cli->iopt[optno].imandatory && !cli->iopt[optno].ioptional)) {
- if (clp->have_val) {
- Clp_OptionError(clp, "%<%O%> can%,t take an argument");
- clp->option = &clp_option_sentinel[-Clp_BadOption];
- return Clp_BadOption;
- } else {
- clp->option = &cli->opt[optno];
- return cli->opt[optno].option_id;
- }
- }
-
- /* Get an argument if we need one, or if it's optional */
- /* Sanity-check the argument type. */
- opt = &cli->opt[optno];
- if (opt->val_type <= 0) {
- clp->option = &clp_option_sentinel[-Clp_Error];
- return Clp_Error;
- }
- vtpos = val_type_binsearch(cli, opt->val_type);
- if (vtpos == cli->nvaltype
- || cli->valtype[vtpos].val_type != opt->val_type) {
- clp->option = &clp_option_sentinel[-Clp_Error];
- return Clp_Error;
- }
-
- /* complain == 1 only if the argument was explicitly given,
- or it is mandatory. */
- complain = (clp->have_val != 0) || cli->iopt[optno].imandatory;
- Clp_SaveParser(clp, &clpsave);
-
- if (cli->iopt[optno].imandatory && !clp->have_val) {
- /* Mandatory argument case */
- /* Allow arguments to options to start with a dash, but only if the
- argument type allows it by not setting Clp_DisallowOptions */
- int disallow = (cli->valtype[vtpos].flags & Clp_DisallowOptions) != 0;
- next_argument(clp, disallow ? 1 : 2);
- if (!clp->have_val) {
- int got_option = cli->xtext != 0;
- Clp_RestoreParser(clp, &clpsave);
- if (got_option)
- Clp_OptionError(clp, "%<%O%> requires a non-option argument");
- else
- Clp_OptionError(clp, "%<%O%> requires an argument");
- clp->option = &clp_option_sentinel[-Clp_BadOption];
- return Clp_BadOption;
- }
-
- } else if (cli->is_short && !clp->have_val
- && cli->xtext[clp_utf8_charlen(cli, cli->xtext)])
- /* The -[option]argument case:
- Assume that the rest of the current string is the argument. */
- next_argument(clp, 1);
-
- /* Parse the argument */
- if (clp->have_val) {
- Clp_ValType *atr = &cli->valtype[vtpos];
- if (atr->func(clp, clp->vstr, complain, atr->user_data) <= 0) {
- /* parser failed */
- clp->have_val = 0;
- if (cli->iopt[optno].imandatory) {
- clp->option = &clp_option_sentinel[-Clp_BadOption];
- return Clp_BadOption;
- } else
- Clp_RestoreParser(clp, &clpsave);
- }
- }
-
- clp->option = opt;
- return opt->option_id;
-}
-
-
-/** @param clp the parser
- * @param allow_options whether options will be allowed
- *
- * Remove and return the next argument from @a clp's argument array. If there
- * are no arguments left, or if the next argument is an option and @a
- * allow_options != 0, then returns null.
- */
-const char *
-Clp_Shift(Clp_Parser *clp, int allow_options)
- /* Returns the next argument from the argument list without parsing it.
- If there are no more arguments, returns 0. */
-{
- Clp_ParserState clpsave;
- Clp_SaveParser(clp, &clpsave);
- next_argument(clp, allow_options ? 2 : 1);
- if (!clp->have_val)
- Clp_RestoreParser(clp, &clpsave);
- return clp->vstr;
-}
-
-
-/*******
- * Clp_OptionError
- **/
-
-typedef struct Clp_BuildString {
- char *text;
- char *pos;
- int capacity;
- int bad;
-} Clp_BuildString;
-
-static Clp_BuildString *
-new_build_string(void)
-{
- Clp_BuildString *bs = (Clp_BuildString *)malloc(sizeof(Clp_BuildString));
- if (!bs) goto bad;
- bs->text = (char *)malloc(256);
- if (!bs->text) goto bad;
- bs->pos = bs->text;
- bs->capacity = 256;
- bs->bad = 0;
- return bs;
-
- bad:
- if (bs) free(bs);
- return 0;
-}
-
-static void
-free_build_string(Clp_BuildString *bs)
-{
- if (bs) free(bs->text);
- free(bs);
-}
-
-static int
-grow_build_string(Clp_BuildString *bs, int want)
-{
- char *new_text;
- int ipos = bs->pos - bs->text;
- int new_capacity = bs->capacity;
- while (want >= new_capacity)
- new_capacity *= 2;
- new_text = (char *)realloc(bs->text, new_capacity);
- if (!new_text) {
- bs->bad = 1;
- return 0;
- } else {
- bs->text = new_text;
- bs->pos = bs->text + ipos;
- bs->capacity = new_capacity;
- return 1;
- }
-}
-
-#define ENSURE_BUILD_STRING(bs, space) \
- ((((bs)->pos - (bs)->text) + (space) >= (bs)->capacity) \
- || grow_build_string((bs), ((bs)->pos - (bs)->text) + (space)))
-
-static void
-append_build_string(Clp_BuildString *bs, const char *s, int l)
-{
- if (l < 0)
- l = strlen(s);
- if (ENSURE_BUILD_STRING(bs, l)) {
- memcpy(bs->pos, s, l);
- bs->pos += l;
- }
-}
-
-
-static Clp_BuildString *
-Clp_VaOptionError(Clp_Parser *clp, Clp_BuildString *bs,
- const char *fmt, va_list val)
-{
- Clp_Internal *cli = clp->internal;
- const char *percent;
- int c;
-
- if (!bs)
- bs = new_build_string();
- if (!bs)
- return 0;
- if (cli->program_name && cli->program_name[0]) {
- append_build_string(bs, cli->program_name, -1);
- append_build_string(bs, ": ", 2);
- }
-
- for (percent = strchr(fmt, '%'); percent; percent = strchr(fmt, '%')) {
- append_build_string(bs, fmt, percent - fmt);
- switch (*++percent) {
-
- case 's': {
- const char *s = va_arg(val, const char *);
- if (s)
- append_build_string(bs, s, -1);
- else
- append_build_string(bs, "(null)", 6);
- break;
- }
-
- case 'C': {
- const char *s = va_arg(val, const char *);
- if (cli->utf8)
- c = decode_utf8(s, 0);
- else
- c = (unsigned char) *s;
- goto char_c;
- }
-
- case 'c':
- c = va_arg(val, int);
- goto char_c;
-
- char_c:
- if (ENSURE_BUILD_STRING(bs, 4)) {
- if (c >= 32 && c <= 126)
- *bs->pos++ = c;
- else if (c < 32) {
- *bs->pos++ = '^';
- *bs->pos++ = c + 64;
- } else if (cli->utf8 && c >= 127 && c < 0x110000) {
- bs->pos = encode_utf8(bs->pos, 4, c);
- } else if (c >= 127 && c <= 255) {
- sprintf(bs->pos, "\\%03o", c & 0xFF);
- bs->pos += 4;
- } else {
- *bs->pos++ = '\\';
- *bs->pos++ = '?';
- }
- }
- break;
-
- case 'd': {
- int d = va_arg(val, int);
- if (ENSURE_BUILD_STRING(bs, 32)) {
- sprintf(bs->pos, "%d", d);
- bs->pos = strchr(bs->pos, 0);
- }
- break;
- }
-
- case 'O': {
- int optno = cli->current_option;
- const Clp_Option *opt = &cli->opt[optno];
- if (optno < 0)
- append_build_string(bs, "(no current option!)", -1);
- else if (cli->current_short) {
- append_build_string(bs, cli->option_chars, -1);
- if (ENSURE_BUILD_STRING(bs, 5)) {
- if (cli->utf8)
- bs->pos = encode_utf8(bs->pos, 5, opt->short_name);
- else
- *bs->pos++ = opt->short_name;
- }
- } else if (cli->negated_by_no) {
- append_build_string(bs, cli->option_chars, -1);
- append_build_string(bs, "no-", 3);
- append_build_string(bs, opt->long_name + cli->iopt[optno].ilongoff, -1);
- } else {
- append_build_string(bs, cli->option_chars, -1);
- append_build_string(bs, opt->long_name + cli->iopt[optno].ilongoff, -1);
- }
- break;
- }
-
- case '%':
- if (ENSURE_BUILD_STRING(bs, 1))
- *bs->pos++ = '%';
- break;
-
- case '`': /* backwards compatibility */
- case '<':
- append_build_string(bs, (cli->utf8 ? "\342\200\230" : "'"), -1);
- break;
-
- case '\'': /* backwards compatibility */
- case ',':
- case '>':
- append_build_string(bs, (cli->utf8 ? "\342\200\231" : "'"), -1);
- break;
-
- default:
- if (ENSURE_BUILD_STRING(bs, 2)) {
- *bs->pos++ = '%';
- *bs->pos++ = *percent;
- }
- break;
-
- }
- fmt = ++percent;
- }
-
- append_build_string(bs, fmt, -1);
- append_build_string(bs, "\n", 1);
-
- return bs;
-}
-
-static void
-do_error(Clp_Parser *clp, Clp_BuildString *bs)
-{
- const char *text;
- if (bs && !bs->bad) {
- *bs->pos = 0;
- text = bs->text;
- } else
- text = "out of memory\n";
-
- if (clp->internal->error_handler != 0)
- (*clp->internal->error_handler)(clp, text);
- else
- fputs(text, stderr);
-}
-
-/** @param clp the parser
- * @param format error format
- *
- * Format an error message from @a format and any additional arguments in the
- * ellipsis. The resulting error string by printing it to standard error or
- * passing it to Clp_SetErrorHandler.
- *
- * The following format characters are accepted:
- *
- * <dl>
- * <dt><tt>%</tt><tt>c</tt></dt>
- * <dd>A character (type <tt>int</tt>). Control characters are printed in
- * caret notation. If the parser is in UTF-8 mode, the character is formatted
- * in UTF-8. Otherwise, special characters are printed with backslashes and
- * octal notation.</dd>
- * <dt><tt>%</tt><tt>s</tt></dt>
- * <dd>A string (type <tt>const char *</tt>).</dd>
- * <dt><tt>%</tt><tt>C</tt></dt>
- * <dd>The argument is a string (type <tt>const char *</tt>). The first
- * character in this string is printed. If the parser is in UTF-8 mode, this
- * may involve multiple bytes.</dd>
- * <dt><tt>%</tt><tt>d</tt></dt>
- * <dd>An integer (type <tt>int</tt>). Printed in decimal.</dd>
- * <dt><tt>%</tt><tt>O</tt></dt>
- * <dd>The current option. No values are read from the argument list; the
- * current option is defined in the Clp_Parser object itself.</dd>
- * <dt><tt>%%</tt></dt>
- * <dd>Prints a percent character.</dd>
- * <dt><tt>%</tt><tt>&lt;</tt></dt>
- * <dd>Prints an open quote string. In UTF-8 mode, prints a left single
- * quote. Otherwise prints a single quote.</dd>
- * <dt><tt>%</tt><tt>&gt;</tt></dt>
- * <dd>Prints a closing quote string. In UTF-8 mode, prints a right single
- * quote. Otherwise prints a single quote.</dd>
- * <dt><tt>%</tt><tt>,</tt></dt>
- * <dd>Prints an apostrophe. In UTF-8 mode, prints a right single quote.
- * Otherwise prints a single quote.</dd>
- * </dl>
- *
- * Note that no flag characters, precision, or field width characters are
- * currently supported.
- *
- * @sa Clp_SetErrorHandler
- */
-int
-Clp_OptionError(Clp_Parser *clp, const char *format, ...)
-{
- Clp_BuildString *bs;
- va_list val;
- va_start(val, format);
- bs = Clp_VaOptionError(clp, 0, format, val);
- va_end(val);
- do_error(clp, bs);
- free_build_string(bs);
- return 0;
-}
-
-static int
-ambiguity_error(Clp_Parser *clp, int ambiguous, int *ambiguous_values,
- const Clp_Option *opt, const Clp_InternOption *iopt,
- const char *prefix, const char *fmt, ...)
-{
- Clp_Internal *cli = clp->internal;
- Clp_BuildString *bs;
- int i;
- va_list val;
- va_start(val, fmt);
- bs = Clp_VaOptionError(clp, 0, fmt, val);
- if (!bs) goto done;
-
- if (clp->internal->program_name && clp->internal->program_name[0]) {
- append_build_string(bs, clp->internal->program_name, -1);
- append_build_string(bs, ": ", 2);
- }
- append_build_string(bs, "(Possibilities are", -1);
-
- for (i = 0; i < ambiguous && i < MAX_AMBIGUOUS_VALUES; i++) {
- int value = ambiguous_values[i];
- const char *no_dash = "";
- if (value < 0)
- value = -(value + 1), no_dash = "no-";
- if (i == 0)
- append_build_string(bs, " ", 1);
- else if (i == ambiguous - 1)
- append_build_string(bs, (i == 1 ? " and " : ", and "), -1);
- else
- append_build_string(bs, ", ", 2);
- append_build_string(bs, (cli->utf8 ? "\342\200\230" : "'"), -1);
- append_build_string(bs, prefix, -1);
- append_build_string(bs, no_dash, -1);
- append_build_string(bs, opt[value].long_name + iopt[value].ilongoff, -1);
- append_build_string(bs, (cli->utf8 ? "\342\200\231" : "'"), -1);
- }
-
- if (ambiguous > MAX_AMBIGUOUS_VALUES)
- append_build_string(bs, ", and others", -1);
- append_build_string(bs, ".)\n", -1);
- va_end(val);
-
- done:
- do_error(clp, bs);
- free_build_string(bs);
- return 0;
-}
-
-static int
-copy_string(char *buf, int buflen, int bufpos, const char *what)
-{
- int l = strlen(what);
- if (l > buflen - bufpos - 1)
- l = buflen - bufpos - 1;
- memcpy(buf + bufpos, what, l);
- return l;
-}
-
-/** @param clp the parser
- * @param buf output buffer
- * @param len length of output buffer
- * @return number of characters written to the buffer, not including the terminating NUL
- *
- * A string that looks like the last option parsed by @a clp is extracted into
- * @a buf. The correct option characters are put into the string first,
- * followed by the option text. The output buffer is null-terminated unless
- * @a len == 0.
- *
- * @sa Clp_CurOptionName
- */
-int
-Clp_CurOptionNameBuf(Clp_Parser *clp, char *buf, int len)
-{
- Clp_Internal *cli = clp->internal;
- int optno = cli->current_option;
- int pos = 0;
- if (optno < 0)
- pos += copy_string(buf, len, pos, "(no current option!)");
- else if (cli->current_short) {
- pos += copy_string(buf, len, pos, cli->option_chars);
- if (cli->utf8)
- pos = (encode_utf8(buf + pos, len - pos - 1, cli->opt[optno].short_name) - buf);
- else if (pos < len - 1)
- buf[pos++] = cli->opt[optno].short_name;
- } else if (cli->negated_by_no) {
- pos += copy_string(buf, len, pos, cli->option_chars);
- pos += copy_string(buf, len, pos, "no-");
- pos += copy_string(buf, len, pos, cli->opt[optno].long_name + cli->iopt[optno].ilongoff);
- } else {
- pos += copy_string(buf, len, pos, cli->option_chars);
- pos += copy_string(buf, len, pos, cli->opt[optno].long_name + cli->iopt[optno].ilongoff);
- }
- if (pos < len)
- buf[pos] = 0;
- return pos;
-}
-
-/** @param clp the parser
- * @return string describing the current option
- *
- * This function acts like Clp_CurOptionNameBuf(), but returns a pointer into
- * a static buffer that will be rewritten on the next call to
- * Clp_CurOptionName().
- *
- * @note This function is not thread safe.
- *
- * @sa Clp_CurOptionName
- */
-const char *
-Clp_CurOptionName(Clp_Parser *clp)
-{
- static char buf[256];
- Clp_CurOptionNameBuf(clp, buf, 256);
- return buf;
-}
-
-#ifdef __cplusplus
-}
-#endif