Get rid of getopt_long and improve --help output.
authorWerner Koch <wk@gnupg.org>
Tue, 17 Mar 2015 10:28:40 +0000 (11:28 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 17 Mar 2015 10:28:40 +0000 (11:28 +0100)
* pinentry/argparse.c, pinentry/argparse.h: New. Taken from GnuPG
master.
* pinentry/Makefile.am (libpinentry_a_SOURCES): Add them.
* pinentry/pinentry.c: Include argparse.h.
(usage): Remove.
(my_strusage): New.
(pinentry_parse_opts): Rewrite.  Do not return a value.  Change call
callers.
--

getopt_long is not generally available, for example it is missing on
AIX.  Instead of adding replacement code we use the option parser
from GnuPG and thus also gain a better --version and --help.

Signed-off-by: Werner Koch <wk@gnupg.org>
12 files changed:
curses/pinentry-curses.c
gtk+-2/pinentry-gtk-2.c
gtk/pinentry-gtk.c
pinentry/Makefile.am
pinentry/argparse.c [new file with mode: 0644]
pinentry/argparse.h [new file with mode: 0644]
pinentry/pinentry.c
pinentry/pinentry.h
qt/main.cpp
qt4/main.cpp
tty/pinentry-tty.c
w32/main.c

index 823206e..20a5c93 100644 (file)
@@ -1,18 +1,18 @@
 /* pinentry-curses.c - A secure curses dialog for PIN entry.
    Copyright (C) 2002 g10 Code GmbH
-   
+
    This file is part of PINENTRY.
-   
+
    PINENTRY is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
+
    PINENTRY 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 General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 pinentry_cmd_handler_t pinentry_cmd_handler = curses_cmd_handler;
 
 \f
-int 
+int
 main (int argc, char *argv[])
 {
   pinentry_init ("pinentry-curses");
 
-  /* Consumes all arguments.  */
-  if (pinentry_parse_opts (argc, argv))
-    {
-      printf ("pinentry-curses (pinentry) " VERSION "\n");
-      exit (EXIT_SUCCESS);
-    }
+  pinentry_parse_opts (argc, argv);
 
   if (pinentry_loop ())
     return 1;
index 1a8c083..0063c3f 100644 (file)
@@ -689,12 +689,7 @@ main (int argc, char *argv[])
   gtk_init (&argc, &argv);
 #endif
 
-  /* Consumes all arguments.  */
-  if (pinentry_parse_opts (argc, argv))
-    {
-      printf(PGMNAME " " VERSION "\n");
-      exit(EXIT_SUCCESS);
-    }
+  pinentry_parse_opts (argc, argv);
 
   if (pinentry_loop ())
     return 1;
index 00bd531..4f9c116 100644 (file)
@@ -1,4 +1,4 @@
-/* gpinentry.c 
+/* gpinentry.c
  * Copyright (C) 2001, 2002 g10 Code GmbH
  * Copyright (C) 1999 Robert Bihlmeyer <robbe@orcus.priv.at>
  *
@@ -6,12 +6,12 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program 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 General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
@@ -33,7 +33,7 @@
 
 #ifdef HAVE_GETOPT_H
 #include <getopt.h>
-#else 
+#else
 #include "getopt.h"
 #endif /* HAVE_GETOPT_H */
 
@@ -56,7 +56,7 @@ static GtkWidget *entry, *insure, *time_out;
 
 #if 0 /* not used */
 /* ok - Return to the command handler routine.  */
-static void 
+static void
 ok (GtkWidget *w, gpointer data)
 {
   gtk_main_quit ();
@@ -65,7 +65,7 @@ ok (GtkWidget *w, gpointer data)
 
 /* unselect - work around a bug in GTK+ that permits word-selection to
    work on the invisible passphrase */
-static void 
+static void
 unselect(GtkWidget *w, GdkEventButton *e)
 {
   static gint lastpos;
@@ -82,14 +82,14 @@ unselect(GtkWidget *w, GdkEventButton *e)
 
 /* constrain_size - constrain size of the window the window should not
    shrink beyond the requisition, and should not grow vertically */
-static void 
+static void
 constrain_size(GtkWidget *win, GtkRequisition *req, gpointer data)
 {
   static gint width, height;
   GdkGeometry geo;
 
   if (req->width == width && req->height == height)
-    return; 
+    return;
   width = req->width;
   height = req->height;
   geo.min_width = width;
@@ -101,19 +101,19 @@ constrain_size(GtkWidget *win, GtkRequisition *req, gpointer data)
 }
 
 /* grab_keyboard - grab the keyboard for maximum security */
-static void 
+static void
 grab_keyboard(GtkWidget *win, GdkEvent *event, gpointer data)
 {
   if (!pinentry->grab)
     return;
-  if (gdk_keyboard_grab(win->window, FALSE, gdk_event_get_time(event))) 
+  if (gdk_keyboard_grab(win->window, FALSE, gdk_event_get_time(event)))
     {
       g_error("could not grab keyboard");
     }
 }
 
 /* ungrab_keyboard - remove grab */
-static void 
+static void
 ungrab_keyboard(GtkWidget *win, GdkEvent *event, gpointer data)
 {
   gdk_keyboard_ungrab(gdk_event_get_time(event));
@@ -172,7 +172,7 @@ button_clicked (GtkWidget *widget, gpointer data)
 }
 
 
-static void 
+static void
 enter_callback (GtkWidget *widget, GtkWidget *anentry)
 {
   button_clicked (widget, "ok");
@@ -270,7 +270,7 @@ create_window (int confirm_mode)
           style = gtk_style_copy(gtk_widget_get_style(w));
           style->fg[GTK_STATE_NORMAL] = color[0];
           gtk_widget_set_style(w, style);
-        } 
+        }
     }
 
   ebox = gtk_hbox_new (FALSE, 5);
@@ -300,22 +300,22 @@ create_window (int confirm_mode)
         {
           sbox = gtk_hbox_new(FALSE, 5);
           gtk_box_pack_start(GTK_BOX(box), sbox, FALSE, FALSE, 0);
-          
+
           w = gtk_label_new ("Forget secret after");
           gtk_box_pack_start(GTK_BOX(sbox), w, FALSE, FALSE, 0);
           gtk_widget_show(w);
-          
+
           time_out = gtk_spin_button_new
             (GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, HUGE_VAL,
                                                1, 60, 60)),2,0);
           gtk_box_pack_start (GTK_BOX(sbox), time_out, FALSE, FALSE, 0);
           gtk_widget_show (time_out);
-       
+
           w = gtk_label_new ("seconds");
-          gtk_box_pack_start (GTK_BOX(sbox), w, FALSE, FALSE, 0); 
+          gtk_box_pack_start (GTK_BOX(sbox), w, FALSE, FALSE, 0);
           gtk_widget_show (w);
           gtk_widget_show (sbox);
-          
+
           insure = gtk_check_button_new_with_label
             ("ask before giving out secret");
           gtk_box_pack_start (GTK_BOX(box), insure, FALSE, FALSE, 0);
@@ -328,7 +328,7 @@ create_window (int confirm_mode)
   bbox = gtk_hbutton_box_new();
   gtk_box_pack_start (GTK_BOX(box), bbox, TRUE, FALSE, 0);
   gtk_container_set_border_width (GTK_CONTAINER (bbox), 5);
-  
+
   w = gtk_button_new_with_label (pinentry->ok ? pinentry->ok : "OK");
   gtk_container_add (GTK_CONTAINER(bbox), w);
   if (!confirm_mode)
@@ -348,14 +348,14 @@ create_window (int confirm_mode)
     }
 
   gtk_widget_show (w);
