output: Refactor driver options to avoid so much copying.
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 8 Feb 2023 19:21:10 +0000 (11:21 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Wed, 8 Feb 2023 19:21:21 +0000 (11:21 -0800)
src/output/ascii.c
src/output/cairo.c
src/output/csv.c
src/output/driver-provider.h
src/output/driver.c
src/output/html.c
src/output/odt.c
src/output/options.c
src/output/options.h
src/output/spv-driver.c
src/output/tex.c

index b94d4941c2362d05a198e844e9685d02bce79e7b..692f7f4d421bbfae5f64bc44bfb5c12e015a21a7 100644 (file)
@@ -326,7 +326,7 @@ static void ascii_submit (struct output_driver *, const struct output_item *);
 static int get_terminal_width (void);
 
 static bool update_page_size (struct ascii_driver *, bool issue_error);
-static int parse_page_size (struct driver_option *);
+static int parse_page_size (struct driver_option);
 
 static void ascii_draw_line (void *, int bb[TABLE_N_AXES][2],
                              const struct table_border_style[TABLE_N_AXES][2]);
@@ -346,10 +346,10 @@ ascii_driver_cast (struct output_driver *driver)
   return UP_CAST (driver, struct ascii_driver, driver);
 }
 
-static struct driver_option *
-opt (struct string_map *options, const char *key, const char *default_value)
+static struct driver_option
+opt (struct driver_options *options, const char *key, const char *default_value)
 {
-  return driver_option_get ("ascii", options, key, default_value);
+  return driver_option_get (options, key, default_value);
 }
 
 /* Return true iff the terminal appears to be an xterm with
@@ -366,8 +366,8 @@ term_is_utf8_xterm (void)
 }
 
 static struct output_driver *
-ascii_create (struct  file_handle *fh, enum settings_output_devices device_type,
-              struct string_map *o)
+ascii_create (struct file_handle *fh, enum settings_output_devices device_type,
+              struct driver_options *o)
 {
   bool append = parse_boolean (opt (o, "append", "false"));
   FILE *file = fn_open (fh, append ? "a" : "w");
@@ -455,13 +455,13 @@ error:
 }
 
 static int
-parse_page_size (struct driver_option *option)
+parse_page_size (struct driver_option option)
 {
-  int dim = atol (option->default_value);
+  int dim = atol (option.default_value);
 
-  if (option->value != NULL)
+  if (option.value != NULL)
     {
-      if (!strcmp (option->value, "auto"))
+      if (!strcmp (option.value, "auto"))
         dim = -1;
       else
         {
@@ -469,17 +469,15 @@ parse_page_size (struct driver_option *option)
           char *tail;
 
           errno = 0;
-          value = strtol (option->value, &tail, 0);
+          value = strtol (option.value, &tail, 0);
           if (value >= 1 && errno != ERANGE && *tail == '\0')
             dim = value;
           else
             msg (MW, _("%s: %s must be positive integer or `auto'"),
-                   option->driver_name, option->name);
+                   option.driver_name, option.name);
         }
     }
 
-  driver_option_destroy (option);
-
   return dim;
 }
 
index da224346f83f1e3a4db63503a3629247a2714865..8ef2b095363b0945040de06eaf5f8d31dd09c8ba 100644 (file)
@@ -129,10 +129,10 @@ xr_driver_cast (struct output_driver *driver)
   return UP_CAST (driver, struct xr_driver, driver);
 }
 
-static struct driver_option *
-opt (struct string_map *options, const char *key, const char *default_value)
+static struct driver_option
+opt (struct driver_options *options, const char *key, const char *default_value)
 {
-  return driver_option_get ("cairo", options, key, default_value);
+  return driver_option_get (options, key, default_value);
 }
 
 static PangoFontDescription *
@@ -162,7 +162,7 @@ parse_font (const char *font, int default_size, bool bold, bool italic)
 }
 
 static PangoFontDescription *
-parse_font_option (struct string_map *options,
+parse_font_option (struct driver_options *options,
                    const char *key, const char *default_value,
                    int default_size, bool bold, bool italic)
 {
@@ -184,7 +184,7 @@ parse_font_option (struct string_map *options,
 
 static struct xr_driver *
 xr_allocate (const char *name, int device_type,
-             enum xr_output_type output_type, struct string_map *o)
+             enum xr_output_type output_type, struct driver_options *o)
 {
   /* Scale factor from inch/72000 to inch/(72 * XR_POINT). */
   const double scale = XR_POINT / 1000.;
