aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS10
-rw-r--r--configure.ac1
-rw-r--r--src/Makefile.am3
-rw-r--r--src/argparse.c667
-rw-r--r--src/argparse.h207
-rw-r--r--src/gpg-error.def.in6
-rw-r--r--src/gpg-error.h.in181
-rw-r--r--src/gpg-error.vers5
-rw-r--r--src/gpgrt-int.h9
-rw-r--r--src/visibility.c32
-rw-r--r--src/visibility.h11
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/t-argparse.c125
13 files changed, 686 insertions, 574 deletions
diff --git a/NEWS b/NEWS
index fe66d2c..0f83cdf 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,16 @@ Noteworthy changes in version 1.29 (unreleased) [C23/A23/R_]
-----------------------------------------------
+ * Interface changes relative to the 1.28 release:
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ gpgrt_argparse New API.
+ gpgrt_strusage New API.
+ gpgrt_set_strusage New API.
+ gpgrt_set_usage_outfnc New API.
+ gpgrt_set_fixed_string_mapper New API.
+ GPGRT_ENABLE_ARGPARSE_MACROS New macro.
+
+
Noteworthy changes in version 1.28 (2018-03-13) [C23/A23/R0]
-----------------------------------------------
diff --git a/configure.ac b/configure.ac
index 1e648d1..12abb48 100644
--- a/configure.ac
+++ b/configure.ac
@@ -155,6 +155,7 @@ AH_BOTTOM([
#define GPG_ERR_ENABLE_ERRNO_MACROS 1
#define GPGRT_ENABLE_ES_MACROS 1
#define GPGRT_ENABLE_LOG_MACROS 1
+#define GPGRT_ENABLE_ARGPARSE_MACROS 1
])
diff --git a/src/Makefile.am b/src/Makefile.am
index 268c2ab..66c4414 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -190,7 +190,8 @@ libgpg_error_la_SOURCES = gettext.h $(arch_sources) \
sysutils.c \
syscall-clamp.c \
logging.c \
- b64dec.c
+ b64dec.c \
+ argparse.c
nodist_libgpg_error_la_SOURCES = gpg-error.h
diff --git a/src/argparse.c b/src/argparse.c
index 331998b..c5a942f 100644
--- a/src/argparse.c
+++ b/src/argparse.c
@@ -1,9 +1,9 @@
/* argparse.c - Argument Parser for option handling
* Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch
* Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
- * Copyright (C) 2015-2017 g10 Code GmbH
+ * Copyright (C) 2015-2018 g10 Code GmbH
*
- * This file is part of GnuPG.
+ * This file is part of Libgpg-error.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
@@ -17,12 +17,9 @@
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-/* This file may be used as part of GnuPG or standalone. A GnuPG
- build is detected by the presence of the macro GNUPG_MAJOR_VERSION.
- Some feature are only availalbe in the GnuPG build mode.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This file was originally a part of GnuPG.
*/
#ifdef HAVE_CONFIG_H
@@ -37,92 +34,86 @@
#include <limits.h>
#include <errno.h>
-#ifdef GNUPG_MAJOR_VERSION
-# include "util.h"
-# include "common-defs.h"
-# include "i18n.h"
-# include "mischelp.h"
-# include "stringhelp.h"
-# include "logging.h"
-# include "utf8conv.h"
-#endif /*GNUPG_MAJOR_VERSION*/
-
-#include "argparse.h"
-
-/* GnuPG uses GPLv3+ but a standalone version of this defaults to
- GPLv2+ because that is the license of this file. Change this if
- you include it in a program which uses GPLv3. If you don't want to
- set a copyright string for your usage() you may also hardcode it
- here. */
-#ifndef GNUPG_MAJOR_VERSION
-
-# define ARGPARSE_GPL_VERSION 2
-# define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME"
-
-#else /* Used by GnuPG */
-
-# define ARGPARSE_GPL_VERSION 3
-# define ARGPARSE_CRIGHT_STR "Copyright (C) 2018 Free Software Foundation, Inc."
-
-#endif /*GNUPG_MAJOR_VERSION*/
-
-/* Replacements for standalone builds. */
-#ifndef GNUPG_MAJOR_VERSION
-# ifndef _
-# define _(a) (a)
-# endif
-# ifndef DIM
-# define DIM(v) (sizeof(v)/sizeof((v)[0]))
-# endif
-# define xtrymalloc(a) malloc ((a))
-# define xtryrealloc(a,b) realloc ((a), (b))
-# define xtrystrdup(a) strdup ((a))
-# define xfree(a) free ((a))
-# define log_error my_log_error
-# define log_bug my_log_bug
-# define trim_spaces(a) my_trim_spaces ((a))
-# define map_static_macro_string(a) (a)
-#endif /*!GNUPG_MAJOR_VERSION*/
-
-
-#define ARGPARSE_STR(v) #v
-#define ARGPARSE_STR2(v) ARGPARSE_STR(v)
-
-
-/* Replacements for standalone builds. */
-#ifndef GNUPG_MAJOR_VERSION
-static void
-my_log_error (const char *fmt, ...)
+#include "gpgrt-int.h"
+
+/* Special short options which are auto-inserterd. */
+#define ARGPARSE_SHORTOPT_HELP 32768
+#define ARGPARSE_SHORTOPT_VERSION 32769
+#define ARGPARSE_SHORTOPT_WARRANTY 32770
+#define ARGPARSE_SHORTOPT_DUMP_OPTIONS 32771
+
+/* A mask for the types. */
+#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values. */
+
+/* Internal object of the public gpgrt_argparse_t object. */
+struct _gpgrt_argparse_internal_s
{
- va_list arg_ptr ;
+ int idx;
+ int inarg;
+ int stopped;
+ const char *last;
+ void *aliases;
+ const void *cur_alias;
+ void *iio_list;
+};
- va_start (arg_ptr, fmt);
- fprintf (stderr, "%s: ", strusage (11));
- vfprintf (stderr, fmt, arg_ptr);
- va_end (arg_ptr);
-}
-static void
-my_log_bug (const char *fmt, ...)
+typedef struct alias_def_s *ALIAS_DEF;
+struct alias_def_s {
+ ALIAS_DEF next;
+ char *name; /* malloced buffer with name, \0, value */
+ const char *value; /* ptr into name */
+};
+
+
+/* Object to store the names for the --ignore-invalid-option option.
+ This is a simple linked list. */
+typedef struct iio_item_def_s *IIO_ITEM_DEF;
+struct iio_item_def_s
{
- va_list arg_ptr ;
+ IIO_ITEM_DEF next;
+ char name[1]; /* String with the long option name. */
+};
+
+
+/* The almost always needed user handler for strusage. */
+static const char *(*strusage_handler)( int ) = NULL;
+/* Optional handler to write strings. See _gpgrt_set_usage_outfnc. */
+static int (*custom_outfnc) (int, const char *);
+/* Optional handler to map strings. See _gpgrt_set_fixed_string_mapper. */
+static const char *(*fixed_string_mapper)(const char*);
+
+static int set_opt_arg(gpgrt_argparse_t *arg, unsigned flags, char *s);
+static void show_help(gpgrt_opt_t *opts, unsigned flags);
+static void show_version(void);
+static int writestrings (int is_error, const char *string,
+ ...) GPGRT_ATTR_SENTINEL(0);
+static int arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts);
+
- va_start (arg_ptr, fmt);
- fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));
- vfprintf (stderr, fmt, arg_ptr);
- va_end (arg_ptr);
- abort ();
-}
+
+
/* Return true if the native charset is utf-8. */
static int
is_native_utf8 (void)
{
- return 1;
+ static char result;
+
+ if (!result)
+ {
+ const char *p = _gpgrt_strusage (8);
+ if (!p || !*p || !strcmp (p, "utf-8"))
+ result = 1;
+ result |= 128;
+ }
+
+ return (result & 1);
}
+
static char *
-my_trim_spaces (char *str)
+trim_spaces (char *str)
{
char *string, *p, *mark;
@@ -145,7 +136,12 @@ my_trim_spaces (char *str)
return str ;
}
-#endif /*!GNUPG_MAJOR_VERSION*/
+
+static const char *
+map_fixed_string (const char *string)
+{
+ return fixed_string_mapper? fixed_string_mapper (string) : string;
+}
@@ -153,66 +149,6 @@ my_trim_spaces (char *str)
* @Summary arg_parse
* #include "argparse.h"
*
- * typedef struct {
- * char *argc; pointer to argc (value subject to change)
- * char ***argv; pointer to argv (value subject to change)
- * unsigned flags; Global flags (DO NOT CHANGE)
- * int err; print error about last option
- * 1 = warning, 2 = abort
- * int r_opt; return option
- * int r_type; type of return value (0 = no argument found)
- * union {
- * int ret_int;
- * long ret_long
- * ulong ret_ulong;
- * char *ret_str;
- * } r; Return values
- * struct {
- * int idx;
- * const char *last;
- * void *aliases;
- * } internal; DO NOT CHANGE
- * } ARGPARSE_ARGS;
- *
- * typedef struct {
- * int short_opt;
- * const char *long_opt;
- * unsigned flags;
- * } ARGPARSE_OPTS;
- *
- * int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts );
- *
- * @Description
- * This is my replacement for getopt(). See the example for a typical usage.
- * Global flags are:
- * Bit 0 : Do not remove options form argv
- * Bit 1 : Do not stop at last option but return other args
- * with r_opt set to -1.
- * Bit 2 : Assume options and real args are mixed.
- * Bit 3 : Do not use -- to stop option processing.
- * Bit 4 : Do not skip the first arg.
- * Bit 5 : allow usage of long option with only one dash
- * Bit 6 : ignore --version
- * all other bits must be set to zero, this value is modified by the
- * function, so assume this is write only.
- * Local flags (for each option):
- * Bit 2-0 : 0 = does not take an argument
- * 1 = takes int argument
- * 2 = takes string argument
- * 3 = takes long argument
- * 4 = takes ulong argument
- * Bit 3 : argument is optional (r_type will the be set to 0)
- * Bit 4 : allow 0x etc. prefixed values.
- * Bit 6 : Ignore this option
- * Bit 7 : This is a command and not an option
- * You stop the option processing by setting opts to NULL, the function will
- * then return 0.
- * @Return Value
- * Returns the args.r_opt or 0 if ready
- * r_opt may be -2/-7 to indicate an unknown option/command.
- * @See Also
- * ArgExpand
- * @Notes
* You do not need to process the options 'h', '--help' or '--version'
* because this function includes standard help processing; but if you
* specify '-h', '--help' or '--version' you have to do it yourself.
@@ -222,7 +158,7 @@ my_trim_spaces (char *str)
* the conversion yourself.
* @Example
*
- * ARGPARSE_OPTS opts[] = {
+ * gpgrt_opt_t opts[] = {
* { 'v', "verbose", 0 },
* { 'd', "debug", 0 },
* { 'o', "output", 2 },
@@ -231,7 +167,7 @@ my_trim_spaces (char *str)
* { 300, "ignored-long-option, ARGPARSE_OP_IGNORE},
* { 500, "have-no-short-option-for-this-long-option", 0 },
* {0} };
- * ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
+ * gpgrt_argparse_t pargs = { &argc, &argv, 0 }
*
* while( ArgParse( &pargs, &opts) ) {
* switch( pargs.r_opt ) {
@@ -249,42 +185,6 @@ my_trim_spaces (char *str)
*
*/
-typedef struct alias_def_s *ALIAS_DEF;
-struct alias_def_s {
- ALIAS_DEF next;
- char *name; /* malloced buffer with name, \0, value */
- const char *value; /* ptr into name */
-};
-
-
-/* Object to store the names for the --ignore-invalid-option option.
- This is a simple linked list. */
-typedef struct iio_item_def_s *IIO_ITEM_DEF;
-struct iio_item_def_s
-{
- IIO_ITEM_DEF next;
- char name[1]; /* String with the long option name. */
-};
-
-static const char *(*strusage_handler)( int ) = NULL;
-static int (*custom_outfnc) (int, const char *);
-
-static int set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s);
-static void show_help(ARGPARSE_OPTS *opts, unsigned flags);
-static void show_version(void);
-static int writestrings (int is_error, const char *string, ...)
-#if __GNUC__ >= 4
- __attribute__ ((sentinel(0)))
-#endif
- ;
-
-
-void
-argparse_register_outfnc (int (*fnc)(int, const char *))
-{
- custom_outfnc = fnc;
-}
-
/* Write STRING and all following const char * arguments either to
stdout or, if IS_ERROR is set, to stderr. The list of strings must
@@ -321,27 +221,68 @@ flushstrings (int is_error)
if (custom_outfnc)
custom_outfnc (is_error? 2:1, NULL);
else
- fflush (is_error? stderr : stdout);
+ _gpgrt_fflush (is_error? es_stderr : es_stdout);
}
static void
-initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
+deinitialize (gpgrt_argparse_t *arg)
{
- if( !(arg->flags & (1<<15)) )
+ xfree (arg->internal);
+ arg->internal = NULL;
+
+ arg->lineno = 0;
+ arg->err = 0;
+}
+
+/* Our own exit handler to clean up used memory. */
+static void
+my_exit (gpgrt_argparse_t *arg, int code)
+{
+ deinitialize (arg);
+ exit (code);
+}
+
+
+static gpg_err_code_t
+initialize (gpgrt_argparse_t *arg, estream_t fp)
+{
+ if (!arg->internal || (arg->flags & ARGPARSE_FLAG_RESET))
{
+ /* Allocate internal data. */
+ if (!arg->internal)
+ {
+ arg->internal = xtrymalloc (sizeof *arg->internal);
+ if (!arg->internal)
+ return _gpg_err_code_from_syserror ();
+ }
+
/* Initialize this instance. */
- arg->internal.idx = 0;
- arg->internal.last = NULL;
- arg->internal.inarg = 0;
- arg->internal.stopped = 0;
- arg->internal.aliases = NULL;
- arg->internal.cur_alias = NULL;
- arg->internal.iio_list = NULL;
+ arg->internal->idx = 0;
+ arg->internal->last = NULL;
+ arg->internal->inarg = 0;
+ arg->internal->stopped = 0;
+ arg->internal->aliases = NULL;
+ arg->internal->cur_alias = NULL;
+ arg->internal->iio_list = NULL;
+
+ /* Clear the error indicator. */
arg->err = 0;
- arg->flags |= 1<<15; /* Mark as initialized. */
+
+ /* Usually an option file will be parsed from the start.
+ * However, we do not open the stream and thus we have no way to
+ * know the current lineno. Using this flag we can allow the
+ * user to provide a lineno which we don't reset. */
+ if (fp || !(arg->flags & ARGPARSE_FLAG_NOLINENO))
+ arg->lineno = 0;
+
+ /* Need to clear the reset request. */
+ arg->flags &= ~ARGPARSE_FLAG_RESET;
+
+ /* Check initial args. */
if ( *arg->argc < 0 )
- log_bug ("invalid argument for arg_parse\n");
+ _gpgrt_log_bug ("invalid argument passed to gpgrt_argparse\n");
+
}
@@ -350,7 +291,7 @@ initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
/* Last option was erroneous. */
const char *s;
- if (filename)
+ if (fp)
{
if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
s = _("argument not expected");
@@ -370,42 +311,46 @@ initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
s = _("out of core");
else
s = _("invalid option");
- log_error ("%s:%u: %s\n", filename, *lineno, s);
+ _gpgrt_log_error ("%s:%u: %s\n",
+ _gpgrt_fname_get (fp), arg->lineno, s);
}
else
{
- s = arg->internal.last? arg->internal.last:"[??]";
+ s = arg->internal->last? arg->internal->last:"[??]";
if ( arg->r_opt == ARGPARSE_MISSING_ARG )
- log_error (_("missing argument for option \"%.50s\"\n"), s);
+ _gpgrt_log_error (_("missing argument for option \"%.50s\"\n"), s);
else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
- log_error (_("invalid argument for option \"%.50s\"\n"), s);
+ _gpgrt_log_error (_("invalid argument for option \"%.50s\"\n"), s);
else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
- log_error (_("option \"%.50s\" does not expect an argument\n"), s);
+ _gpgrt_log_error (_("option \"%.50s\" does not expect "
+ "an argument\n"), s);
else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
- log_error (_("invalid command \"%.50s\"\n"), s);
+ _gpgrt_log_error (_("invalid command \"%.50s\"\n"), s);
else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
- log_error (_("option \"%.50s\" is ambiguous\n"), s);
+ _gpgrt_log_error (_("option \"%.50s\" is ambiguous\n"), s);
else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
- log_error (_("command \"%.50s\" is ambiguous\n"),s );
+ _gpgrt_log_error (_("command \"%.50s\" is ambiguous\n"),s );
else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
- log_error ("%s\n", _("out of core\n"));
+ _gpgrt_log_error ("%s\n", _("out of core\n"));
else
- log_error (_("invalid option \"%.50s\"\n"), s);
+ _gpgrt_log_error (_("invalid option \"%.50s\"\n"), s);
}
if (arg->err != ARGPARSE_PRINT_WARNING)
- exit (2);
+ my_exit (arg, 2);
arg->err = 0;
}
/* Zero out the return value union. */
arg->r.ret_str = NULL;
arg->r.ret_long = 0;
+
+ return 0;
}
static void
-store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
+store_alias( gpgrt_argparse_t *arg, char *name, char *value )
{
/* TODO: replace this dummy function with a rea one
* and fix the probelms IRIX has with (ALIAS_DEV)arg..
@@ -418,17 +363,17 @@ store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
ALIAS_DEF a = xmalloc( sizeof *a );
a->name = name;
a->value = value;
- a->next = (ALIAS_DEF)arg->internal.aliases;
- (ALIAS_DEF)arg->internal.aliases = a;
+ a->next = (ALIAS_DEF)arg->internal->aliases;
+ (ALIAS_DEF)arg->internal->aliases = a;
#endif
}
/* Return true if KEYWORD is in the ignore-invalid-option list. */
static int
-ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
+ignore_invalid_option_p (gpgrt_argparse_t *arg, const char *keyword)
{
- IIO_ITEM_DEF item = arg->internal.iio_list;
+ IIO_ITEM_DEF item = arg->internal->iio_list;
for (; item; item = item->next)
if (!strcmp (item->name, keyword))
@@ -442,7 +387,7 @@ ignore_invalid_option_p (ARGPARSE_ARGS *arg, const char *keyword)
character read wll be the first of a new line. The function
returns 0 on success or true on malloc failure. */
static int
-ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
+ignore_invalid_option_add (gpgrt_argparse_t *arg, estream_t fp)
{
IIO_ITEM_DEF item;
int c;
@@ -453,7 +398,7 @@ ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
while (!ready)
{
- c = getc (fp);
+ c = _gpgrt_fgetc (fp);
if (c == '\n')
ready = 1;
else if (c == EOF)
@@ -501,8 +446,8 @@ ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
if (!item)
return 1;
strcpy (item->name, name);
- item->next = (IIO_ITEM_DEF)arg->internal.iio_list;
- arg->internal.iio_list = item;
+ item->next = (IIO_ITEM_DEF)arg->internal->iio_list;
+ arg->internal->iio_list = item;
}
state = skipWS;
goto again;
@@ -514,16 +459,16 @@ ignore_invalid_option_add (ARGPARSE_ARGS *arg, FILE *fp)
/* Clear the entire ignore-invalid-option list. */
static void
-ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
+ignore_invalid_option_clear (gpgrt_argparse_t *arg)
{
IIO_ITEM_DEF item, tmpitem;
- for (item = arg->internal.iio_list; item; item = tmpitem)
+ for (item = arg->internal->iio_list; item; item = tmpitem)
{
tmpitem = item->next;
xfree (item);
}
- arg->internal.iio_list = NULL;
+ arg->internal->iio_list = NULL;
}
@@ -550,8 +495,7 @@ ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
* Note: Abbreviation of options is here not allowed.
*/
int
-optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
- ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+_gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts)
{
int state, i, c;
int idx=0;
@@ -562,18 +506,26 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
int unread_buf[3]; /* We use an int so that we can store EOF. */
int unread_buf_count = 0;
+ if (arg && !opts)
+ {
+ deinitialize (arg);
+ return 0;
+ }
+
if (!fp) /* Divert to arg_parse() in this case. */
return arg_parse (arg, opts);
- initialize (arg, filename, lineno);
+ if (initialize (arg, fp))
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+
/* If the LINENO is zero we assume that we are at the start of a
* file and we skip over a possible Byte Order Mark. */
- if (!*lineno)
+ if (!arg->lineno)
{
- unread_buf[0] = getc (fp);
- unread_buf[1] = getc (fp);
- unread_buf[2] = getc (fp);
+ unread_buf[0] = _gpgrt_fgetc (fp);
+ unread_buf[1] = _gpgrt_fgetc (fp);
+ unread_buf[2] = _gpgrt_fgetc (fp);
if (unread_buf[0] != 0xef
|| unread_buf[1] != 0xbb
|| unread_buf[2] != 0xbf)
@@ -587,11 +539,11 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
if (unread_buf_count)
c = unread_buf[3 - unread_buf_count--];
else
- c = getc (fp);
+ c = _gpgrt_fgetc (fp);
if (c == '\n' || c== EOF )
{
if ( c != EOF )
- ++*lineno;
+ arg->lineno++;
if (state == -1)
break;
else if (state == 2)
@@ -717,7 +669,7 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
else if (c == EOF)
{
ignore_invalid_option_clear (arg);
- if (ferror (fp))
+ if (_gpgrt_ferror (fp))
arg->r_opt = ARGPARSE_READ_ERROR;
else
arg->r_opt = 0; /* EOF. */
@@ -762,7 +714,7 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
break;
}
state = i = 0;
- ++*lineno;
+ arg->lineno++;
}
else if (ignore_invalid_option_p (arg, keyword))
state = 1; /* Process like a comment. */
@@ -851,8 +803,7 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
static int
-find_long_option( ARGPARSE_ARGS *arg,
- ARGPARSE_OPTS *opts, const char *keyword )
+find_long_option (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, const char *keyword)
{
int i;
size_t n;
@@ -872,10 +823,10 @@ find_long_option( ARGPARSE_ARGS *arg,
{
ALIAS_DEF a;
/* see whether it is an alias */
- for( a = args->internal.aliases; a; a = a->next ) {
+ for( a = args->internal->aliases; a; a = a->next ) {
if( !strcmp( a->name, keyword) ) {
/* todo: must parse the alias here */
- args->internal.cur_alias = a;
+ args->internal->cur_alias = a;
return -3; /* alias available */
}
}
@@ -900,8 +851,9 @@ find_long_option( ARGPARSE_ARGS *arg,
return -1; /* Not found. */
}
-int
-arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+
+static int
+arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts)
{
int idx;
int argc;
@@ -911,13 +863,13 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
/* Fill in missing standard options: help, version, warranty and
* dump-options. */
- ARGPARSE_OPTS help_opt
+ gpgrt_opt_t help_opt
= ARGPARSE_s_n (ARGPARSE_SHORTOPT_HELP, "help", "@");
- ARGPARSE_OPTS version_opt
+ gpgrt_opt_t version_opt
= ARGPARSE_s_n (ARGPARSE_SHORTOPT_VERSION, "version", "@");
- ARGPARSE_OPTS warranty_opt
+ gpgrt_opt_t warranty_opt
= ARGPARSE_s_n (ARGPARSE_SHORTOPT_WARRANTY, "warranty", "@");
- ARGPARSE_OPTS dump_options_opt
+ gpgrt_opt_t dump_options_opt
= ARGPARSE_s_n(ARGPARSE_SHORTOPT_DUMP_OPTIONS, "dump-options", "@");
int seen_help = 0;
int seen_version = 0;
@@ -949,10 +901,12 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
if (! seen_dump_options)
opts[i++] = dump_options_opt;
- initialize( arg, NULL, NULL );
+ if (initialize( arg, NULL))
+ return (arg->r_opt = ARGPARSE_OUT_OF_CORE);
+
argc = *arg->argc;
argv = *arg->argv;
- idx = arg->internal.idx;
+ idx = arg->internal->idx;
if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
{
@@ -969,16 +923,16 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
}
s = *argv;
- arg->internal.last = s;
+ arg->internal->last = s;
- if (arg->internal.stopped && (arg->flags & ARGPARSE_FLAG_ALL))
+ if (arg->internal->stopped && (arg->flags & ARGPARSE_FLAG_ALL))
{
arg->r_opt = ARGPARSE_IS_ARG; /* Not an option but an argument. */
arg->r_type = 2;
arg->r.ret_str = s;
argc--; argv++; idx++; /* set to next one */
}
- else if( arg->internal.stopped )
+ else if( arg->internal->stopped )
{
arg->r_opt = 0;
goto leave; /* Ready. */
@@ -988,11 +942,11 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
/* Long option. */
char *argpos;
- arg->internal.inarg = 0;
+ arg->internal->inarg = 0;
if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
{
/* Stop option processing. */
- arg->internal.stopped = 1;
+ arg->internal->stopped = 1;
arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
argc--; argv++; idx++;
goto next_one;
@@ -1012,13 +966,13 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
{
show_version ();
- exit(0);
+ my_exit (arg, 0);
}
}
else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_WARRANTY)
{
- writestrings (0, strusage (16), "\n", NULL);
- exit (0);
+ writestrings (0, _gpgrt_strusage (16), "\n", NULL);
+ my_exit (arg, 0);
}
else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS)
{
@@ -1027,7 +981,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
writestrings (0, "--", opts[i].long_opt, "\n", NULL);
}
- exit (0);
+ my_exit (arg, 0);
}
if ( i == -2 )
@@ -1086,15 +1040,15 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
}
argc--; argv++; idx++; /* Set to next one. */
}
- else if ( (*s == '-' && s[1]) || arg->internal.inarg )
+ else if ( (*s == '-' && s[1]) || arg->internal->inarg )
{
/* Short option. */
int dash_kludge = 0;
i = 0;
- if ( !arg->internal.inarg )
+ if ( !arg->internal->inarg )
{
- arg->internal.inarg++;
+ arg->internal->inarg++;
if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
{
for (i=0; opts[i].short_opt; i++ )
@@ -1105,7 +1059,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
}
}
}
- s += arg->internal.inarg;
+ s += arg->internal->inarg;
if (!dash_kludge )
{
@@ -1122,7 +1076,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
{
arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
- arg->internal.inarg++; /* Point to the next arg. */
+ arg->internal->inarg++; /* Point to the next arg. */
arg->r.ret_str = s;
}
else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
@@ -1163,12 +1117,12 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
{
/* Does not take an argument. */
arg->r_type = ARGPARSE_TYPE_NONE;
- arg->internal.inarg++; /* Point to the next arg. */
+ arg->internal->inarg++; /* Point to the next arg. */
}
if ( !s[1] || dash_kludge )
{
/* No more concatenated short options. */
- arg->internal.inarg = 0;
+ arg->internal->inarg = 0;
argc--; argv++; idx++;
}
}
@@ -1181,14 +1135,14 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
}
else
{
- arg->internal.stopped = 1; /* Stop option processing. */
+ arg->internal->stopped = 1; /* Stop option processing. */
goto next_one;
}
leave:
*arg->argc = argc;
*arg->argv = argv;
- arg->internal.idx = idx;
+ arg->internal->idx = idx;
return arg->r_opt;
}
@@ -1196,7 +1150,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
/* Returns: -1 on error, 0 for an integer type and 1 for a non integer
type argument. */
static int
-set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
+set_opt_arg (gpgrt_argparse_t *arg, unsigned flags, char *s)
{
int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
long l;
@@ -1250,7 +1204,7 @@ set_opt_arg (ARGPARSE_ARGS *arg, unsigned flags, char *s)
static size_t
-long_opt_strlen( ARGPARSE_OPTS *o )
+long_opt_strlen( gpgrt_opt_t *o )
{
size_t n = strlen (o->long_opt);
@@ -1285,22 +1239,22 @@ long_opt_strlen( ARGPARSE_OPTS *o )
* bar and the next one as arguments of the long option.
*/
static void
-show_help (ARGPARSE_OPTS *opts, unsigned int flags)
+show_help (gpgrt_opt_t *opts, unsigned int flags)
{
const char *s;
char tmp[2];
show_version ();
writestrings (0, "\n", NULL);
- s = strusage (42);
+ s = _gpgrt_strusage (42);
if (s && *s == '1')
{
- s = strusage (40);
+ s = _gpgrt_strusage (40);
writestrings (1, s, NULL);
if (*s && s[strlen(s)] != '\n')
writestrings (1, "\n", NULL);
}
- s = strusage(41);
+ s = _gpgrt_strusage(41);
writestrings (0, s, "\n", NULL);
if ( opts[0].description )
{
@@ -1322,7 +1276,7 @@ show_help (ARGPARSE_OPTS *opts, unsigned int flags)
writestrings (0, "Options:", "\n", NULL);
for (i=0; opts[i].short_opt; i++ )
{
- s = map_static_macro_string (_( opts[i].description ));
+ s = map_fixed_string (_( opts[i].description ));
if ( s && *s== '@' && !s[1] ) /* Hide this line. */
continue;
if ( s && *s == '@' ) /* Unindented comment only line. */
@@ -1428,15 +1382,16 @@ show_help (ARGPARSE_OPTS *opts, unsigned int flags)
writestrings (0, "\n(A single dash may be used "
"instead of the double ones)\n", NULL);
}
- if ( (s=strusage(19)) )
+ if ( (s=_gpgrt_strusage(19)) )
{
writestrings (0, "\n", NULL);
writestrings (0, s, NULL);
}
flushstrings (0);
- exit(0);
+ exit (0);
}
+
static void
show_version ()
{
@@ -1444,48 +1399,48 @@ show_version ()
int i;
/* Version line. */
- writestrings (0, strusage (11), NULL);
- if ((s=strusage (12)))
+ writestrings (0, _gpgrt_strusage (11), NULL);
+ if ((s=_gpgrt_strusage (12)))
writestrings (0, " (", s, ")", NULL);
- writestrings (0, " ", strusage (13), "\n", NULL);
+ writestrings (0, " ", _gpgrt_strusage (13), "\n", NULL);
/* Additional version lines. */
for (i=20; i < 30; i++)
- if ((s=strusage (i)))
+ if ((s=_gpgrt_strusage (i)))
writestrings (0, s, "\n", NULL);
/* Copyright string. */
- if ((s=strusage (14)))
+ if ((s=_gpgrt_strusage (14)))
writestrings (0, s, "\n", NULL);
/* Licence string. */
- if( (s=strusage (10)) )
+ if( (s=_gpgrt_strusage (10)) )
writestrings (0, s, "\n", NULL);
/* Copying conditions. */
- if ( (s=strusage(15)) )
+ if ( (s=_gpgrt_strusage(15)) )
writestrings (0, s, NULL);
/* Thanks. */
- if ((s=strusage(18)))
+ if ((s=_gpgrt_strusage(18)))
writestrings (0, s, NULL);
/* Additional program info. */
for (i=30; i < 40; i++ )
- if ( (s=strusage (i)) )
+ if ( (s=_gpgrt_strusage (i)) )
writestrings (0, s, NULL);
flushstrings (0);
}
void
-usage (int level)
+_gpgrt_usage (int level)
{
const char *p;
if (!level)
{
- writestrings (1, strusage(11), " ", strusage(13), "; ",
- strusage (14), "\n", NULL);
+ writestrings (1, _gpgrt_strusage(11), " ", _gpgrt_strusage(13), "; ",
+ _gpgrt_strusage (14), "\n", NULL);
flushstrings (1);
}
else if (level == 1)
{
- p = strusage (40);
+ p = _gpgrt_strusage (40);
writestrings (1, p, NULL);
if (*p && p[strlen(p)] != '\n')
writestrings (1, "\n", NULL);
@@ -1493,15 +1448,15 @@ usage (int level)
}
else if (level == 2)
{
- p = strusage (42);
+ p = _gpgrt_strusage (42);
if (p && *p == '1')
{
- p = strusage (40);
+ p = _gpgrt_strusage (40);
writestrings (1, p, NULL);
if (*p && p[strlen(p)] != '\n')
writestrings (1, "\n", NULL);
}
- writestrings (0, strusage(41), "\n", NULL);
+ writestrings (0, _gpgrt_strusage(41), "\n", NULL);
exit (0);
}
}
@@ -1510,6 +1465,8 @@ usage (int level)
* 0: Print copyright string to stderr
* 1: Print a short usage hint to stderr and terminate
* 2: Print a long usage hint to stdout and terminate
+ * 8: Return NULL for UTF-8 or string with the native charset.
+ * 9: Return the SPDX License tag.
* 10: Return license info string
* 11: Return the name of the program
* 12: Return optional name of package which includes this program.
@@ -1530,38 +1487,69 @@ usage (int level)
* before the long usage note.
*/
const char *
-strusage( int level )
+_gpgrt_strusage (int level)
{
const char *p = strusage_handler? strusage_handler(level) : NULL;
+ const char *tmp;
if ( p )
- return map_static_macro_string (p);
+ return map_fixed_string (p);
switch ( level )
{
+ case 8: break; /* Default to utf-8. */
+ case 9:
+ p = "GPL-3.0-or-later"; /* Suggested license. */
+ break;
+
case 10:
-#if ARGPARSE_GPL_VERSION == 3
- p = ("License GPLv3+: GNU GPL version 3 or later "
- "<https://gnu.org/licenses/gpl.html>");
-#else
- p = ("License GPLv2+: GNU GPL version 2 or later "
- "<https://gnu.org/licenses/>");
-#endif
+ tmp = _gpgrt_strusage (9);
+ if (tmp && !strcmp (tmp, "GPL-2.0-or-later"))
+ p = ("License GPL-2.0-or-later <https://gnu.org/licenses/>");
+ else if (tmp && !strcmp (tmp, "LGPL-2.1-or-later"))
+ p = ("License LGPL-2.1-or-later <https://gnu.org/licenses/>");
+ else /* Default to GPLv3+. */
+ p = ("License GPL-3.0-or-later <https://gnu.org/licenses/gpl.html>");
break;
case 11: p = "foo"; break;
case 13: p = "0.0"; break;
- case 14: p = ARGPARSE_CRIGHT_STR; break;
+ case 14: p = "Copyright (C) YEAR NAME"; break;
case 15: p =
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n";
break;
- case 16: p =
+ case 16:
+ tmp = _gpgrt_strusage (9);
+ if (tmp && !strcmp (tmp, "GPL-2.0-or-later"))
+ p =
"This is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
-"the Free Software Foundation; either version "
-ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
-" of the License, or\n"
+"the Free Software Foundation; either version 2 of the License, or\n"
+"(at your option) any later version.\n\n"
+"It is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU General Public License for more details.\n\n"
+"You should have received a copy of the GNU General Public License\n"
+"along with this software. If not, see <https://gnu.org/licenses/>.\n";
+ else if (tmp && !strcmp (tmp, "LGPL-2.1-or-later"))
+ p =
+"This is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU Lesser General Public License as\n"
+"published by the Free Software Foundation; either version 2.1 of\n"
+"the License, or (at your option) any later version.\n\n"
+"It is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU Lesser General Public License for more details.\n\n"
+"You should have received a copy of the GNU General Public License\n"
+"along with this software. If not, see <https://gnu.org/licenses/>.\n";
+ else /* Default */
+ p =
+"This is free software; you can redistribute it and/or modify\n"
+"it under the terms of the GNU General Public License as published by\n"
+"the Free Software Foundation; either version 3 of the License, or\n"
"(at your option) any later version.\n\n"
"It is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
@@ -1580,81 +1568,30 @@ ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
/* Set the usage handler. This function is basically a constructor. */
void
-set_strusage ( const char *(*f)( int ) )
+_gpgrt_set_strusage (const char *(*f)(int) )
{
strusage_handler = f;
}
-#ifdef TEST
-static struct {
- int verbose;
- int debug;
- char *outfile;
- char *crf;
- int myopt;
- int echo;
- int a_long_one;
-} opt;
-
-int
-main(int argc, char **argv)
+/* Set a function to write strings which is the used instead of
+ * estream. The first arg of that function is MODE and the second the
+ * STRING to write. A mode of 1 is used for writing to stdout and a
+ * mode of 2 to write to stderr. Other modes are reserved and should
+ * not output anything. A NULL for STRING requests a flush. */
+void
+_gpgrt_set_usage_outfnc (int (*f)(int, const char *))
{
- ARGPARSE_OPTS opts[] = {
- ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
- ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
- "was wir eingegeben haben")),
- ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
- ARGPARSE_s_s('o', "output", 0 ),
- ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
- /* Note that on a non-utf8 terminal the ß might garble the output. */
- ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
- ARGPARSE_o_i('m', "my-option", 0),
- ARGPARSE_s_n(500, "a-long-option", 0 ),
- ARGPARSE_end()
- };
- ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
- | ARGPARSE_FLAG_MIXED
- | ARGPARSE_FLAG_ONEDASH) };
- int i;
+ custom_outfnc = f;
+}
- while (arg_parse (&pargs, opts))
- {
- switch (pargs.r_opt)
- {
- case ARGPARSE_IS_ARG :
- printf ("arg='%s'\n", pargs.r.ret_str);
- break;
- case 'v': opt.verbose++; break;
- case 'e': opt.echo++; break;
- case 'd': opt.debug++; break;
- case 'o': opt.outfile = pargs.r.ret_str; break;
- case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
- case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
- case 500: opt.a_long_one++; break;
- default : pargs.err = ARGPARSE_PRINT_WARNING; break;
- }
- }
- for (i=0; i < argc; i++ )
- printf ("%3d -> (%s)\n", i, argv[i] );
- puts ("Options:");
- if (opt.verbose)
- printf (" verbose=%d\n", opt.verbose );
- if (opt.debug)
- printf (" debug=%d\n", opt.debug );
- if (opt.outfile)
- printf (" outfile='%s'\n", opt.outfile );
- if (opt.crf)
- printf (" crffile='%s'\n", opt.crf );
- if (opt.myopt)
- printf (" myopt=%d\n", opt.myopt );
- if (opt.a_long_one)
- printf (" a-long-one=%d\n", opt.a_long_one );
- if (opt.echo)
- printf (" echo=%d\n", opt.echo );
- return 0;
+/* Register function F as a string mapper which takes a string as
+ * argument, replaces known "@FOO@" style macros and returns a new
+ * fixed string. Warning: The input STRING must have been allocated
+ * statically. */
+void
+_gpgrt_set_fixed_string_mapper (const char *(*f)(const char*))
+{
+ fixed_string_mapper = f;
}
-#endif /*TEST*/
-
-/**** bottom of file ****/
diff --git a/src/argparse.h b/src/argparse.h
deleted file mode 100644
index 4167d66..0000000
--- a/src/argparse.h
+++ /dev/null
@@ -1,207 +0,0 @@
-/* argparse.h - Argument parser for option handling.
- * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch
- * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
- * Copyright (C) 2015-2017 g10 Code GmbH
- *
- * This file is part of GnuPG.
- *
- * This file is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, see <https://www.gnu.org/licenses/>.
- * SPDX-License-Identifier: LGPL-2.1+
- */
-
-#ifndef GNUPG_COMMON_ARGPARSE_H
-#define GNUPG_COMMON_ARGPARSE_H
-
-#include <stdio.h>
-
-typedef struct
-{
- int *argc; /* Pointer to ARGC (value subject to change). */
- char ***argv; /* Pointer to ARGV (value subject to change). */
- unsigned int flags; /* Global flags. May be set prior to calling the
- parser. The parser may change the value. */
- int err; /* Print error description for last option.
- Either 0, ARGPARSE_PRINT_WARNING or
- ARGPARSE_PRINT_ERROR. */
-
- int r_opt; /* Returns option code. */
- int r_type; /* Returns type of option value. */
- union {
- int ret_int;
- long ret_long;
- unsigned long ret_ulong;
- char *ret_str;
- } r; /* Return values */
-
- struct {
- int idx;
- int inarg;
- int stopped;
- const char *last;
- void *aliases;
- const void *cur_alias;
- void *iio_list;
- } internal; /* Private - do not change. */
-} ARGPARSE_ARGS;
-
-typedef struct
-{
- int short_opt;
- const char *long_opt;
- unsigned int flags;
- const char *description; /* Optional option description. */
-} ARGPARSE_OPTS;
-
-/* Short options. */
-#define ARGPARSE_SHORTOPT_HELP 32768
-#define ARGPARSE_SHORTOPT_VERSION 32769
-#define ARGPARSE_SHORTOPT_WARRANTY 32770
-#define ARGPARSE_SHORTOPT_DUMP_OPTIONS 32771
-
-
-/* Global flags (ARGPARSE_ARGS). */
-#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */
-#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return
- remaining args with R_OPT set to -1. */
-#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */
-#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */
-#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */
-#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */
-#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */
-
-#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */
-
-/* Flags for each option (ARGPARSE_OPTS). The type code may be
- ORed with the OPT flags. */
-#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */
-#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */
-#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */
-#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */
-#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */
-#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */
-#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */
-#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */
-#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */
-
-#define ARGPARSE_TYPE_MASK 7 /* Mask for the type values (internal). */
-
-/* A set of macros to make option definitions easier to read. */
-#define ARGPARSE_x(s,l,t,f,d) \
- { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) }
-
-#define ARGPARSE_s(s,l,t,d) \
- { (s), (l), ARGPARSE_TYPE_ ## t, (d) }
-#define ARGPARSE_s_n(s,l,d) \
- { (s), (l), ARGPARSE_TYPE_NONE, (d) }
-#define ARGPARSE_s_i(s,l,d) \
- { (s), (l), ARGPARSE_TYPE_INT, (d) }
-#define ARGPARSE_s_s(s,l,d) \
- { (s), (l), ARGPARSE_TYPE_STRING, (d) }
-#define ARGPARSE_s_l(s,l,d) \
- { (s), (l), ARGPARSE_TYPE_LONG, (d) }
-#define ARGPARSE_s_u(s,l,d) \
- { (s), (l), ARGPARSE_TYPE_ULONG, (d) }
-
-#define ARGPARSE_o(s,l,t,d) \
- { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) }
-#define ARGPARSE_o_n(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) }
-#define ARGPARSE_o_i(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) }
-#define ARGPARSE_o_s(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) }
-#define ARGPARSE_o_l(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) }
-#define ARGPARSE_o_u(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) }
-
-#define ARGPARSE_p(s,l,t,d) \
- { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_p_n(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_p_i(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_p_s(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_p_l(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_p_u(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) }
-
-#define ARGPARSE_op(s,l,t,d) \
- { (s), (l), (ARGPARSE_TYPE_ ## t \
- | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_op_n(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_NONE \
- | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_op_i(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_INT \
- | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_op_s(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_STRING \
- | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_op_l(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_LONG \
- | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
-#define ARGPARSE_op_u(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_ULONG \
- | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
-
-#define ARGPARSE_c(s,l,d) \
- { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) }
-
-#define ARGPARSE_ignore(s,l) \
- { (s), (l), (ARGPARSE_OPT_IGNORE), "@" }
-
-#define ARGPARSE_group(s,d) \
- { (s), NULL, 0, (d) }
-
-/* Placeholder options for help, version, warranty and dump-options. See arg_parse(). */
-#define ARGPARSE_end() \
- { 0, NULL, 0, NULL }, \
- { 0, NULL, 0, NULL }, \
- { 0, NULL, 0, NULL }, \
- { 0, NULL, 0, NULL }, \
- { 0, NULL, 0, NULL }
-
-
-/* Other constants. */
-#define ARGPARSE_PRINT_WARNING 1
-#define ARGPARSE_PRINT_ERROR 2
-
-
-/* Error values. */
-#define ARGPARSE_IS_ARG (-1)
-#define ARGPARSE_INVALID_OPTION (-2)
-#define ARGPARSE_MISSING_ARG (-3)
-#define ARGPARSE_KEYWORD_TOO_LONG (-4)
-#define ARGPARSE_READ_ERROR (-5)
-#define ARGPARSE_UNEXPECTED_ARG (-6)
-#define ARGPARSE_INVALID_COMMAND (-7)
-#define ARGPARSE_AMBIGUOUS_OPTION (-8)
-#define ARGPARSE_AMBIGUOUS_COMMAND (-9)
-#define ARGPARSE_INVALID_ALIAS (-10)
-#define ARGPARSE_OUT_OF_CORE (-11)
-#define ARGPARSE_INVALID_ARG (-12)
-
-
-int arg_parse (ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
-int optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
- ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
-void usage (int level);
-const char *strusage (int level);
-void set_strusage (const char *(*f)( int ));
-void argparse_register_outfnc (int (*fnc)(int, const char *));
-
-#endif /*GNUPG_COMMON_ARGPARSE_H*/
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index eea6e4a..7a6a2ef 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -207,5 +207,11 @@ EXPORTS
;; gpgrt_kill_process @158
;; gpgrt_release_process @159
+ gpgrt_argparse @160
+ gpgrt_strusage @161
+ gpgrt_set_strusage @162
+ gpgrt_set_usage_outfnc @163
+ gpgrt_set_fixed_string_mapper @164
+
;; end of file with public symbols for Windows.
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index cc2e361..86bb5b2 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -83,6 +83,12 @@ extern "C" {
GPGRT_ENABLE_ES_MACROS: Define to provide "es_" macros for the
estream functions.
+ GPGRT_ENABLE_LOG_MACROS: Define to provide short versions of the
+ log functions.
+
+ GPGRT_ENABLE_ARGPARSE_MACROS: Needs to be defined to provide the
+ mandatory macros of the argparse interface.
+
In addition to the error codes, Libgpg-error also provides a set of
functions used by most GnuPG components. */
@@ -1079,6 +1085,181 @@ void gpgrt_release_process (pid_t pid);
#endif /*0*/
+
+
+/*
+ * Option parsing.
+ */
+
+struct _gpgrt_argparse_internal_s;
+typedef struct
+{
+ int *argc; /* Pointer to ARGC (value subject to change). */
+ char ***argv; /* Pointer to ARGV (value subject to change). */
+ unsigned int flags; /* Global flags. May be set prior to calling the
+ parser. The parser may change the value. */
+ int err; /* Print error description for last option.
+ Either 0, ARGPARSE_PRINT_WARNING or
+ ARGPARSE_PRINT_ERROR. */
+ unsigned int lineno;/* The current line number. */
+ int r_opt; /* Returns option code. */
+ int r_type; /* Returns type of option value. */
+ union {
+ int ret_int;
+ long ret_long;
+ unsigned long ret_ulong;
+ char *ret_str;
+ } r; /* Return values */
+
+ struct _gpgrt_argparse_internal_s *internal;
+} gpgrt_argparse_t;
+
+
+typedef struct
+{
+ int short_opt;
+ const char *long_opt;
+ unsigned int flags;
+ const char *description; /* Optional description. */
+} gpgrt_opt_t;
+
+
+#ifdef GPGRT_ENABLE_ARGPARSE_MACROS
+
+/* Global flags for (gpgrt_argparse_t).flags. */
+#define ARGPARSE_FLAG_KEEP 1 /* Do not remove options form argv. */
+#define ARGPARSE_FLAG_ALL 2 /* Do not stop at last option but return
+ remaining args with R_OPT set to -1. */
+#define ARGPARSE_FLAG_MIXED 4 /* Assume options and args are mixed. */
+#define ARGPARSE_FLAG_NOSTOP 8 /* Do not stop processing at "--". */
+#define ARGPARSE_FLAG_ARG0 16 /* Do not skip the first arg. */
+#define ARGPARSE_FLAG_ONEDASH 32 /* Allow long options with one dash. */
+#define ARGPARSE_FLAG_NOVERSION 64 /* No output for "--version". */
+#define ARGPARSE_FLAG_RESET 128 /* Request to reset the internal state. */
+#define ARGPARSE_FLAG_STOP_SEEN 256 /* Set to true if a "--" has been seen. */
+#define ARGPARSE_FLAG_NOLINENO 512 /* Do not zero the lineno field. */
+
+/* Constants for (gpgrt_argparse_t).err. */
+#define ARGPARSE_PRINT_WARNING 1 /* Print a diagnostic. */
+#define ARGPARSE_PRINT_ERROR 2 /* Print a diagnostic and call exit. */
+
+/* Special return values of gpgrt_argparse. */
+#define ARGPARSE_IS_ARG (-1)
+#define ARGPARSE_INVALID_OPTION (-2)
+#define ARGPARSE_MISSING_ARG (-3)
+#define ARGPARSE_KEYWORD_TOO_LONG (-4)
+#define ARGPARSE_READ_ERROR (-5)
+#define ARGPARSE_UNEXPECTED_ARG (-6)
+#define ARGPARSE_INVALID_COMMAND (-7)
+#define ARGPARSE_AMBIGUOUS_OPTION (-8)
+#define ARGPARSE_AMBIGUOUS_COMMAND (-9)
+#define ARGPARSE_INVALID_ALIAS (-10)
+#define ARGPARSE_OUT_OF_CORE (-11)
+#define ARGPARSE_INVALID_ARG (-12)
+
+/* Flags for the option descriptor (gpgrt_opt_t)->flags. Note that
+ * a TYPE constant may be or-ed with the OPT constants. */
+#define ARGPARSE_TYPE_NONE 0 /* Does not take an argument. */
+#define ARGPARSE_TYPE_INT 1 /* Takes an int argument. */
+#define ARGPARSE_TYPE_STRING 2 /* Takes a string argument. */
+#define ARGPARSE_TYPE_LONG 3 /* Takes a long argument. */
+#define ARGPARSE_TYPE_ULONG 4 /* Takes an unsigned long argument. */
+#define ARGPARSE_OPT_OPTIONAL (1<<3) /* Argument is optional. */
+#define ARGPARSE_OPT_PREFIX (1<<4) /* Allow 0x etc. prefixed values. */
+#define ARGPARSE_OPT_IGNORE (1<<6) /* Ignore command or option. */
+#define ARGPARSE_OPT_COMMAND (1<<7) /* The argument is a command. */
+
+/* A set of macros to make option definitions easier to read. */
+#define ARGPARSE_x(s,l,t,f,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t | (f), (d) }
+
+#define ARGPARSE_s(s,l,t,d) \
+ { (s), (l), ARGPARSE_TYPE_ ## t, (d) }
+#define ARGPARSE_s_n(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_NONE, (d) }
+#define ARGPARSE_s_i(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_INT, (d) }
+#define ARGPARSE_s_s(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_STRING, (d) }
+#define ARGPARSE_s_l(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_LONG, (d) }
+#define ARGPARSE_s_u(s,l,d) \
+ { (s), (l), ARGPARSE_TYPE_ULONG, (d) }
+
+#define ARGPARSE_o(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_OPTIONAL), (d) }
+#define ARGPARSE_o_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_OPTIONAL), (d) }
+
+#define ARGPARSE_p(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_p_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_op(s,l,t,d) \
+ { (s), (l), (ARGPARSE_TYPE_ ## t \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_n(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_i(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_INT \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_s(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_STRING \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_l(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_LONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+#define ARGPARSE_op_u(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_ULONG \
+ | ARGPARSE_OPT_OPTIONAL | ARGPARSE_OPT_PREFIX), (d) }
+
+#define ARGPARSE_c(s,l,d) \
+ { (s), (l), (ARGPARSE_TYPE_NONE | ARGPARSE_OPT_COMMAND), (d) }
+
+#define ARGPARSE_ignore(s,l) \
+ { (s), (l), (ARGPARSE_OPT_IGNORE), "@" }
+
+#define ARGPARSE_group(s,d) \
+ { (s), NULL, 0, (d) }
+
+/* Placeholder options for help, version, warranty and dump-options.
+ * See arg_parse(). FIXME: We need to hide this from the API. */
+#define ARGPARSE_end() \
+ { 0, NULL, 0, NULL }, \
+ { 0, NULL, 0, NULL }, \
+ { 0, NULL, 0, NULL }, \
+ { 0, NULL, 0, NULL }, \
+ { 0, NULL, 0, NULL }
+#endif /* GPGRT_ENABLE_ARGPARSE_MACROS */
+
+
+int gpgrt_argparse (gpgrt_stream_t fp,
+ gpgrt_argparse_t *arg, gpgrt_opt_t *opts);
+const char *gpgrt_strusage (int level);
+void gpgrt_set_strusage (const char *(*f)(int));
+void gpgrt_set_usage_outfnc (int (*f)(int, const char *));
+void gpgrt_set_fixed_string_mapper (const char *(*f)(const char*));
+
+
+
#ifdef __cplusplus
}
#endif
diff --git a/src/gpg-error.vers b/src/gpg-error.vers
index 1105e80..cdef0cd 100644
--- a/src/gpg-error.vers
+++ b/src/gpg-error.vers
@@ -179,6 +179,11 @@ GPG_ERROR_1.0 {
# gpgrt_kill_process;
# gpgrt_release_process;
+ gpgrt_argparse;
+ gpgrt_strusage;
+ gpgrt_set_strusage;
+ gpgrt_set_usage_outfnc;
+ gpgrt_set_fixed_string_mapper;
local:
*;
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index fcce082..794874e 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -711,6 +711,15 @@ void _gpgrt_kill_process (pid_t pid);
void _gpgrt_release_process (pid_t pid);
+/*
+ * Local prototypes for argparse.
+ */
+int _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts);
+const char *_gpgrt_strusage (int level);
+void _gpgrt_set_strusage (const char *(*f)(int));
+void _gpgrt_set_usage_outfnc (int (*fnc)(int, const char *));
+void _gpgrt_set_fixed_string_mapper (const char *(*f)(const char*));
+
/*
diff --git a/src/visibility.c b/src/visibility.c
index 9358163..7058c91 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1066,6 +1066,38 @@ gpgrt_release_process (pid_t pid)
}
#endif /*0*/
+
+int
+gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts)
+{
+ return _gpgrt_argparse (fp, arg, opts);
+}
+
+const char *
+gpgrt_strusage (int level)
+{
+ return _gpgrt_strusage (level);
+}
+
+void
+gpgrt_set_strusage (const char *(*f)(int))
+{
+ _gpgrt_set_strusage (f);
+}
+
+void
+gpgrt_set_usage_outfnc (int (*f)(int, const char *))
+{
+ _gpgrt_set_usage_outfnc (f);
+}
+
+void
+gpgrt_set_fixed_string_mapper (const char *(*f)(const char*))
+{
+ _gpgrt_set_fixed_string_mapper (f);
+}
+
+
/* For consistency reasons we use function wrappers also for Windows
* specific function despite that they are technically not needed. */
diff --git a/src/visibility.h b/src/visibility.h
index f37555a..51d9e38 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -199,6 +199,12 @@ MARK_VISIBLE (gpgrt_kill_process)
MARK_VISIBLE (gpgrt_release_process)
#endif
+MARK_VISIBLE (gpgrt_argparse)
+MARK_VISIBLE (gpgrt_set_strusage)
+MARK_VISIBLE (gpgrt_strusage)
+MARK_VISIBLE (gpgrt_set_fixed_string_mapper);
+MARK_VISIBLE (gpgrt_set_usage_outfnc);
+
#undef MARK_VISIBLE
#else /*!_GPGRT_INCL_BY_VISIBILITY_C*/
@@ -359,6 +365,11 @@ MARK_VISIBLE (gpgrt_release_process)
#define gpgrt_kill_process _gpgrt_USE_UNDERSCORED_FUNCTION
#define gpgrt_release_process _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_argparse _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_set_strusage _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_strusage _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_set_usage_outfnc _gpgrt_USE_UNDERSCORED_FUNCTION
+#define gpgrt_set_fixed_string_mapper _gpgrt_USE_UNDERSCORED_FUNCTION
/* Windows specific functions. */
#define gpgrt_w32_reg_query_string _gpgrt_USE_UNDERSCORED_FUNCTION
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a3c6cbd..cc3a2ad 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,7 +27,8 @@ endif
gpg_error_lib = ../src/libgpg-error.la
-TESTS = t-version t-strerror t-syserror t-lock t-printf t-poll t-b64dec
+TESTS = t-version t-strerror t-syserror t-lock t-printf t-poll t-b64dec \
+ t-argparse
AM_CPPFLAGS = -I$(top_builddir)/src $(extra_includes)
diff --git a/tests/t-argparse.c b/tests/t-argparse.c
new file mode 100644
index 0000000..177992a
--- /dev/null
+++ b/tests/t-argparse.c
@@ -0,0 +1,125 @@
+/* t-argparse.c - Check the argparse API
+ * Copyright (C) 2018 g10 Code GmbH
+ *
+ * This file is part of Libgpg-error.
+ *
+ * Libgpg-error is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgpg-error is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "../src/gpg-error.h"
+
+
+static struct {
+ int verbose;
+ int debug;
+ char *outfile;
+ char *crf;
+ int myopt;
+ int echo;
+ int a_long_one;
+} opt;
+
+
+
+static const char *
+my_strusage (int level)
+{
+ const char *p;
+
+ switch (level)
+ {
+ case 9: p = "GPL-2.0-or-later"; break;
+
+ case 11: p = "t-argparse"; break;
+
+ default: p = NULL;
+ }
+ return p;
+}
+
+
+
+int
+main (int argc, char **argv)
+{
+ gpgrt_opt_t opts[] = {
+ ARGPARSE_x ('v', "verbose", NONE, 0, "Laut sein"),
+ ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
+ "was wir eingegeben haben")),
+ ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
+ ARGPARSE_s_s('o', "output", 0 ),
+ ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
+ /* Note that on a non-utf8 terminal the ß might garble the output. */
+ ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
+ ARGPARSE_o_i('m', "my-option", 0),
+ ARGPARSE_s_n(500, "a-long-option", 0 ),
+ ARGPARSE_end()
+ };
+ gpgrt_argparse_t pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
+ | ARGPARSE_FLAG_MIXED
+ | ARGPARSE_FLAG_ONEDASH) };
+ int i;
+
+ gpgrt_set_strusage (my_strusage);
+
+
+ while (gpgrt_argparse (NULL, &pargs, opts))
+ {
+ switch (pargs.r_opt)
+ {
+ case ARGPARSE_IS_ARG :
+ printf ("arg='%s'\n", pargs.r.ret_str);
+ break;
+ case 'v': opt.verbose++; break;
+ case 'e': opt.echo++; break;
+ case 'd': opt.debug++; break;
+ case 'o': opt.outfile = pargs.r.ret_str; break;
+ case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ case 500: opt.a_long_one++; break;
+ default : pargs.err = ARGPARSE_PRINT_ERROR; break;
+ }
+ }
+ for (i=0; i < argc; i++ )
+ printf ("%3d -> (%s)\n", i, argv[i] );
+ puts ("Options:");
+ if (opt.verbose)
+ printf (" verbose=%d\n", opt.verbose );
+ if (opt.debug)
+ printf (" debug=%d\n", opt.debug );
+ if (opt.outfile)
+ printf (" outfile='%s'\n", opt.outfile );
+ if (opt.crf)
+ printf (" crffile='%s'\n", opt.crf );
+ if (opt.myopt)
+ printf (" myopt=%d\n", opt.myopt );
+ if (opt.a_long_one)
+ printf (" a-long-one=%d\n", opt.a_long_one );
+ if (opt.echo)
+ printf (" echo=%d\n", opt.echo );
+
+ gpgrt_argparse (NULL, &pargs, NULL);
+
+ return 0;
+}