-  
+
   if (!pinentry->one_button)
     {
-      w = gtk_button_new_with_label (pinentry->cancel 
+      w = gtk_button_new_with_label (pinentry->cancel
                                      ? pinentry->cancel : "Cancel");
       gtk_container_add (GTK_CONTAINER(bbox), w);
       gtk_accel_group_add (acc, GDK_Escape, 0, 0, GTK_OBJECT(w), "clicked");
-      gtk_signal_connect (GTK_OBJECT(w), "clicked", 
+      gtk_signal_connect (GTK_OBJECT(w), "clicked",
                           confirm_mode? confirm_button_clicked: button_clicked,
                           NULL);
       GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT);
@@ -399,7 +399,7 @@ gtk_cmd_handler (pinentry_t pe)
 
 pinentry_cmd_handler_t pinentry_cmd_handler = gtk_cmd_handler;
 
-int 
+int
 main (int argc, char *argv[])
 {
   pinentry_init (PGMNAME);
@@ -413,12 +413,7 @@ main (int argc, char *argv[])
   gtk_init (&argc, &argv);
 #endif
 
-  /* Consumes all arguments.  */
-  if (pinentry_parse_opts (argc, argv))
-    {
-      printf ("pinentry-gtk (pinentry) " VERSION "\n");
-      exit (EXIT_SUCCESS);
-    }
+  pinentry_parse_opts (argc, argv);
 
   if (pinentry_loop ())
     return 1;
index 5516d52..c3926b2 100644 (file)
@@ -31,5 +31,5 @@ noinst_LIBRARIES = libpinentry.a $(pinentry_curses)
 
 AM_CPPFLAGS = -I$(top_srcdir)/assuan -I$(top_srcdir)/secmem
 
-libpinentry_a_SOURCES = pinentry.h pinentry.c
+libpinentry_a_SOURCES = pinentry.h pinentry.c argparse.c argparse.h
 libpinentry_curses_a_SOURCES = pinentry-curses.h pinentry-curses.c
diff --git a/pinentry/argparse.c b/pinentry/argparse.c
new file mode 100644 (file)
index 0000000..e31b67e
--- /dev/null
@@ -0,0 +1,1607 @@
+/* [argparse.c wk 17.06.97] Argument Parser for option handling
+ * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch
+ *
+ * This file is part of JNLIB, which is a subsystem of GnuPG.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * JNLIB 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+
+#ifdef GNUPG_MAJOR_VERSION
+# include "libjnlib-config.h"
+# include "mischelp.h"
+# include "stringhelp.h"
+# include "logging.h"
+# ifdef JNLIB_NEED_UTF8CONV
+#  include "utf8conv.h"
+# endif
+#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 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) 2015 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 jnlib_malloc(a)    malloc ((a))
+# define jnlib_realloc(a,b) realloc ((a), (b))
+# define jnlib_strdup(a)    strdup ((a))
+# define jnlib_free(a)      free ((a))
+# define jnlib_log_error    my_log_error
+# define jnlib_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, ...)
+{
+  va_list arg_ptr ;
+
+  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, ...)
+{
+  va_list arg_ptr ;
+
+  va_start (arg_ptr, fmt);
+  fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));
+  vfprintf (stderr, fmt, arg_ptr);
+  va_end (arg_ptr);
+  abort ();
+}
+
+static char *
+my_trim_spaces (char *str)
+{
+  char *string, *p, *mark;
+
+  string = str;
+  /* Find first non space character. */
+  for (p=string; *p && isspace (*(unsigned char*)p) ; p++)
+    ;
+  /* Move characters. */
+  for ((mark = NULL); (*string = *p); string++, p++)
+    if (isspace (*(unsigned char*)p))
+      {
+        if (!mark)
+          mark = string;
+      }
+    else
+      mark = NULL;
+  if (mark)
+    *mark = '\0' ;  /* Remove trailing spaces. */
+
+  return str ;
+}
+
+#endif /*!GNUPG_MAJOR_VERSION*/
+
+
+
+/*********************************
+ * @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.
+ *  The option '--' stops argument processing; if bit 1 is set the function
+ *  continues to return normal arguments.
+ *  To process float args or unsigned args you must use a string args and do
+ *  the conversion yourself.
+ * @Example
+ *
+ *     ARGPARSE_OPTS opts[] = {
+ *     { 'v', "verbose",   0 },
+ *     { 'd', "debug",     0 },
+ *     { 'o', "output",    2 },
+ *     { 'c', "cross-ref", 2|8 },
+ *     { 'm', "my-option", 1|8 },
+ *     { 300, "ignored-long-option, ARGPARSE_OP_IGNORE},
+ *     { 500, "have-no-short-option-for-this-long-option", 0 },
+ *     {0} };
+ *     ARGPARSE_ARGS pargs = { &argc, &argv, 0 }
+ *
+ *     while( ArgParse( &pargs, &opts) ) {
+ *        switch( pargs.r_opt ) {
+ *          case 'v': opt.verbose++; 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 = 1; break; -- force warning output --
+ *        }
+ *     }
+ *     if( argc > 1 )
+ *        log_fatal( "Too many args");
+ *
+ */
+
+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
+   be terminated by a NULL.  */
+static int
+writestrings (int is_error, const char *string, ...)
+{
+  va_list arg_ptr;
+  const char *s;
+  int count = 0;
+
+  if (string)
+    {
+      s = string;
+      va_start (arg_ptr, string);
+      do
+        {
+          if (custom_outfnc)
+            custom_outfnc (is_error? 2:1, s);
+          else
+            fputs (s, is_error? stderr : stdout);
+          count += strlen (s);
+        }
+      while ((s = va_arg (arg_ptr, const char *)));
+      va_end (arg_ptr);
+    }
+  return count;
+}
+
+
+static void
+flushstrings (int is_error)
+{
+  if (custom_outfnc)
+    custom_outfnc (is_error? 2:1, NULL);
+  else
+    fflush (is_error? stderr : stdout);
+}
+
+
+static void
+initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
+{
+  if( !(arg->flags & (1<<15)) )
+    {
+      /* 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->err = 0;
+      arg->flags |= 1<<15; /* Mark as initialized.  */
+      if ( *arg->argc < 0 )
+        jnlib_log_bug ("invalid argument for arg_parse\n");
+    }
+
+
+  if (arg->err)
+    {
+      /* Last option was erroneous.  */
+      const char *s;
+
+      if (filename)
+        {
+          if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
+            s = _("argument not expected");
+          else if ( arg->r_opt == ARGPARSE_READ_ERROR )
+            s = _("read error");
+          else if ( arg->r_opt == ARGPARSE_KEYWORD_TOO_LONG )
+            s = _("keyword too long");
+          else if ( arg->r_opt == ARGPARSE_MISSING_ARG )
+            s = _("missing argument");
+          else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
+            s = _("invalid argument");
+          else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
+            s = _("invalid command");
+          else if ( arg->r_opt == ARGPARSE_INVALID_ALIAS )
+            s = _("invalid alias definition");
+          else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
+            s = _("out of core");
+          else
+            s = _("invalid option");
+          jnlib_log_error ("%s:%u: %s\n", filename, *lineno, s);
+       }
+      else
+        {
+          s = arg->internal.last? arg->internal.last:"[??]";
+
+          if ( arg->r_opt == ARGPARSE_MISSING_ARG )
+            jnlib_log_error (_("missing argument for option \"%.50s\"\n"), s);
+          else if ( arg->r_opt == ARGPARSE_INVALID_ARG )
+            jnlib_log_error (_("invalid argument for option \"%.50s\"\n"), s);
+          else if ( arg->r_opt == ARGPARSE_UNEXPECTED_ARG )
+            jnlib_log_error (_("option \"%.50s\" does not expect an "
+                               "argument\n"), s );
+          else if ( arg->r_opt == ARGPARSE_INVALID_COMMAND )
+            jnlib_log_error (_("invalid command \"%.50s\"\n"), s);
+          else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_OPTION )
+            jnlib_log_error (_("option \"%.50s\" is ambiguous\n"), s);
+          else if ( arg->r_opt == ARGPARSE_AMBIGUOUS_COMMAND )
+            jnlib_log_error (_("command \"%.50s\" is ambiguous\n"),s );
+          else if ( arg->r_opt == ARGPARSE_OUT_OF_CORE )
+            jnlib_log_error ("%s\n", _("out of core\n"));
+          else
+            jnlib_log_error (_("invalid option \"%.50s\"\n"), s);
+       }
+      if (arg->err != ARGPARSE_PRINT_WARNING)
+        exit (2);
+      arg->err = 0;
+    }
+
+  /* Zero out the return value union.  */
+  arg->r.ret_str = NULL;
+  arg->r.ret_long = 0;
+}
+
+
+static void
+store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
+{
+    /* TODO: replace this dummy function with a rea one
+     * and fix the probelms IRIX has with (ALIAS_DEV)arg..
+     * used as lvalue
+     */
+  (void)arg;
+  (void)name;
+  (void)value;
+#if 0
+    ALIAS_DEF a = jnlib_xmalloc( sizeof *a );
+    a->name = name;
+    a->value = value;
+    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)
+{
+  IIO_ITEM_DEF item = arg->internal.iio_list;
+
+  for (; item; item = item->next)
+    if (!strcmp (item->name, keyword))
+      return 1;
+  return 0;
+}
+
+
+/* Add the keywords up to the next LF to the list of to be ignored
+   options.  After returning FP will either be at EOF or the next
+   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)
+{
+  IIO_ITEM_DEF item;
+  int c;
+  char name[100];
+  int namelen = 0;
+  int ready = 0;
+  enum { skipWS, collectNAME, skipNAME, addNAME} state = skipWS;
+
+  while (!ready)
+    {
+      c = getc (fp);
+      if (c == '\n')
+        ready = 1;
+      else if (c == EOF)
+        {
+          c = '\n';
+          ready = 1;
+        }
+    again:
+      switch (state)
+        {
+        case skipWS:
+          if (!isascii (c) || !isspace(c))
+            {
+              namelen = 0;
+              state = collectNAME;
+              goto again;
+            }
+          break;
+
+        case collectNAME:
+          if (isspace (c))
+            {
+              state = addNAME;
+              goto again;
+            }
+          else if (namelen < DIM(name)-1)
+            name[namelen++] = c;
+          else /* Too long.  */
+            state = skipNAME;
+          break;
+
+        case skipNAME:
+          if (isspace (c))
+            {
+              state = skipWS;
+              goto again;
+            }
+          break;
+
+        case addNAME:
+          name[namelen] = 0;
+          if (!ignore_invalid_option_p (arg, name))
+            {
+              item = jnlib_malloc (sizeof *item + namelen);
+              if (!item)
+                return 1;
+              strcpy (item->name, name);
+              item->next = (IIO_ITEM_DEF)arg->internal.iio_list;
+              arg->internal.iio_list = item;
+            }
+          state = skipWS;
+          goto again;
+        }
+    }
+  return 0;
+}
+
+
+/* Clear the entire ignore-invalid-option list.  */
+static void
+ignore_invalid_option_clear (ARGPARSE_ARGS *arg)
+{
+  IIO_ITEM_DEF item, tmpitem;
+
+  for (item = arg->internal.iio_list; item; item = tmpitem)
+    {
+      tmpitem = item->next;
+      jnlib_free (item);
+    }
+  arg->internal.iio_list = NULL;
+}
+
+
+
+/****************
+ * Get options from a file.
+ * Lines starting with '#' are comment lines.
+ * Syntax is simply a keyword and the argument.
+ * Valid keywords are all keywords from the long_opt list without
+ * the leading dashes. The special keywords "help", "warranty" and "version"
+ * are not valid here.
+ * The special keyword "alias" may be used to store alias definitions,
+ * which are later expanded like long options.
+ * The option
+ *   ignore-invalid-option OPTIONNAMEs
+ * is recognized and updates a list of option which should be ignored if they
+ * are not defined.
+ * Caller must free returned strings.
+ * If called with FP set to NULL command line args are parse instead.
+ *
+ * Q: Should we allow the syntax
+ *     keyword = value
+ *    and accept for boolean options a value of 1/0, yes/no or true/false?
+ * Note: Abbreviation of options is here not allowed.
+ */
+int
+optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
+              ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+  int state, i, c;
+  int idx=0;
+  char keyword[100];
+  char *buffer = NULL;
+  size_t buflen = 0;
+  int in_alias=0;
+
+  if (!fp) /* Divert to to arg_parse() in this case.  */
+    return arg_parse (arg, opts);
+
+  initialize (arg, filename, lineno);
+
+  /* Find the next keyword.  */
+  state = i = 0;
+  for (;;)
+    {
+      c = getc (fp);
+      if (c == '\n' || c== EOF )
+        {
+          if ( c != EOF )
+            ++*lineno;
+          if (state == -1)
+            break;
+          else if (state == 2)
+            {
+              keyword[i] = 0;
+              for (i=0; opts[i].short_opt; i++ )
+                {
+                  if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
+                    break;
+                }
+              idx = i;
+              arg->r_opt = opts[idx].short_opt;
+              if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
+                {
+                  state = i = 0;
+                  continue;
+                }
+              else if (!opts[idx].short_opt )
+                {
+                  if (!strcmp (keyword, "ignore-invalid-option"))
+                    {
+                      /* No argument - ignore this meta option.  */
+                      state = i = 0;
+                      continue;
+                    }
+                  else if (ignore_invalid_option_p (arg, keyword))
+                    {
+                      /* This invalid option is in the iio list.  */
+                      state = i = 0;
+                      continue;
+                    }
+                  arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+                                ? ARGPARSE_INVALID_COMMAND
+                                : ARGPARSE_INVALID_OPTION);
+                }
+              else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+                arg->r_type = 0; /* Does not take an arg. */
+              else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) )
+                arg->r_type = 0; /* Arg is optional.  */
+              else
+                arg->r_opt = ARGPARSE_MISSING_ARG;
+
+              break;
+           }
+          else if (state == 3)
+            {
+              /* No argument found.  */
+              if (in_alias)
+                arg->r_opt = ARGPARSE_MISSING_ARG;
+              else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+                arg->r_type = 0; /* Does not take an arg. */
+              else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
+                arg->r_type = 0; /* No optional argument. */
+              else
+                arg->r_opt = ARGPARSE_MISSING_ARG;
+
+              break;
+           }
+          else if (state == 4)
+            {
+              /* Has an argument. */
+              if (in_alias)
+                {
+                  if (!buffer)
+                    arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+                  else
+                    {
+                      char *p;
+
+                      buffer[i] = 0;
+                      p = strpbrk (buffer, " \t");
+                      if (p)
+                        {
+                          *p++ = 0;
+                          trim_spaces (p);
+                       }
+                      if (!p || !*p)
+                        {
+                          jnlib_free (buffer);
+                          arg->r_opt = ARGPARSE_INVALID_ALIAS;
+                        }
+                      else
+                        {
+                          store_alias (arg, buffer, p);
+                        }
+                   }
+               }
+              else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
+                arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
+              else
+                {
+                  char *p;
+
+                  if (!buffer)
+                    {
+                      keyword[i] = 0;
+                      buffer = jnlib_strdup (keyword);
+                      if (!buffer)
+                        arg->r_opt = ARGPARSE_OUT_OF_CORE;
+                   }
+                  else
+                    buffer[i] = 0;
+
+                  if (buffer)
+                    {
+                      trim_spaces (buffer);
+                      p = buffer;
+                      if (*p == '"')
+                        {
+                          /* Remove quotes. */
+                          p++;
+                          if (*p && p[strlen(p)-1] == '\"' )
+                            p[strlen(p)-1] = 0;
+                        }
+                      if (!set_opt_arg (arg, opts[idx].flags, p))
+                        jnlib_free(buffer);
+                    }
+                }
+              break;
+            }
+          else if (c == EOF)
+            {
+              ignore_invalid_option_clear (arg);
+              if (ferror (fp))
+                arg->r_opt = ARGPARSE_READ_ERROR;
+              else
+                arg->r_opt = 0; /* EOF. */
+              break;
+            }
+          state = 0;
+          i = 0;
+        }
+      else if (state == -1)
+        ; /* Skip. */
+      else if (state == 0 && isascii (c) && isspace(c))
+        ; /* Skip leading white space.  */
+      else if (state == 0 && c == '#' )
+        state = 1;     /* Start of a comment.  */
+      else if (state == 1)
+        ; /* Skip comments. */
+      else if (state == 2 && isascii (c) && isspace(c))
+        {
+          /* Check keyword.  */
+          keyword[i] = 0;
+          for (i=0; opts[i].short_opt; i++ )
+            if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword))
+              break;
+          idx = i;
+          arg->r_opt = opts[idx].short_opt;
+          if ((opts[idx].flags & ARGPARSE_OPT_IGNORE))
+            {
+              state = 1; /* Process like a comment.  */
+            }
+          else if (!opts[idx].short_opt)
+            {
+              if (!strcmp (keyword, "alias"))
+                {
+                  in_alias = 1;
+                  state = 3;
+                }
+              else if (!strcmp (keyword, "ignore-invalid-option"))
+                {
+                  if (ignore_invalid_option_add (arg, fp))
+                    {
+                      arg->r_opt = ARGPARSE_OUT_OF_CORE;
+                      break;
+                    }
+                  state = i = 0;
+                  ++*lineno;
+                }
+              else if (ignore_invalid_option_p (arg, keyword))
+                state = 1; /* Process like a comment.  */
+              else
+                {
+                  arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
+                                ? ARGPARSE_INVALID_COMMAND
+                                : ARGPARSE_INVALID_OPTION);
+                  state = -1; /* Skip rest of line and leave.  */
+                }
+            }
+          else
+            state = 3;
+        }
+      else if (state == 3)
+        {
+          /* Skip leading spaces of the argument.  */
+          if (!isascii (c) || !isspace(c))
+            {
+              i = 0;
+              keyword[i++] = c;
+              state = 4;
+            }
+        }
+      else if (state == 4)
+        {
+          /* Collect the argument. */
+          if (buffer)
+            {
+              if (i < buflen-1)
+                buffer[i++] = c;
+              else
+                {
+                  char *tmp;
+                  size_t tmplen = buflen + 50;
+
+                  tmp = jnlib_realloc (buffer, tmplen);
+                  if (tmp)
+                    {
+                      buflen = tmplen;
+                      buffer = tmp;
+                      buffer[i++] = c;
+                    }
+                  else
+                    {
+                      jnlib_free (buffer);
+                      arg->r_opt = ARGPARSE_OUT_OF_CORE;
+                      break;
+                    }
+                }
+            }
+          else if (i < DIM(keyword)-1)
+            keyword[i++] = c;
+          else
+            {
+              size_t tmplen = DIM(keyword) + 50;
+              buffer = jnlib_malloc (tmplen);
+              if (buffer)
+                {
+                  buflen = tmplen;
+                  memcpy(buffer, keyword, i);
+                  buffer[i++] = c;
+                }
+              else
+                {
+                  arg->r_opt = ARGPARSE_OUT_OF_CORE;
+                  break;
+                }
+            }
+        }
+      else if (i >= DIM(keyword)-1)
+        {
+          arg->r_opt = ARGPARSE_KEYWORD_TOO_LONG;
+          state = -1; /* Skip rest of line and leave.  */
+        }
+      else
+        {
+          keyword[i++] = c;
+          state = 2;
+        }
+    }
+
+  return arg->r_opt;
+}
+
+
+
+static int
+find_long_option( ARGPARSE_ARGS *arg,
+                 ARGPARSE_OPTS *opts, const char *keyword )
+{
+    int i;
+    size_t n;
+
+    (void)arg;
+
+    /* Would be better if we can do a binary search, but it is not
+       possible to reorder our option table because we would mess
+       up our help strings - What we can do is: Build a nice option
+       lookup table wehn this function is first invoked */
+    if( !*keyword )
+       return -1;
+    for(i=0; opts[i].short_opt; i++ )
+       if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
+           return i;
+#if 0
+    {
+       ALIAS_DEF a;
+       /* see whether it is an alias */
+       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;
+               return -3; /* alias available */
+           }
+       }
+    }
+#endif
+    /* not found, see whether it is an abbreviation */
+    /* aliases may not be abbreviated */
+    n = strlen( keyword );
+    for(i=0; opts[i].short_opt; i++ ) {
+       if( opts[i].long_opt && !strncmp( opts[i].long_opt, keyword, n ) ) {
+           int j;
+           for(j=i+1; opts[j].short_opt; j++ ) {
+               if( opts[j].long_opt
+                   && !strncmp( opts[j].long_opt, keyword, n ) )
+                   return -2;  /* abbreviation is ambiguous */
+           }
+           return i;
+       }
+    }
+    return -1;  /* Not found.  */
+}
+
+int
+arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
+{
+  int idx;
+  int argc;
+  char **argv;
+  char *s, *s2;
+  int i;
+
+  initialize( arg, NULL, NULL );
+  argc = *arg->argc;
+  argv = *arg->argv;
+  idx = arg->internal.idx;
+
+  if (!idx && argc && !(arg->flags & ARGPARSE_FLAG_ARG0))
+    {
+      /* Skip the first argument.  */
+      argc--; argv++; idx++;
+    }
+
+ next_one:
+  if (!argc)
+    {
+      /* No more args.  */
+      arg->r_opt = 0;
+      goto leave; /* Ready. */
+    }
+
+  s = *argv;
+  arg->internal.last = s;
+
+  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 )
+    {
+      arg->r_opt = 0;
+      goto leave; /* Ready.  */
+    }
+  else if ( *s == '-' && s[1] == '-' )
+    {
+      /* Long option.  */
+      char *argpos;
+
+      arg->internal.inarg = 0;
+      if (!s[2] && !(arg->flags & ARGPARSE_FLAG_NOSTOP))
+        {
+          /* Stop option processing.  */
+          arg->internal.stopped = 1;
+          arg->flags |= ARGPARSE_FLAG_STOP_SEEN;
+          argc--; argv++; idx++;
+          goto next_one;
+       }
+
+      argpos = strchr( s+2, '=' );
+      if ( argpos )
+        *argpos = 0;
+      i = find_long_option ( arg, opts, s+2 );
+      if ( argpos )
+        *argpos = '=';
+
+      if ( i < 0 && !strcmp ( "help", s+2) )
+        show_help (opts, arg->flags);
+      else if ( i < 0 && !strcmp ( "version", s+2) )
+        {
+          if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
+            {
+              show_version ();
+              exit(0);
+            }
+       }
+      else if ( i < 0 && !strcmp( "warranty", s+2))
+        {
+          writestrings (0, strusage (16), "\n", NULL);
+          exit (0);
+       }
+      else if ( i < 0 && !strcmp( "dump-options", s+2) )
+        {
+          for (i=0; opts[i].short_opt; i++ )
+            {
+              if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE))
+                writestrings (0, "--", opts[i].long_opt, "\n", NULL);
+           }
+          writestrings (0, "--dump-options\n--help\n--version\n--warranty\n",
+                        NULL);
+          exit (0);
+       }
+
+      if ( i == -2 )
+        arg->r_opt = ARGPARSE_AMBIGUOUS_OPTION;
+      else if ( i == -1 )
+        {
+          arg->r_opt = ARGPARSE_INVALID_OPTION;
+          arg->r.ret_str = s+2;
+       }
+      else
+        arg->r_opt = opts[i].short_opt;
+      if ( i < 0 )
+        ;
+      else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
+        {
+          if ( argpos )
+            {
+              s2 = argpos+1;
+              if ( !*s2 )
+                s2 = NULL;
+           }
+          else
+            s2 = argv[1];
+          if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+            {
+              arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional.  */
+           }
+          else if ( !s2 )
+            {
+              arg->r_opt = ARGPARSE_MISSING_ARG;
+           }
+          else if ( !argpos && *s2 == '-'
+                    && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+            {
+              /* The argument is optional and the next seems to be an
+                 option.  We do not check this possible option but
+                 assume no argument */
+              arg->r_type = ARGPARSE_TYPE_NONE;
+           }
+          else
+            {
+              set_opt_arg (arg, opts[i].flags, s2);
+              if ( !argpos )
+                {
+                  argc--; argv++; idx++; /* Skip one.  */
+               }
+           }
+       }
+      else
+        {
+          /* Does not take an argument. */
+          if ( argpos )
+            arg->r_type = ARGPARSE_UNEXPECTED_ARG;
+          else
+            arg->r_type = 0;
+       }
+      argc--; argv++; idx++; /* Set to next one.  */
+    }
+    else if ( (*s == '-' && s[1]) || arg->internal.inarg )
+      {
+        /* Short option.  */
+       int dash_kludge = 0;
+
+       i = 0;
+       if ( !arg->internal.inarg )
+          {
+           arg->internal.inarg++;
+           if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) )
+              {
+                for (i=0; opts[i].short_opt; i++ )
+                  if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1))
+                    {
+                      dash_kludge = 1;
+                      break;
+                   }
+              }
+          }
+       s += arg->internal.inarg;
+
+       if (!dash_kludge )
+          {
+           for (i=0; opts[i].short_opt; i++ )
+              if ( opts[i].short_opt == *s )
+                break;
+          }
+
+       if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) )
+          show_help (opts, arg->flags);
+
+       arg->r_opt = opts[i].short_opt;
+       if (!opts[i].short_opt )
+          {
+           arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)?
+              ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION;
+           arg->internal.inarg++; /* Point to the next arg.  */
+           arg->r.ret_str = s;
+          }
+       else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
+          {
+           if ( s[1] && !dash_kludge )
+              {
+               s2 = s+1;
+               set_opt_arg (arg, opts[i].flags, s2);
+              }
+           else
+              {
+               s2 = argv[1];
+               if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+                  {
+                   arg->r_type = ARGPARSE_TYPE_NONE;
+                  }
+               else if ( !s2 )
+                  {
+                   arg->r_opt = ARGPARSE_MISSING_ARG;
+                  }
+               else if ( *s2 == '-' && s2[1]
+                          && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) )
+                  {
+                   /* The argument is optional and the next seems to
+                      be an option.  We do not check this possible
+                      option but assume no argument.  */
+                   arg->r_type = ARGPARSE_TYPE_NONE;
+                  }
+               else
+                  {
+                   set_opt_arg (arg, opts[i].flags, s2);
+                   argc--; argv++; idx++; /* Skip one.  */
+                  }
+              }
+           s = "x"; /* This is so that !s[1] yields false.  */
+          }
+       else
+          {
+            /* Does not take an argument.  */
+           arg->r_type = ARGPARSE_TYPE_NONE;
+           arg->internal.inarg++; /* Point to the next arg.  */
+          }
+       if ( !s[1] || dash_kludge )
+          {
+            /* No more concatenated short options.  */
+           arg->internal.inarg = 0;
+           argc--; argv++; idx++;
+          }
+      }
+  else if ( arg->flags & ARGPARSE_FLAG_MIXED )
+    {
+      arg->r_opt = ARGPARSE_IS_ARG;
+      arg->r_type = 2;
+      arg->r.ret_str = s;
+      argc--; argv++; idx++; /* Set to next one.  */
+    }
+  else
+    {
+      arg->internal.stopped = 1; /* Stop option processing.  */
+      goto next_one;
+    }
+
+ leave:
+  *arg->argc = argc;
+  *arg->argv = argv;
+  arg->internal.idx = idx;
+  return arg->r_opt;
+}
+
+
+/* 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)
+{
+  int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
+  long l;
+
+  switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
+    {
+    case ARGPARSE_TYPE_LONG:
+    case ARGPARSE_TYPE_INT:
+      errno = 0;
+      l = strtol (s, NULL, base);
+      if ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)
+        {
+          arg->r_opt = ARGPARSE_INVALID_ARG;
+          return -1;
+        }
+      if (arg->r_type == ARGPARSE_TYPE_LONG)
+        arg->r.ret_long = l;
+      else if ( (l < 0 && l < INT_MIN) || l > INT_MAX )
+        {
+          arg->r_opt = ARGPARSE_INVALID_ARG;
+          return -1;
+        }
+      else
+        arg->r.ret_int = (int)l;
+      return 0;
+
+    case ARGPARSE_TYPE_ULONG:
+      while (isascii (*s) && isspace(*s))
+        s++;
+      if (*s == '-')
+        {
+          arg->r.ret_ulong = 0;
+          arg->r_opt = ARGPARSE_INVALID_ARG;
+          return -1;
+        }
+      errno = 0;
+      arg->r.ret_ulong = strtoul (s, NULL, base);
+      if (arg->r.ret_ulong == ULONG_MAX && errno == ERANGE)
+        {
+          arg->r_opt = ARGPARSE_INVALID_ARG;
+          return -1;
+        }
+      return 0;
+
+    case ARGPARSE_TYPE_STRING:
+    default:
+      arg->r.ret_str = s;
+      return 1;
+    }
+}
+
+
+static size_t
+long_opt_strlen( ARGPARSE_OPTS *o )
+{
+  size_t n = strlen (o->long_opt);
+
+  if ( o->description && *o->description == '|' )
+    {
+      const char *s;
+#ifdef JNLIB_NEED_UTF8CONV
+      int is_utf8 = is_native_utf8 ();
+#endif
+
+      s=o->description+1;
+      if ( *s != '=' )
+        n++;
+      /* For a (mostly) correct length calculation we exclude
+         continuation bytes (10xxxxxx) if we are on a native utf8
+         terminal. */
+      for (; *s && *s != '|'; s++ )
+#ifdef JNLIB_NEED_UTF8CONV
+        if ( is_utf8 && (*s&0xc0) != 0x80 )
+#endif
+          n++;
+    }
+  return n;
+}
+
+
+/****************
+ * Print formatted help. The description string has some special
+ * meanings:
+ *  - A description string which is "@" suppresses help output for
+ *    this option
+ *  - a description,ine which starts with a '@' and is followed by
+ *    any other characters is printed as is; this may be used for examples
+ *    ans such.
+ *  - A description which starts with a '|' outputs the string between this
+ *    bar and the next one as arguments of the long option.
+ */
+static void
+show_help (ARGPARSE_OPTS *opts, unsigned int flags)
+{
+  const char *s;
+  char tmp[2];
+
+  show_version ();
+  writestrings (0, "\n", NULL);
+  s = strusage (42);
+  if (s && *s == '1')
+    {
+      s = strusage (40);
+      writestrings (1, s, NULL);
+      if (*s && s[strlen(s)] != '\n')
+        writestrings (1, "\n", NULL);
+    }
+  s = strusage(41);
+  writestrings (0, s, "\n", NULL);
+  if ( opts[0].description )
+    {
+      /* Auto format the option description.  */
+      int i,j, indent;
+
+      /* Get max. length of long options.  */
+      for (i=indent=0; opts[i].short_opt; i++ )
+        {
+          if ( opts[i].long_opt )
+            if ( !opts[i].description || *opts[i].description != '@' )
+              if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 )
+                indent = j;
+       }
+
+      /* Example: " -v, --verbose   Viele Sachen ausgeben" */
+      indent += 10;
+      if ( *opts[0].description != '@' )
+        writestrings (0, "Options:", "\n", NULL);
+      for (i=0; opts[i].short_opt; i++ )
+        {
+          s = map_static_macro_string (_( opts[i].description ));
+          if ( s && *s== '@' && !s[1] ) /* Hide this line.  */
+            continue;
+          if ( s && *s == '@' )  /* Unindented comment only line.  */
+            {
+              for (s++; *s; s++ )
+                {
+                  if ( *s == '\n' )
+                    {
+                      if( s[1] )
+                        writestrings (0, "\n", NULL);
+                   }
+                  else
+                    {
+                      tmp[0] = *s;
+                      tmp[1] = 0;
+                      writestrings (0, tmp, NULL);
+                    }
+                }
+              writestrings (0, "\n", NULL);
+              continue;
+           }
+
+          j = 3;
+          if ( opts[i].short_opt < 256 )
+            {
+              tmp[0] = opts[i].short_opt;
+              tmp[1] = 0;
+              writestrings (0, " -", tmp, NULL );
+              if ( !opts[i].long_opt )
+                {
+                  if (s && *s == '|' )
+                    {
+                      writestrings (0, " ", NULL); j++;
+                      for (s++ ; *s && *s != '|'; s++, j++ )
+                        {
+                          tmp[0] = *s;
+                          tmp[1] = 0;
+                          writestrings (0, tmp, NULL);
+                        }
+                      if ( *s )
+                        s++;
+                   }
+               }
+           }
+          else
+            writestrings (0, "   ", NULL);
+          if ( opts[i].long_opt )
+            {
+              tmp[0] = opts[i].short_opt < 256?',':' ';
+              tmp[1] = 0;
+              j += writestrings (0, tmp, " --", opts[i].long_opt, NULL);
+              if (s && *s == '|' )
+                {
+                  if ( *++s != '=' )
+                    {
+                      writestrings (0, " ", NULL);
+                      j++;
+                   }
+                  for ( ; *s && *s != '|'; s++, j++ )
+                    {
+                      tmp[0] = *s;
+                      tmp[1] = 0;
+                      writestrings (0, tmp, NULL);
+                    }
+                  if ( *s )
+                    s++;
+               }
+              writestrings (0, "   ", NULL);
+              j += 3;
+           }
+          for (;j < indent; j++ )
+            writestrings (0, " ", NULL);
+          if ( s )
+            {
+              if ( *s && j > indent )
+                {
+                  writestrings (0, "\n", NULL);
+                  for (j=0;j < indent; j++ )
+                    writestrings (0, " ", NULL);
+               }
+              for (; *s; s++ )
+                {
+                  if ( *s == '\n' )
+                    {
+                      if ( s[1] )
+                        {
+                          writestrings (0, "\n", NULL);
+                          for (j=0; j < indent; j++ )
+                            writestrings (0, " ", NULL);
+                       }
+                   }
+                  else
+                    {
+                      tmp[0] = *s;
+                      tmp[1] = 0;
+                      writestrings (0, tmp, NULL);
+                    }
+               }
+           }
+          writestrings (0, "\n", NULL);
+       }
+       if ( (flags & ARGPARSE_FLAG_ONEDASH) )
+          writestrings (0, "\n(A single dash may be used "
+                        "instead of the double ones)\n", NULL);
+    }
+  if ( (s=strusage(19)) )
+    {
+      writestrings (0, "\n", NULL);
+      writestrings (0, s, NULL);
+    }
+  flushstrings (0);
+  exit(0);
+}
+
+static void
+show_version ()
+{
+  const char *s;
+  int i;
+
+  /* Version line.  */
+  writestrings (0, strusage (11), NULL);
+  if ((s=strusage (12)))
+    writestrings (0, " (", s, ")", NULL);
+  writestrings (0, " ", strusage (13), "\n", NULL);
+  /* Additional version lines. */
+  for (i=20; i < 30; i++)
+    if ((s=strusage (i)))
+      writestrings (0, s, "\n", NULL);
+  /* Copyright string.  */
+  if ((s=strusage (14)))
+    writestrings (0, s, "\n", NULL);
+  /* Licence string.  */
+  if( (s=strusage (10)) )
+    writestrings (0, s, "\n", NULL);
+  /* Copying conditions. */
+  if ( (s=strusage(15)) )
+    writestrings (0, s, NULL);
+  /* Thanks. */
+  if ((s=strusage(18)))
+    writestrings (0, s, NULL);
+  /* Additional program info. */
+  for (i=30; i < 40; i++ )
+    if ( (s=strusage (i)) )
+      writestrings (0, s, NULL);
+  flushstrings (0);
+}
+
+
+void
+usage (int level)
+{
+  const char *p;
+
+  if (!level)
+    {
+      writestrings (1, strusage(11), " ", strusage(13), "; ",
+                    strusage (14), "\n", NULL);
+      flushstrings (1);
+    }
+  else if (level == 1)
+    {
+      p = strusage (40);
+      writestrings (1, p, NULL);
+      if (*p && p[strlen(p)] != '\n')
+        writestrings (1, "\n", NULL);
+      exit (2);
+    }
+  else if (level == 2)
+    {
+      p = strusage (42);
+      if (p && *p == '1')
+        {
+          p = strusage (40);
+          writestrings (1, p, NULL);
+          if (*p && p[strlen(p)] != '\n')
+            writestrings (1, "\n", NULL);
+        }
+      writestrings (0, strusage(41), "\n", NULL);
+      exit (0);
+    }
+}
+
+/* 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
+ *    10: Return license info string
+ *    11: Return the name of the program
+ *    12: Return optional name of package which includes this program.
+ *    13: version  string
+ *    14: copyright string
+ *    15: Short copying conditions (with LFs)
+ *    16: Long copying conditions (with LFs)
+ *    17: Optional printable OS name
+ *    18: Optional thanks list (with LFs)
+ *    19: Bug report info
+ *20..29: Additional lib version strings.
+ *30..39: Additional program info (with LFs)
+ *    40: short usage note (with LF)
+ *    41: long usage note (with LF)
+ *    42: Flag string:
+ *          First char is '1':
+ *             The short usage notes needs to be printed
+ *             before the long usage note.
+ */
+const char *
+strusage( int level )
+{
+  const char *p = strusage_handler? strusage_handler(level) : NULL;
+
+  if ( p )
+    return map_static_macro_string (p);
+
+  switch ( level )
+    {
+
+    case 10:
+#if ARGPARSE_GPL_VERSION == 3
+      p = ("License GPLv3+: GNU GPL version 3 or later "
+           "<http://gnu.org/licenses/gpl.html>");
+#else
+      p = ("License GPLv2+: GNU GPL version 2 or later "
+           "<http://gnu.org/licenses/>");
+#endif
+      break;
+    case 11: p = "foo"; break;
+    case 13: p = "0.0"; break;
+    case 14: p = ARGPARSE_CRIGHT_STR; 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 =
+"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"
+"(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 <http://www.gnu.org/licenses/>.\n";
+      break;
+    case 40: /* short and long usage */
+    case 41: p = ""; break;
+    }
+
+  return p;
+}
+
+
+/* Set the usage handler.  This function is basically a constructor.  */
+void
+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)
+{
+  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;
+
+  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;
+}
+#endif /*TEST*/
+
+/**** bottom of file ****/
diff --git a/pinentry/argparse.h b/pinentry/argparse.h
new file mode 100644 (file)
index 0000000..b4dc253
--- /dev/null
@@ -0,0 +1,203 @@
+/* argparse.h - Argument parser for option handling.
+ *     Copyright (C) 1998,1999,2000,2001,2006 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB, which is a subsystem of GnuPG.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of either
+ *
+ *   - the GNU Lesser General Public License as published by the Free
+ *     Software Foundation; either version 3 of the License, or (at
+ *     your option) any later version.
+ *
+ * or
+ *
+ *   - the GNU General Public License as published by the Free
+ *     Software Foundation; either version 2 of the License, or (at
+ *     your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * JNLIB 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBJNLIB_ARGPARSE_H
+#define LIBJNLIB_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;
+
+
+/* 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) }
+
+#define ARGPARSE_end()  { 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 /*LIBJNLIB_ARGPARSE_H*/
index 2d73464..22506b6 100644 (file)
@@ -1,5 +1,5 @@
 /* pinentry.c - The PIN entry support library
-   Copyright (C) 2002, 2003, 2007, 2008, 2010 g10 Code GmbH
+   Copyright (C) 2002, 2003, 2007, 2008, 2010, 2015 g10 Code GmbH
 
    This file is part of PINENTRY.
 
@@ -46,6 +46,7 @@
 #include "assuan.h"
 #include "memory.h"
 #include "secmem-util.h"
+#include "argparse.h"
 #include "pinentry.h"
 
 #ifdef HAVE_W32CE_SYSTEM
@@ -408,26 +409,46 @@ pinentry_have_display (int argc, char **argv)
 
 
 \f
-static void
-usage (void)
+/* Print usage information and and provide strings for help. */
+static const char *
+my_strusage( int level )
 {
-  fprintf (stdout, "Usage: %s [OPTION]...\n"
-"Ask securely for a secret and print it to stdout.\n"
-"\n"
-"      --display DISPLAY Set the X display\n"
-"      --ttyname PATH    Set the tty terminal node name\n"
-"      --ttytype NAME    Set the tty terminal type\n"
-"      --lc-ctype        Set the tty LC_CTYPE value\n"
-"      --lc-messages     Set the tty LC_MESSAGES value\n"
-"      --timeout SECS    Timeout waiting for input after this many seconds\n"
-#ifdef ENABLE_ENHANCED
-"  -e, --enhanced        Ask for timeout and insurance, too\n"
-#endif
-"  -g, --no-global-grab  Grab keyboard only while window is focused\n"
-"      --parent-wid      Parent window ID (for positioning)\n"
-"  -d, --debug           Turn on debugging output\n"
-"  -h, --help            Display this help and exit\n"
-"      --version         Output version information and exit\n", this_pgmname);
+  const char *p;
+
+  switch (level)
+    {
+    case 11: p = this_pgmname; break;
+    case 12: p = "pinentry"; break;
+    case 13: p = PACKAGE_VERSION; break;
+    case 14: p = "Copyright (C) 2015 g10 Code GmbH"; break;
+    case 19: p = "Please report bugs to <" PACKAGE_BUGREPORT ">.\n"; break;
+    case 1:
+    case 40:
+      {
+        static char *str;
+
+        if (!str)
+          {
+            size_t n = 50 + strlen (this_pgmname);
+            str = malloc (n);
+            if (str)
+              snprintf (str, n, "Usage: %s [options] (-h for help)",
+                        this_pgmname);
+          }
+        p = str;
+      }
+      break;
+    case 41:
+      p = "Ask securely for a secret and print it to stdout.";
+      break;
+
+    case 42:
+      p = "1"; /* Flag print 40 as part of 41. */
+      break;
+
+    default: p = NULL; break;
+    }
+  return p;
 }
 
 