@@ -281,7 +281,7 @@ xr_allocate (const char *name, int device_type,
 
 static struct output_driver *
 xr_create (struct file_handle *fh, enum settings_output_devices device_type,
-           struct string_map *o, enum xr_output_type output_type)
+           struct driver_options *o, enum xr_output_type output_type)
 {
   const char *file_name = fh_get_file_name (fh);
   struct xr_driver *xr = xr_allocate (file_name, device_type, output_type, o);
@@ -328,29 +328,29 @@ xr_create (struct file_handle *fh, enum settings_output_devices device_type,
 }
 
 static struct output_driver *
-xr_pdf_create (struct  file_handle *fh, enum settings_output_devices device_type,
-               struct string_map *o)
+xr_pdf_create (struct file_handle *fh, enum settings_output_devices device_type,
+               struct driver_options *o)
 {
   return xr_create (fh, device_type, o, XR_PDF);
 }
 
 static struct output_driver *
-xr_ps_create (struct  file_handle *fh, enum settings_output_devices device_type,
-               struct string_map *o)
+xr_ps_create (struct file_handle *fh, enum settings_output_devices device_type,
+              struct driver_options *o)
 {
   return xr_create (fh, device_type, o, XR_PS);
 }
 
 static struct output_driver *
 xr_svg_create (struct file_handle *fh, enum settings_output_devices device_type,
-               struct string_map *o)
+               struct driver_options *o)
 {
   return xr_create (fh, device_type, o, XR_SVG);
 }
 
 static struct output_driver *
 xr_png_create (struct file_handle *fh, enum settings_output_devices device_type,
-               struct string_map *o)
+               struct driver_options *o)
 {
   return xr_create (fh, device_type, o, XR_PNG);
 }
index e63e828d4e7daf219a231fcb996220578d93d265..e6b769b383039c740abdb9c5321c86b5d889724a 100644 (file)
@@ -65,15 +65,15 @@ csv_driver_cast (struct output_driver *driver)
   return UP_CAST (driver, struct csv_driver, driver);
 }
 
-static struct driver_option *
-opt (struct string_map *options, const char *key, const char *default_value)
+static struct driver_option
+opt (struct driver_options *options, const char *key, const char *default_value)
 {
-  return driver_option_get ("csv", options, key, default_value);
+  return driver_option_get (options, key, default_value);
 }
 
 static struct output_driver *
 csv_create (struct file_handle *fh, enum settings_output_devices device_type,
-            struct string_map *o)
+            struct driver_options *o)
 {
   FILE *file = fn_open (fh, "w");
   if (!file)
index d0a054e8e0ef5ca1396b6a9bf42962c786a40d85..ffa483b4618db20297b00cde88a40aa47d9b1a12 100644 (file)
@@ -28,6 +28,7 @@ struct output_iterator;
 struct string_map;
 struct file_handle;
 struct page_setup;
+struct driver_options;
 
 /* A configured output driver. */
 struct output_driver
@@ -113,7 +114,7 @@ struct output_driver_factory
        is desirable). */
     struct output_driver *(*create) (struct file_handle *,
                                      enum settings_output_devices type,
-                                     struct string_map *options);
+                                     struct driver_options *);
   };
 
 #endif /* output/driver-provider.h */
index 92de2f5f176092254a775a8d33195b68f4c9939f..ba2d54f9f5060f055a96be78ba517ef3d7913cb7 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "output/driver.h"
 #include "output/driver-provider.h"
+#include "output/options.h"
 
 #include <ctype.h>
 #include <errno.h>
