Add --logger-fd alias.
[gnupg.git] / jnlib / argparse.c
index 6293d3e..3104db4 100644 (file)
@@ -1,20 +1,21 @@
 /* [argparse.c wk 17.06.97] Argument Parser for option handling
- *     Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
- *  This file is part of GnuPG.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2006
+ *               2007  Free Software Foundation, Inc.
  *
- *  GnuPG 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 file is part of JNLIB.
  *
- *  GnuPG 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.
+ * JNLIB 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 3 of
+ * the License, or (at your option) any later version.
  *
- *  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 02111-1307, USA
+ * 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
+ * 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 <http://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -27,6 +28,9 @@
 #include "mischelp.h"
 #include "stringhelp.h"
 #include "logging.h"
+#ifdef JNLIB_NEED_UTF8CONV
+#include "utf8conv.h"
+#endif
 #include "argparse.h"
 
 
@@ -145,63 +149,71 @@ static void show_version(void);
 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->err = 0;
-       arg->flags |= 1<<15; /* mark initialized */
-       if( *arg->argc < 0 )
-           jnlib_log_bug("Invalid argument for ArgParse\n");
+  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->err = 0;
+      arg->flags |= 1<<15; /* Mark as initialized.  */
+      if ( *arg->argc < 0 )
+        jnlib_log_bug ("invalid argument for arg_parsee\n");
     }
