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]);
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
}
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");
}
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
{
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;
}
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 *
}
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)
{
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.;
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);
}
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);
}
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)
struct string_map;
struct file_handle;
struct page_setup;
+struct driver_options;
/* A configured output driver. */
struct output_driver
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 */
#include "output/driver.h"
#include "output/driver-provider.h"
+#include "output/options.h"
#include <ctype.h>
#include <errno.h>
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 : "");
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;
}
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
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)
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);
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
}
/* 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;
}
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, ", ");
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)
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.
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
/* 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;
}
#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 */
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);
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)