@@ -538,19 +539,11 @@ default_device_type (const char *file_name)
 struct output_driver *
 output_driver_create (struct string_map *options)
 {
-  enum settings_output_devices device_type;
-  const struct output_driver_factory *f;
-  struct output_driver *driver;
-  char *device_string;
-  char *file_name;
-  char *format;
-
-  format = string_map_find_and_delete (options, "format");
-  file_name = string_map_find_and_delete (options, "output-file");
-
-  if (format == NULL)
+  char *format = string_map_find_and_delete (options, "format");
+  char *file_name = string_map_find_and_delete (options, "output-file");
+  if (!format)
     {
-      if (file_name != NULL)
+      if (file_name)
         {
           const char *extension = strrchr (file_name, '.');
           format = xstrdup (extension != NULL ? extension + 1 : "");
@@ -558,42 +551,45 @@ output_driver_create (struct string_map *options)
       else
         format = xstrdup ("txt");
     }
-  f = find_factory (format);
+  const struct output_driver_factory *f = find_factory (format);
+
+  struct driver_options o = {
+    .driver_name = f->extension,
+    .map = STRING_MAP_INITIALIZER (o.map),
+    .garbage = STRING_ARRAY_INITIALIZER,
+  };
+  string_map_swap (&o.map, options);
 
   if (file_name == NULL)
     file_name = xstrdup (f->default_file_name);
 
   /* XXX should use parse_enum(). */
-  device_string = string_map_find_and_delete (options, "device");
-  if (device_string == NULL || device_string[0] == '\0')
-    device_type = default_device_type (file_name);
-  else if (!strcmp (device_string, "terminal"))
-    device_type = SETTINGS_DEVICE_TERMINAL;
-  else if (!strcmp (device_string, "listing"))
-    device_type = SETTINGS_DEVICE_LISTING;
-  else
-    {
-      msg (MW, _("%s is not a valid device type (the choices are `%s' and `%s')"),
-                     device_string, "terminal", "listing");
-      device_type = default_device_type (file_name);
-    }
-
-  struct file_handle *fh = fh_create_file (NULL, file_name, NULL, fh_default_properties ());
-
-  driver = f->create (fh, device_type, options);
-  if (driver != NULL)
+  enum settings_output_devices default_type = default_device_type (file_name);
+  const char *default_type_string = (default_type == SETTINGS_DEVICE_TERMINAL
+                                ? "terminal" : "listing");
+  enum settings_output_devices device_type = parse_enum (
+    driver_option_get (&o, "device", default_type_string),
+    "terminal", SETTINGS_DEVICE_TERMINAL,
+    "listing", SETTINGS_DEVICE_LISTING,
+    NULL_SENTINEL);
+
+  struct file_handle *fh = fh_create_file (NULL, file_name, NULL,
+                                           fh_default_properties ());
+  struct output_driver *driver = f->create (fh, device_type, &o);
+  if (driver)
     {
       const struct string_map_node *node;
       const char *key;
 
-      STRING_MAP_FOR_EACH_KEY (key, node, options)
+      STRING_MAP_FOR_EACH_KEY (key, node, &o.map)
         msg (MW, _("%s: unknown option `%s'"), file_name, key);
     }
-  string_map_clear (options);
+
+  string_map_destroy (&o.map);
+  string_array_destroy (&o.garbage);
 
   free (file_name);
   free (format);
-  free (device_string);
 
   return driver;
 }
index 0e6e8d822d71abedb0d761f702a5719c0aa42590..d3049e6564bd95e5c925a99a605c7bb2e96cd8a8 100644 (file)
@@ -84,10 +84,10 @@ html_driver_cast (struct output_driver *driver)
   return UP_CAST (driver, struct html_driver, driver);
 }
 
-static struct driver_option *
-opt (struct string_map *options, const char *key, const char *default_value)
+static struct driver_option
+opt (struct driver_options *options, const char *key, const char *default_value)
 {
-  return driver_option_get ("html", options, key, default_value);
+  return driver_option_get (options, key, default_value);
 }
 
 static void