@@ -481,40 +502,37 @@ parse_color (char *arg, pinentry_color_t *color_p, int *bright_p)
   return new_arg;
 }
 
-/* Parse the command line options.  Returns 1 if user should print
-   version and exit.  Can exit the program if only help output is
-   requested.  */
-int
+/* Parse the command line options.  May exit the program if only help
+   or version output is requested.  */
+void
 pinentry_parse_opts (int argc, char *argv[])
 {
-  int opt;
-  int opt_help = 0;
-  int opt_version = 0;
-  struct option opts[] =
-    {{ "debug", no_argument,             0, 'd' },
-     { "display", required_argument,     0, 'D' },
-     { "ttyname", required_argument,     0, 'T' },
-     { "ttytype", required_argument,     0, 'N' },
-     { "lc-ctype", required_argument,    0, 'C' },
-     { "lc-messages", required_argument, 0, 'M' },
+  static ARGPARSE_OPTS opts[] = {
+    ARGPARSE_s_n('d', "debug",    "Turn on debugging output"),
+    ARGPARSE_s_s('D', "display",  "|DISPLAY|Set the X display"),
+    ARGPARSE_s_s('T', "ttyname",  "|FILE|Set the tty terminal node name"),
+    ARGPARSE_s_s('N', "ttytype",  "|NAME|Set the tty terminal type"),
+    ARGPARSE_s_s('C', "lc-ctype", "|STRING|Set the tty LC_CTYPE value"),
+    ARGPARSE_s_s('M', "lc-messages", "|STRING|Set the tty LC_MESSAGES value"),
 #ifdef ENABLE_ENHANCED
-     { "enhanced", no_argument,          0, 'e' },
+    ARGPARSE_s_n('e', "enhanced", "Ask for timeout and insurance, too"),
 #endif
-     { "no-global-grab", no_argument,    0, 'g' },
-     { "parent-wid", required_argument,  0, 'W' },
-     { "colors", required_argument,     0, 'c' },
-     { "help", no_argument,              0, 'h' },
-     { "version", no_argument, &opt_version, 1 },
-     { "timeout", required_argument, 0, 'o' },
-     { NULL, 0, NULL, 0 }};
-
-  while ((opt = getopt_long (argc, argv, "degh", opts, NULL)) != -1)
+    ARGPARSE_s_i('o', "timeout",
+                 "|SECS|Timeout waiting for input after this many seconds"),
+    ARGPARSE_s_n('g', "no-global-grab",
+                 "Grab keyboard only while window is focused"),
+    ARGPARSE_s_u('W', "parent-wid", "Parent window ID (for positioning)"),
+    ARGPARSE_s_s('c', "colors", "|STRING|Set custom colors for ncurses"),
+    ARGPARSE_end()
+  };
+  ARGPARSE_ARGS pargs = { &argc, &argv, 0 };
+
+  set_strusage (my_strusage);
+
+  while (arg_parse  (&pargs, opts))
     {
-      switch (opt)
+      switch (pargs.r_opt)
         {
-        case 0:
-        case '?':
-          break;
         case 'd':
           pinentry.debug = 1;
           break;
@@ -526,14 +544,11 @@ pinentry_parse_opts (int argc, char *argv[])
         case 'g':
           pinentry.grab = 0;
           break;
-        case 'h':
-          opt_help = 1;
-          break;
 
        case 'D':
           /* Note, this is currently not used because the GUI engine
              has already been initialized when parsing these options. */
-         pinentry.display = strdup (optarg);
+         pinentry.display = strdup (pargs.r.ret_str);
          if (!pinentry.display)
            {
 #ifndef HAVE_W32CE_SYSTEM
@@ -543,7 +558,7 @@ pinentry_parse_opts (int argc, char *argv[])
            }
          break;
        case 'T':
-         pinentry.ttyname = strdup (optarg);
+         pinentry.ttyname = strdup (pargs.r.ret_str);
          if (!pinentry.ttyname)
            {
 #ifndef HAVE_W32CE_SYSTEM
@@ -553,7 +568,7 @@ pinentry_parse_opts (int argc, char *argv[])
            }
          break;
        case 'N':
-         pinentry.ttytype = strdup (optarg);
+         pinentry.ttytype = strdup (pargs.r.ret_str);
          if (!pinentry.ttytype)
            {
 #ifndef HAVE_W32CE_SYSTEM
@@ -563,7 +578,7 @@ pinentry_parse_opts (int argc, char *argv[])
            }
          break;
        case 'C':
-         pinentry.lc_ctype = strdup (optarg);
+         pinentry.lc_ctype = strdup (pargs.r.ret_str);
          if (!pinentry.lc_ctype)
            {
 #ifndef HAVE_W32CE_SYSTEM
@@ -573,7 +588,7 @@ pinentry_parse_opts (int argc, char *argv[])
            }
          break;
        case 'M':
-         pinentry.lc_messages = strdup (optarg);
+         pinentry.lc_messages = strdup (pargs.r.ret_str);
          if (!pinentry.lc_messages)
            {
 #ifndef HAVE_W32CE_SYSTEM
@@ -583,34 +598,30 @@ pinentry_parse_opts (int argc, char *argv[])
            }
          break;
        case 'W':
-         pinentry.parent_wid = atoi (optarg);
-         /* FIXME: Add some error handling.  Use strtol.  */
+         pinentry.parent_wid = pargs.r.ret_ulong;
          break;
 
        case 'c':
-         optarg = parse_color (optarg, &pinentry.color_fg,
-                               &pinentry.color_fg_bright);
-         optarg = parse_color (optarg, &pinentry.color_bg, NULL);
-         optarg = parse_color (optarg, &pinentry.color_so,
-                               &pinentry.color_so_bright);
+          {
+            char *tmpstr = pargs.r.ret_str;
+
+            tmpstr = parse_color (tmpstr, &pinentry.color_fg,
+                                  &pinentry.color_fg_bright);
+            tmpstr = parse_color (tmpstr, &pinentry.color_bg, NULL);
+            tmpstr = parse_color (tmpstr, &pinentry.color_so,
+                                  &pinentry.color_so_bright);
+          }
          break;
 
        case 'o':
-         pinentry.timeout = atoi(optarg);
+         pinentry.timeout = pargs.r.ret_int;
          break;
+
         default:
-          fprintf (stderr, "%s: oops: option not handled\n", this_pgmname);
+          pargs.err = ARGPARSE_PRINT_WARNING;
          break;
         }
     }
-  if (opt_version)
-    return 1;
-  if (opt_help)
-    {
-      usage ();
-      exit (EXIT_SUCCESS);
-    }
-  return 0;
 }
 
 \f