-
-
-    if( arg->err ) { /* last option was erroneous */
-       const char *s;
-
-       if( filename ) {
-           if( arg->r_opt == -6 )
-               s = "%s:%u: argument not expected\n";
-           else if( arg->r_opt == -5 )
-               s = "%s:%u: read error\n";
-           else if( arg->r_opt == -4 )
-               s = "%s:%u: keyword too long\n";
-           else if( arg->r_opt == -3 )
-               s = "%s:%u: missing argument\n";
-           else if( arg->r_opt == -7 )
-               s = "%s:%u: invalid command\n";
-           else if( arg->r_opt == -10 )
-               s = "%s:%u: invalid alias definition\n";
-           else
-               s = "%s:%u: invalid option\n";
-           jnlib_log_error(s, filename, *lineno );
+  
+  
+  if (arg->err)
+    {
+      /* Last option was erroneous.  */
+      const char *s;
+      
+      if (filename)
+        {
+          if ( arg->r_opt == -6 )
+            s = _("argument not expected");
+          else if ( arg->r_opt == -5 )
+            s = _("read error");
+          else if ( arg->r_opt == -4 )
+            s = _("keyword too long");
+          else if ( arg->r_opt == -3 )
+            s = _("missing argument");
+          else if ( arg->r_opt == -7 )
+            s = _("invalid command");
+          else if ( arg->r_opt == -10 )
+            s = _("invalid alias definition");
+          else
+            s = _("invalid option");
+          jnlib_log_error ("%s:%u: %s\n", filename, *lineno, s);
        }
-       else {
-           if( arg->r_opt == -3 )
-               s = "Missing argument for option \"%.50s\"\n";
-           else if( arg->r_opt == -6 )
-               s = "Option \"%.50s\" does not expect an argument\n";
-           else if( arg->r_opt == -7 )
-               s = "Invalid command \"%.50s\"\n";
-           else if( arg->r_opt == -8 )
-               s = "Option \"%.50s\" is ambiguous\n";
-           else if( arg->r_opt == -9 )
-               s = "Command \"%.50s\" is ambiguous\n";
-           else
-               s = "Invalid option \"%.50s\"\n";
-           jnlib_log_error(s, arg->internal.last? arg->internal.last:"[??]" );
+      else 
+        {
+          s = arg->internal.last? arg->internal.last:"[??]";
+            
+          if ( arg->r_opt == -3 )
+            jnlib_log_error (_("missing argument for option \"%.50s\"\n"), s);
+          else if ( arg->r_opt == -6 )
+            jnlib_log_error (_("option \"%.50s\" does not expect an "
+                               "argument\n"), s );
+          else if ( arg->r_opt == -7 )
+            jnlib_log_error (_("invalid command \"%.50s\"\n"), s);
+          else if ( arg->r_opt == -8 )
+            jnlib_log_error (_("option \"%.50s\" is ambiguous\n"), s);
+          else if ( arg->r_opt == -9 )
+            jnlib_log_error (_("command \"%.50s\" is ambiguous\n"),s );
+          else
+            jnlib_log_error (_("invalid option \"%.50s\"\n"), s);
        }
-       if( arg->err != 1 )
-           exit(2);
-       arg->err = 0;
+      if ( arg->err != 1 )
+        exit (2);
+      arg->err = 0;
     }
 
-    /* clearout the return value union */
-    arg->r.ret_str = NULL;
-    arg->r.ret_long= 0;
+  /* Zero out the return value union.  */
+  arg->r.ret_str = NULL;
+  arg->r.ret_long = 0;
 }
 
 
@@ -275,10 +287,12 @@ optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
                    arg->r_opt = -arg->r_opt;
                if( !opts[idx].short_opt )   /* unknown command/option */
                    arg->r_opt = (opts[idx].flags & 256)? -7:-2;
-               else if( (opts[idx].flags & 8) ) /* no argument */
-                   arg->r_opt = -3;           /* error */
-               else                           /* no or optional argument */
+               else if( !(opts[idx].flags & 7) ) /* does not take an arg */
                    arg->r_type = 0;           /* okay */
+               else if( (opts[idx].flags & 8) )  /* argument is optional */
+                    arg->r_type = 0;          /* okay */
+               else                           /* required argument */
+                   arg->r_opt = -3;           /* error */
                break;
            }
            else if( state == 3 ) {            /* no argument found */
@@ -432,7 +446,7 @@ find_long_option( ARGPARSE_ARGS *arg,
     for(i=0; opts[i].short_opt; i++ )
        if( opts[i].long_opt && !strcmp( opts[i].long_opt, keyword) )
            return i;
-  #if 0
+#if 0
     {
        ALIAS_DEF a;
        /* see whether it is an alias */
@@ -444,7 +458,7 @@ find_long_option( ARGPARSE_ARGS *arg,
            }
        }
     }
-  #endif
+#endif
     /* not found, see whether it is an abbreviation */
     /* aliases may not be abbreviated */
     n = strlen( keyword );
@@ -693,18 +707,28 @@ set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
 static size_t
 long_opt_strlen( ARGPARSE_OPTS *o )
 {
-    size_t n = strlen(o->long_opt);
-
-    if( o->description && *o->description == '|' ) {
-       const char *s;
+  size_t n = strlen (o->long_opt);
 
-       s=o->description+1;
-       if( *s != '=' )
-           n++;
-       for(; *s && *s != '|'; s++ )
-           n++;
+  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;
+  return n;
 }
 
 /****************
@@ -814,8 +838,21 @@ show_help( ARGPARSE_OPTS *opts, unsigned flags )
            puts("\n(A single dash may be used instead of the double ones)");
     }
     if( (s=strusage(19)) ) {  /* bug reports to ... */
+        char *s2;
+
        putchar('\n');
-       fputs(s, stdout);
+        s2 = strstr (s, "@EMAIL@");
+        if (s2)
+          {
+            if (s2-s)
+              fwrite (s, s2-s, 1, stdout);
+            fputs (PACKAGE_BUGREPORT, stdout);
+            s2 += 7;
+            if (*s2)
+              fputs (s2, stdout);
+          }
+        else
+          fputs(s, stdout);
     }
     fflush(stdout);
     exit(0);
@@ -824,64 +861,71 @@ show_help( ARGPARSE_OPTS *opts, unsigned flags )
 static void
 show_version()
 {
-    const char *s;
-    int i;
-    /* version line */
-    fputs(strusage(11), stdout);
-    if( (s=strusage(12)) )
-       printf(" (%s)", s );
-    printf(" %s\n", strusage(13) );
-    /* additional version lines */
-    for(i=20; i < 30; i++ )
-       if( (s=strusage(i)) )
-           printf("%s\n", s );
-    /* copyright string */
-    if( (s=strusage(14)) )
-       printf("%s\n", s );
-    /* copying conditions */
-    if( (s=strusage(15)) )
-       fputs(s, stdout);
-    /* thanks */
-    if( (s=strusage(18)) )
-       fputs(s, stdout);
-    /* additional program info */
-    for(i=30; i < 40; i++ )
-       if( (s=strusage(i)) )
-           fputs( (const byte*)s, stdout);
-    fflush(stdout);
+  const char *s;
+  int i;
+
+  /* Version line.  */
+  fputs (strusage (11), stdout);
+  if ((s=strusage (12)))
+    printf (" (%s)", s );
+  printf (" %s\n", strusage (13) );
+  /* Additional version lines. */
+  for (i=20; i < 30; i++)
+    if ((s=strusage (i)))
+      printf ("%s\n", s );
+  /* Copyright string.  */
+  if( (s=strusage (14)) )
+    printf("%s\n", s );
+  /* Licence string.  */
+  if( (s=strusage (10)) )
+    printf("%s\n", s );
+  /* Copying conditions. */
+  if ( (s=strusage(15)) )
+    fputs (s, stdout);
+  /* Thanks. */
+  if ((s=strusage(18)))
+    fputs (s, stdout);
+  /* Additional program info. */
+  for (i=30; i < 40; i++ )
+    if ( (s=strusage (i)) )
+      fputs (s, stdout);
+  fflush(stdout);
 }
 
 
 void
-usage( int level )
+usage (int level)
 {
-    if( !level ) {
-       fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13),
-                                                    strusage(14) );
-       fflush(stderr);
+  if (!level)
+    {
+      fprintf(stderr,"%s %s; %s\n", strusage(11), strusage(13), strusage (14));
+      fflush (stderr);
     }
-    else if( level == 1 ) {
-       fputs(strusage(40),stderr);
-       exit(2);
+  else if (level == 1)
+    {
+      fputs (strusage (40), stderr);
+      exit (2);
     }
-    else if( level == 2 ) {
-       puts(strusage(41));
-       exit(0);
+  else if (level == 2) 
+    {
+      puts (strusage(41));
+      exit (0);
     }
 }
 
 /* Level
- *     0: Copyright String auf stderr ausgeben
- *     1: Kurzusage auf stderr ausgeben und beenden
- *     2: Langusage auf stdout ausgeben und beenden
- *    11: name of program
- *    12: optional name of package which includes this program.
+ *     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)
+ *    18: Optional thanks list (with LFs)
  *    19: Bug report info
  *20..29: Additional lib version strings.
  *30..39: Additional program info (with LFs)
@@ -897,25 +941,27 @@ strusage( int level )
        return p;
 
     switch( level ) {
+      case 10: p = ("License GPLv3+: GNU GPL version 3 or later "
+                    "<http://gnu.org/licenses/gpl.html>");
+        break;
       case 11: p = "foo"; break;
       case 13: p = "0.0"; break;
-      case 14: p = "Copyright (C) 2000 Free Software Foundation, Inc."; break;
+      case 14: p = "Copyright (C) 2007 Free Software Foundation, Inc."; break;
       case 15: p =
-"This program comes with ABSOLUTELY NO WARRANTY.\n"
-"This is free software, and you are welcome to redistribute it\n"
-"under certain conditions. See the file COPYING for details.\n"; break;
+"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 2 of the License, or\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"
 "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 program; if not, write to the Free Software\n"
-"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\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;
@@ -947,17 +993,20 @@ main(int argc, char **argv)
 {
     ARGPARSE_OPTS opts[] = {
     { 'v', "verbose",   0 , "Laut sein"},
-    { 'e', "echo"   ,   0 , "Zeile ausgeben, damit wir sehen, was wir einegegeben haben"},
-    { 'd', "debug",     0 , "Debug\nfalls mal etasws\nSchief geht"},
+    { 'e', "echo"   ,   0 , ("Zeile ausgeben, damit wir sehen, was wir ein"
+                             " gegeben haben")},
+    { 'd', "debug",     0 , "Debug\nfalls mal etwas\nschief geht"},
     { 'o', "output",    2   },
     { 'c', "cross-ref", 2|8, "cross-reference erzeugen\n" },
+    /* Note that on a non-utf8 terminal the ß might garble the output. */
+    { 's', "street",  0,     "|Straße|set the name of the street to Straße" },
     { 'm', "my-option", 1|8 },
     { 500, "a-long-option", 0 },
     {0} };
     ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
     int i;
 
-    while( ArgParse( &pargs, opts) ) {
+    while( arg_parse ( &pargs, opts) ) {
        switch( pargs.r_opt ) {
          case -1 : printf( "arg=`%s'\n", pargs.r.ret_str); break;
          case 'v': opt.verbose++; break;