@@ -176,7 +176,7 @@ put_header (struct html_driver *html)
 
 static struct output_driver *
 html_create (struct file_handle *fh, enum settings_output_devices device_type,
-             struct string_map *o)
+             struct driver_options *o)
 {
   FILE *file = fn_open (fh, "w");
   if (!file)
index 2f58586530ac78cb8b927656756797e360d26345..b0cf5cef9ef0c9e8cb9937662bae3c2d78255948 100644 (file)
@@ -282,7 +282,7 @@ write_meta_data (struct odt_driver *odt)
 
 static struct output_driver *
 odt_create (struct file_handle *fh, enum settings_output_devices device_type,
-            struct string_map *o UNUSED)
+            struct driver_options *o UNUSED)
 {
   const char *file_name = fh_get_file_name (fh);
   struct zip_writer *zip = zip_writer_create (file_name);
index 23715c693204e6c4b6a21684880f604bafb223a7..c05ea746c04d199e6f936d60ef5107af9fffdb5a 100644 (file)
    is used only in error messages).  The option named NAME is extracted from
    OPTIONS.  DEFAULT_VALUE is the default value of the option, used if the
    given option was not supplied or was invalid. */
-struct driver_option *
-driver_option_get (const char *driver_name, struct string_map *options,
+struct driver_option
+driver_option_get (struct driver_options *options,
                    const char *name, const char *default_value)
 {
-  struct driver_option *option = xmalloc (sizeof *option);
-  option->driver_name = xstrdup (driver_name);
-  option->name = xstrdup (name);
-  option->value = string_map_find_and_delete (options, name);
-  option->default_value = xstrdup_if_nonnull (default_value);
-  return option;
-}
-
-/* Frees driver option O. */
-void
-driver_option_destroy (struct driver_option *o)
-{
-  if (o != NULL)
-    {
-      free (o->driver_name);
-      free (o->name);
-      free (o->value);
-      free (o->default_value);
-      free (o);
-    }
+  char *value = string_map_find_and_delete (&options->map, name);
+  if (value)
+    string_array_append_nocopy (&options->garbage, value);
+  return (struct driver_option) {
+    .driver_name = options->driver_name,
+    .name = name,
+    .value = value,
+    .default_value = default_value,
+  };
 }
 
 /* Stores the paper size of the value of option O into *H and *V, in 1/72000"
-   units.  Any syntax accepted by measure_paper() may be used.
-
-   Destroys O. */
+   units.  Any syntax accepted by measure_paper() may be used. */
 void
-parse_paper_size (struct driver_option *o, int *h, int *v)
+parse_paper_size (struct driver_option o, int *h, int *v)
 {
-  if (o->value == NULL || !measure_paper (o->value, h, v))
-    measure_paper (o->default_value, h, v);
-  driver_option_destroy (o);
+  if (!o.value || !measure_paper (o.value, h, v))
+    measure_paper (o.default_value, h, v);
 }
 
 static int
@@ -99,24 +85,18 @@ do_parse_boolean (const char *driver_name, const char *key,
 }
 
 /* Parses and return O's value as a Boolean value.  "true" and "false", "yes"
-   and "no", "on" and "off", and "1" and "0" are acceptable boolean strings.
-
-   Destroys O. */
+   and "no", "on" and "off", and "1" and "0" are acceptable boolean strings. */
 bool
-parse_boolean (struct driver_option *o)
+parse_boolean (struct driver_option o)
 {
-  bool retval;
-
-  retval = do_parse_boolean (o->driver_name, o->name, o->default_value) > 0;
-  if (o->value != NULL)
+  bool retval = do_parse_boolean (o.driver_name, o.name, o.default_value) > 0;
+  if (o.value)
     {
-      int value = do_parse_boolean (o->driver_name, o->name, o->value);
+      int value = do_parse_boolean (o.driver_name, o.name, o.value);
       if (value >= 0)
         retval = value;
     }
 
-  driver_option_destroy (o);
-
   return retval;
 }
 
@@ -128,39 +108,30 @@ parse_boolean (struct driver_option *o)
    way.  If the default value still does not match, parse_enum() returns 0.
 
    Example: parse_enum (o, "a", 1, "b", 2, NULL_SENTINEL) returns 1 if O's
-   value if "a", 2 if O's value is "b".
-
-   Destroys O. */
+   value if "a", 2 if O's value is "b". */
 int
-parse_enum (struct driver_option *o, ...)
+parse_enum (struct driver_option o, ...)
 {
   va_list args;
-  int retval;
-
-  retval = 0;
   va_start (args, o);
+
+  int retval = 0;
   for (;;)
     {
-      const char *s;
-      int value;
-
-      s = va_arg (args, const char *);
-      if (s == NULL)
+      const char *s = va_arg (args, const char *);
+      if (!s)
         {
-          if (o->value != NULL)
+          if (o.value)
             {
-              struct string choices;
-              int i;
-
-              ds_init_empty (&choices);
+              struct string choices = DS_EMPTY_INITIALIZER;
               va_end (args);
               va_start (args, o);
-              for (i = 0; ; i++)
+              for (int i = 0; ; i++)
                 {
                   s = va_arg (args, const char *);
-                  if (s == NULL)
+                  if (!s)
                     break;
-                  value = va_arg (args, int);
+                  va_arg (args, int);
 
                   if (i > 0)
                     ds_put_cstr (&choices, ", ");
@@ -169,43 +140,39 @@ parse_enum (struct driver_option *o, ...)
 
               msg (MW, _("%s: `%s' is `%s' but one of the following "
                              "is required: %s"),
-                     o->driver_name, o->name, o->value, ds_cstr (&choices));
+                     o.driver_name, o.name, o.value, ds_cstr (&choices));
               ds_destroy (&choices);
             }
           break;
         }
-      value = va_arg (args, int);
 
-      if (o->value != NULL && !strcmp (s, o->value))
+      int value = va_arg (args, int);
+      if (o.value && !strcmp (s, o.value))
         {
           retval = value;
           break;
         }
-      else if (!strcmp (s, o->default_value))
+      else if (!strcmp (s, o.default_value))
         retval = value;
     }
   va_end (args);
-  driver_option_destroy (o);
   return retval;
 }
 
 /* Parses O's value as an integer in the range MIN_VALUE to MAX_VALUE
-   (inclusive) and returns the integer.
-
-   Destroys O. */
+   (inclusive) and returns the integer. */
 int
-parse_int (struct driver_option *o, int min_value, int max_value)
+parse_int (struct driver_option o, int min_value, int max_value)
 {
-  int retval = strtol (o->default_value, NULL, 0);
+  int retval = strtol (o.default_value, NULL, 0);
 
-  if (o->value != NULL)
+  if (o.value)
     {
-      int value;
-      char *tail;
-
       errno = 0;
-      value = strtol (o->value, &tail, 0);
-      if (tail != o->value && *tail == '\0' && errno != ERANGE
+
+      char *tail;
+      int value = strtol (o.value, &tail, 0);
+      if (tail != o.value && *tail == '\0' && errno != ERANGE
           && value >= min_value && value <= max_value)
         retval = value;
       else if (max_value == INT_MAX)
@@ -213,68 +180,53 @@ parse_int (struct driver_option *o, int min_value, int max_value)
           if (min_value == 0)
             msg (MW, _("%s: `%s' is `%s' but a non-negative integer "
                            "is required"),
-                   o->driver_name, o->name, o->value);
+                   o.driver_name, o.name, o.value);
           else if (min_value == 1)
             msg (MW, _("%s: `%s' is `%s' but a positive integer is "
-                           "required"), o->driver_name, o->name, o->value);
+                           "required"), o.driver_name, o.name, o.value);
           else if (min_value == INT_MIN)
             msg (MW, _("%s: `%s' is `%s' but an integer is required"),
-                   o->driver_name, o->name, o->value);
+                   o.driver_name, o.name, o.value);
           else
             msg (MW, _("%s: `%s' is `%s' but an integer greater "
                            "than %d is required"),
-                   o->driver_name, o->name, o->value, min_value - 1);
+                   o.driver_name, o.name, o.value, min_value - 1);
         }
       else
         msg (MW, _("%s: `%s' is `%s'  but an integer between %d and "
                        "%d is required"),
-               o->driver_name, o->name, o->value, min_value, max_value);
+               o.driver_name, o.name, o.value, min_value, max_value);
     }