index b6c863e..6787130 100644 (file)
@@ -197,10 +197,9 @@ void pinentry_init (const char *pgmname);
    "--display". */
 int pinentry_have_display (int argc, char **argv);
 
-/* Parse the command line options.  Returns 1 if user should print
-   version and exit.  Can exit the program if only help output is
-   requested.  */
-int pinentry_parse_opts (int argc, char *argv[]);
+/* Parse the command line options.  May exit the program if only help
+   or version output is requested.  */
+void pinentry_parse_opts (int argc, char *argv[]);
 
 \f
 /* The caller must define this variable to process assuan commands.  */
index 1f21c03..c0ca6de 100644 (file)
@@ -3,17 +3,17 @@
    Copyright (C) 2003 g10 Code GmbH
    Written by Steffen Hansen <steffen@klaralvdalens-datakonsult.se>.
    Modified by Marcus Brinkmann <marcus@g10code.de>.
-   
+
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.
+
    This program 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 General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
@@ -87,7 +87,7 @@ public:
     QWidget::destroy();
     create( wid, false, false );
   }
+
   ~ForeignWidget()
   {
     destroy( false, false );
@@ -167,16 +167,16 @@ qt_cmd_handler (pinentry_t pe)
         (QString::fromUtf8 (pe->cancel ? pe->cancel :
                             pe->default_cancel? pe->default_cancel: "&Cancel"));
       bool ret;
-      
+
       ret = QMessageBox::information (parent, "", desc, ok, can );
-      
+
       return !ret;
     }
 }
 
 pinentry_cmd_handler_t pinentry_cmd_handler = qt_cmd_handler;
 
