agent: Fix segv running in --server mode
[gnupg.git] / common / argparse.c
index b6abf86..331998b 100644 (file)
@@ -1,32 +1,23 @@
-/* [argparse.c wk 17.06.97] Argument Parser for option handling
+/* argparse.c - Argument Parser for option handling
+ * Copyright (C) 1997-2001, 2006-2008, 2013-2017 Werner Koch
  * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
- * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch
+ * Copyright (C) 2015-2017 g10 Code GmbH
  *
  * This file is part of GnuPG.
  *
- * GnuPG is free software; you can redistribute it and/or modify it
- * under the terms of either
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
  *
- *   - 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.
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
  *
- * 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.
- *
- * 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.
- *
- * 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/>.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1+
  */
 
 /* This file may be used as part of GnuPG or standalone.  A GnuPG
@@ -61,7 +52,7 @@
 /* GnuPG uses GPLv3+ but a standalone version of this defaults to
    GPLv2+ because that is the license of this file.  Change this if
    you include it in a program which uses GPLv3.  If you don't want to
-   set a copyright string for your usage() you may also hardcode it
+   set a copyright string for your usage() you may also hardcode it
    here.  */
 #ifndef GNUPG_MAJOR_VERSION
 
@@ -71,7 +62,7 @@
 #else /* Used by GnuPG  */
 
 # define ARGPARSE_GPL_VERSION      3
-# define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc."
+# define ARGPARSE_CRIGHT_STR "Copyright (C) 2018 Free Software Foundation, Inc."
 
 #endif /*GNUPG_MAJOR_VERSION*/
 
@@ -568,17 +559,35 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
   char *buffer = NULL;
   size_t buflen = 0;
   int in_alias=0;
+  int unread_buf[3];  /* We use an int so that we can store EOF.  */
+  int unread_buf_count = 0;
 
-  if (!fp) /* Divert to to arg_parse() in this case.  */
+  if (!fp) /* Divert to arg_parse() in this case.  */
     return arg_parse (arg, opts);
 
   initialize (arg, filename, lineno);
 
+  /* If the LINENO is zero we assume that we are at the start of a
+   * file and we skip over a possible Byte Order Mark.  */
+  if (!*lineno)
+    {
+      unread_buf[0] = getc (fp);
+      unread_buf[1] = getc (fp);
+      unread_buf[2] = getc (fp);
+      if (unread_buf[0] != 0xef
+          || unread_buf[1] != 0xbb
+          || unread_buf[2] != 0xbf)
+        unread_buf_count = 3;
+    }
+
   /* Find the next keyword.  */
   state = i = 0;
   for (;;)
     {
-      c = getc (fp);
+      if (unread_buf_count)
+        c = unread_buf[3 - unread_buf_count--];
+      else
+        c = getc (fp);
       if (c == '\n' || c== EOF )
         {
           if ( c != EOF )
@@ -699,6 +708,8 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
                         }
                       if (!set_opt_arg (arg, opts[idx].flags, p))
                         xfree (buffer);
+                      else
+                        gpgrt_annotate_leaked_object (buffer);
                     }
                 }
               break;
@@ -878,7 +889,9 @@ find_long_option( ARGPARSE_ARGS *arg,
            int j;
            for(j=i+1; opts[j].short_opt; j++ ) {
                if( opts[j].long_opt
-                   && !strncmp( opts[j].long_opt, keyword, n ) )
+                   && !strncmp( opts[j].long_opt, keyword, n )
+                    && !(opts[j].short_opt == opts[i].short_opt
+                         && opts[j].flags == opts[i].flags ) )
                    return -2;  /* abbreviation is ambiguous */
            }
            return i;
@@ -896,6 +909,46 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
   char *s, *s2;
   int i;
 
+  /* Fill in missing standard options: help, version, warranty and
+   * dump-options.  */
+  ARGPARSE_OPTS help_opt
+    = ARGPARSE_s_n (ARGPARSE_SHORTOPT_HELP, "help", "@");
+  ARGPARSE_OPTS version_opt
+    = ARGPARSE_s_n (ARGPARSE_SHORTOPT_VERSION, "version", "@");
+  ARGPARSE_OPTS warranty_opt
+    = ARGPARSE_s_n (ARGPARSE_SHORTOPT_WARRANTY, "warranty", "@");
+  ARGPARSE_OPTS dump_options_opt
+    = ARGPARSE_s_n(ARGPARSE_SHORTOPT_DUMP_OPTIONS, "dump-options", "@");
+  int seen_help = 0;
+  int seen_version = 0;
+  int seen_warranty = 0;
+  int seen_dump_options = 0;
+
+  i = 0;
+  while (opts[i].short_opt)
+    {
+      if (opts[i].long_opt)
+       {
+         if (!strcmp(opts[i].long_opt, help_opt.long_opt))
+           seen_help = 1;
+         else if (!strcmp(opts[i].long_opt, version_opt.long_opt))
+           seen_version = 1;
+         else if (!strcmp(opts[i].long_opt, warranty_opt.long_opt))
+           seen_warranty = 1;
+         else if (!strcmp(opts[i].long_opt, dump_options_opt.long_opt))
+           seen_dump_options = 1;
+       }
+      i++;
+    }
+  if (! seen_help)
+    opts[i++] = help_opt;
+  if (! seen_version)
+    opts[i++] = version_opt;
+  if (! seen_warranty)
+    opts[i++] = warranty_opt;
+  if (! seen_dump_options)
+    opts[i++] = dump_options_opt;
+
   initialize( arg, NULL, NULL );
   argc = *arg->argc;
   argv = *arg->argv;
@@ -952,9 +1005,9 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
       if ( argpos )
         *argpos = '=';
 
-      if ( i < 0 && !strcmp ( "help", s+2) )
+      if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_HELP)
         show_help (opts, arg->flags);
-      else if ( i < 0 && !strcmp ( "version", s+2) )
+      else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_VERSION)
         {
           if (!(arg->flags & ARGPARSE_FLAG_NOVERSION))
             {
@@ -962,20 +1015,18 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
               exit(0);
             }
        }
-      else if ( i < 0 && !strcmp( "warranty", s+2))
+      else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_WARRANTY)
         {
           writestrings (0, strusage (16), "\n", NULL);
           exit (0);
        }
-      else if ( i < 0 && !strcmp( "dump-options", s+2) )
+      else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS)
         {
           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);
        }
 
@@ -1492,10 +1543,10 @@ strusage( int level )
     case 10:
 #if ARGPARSE_GPL_VERSION == 3
       p = ("License GPLv3+: GNU GPL version 3 or later "
-           "<http://gnu.org/licenses/gpl.html>");
+           "<https://gnu.org/licenses/gpl.html>");
 #else
       p = ("License GPLv2+: GNU GPL version 2 or later "
-           "<http://gnu.org/licenses/>");
+           "<https://gnu.org/licenses/>");
 #endif
       break;
     case 11: p = "foo"; break;
@@ -1517,7 +1568,7 @@ ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
 "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";
+"along with this software.  If not, see <https://gnu.org/licenses/>.\n";
       break;
     case 40: /* short and long usage */
     case 41: p = ""; break;