-
-  driver_option_destroy (o);
   return retval;
 }
 
 /* Parses O's value as a dimension, as understood by measure_dimension(), and
-   returns its length in units of 1/72000".
-
-   Destroys O. */
+   returns its length in units of 1/72000". */
 int
-parse_dimension (struct driver_option *o)
+parse_dimension (struct driver_option o)
 {
-  int retval;
-
-  retval = (o->value != NULL ? measure_dimension (o->value)
-            : o->default_value != NULL ? measure_dimension (o->default_value)
-            : -1);
-
-  driver_option_destroy (o);
-  return retval;
+  return (o.value ? measure_dimension (o.value)
+          : o.default_value ? measure_dimension (o.default_value)
+          : -1);
 }
 
 /* Parses O's value as a string and returns it as a malloc'd string that the
-   caller is responsible for freeing.
-
-   Destroys O. */
+   caller is responsible for freeing. */
 char *
-parse_string (struct driver_option *o)
+parse_string (struct driver_option o)
 {
-  char *retval = xstrdup (o->value != NULL ? o->value : o->default_value);
-  driver_option_destroy (o);
-  return retval;
+  return xstrdup (o.value ? o.value : o.default_value);
 }
 
 static char *
 default_chart_file_name (const char *file_name)
 {
-  if (strcmp (file_name, "-"))
-    {
-      const char *extension = strrchr (file_name, '.');
-      int stem_length = extension ? extension - file_name : strlen (file_name);
-      return xasprintf ("%.*s-#", stem_length, file_name);
-    }
-  else
+  if (!strcmp (file_name, "-"))
     return NULL;
+
+  const char *extension = strrchr (file_name, '.');
+  int stem_length = extension ? extension - file_name : strlen (file_name);
+  return xasprintf ("%.*s-#", stem_length, file_name);
 }
 
 /* Parses and returns a chart file name, or NULL if no charts should be output.
@@ -282,41 +234,31 @@ default_chart_file_name (const char *file_name)
    which the client will presumably replace by a number as part of writing
    charts to separate files.
 
-   If O->value is "none", then this function returns NULL.
+   If o.value is "none", then this function returns NULL.
 
-   If O->value is non-NULL but not "none", returns a copy of that string (if it
+   If o.value is non-NULL but not "none", returns a copy of that string (if it
    contains '#').
 
-   If O->value is NULL, then O's default_value should be the name of the main
+   If o.value is NULL, then O's default_value should be the name of the main
    output file.  Returns NULL if default_value is "-", and otherwise returns a
-   copy of string string with its extension stripped off and "-#.png" appended.
-
-   Destroys O. */
+   copy of string string with its extension stripped off and "-#.png"
+   appended. */
 char *