-int 
+int
 main (int argc, char *argv[])
 {
   pinentry_init ("pinentry-qt");
@@ -205,7 +205,7 @@ main (int argc, char *argv[])
           fprintf (stderr, "pinentry-qt: can't fixup argument list: %s\n",
                    strerror (errno));
           exit (EXIT_FAILURE);
-          
+
         }
       for (done=0,p=*new_argv,i=0; i < argc; i++)
         if (!done && !strcmp (argv[i], "--display"))
@@ -224,14 +224,9 @@ main (int argc, char *argv[])
       i = argc;
       new QApplication (i, new_argv);
     }
-  
 
-  /* Consumes all arguments.  */
-  if (pinentry_parse_opts (argc, argv))
-    {
-      printf ("pinentry-qt (pinentry) " VERSION "\n");
-      exit (EXIT_SUCCESS);
-    }
+
+  pinentry_parse_opts (argc, argv);
 
   if (pinentry_loop ())
     return 1;
index b2a69f2..37b6e7b 100644 (file)
@@ -123,7 +123,7 @@ static QString from_utf8( const char * s ) {
         else
             return QString::fromLocal8Bit( s );
       }
-    
+
     return result;
 }
 
@@ -149,7 +149,7 @@ qt_cmd_handler (pinentry_t pe)
   const QString title =
       pe->title ? from_utf8( pe->title ) :
       /* else */  QLatin1String( "pinentry-qt4" ) ;
