Register DCO for Stefan Tomanek.
[gnupg.git] / common / argparse.c
index 3021745..c713bf6 100644 (file)
@@ -1,6 +1,7 @@
 /* [argparse.c wk 17.06.97] Argument Parser for option handling
  * Copyright (C) 1998, 1999, 2000, 2001, 2006
- *               2007, 2008  Free Software Foundation, Inc.
+ *               2007, 2008, 2012  Free Software Foundation, Inc.
+ * Copyright (C) 1997, 2013 Werner Koch
  *
  * This file is part of JNLIB, which is a subsystem of GnuPG.
  *
  *              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 7 : this is a command and not an option
+ *     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
  *     { '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 }
@@ -155,6 +158,16 @@ struct alias_def_s {
     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 *);
 
@@ -226,6 +239,7 @@ initialize( ARGPARSE_ARGS *arg, const char *filename, unsigned *lineno )
       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 )
@@ -308,6 +322,111 @@ store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
 #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.
@@ -317,6 +436,10 @@ store_alias( ARGPARSE_ARGS *arg, char *name, char *value )
  * 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.
  *
@@ -362,13 +485,32 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
                 }
               idx = i;
               arg->r_opt = opts[idx].short_opt;
-              if (!opts[idx].short_opt )
-                arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND)
-                              ? ARGPARSE_INVALID_COMMAND
-                              : ARGPARSE_INVALID_OPTION);
-              else if (!(opts[idx].flags & 7))
+              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 & 8) )
+              else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) )
                 arg->r_type = 0; /* Arg is optional.  */
               else
                 arg->r_opt = ARGPARSE_MISSING_ARG;
@@ -380,9 +522,9 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
               /* No argument found.  */
               if (in_alias)
                 arg->r_opt = ARGPARSE_MISSING_ARG;
-              else if (!(opts[idx].flags & 7))
+              else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
                 arg->r_type = 0; /* Does not take an arg. */
-              else if ((opts[idx].flags & 8))
+              else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL))
                 arg->r_type = 0; /* No optional argument. */
               else
                 arg->r_opt = ARGPARSE_MISSING_ARG;
@@ -418,7 +560,7 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
                         }
                    }
                }
-              else if (!(opts[idx].flags & 7))
+              else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK))
                 arg->r_opt = ARGPARSE_UNEXPECTED_ARG;
               else
                 {
@@ -453,6 +595,7 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
             }
           else if (c == EOF)
             {
+              ignore_invalid_option_clear (arg);
               if (ferror (fp))
                 arg->r_opt = ARGPARSE_READ_ERROR;
               else
@@ -479,13 +622,29 @@ optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
               break;
           idx = i;
           arg->r_opt = opts[idx].short_opt;
-          if (!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)
@@ -615,7 +774,7 @@ find_long_option( ARGPARSE_ARGS *arg,
            return i;
        }
     }
-    return -1;
+    return -1;  /* Not found.  */
 }
 
 int
@@ -702,7 +861,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
         {
           for (i=0; opts[i].short_opt; i++ )
             {
-              if ( opts[i].long_opt )
+              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",
@@ -721,7 +880,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
         arg->r_opt = opts[i].short_opt;
       if ( i < 0 )
         ;
-      else if ( (opts[i].flags & 0x07) )
+      else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
         {
           if ( argpos )
             {
@@ -805,7 +964,7 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
            arg->internal.inarg++; /* Point to the next arg.  */
            arg->r.ret_str = s;
           }
-       else if ( (opts[i].flags & 7) )
+       else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) )
           {
            if ( s[1] && !dash_kludge )
               {
@@ -877,9 +1036,9 @@ arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts)
 static int
 set_opt_arg(ARGPARSE_ARGS *arg, unsigned flags, char *s)
 {
-  int base = (flags & 16)? 0 : 10;
+  int base = (flags & ARGPARSE_OPT_PREFIX)? 0 : 10;
 
-  switch ( (arg->r_type = (flags & 7)) )
+  switch ( (arg->r_type = (flags & ARGPARSE_TYPE_MASK)) )
     {
     case ARGPARSE_TYPE_INT:
       arg->r.ret_int = (int)strtol(s,NULL,base);
@@ -967,7 +1126,7 @@ show_help (ARGPARSE_OPTS *opts, unsigned int flags)
         writestrings (0, "Options:", "\n", NULL);
       for (i=0; opts[i].short_opt; i++ )
         {
-          s = _( opts[i].description );
+          s = map_static_macro_string (_( opts[i].description ));
           if ( s && *s== '@' && !s[1] ) /* Hide this line.  */
             continue;
           if ( s && *s == '@' )  /* Unindented comment only line.  */
@@ -1075,35 +1234,8 @@ show_help (ARGPARSE_OPTS *opts, unsigned int flags)
     }
   if ( (s=strusage(19)) )
     {
-      /* bug reports to ... */
-      char *s2;
-
       writestrings (0, "\n", NULL);
-      s2 = strstr (s, "@EMAIL@");
-      if (s2)
-        {
-          if (s2-s)
-            {
-              const char *s3;
-
-              for (s3=s; s3 < s2; s3++)
-                {
-                  tmp[0] = *s3;
-                  tmp[1] = 0;
-                  writestrings (0, tmp, NULL);
-                }
-            }
-#ifdef PACKAGE_BUGREPORT
-          writestrings (0, PACKAGE_BUGREPORT, NULL);
-#else
-          writestrings (0, "bug@example.org", NULL);
-#endif
-          s2 += 7;
-          if (*s2)
-            writestrings (0, s2, NULL);
-        }
-      else
-        writestrings (0, s, NULL);
+      writestrings (0, s, NULL);
     }
   flushstrings (0);
   exit(0);
@@ -1195,7 +1327,7 @@ strusage( int level )
   const char *p = strusage_handler? strusage_handler(level) : NULL;
 
   if ( p )
-    return p;
+    return map_static_macro_string (p);
 
   switch ( level )
     {
@@ -1204,7 +1336,7 @@ strusage( int level )
       break;
     case 11: p = "foo"; break;
     case 13: p = "0.0"; break;
-    case 14: p = "Copyright (C) 2011 Free Software Foundation, Inc."; break;
+    case 14: p = "Copyright (C) 2014 Free Software Foundation, Inc."; 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";