-parse_chart_file_name (struct driver_option *o)
+parse_chart_file_name (struct driver_option o)
 {
-  char *chart_file_name;
-
-  if (o->value != NULL)
+  if (!o.value)
+    return default_chart_file_name (o.default_value);
+  else if (!strcmp (o.value, "none"))
+    return NULL;
+  else if (strchr (o.value, '#') != NULL)
+    return xstrdup (o.value);
+  else
     {
-      if (!strcmp (o->value, "none"))
-        chart_file_name = NULL;
-      else if (strchr (o->value, '#') != NULL)
-        chart_file_name = xstrdup (o->value);
-      else
-        {
-          msg (MW, _("%s: `%s' is `%s' but a file name that contains "
-                         "`#' is required."),
-               o->driver_name, o->name, o->value);
-          chart_file_name = default_chart_file_name (o->default_value);
-        }
+      msg (MW, _("%s: `%s' is `%s' but a file name that contains "
+                 "`#' is required."),
+           o.driver_name, o.name, o.value);
+      return default_chart_file_name (o.default_value);
     }
-  else
-    chart_file_name = default_chart_file_name (o->default_value);
-
-  driver_option_destroy (o);
-
-  return chart_file_name;
 }
 
 static int
@@ -584,17 +526,13 @@ parse_color__ (const char *s, struct cell_color *color)
 
 /* Parses and returns color information from O. */
 struct cell_color