-      
+
 
   if (want_pass)
     {
@@ -311,15 +311,7 @@ main (int argc, char *argv[])
     }
 
 
-  /* Consumes all arguments.  */
-  if (pinentry_parse_opts (argc, argv))
-    {
-      printf ("pinentry-qt4 (pinentry) " /* VERSION */ "\n");
-      return EXIT_SUCCESS;
-    }
-  else
-    {
-      return pinentry_loop () ? EXIT_FAILURE : EXIT_SUCCESS ;
-    }
+  pinentry_parse_opts (argc, argv);
 
+  return pinentry_loop () ? EXIT_FAILURE : EXIT_SUCCESS ;
 }
index 2c40d42..8f680fd 100644 (file)
@@ -189,11 +189,7 @@ main (int argc, char *argv[])
   pinentry_init ("pinentry-tty");
 
   /* Consumes all arguments.  */
-  if (pinentry_parse_opts(argc, argv))
-    {
-      printf ("pinentry-tty (pinentry) " VERSION "\n");
-      exit(EXIT_SUCCESS);
-    }
+  pinentry_parse_opts(argc, argv);
 
   if (pinentry_loop ())
     return 1;
index 85bf2b1..fee37c1 100644 (file)
@@ -628,9 +628,7 @@ main (int argc, char **argv)
 
   pinentry_init (PGMNAME);
 
-  /* Consumes all arguments.  */
-  if (pinentry_parse_opts (argc, argv))
-    exit (EXIT_SUCCESS);
+  pinentry_parse_opts (argc, argv);
 
 /*   debugfp = fopen ("pinentry.log", "w"); */
 /*   if (!debugfp) */