-parse_color (struct driver_option *o)
+parse_color (struct driver_option o)
 {
   struct cell_color color = CELL_COLOR_BLACK;
-  parse_color__ (o->default_value, &color);
-  if (o->value)
-    {
-      if (!parse_color__ (o->value, &color))
-        msg (MW, _("%s: `%s' is `%s', which could not be parsed as a color"),
-             o->driver_name, o->name, o->value);
-    }
-  driver_option_destroy (o);
+  parse_color__ (o.default_value, &color);
+  if (o.value && !parse_color__ (o.value, &color))
+    msg (MW, _("%s: `%s' is `%s', which could not be parsed as a color"),
+         o.driver_name, o.name, o.value);
   return color;
 }
 
index 36d7bac9fb4aba32b9bd188014cb954fa96faf43..2c0fc5c13f674e8cc1885805185d0b901d1f1379 100644 (file)
 
 #include <stdbool.h>
 #include "libpspp/compiler.h"
+#include "libpspp/string-map.h"
+#include "libpspp/string-array.h"
 
 struct output_driver;
 struct string_map;
 
+struct driver_options
+  {
+    const char *driver_name;
+    struct string_map map;
+    struct string_array garbage;
+  };
+
 /* An option being parsed. */
 struct driver_option
   {
-    char *driver_name;          /* Driver's name, for use in error messages. */
-    char *name;                 /* Option name, for use in error messages.  */
-    char *value;                /* Value supplied by user (NULL if none). */
-    char *default_value;        /* Default value supplied by driver. */
+    const char *driver_name;    /* Driver's name, for use in error messages. */
+    const char *name;           /* Option name, for use in error messages.  */
+    const char *value;          /* Value supplied by user (NULL if none). */
+    const char *default_value;  /* Default value supplied by driver. */
   };
 
-struct driver_option *driver_option_get (const char *driver_name,
-                                         struct string_map *,
-                                         const char *name,
-                                         const char *default_value);
-void driver_option_destroy (struct driver_option *);
-
-void parse_paper_size (struct driver_option *, int *h, int *v);
-bool parse_boolean (struct driver_option *);
-int parse_enum (struct driver_option *, ...) SENTINEL(0);
-int parse_int (struct driver_option *, int min_value, int max_value);
-int parse_dimension (struct driver_option *);
-char *parse_string (struct driver_option *);
-char *parse_chart_file_name (struct driver_option *);
-
-struct cell_color parse_color (struct driver_option *);
+struct driver_option driver_option_get (struct driver_options *,
+                                        const char *name,
+                                        const char *default_value);
+
+void parse_paper_size (struct driver_option, int *h, int *v);
+bool parse_boolean (struct driver_option);
+int parse_enum (struct driver_option, ...) SENTINEL(0);
+int parse_int (struct driver_option, int min_value, int max_value);
+int parse_dimension (struct driver_option);
+char *parse_string (struct driver_option);
+char *parse_chart_file_name (struct driver_option);
+
+struct cell_color parse_color (struct driver_option);
 bool parse_color__ (const char *, struct cell_color *);
 
 #endif /* output/options.h */
index 5dcb9fee21835e54243f3143817afb968eb435cd..6fdcbb5bdcaf8343d5fd722041cc18d37efb00ae 100644 (file)
@@ -49,7 +49,7 @@ spv_driver_cast (struct output_driver *driver)
 
 static struct output_driver *
 spv_create (struct file_handle *fh, enum settings_output_devices device_type,
-            struct string_map *o UNUSED)
+            struct driver_options *o UNUSED)
 {
   struct spv_writer *writer;
   char *error = spv_writer_open (fh_get_file_name (fh), &writer);
index 4ffe33b1f9954e3b8edb51f277a06119a086148c..8a88452ec8a22760c146edd8f4c27e800d54a85b 100644 (file)
@@ -108,15 +108,15 @@ tex_driver_cast (struct output_driver *driver)
   return UP_CAST (driver, struct tex_driver, driver);
 }
 
-static struct driver_option *
-opt (struct string_map *options, const char *key, const char *default_value)
+static struct driver_option
+opt (struct driver_options *options, const char *key, const char *default_value)
 {
-  return driver_option_get ("tex", options, key, default_value);
+  return driver_option_get (options, key, default_value);
 }
 
 static struct output_driver *
 tex_create (struct file_handle *fh, enum settings_output_devices device_type,
-             struct string_map *o)
+            struct driver_options *o)
 {
   FILE *file = fn_open (fh, "w");
   if (!file)