1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include <output/driver.h>
20 #include <output/driver-provider.h>
28 #include <data/file-name.h>
29 #include <data/settings.h>
30 #include <libpspp/array.h>
31 #include <libpspp/assertion.h>
32 #include <libpspp/string-map.h>
33 #include <libpspp/string-set.h>
34 #include <libpspp/str.h>
35 #include <output/output-item.h>
36 #include <output/text-item.h>
43 #define _(msgid) gettext (msgid)
45 static const struct output_driver_class *driver_classes[];
47 static struct output_driver **drivers;
48 static size_t n_drivers, allocated_drivers;
50 static unsigned int enabled_device_types = ((1u << OUTPUT_DEVICE_UNKNOWN)
51 | (1u << OUTPUT_DEVICE_LISTING)
52 | (1u << OUTPUT_DEVICE_SCREEN)
53 | (1u << OUTPUT_DEVICE_PRINTER));
55 static struct output_item *deferred_syntax;
56 static bool in_command;
63 struct output_driver *d = drivers[--n_drivers];
64 output_driver_destroy (d);
69 expand_macro (const char *name, struct string *dst, void *macros_)
71 const struct string_map *macros = macros_;
73 if (!strcmp (name, "viewwidth"))
74 ds_put_format (dst, "%d", settings_get_viewwidth ());
75 else if (!strcmp (name, "viewlength"))
76 ds_put_format (dst, "%d", settings_get_viewlength ());
79 const char *value = string_map_find (macros, name);
81 ds_put_cstr (dst, value);
85 /* Defines one configuration macro based on the text in BP, which
86 should be of the form `KEY=VALUE'. Returns true if
87 successful, false if S is not in the proper form. */
89 output_define_macro (const char *s, struct string_map *macros)
91 const char *key_start, *value;
95 s += strspn (s, CC_SPACES);
98 key_len = strcspn (s, "=" CC_SPACES);
103 s += strspn (s, CC_SPACES);
107 s += strspn (s, CC_SPACES);
110 key = xmemdup0 (key_start, key_len);
111 if (!string_map_contains (macros, key))
113 struct string expanded_value = DS_EMPTY_INITIALIZER;
115 fn_interp_vars (ss_cstr (value), expand_macro, ¯os, &expanded_value);
116 string_map_insert_nocopy (macros, key, ds_steal_cstr (&expanded_value));
125 add_driver_names (char *to, struct string_set *names)
127 char *save_ptr = NULL;
130 for (name = strtok_r (to, CC_SPACES, &save_ptr); name != NULL;
131 name = strtok_r (NULL, CC_SPACES, &save_ptr))
132 string_set_insert (names, name);
136 init_default_drivers (void)
138 error (0, 0, _("using default output driver configuration"));
139 output_configure_driver ("list:ascii:listing:"
140 "length=66 width=79 output-file=\"pspp.list\"");
144 warn_unused_drivers (const struct string_set *unused_drivers,
145 const struct string_set *requested_drivers)
147 const struct string_set_node *node;
150 STRING_SET_FOR_EACH (name, node, unused_drivers)
151 if (string_set_contains (requested_drivers, name))
152 error (0, 0, _("unknown output driver `%s'"), name);
154 error (0, 0, _("output driver `%s' referenced but never defined"), name);
158 output_read_configuration (const struct string_map *macros_,
159 const struct string_set *driver_names_)
161 struct string_map macros = STRING_MAP_INITIALIZER (macros);
162 struct string_set driver_names = STRING_SET_INITIALIZER (driver_names);
163 char *devices_file_name = NULL;
164 FILE *devices_file = NULL;
165 struct string line = DS_EMPTY_INITIALIZER;
168 ds_init_empty (&line);
170 devices_file_name = fn_search_path ("devices", config_path);
171 if (devices_file_name == NULL)
173 error (0, 0, _("cannot find output initialization file "
174 "(use `-vv' to view search path)"));
177 devices_file = fopen (devices_file_name, "r");
178 if (devices_file == NULL)
180 error (0, errno, _("cannot open \"%s\""), devices_file_name);
184 string_map_replace_map (¯os, macros_);
185 string_set_union (&driver_names, driver_names_);
186 if (string_set_is_empty (&driver_names))
187 string_set_insert (&driver_names, "default");
192 char *cp, *delimiter, *name;
194 if (!ds_read_config_line (&line, &line_number, devices_file))
196 if (ferror (devices_file))
197 error (0, errno, _("reading \"%s\""), devices_file_name);
201 cp = ds_cstr (&line);
202 cp += strspn (cp, CC_SPACES);
206 else if (!strncmp ("define", cp, 6) && isspace ((unsigned char) cp[6]))
208 if (!output_define_macro (&cp[7], ¯os))
209 error_at_line (0, 0, devices_file_name, line_number,
210 _("\"%s\" is not a valid macro definition"),
215 delimiter = cp + strcspn (cp, ":=");
216 name = xmemdup0 (cp, delimiter - cp);
217 if (*delimiter == '=')
219 if (string_set_delete (&driver_names, name))
220 add_driver_names (delimiter + 1, &driver_names);
222 else if (*delimiter == ':')
224 if (string_set_delete (&driver_names, name))
226 fn_interp_vars (ds_ss (&line), expand_macro, ¯os, &line);
227 output_configure_driver (ds_cstr (&line));
231 error_at_line (0, 0, devices_file_name, line_number,
236 warn_unused_drivers (&driver_names, driver_names_);
239 if (devices_file != NULL)
240 fclose (devices_file);
241 free (devices_file_name);
243 string_set_destroy (&driver_names);
244 string_map_destroy (¯os);
248 error (0, 0, _("no active output drivers"));
249 init_default_drivers ();
253 /* Obtains a token from S and advances its position. Errors are
254 reported against the given DRIVER_NAME.
255 The token is stored in TOKEN. Returns true if successful,
256 false on syntax error.
258 Caller is responsible for skipping leading spaces. */
260 get_option_token (char **s_, const char *driver_name,
261 struct string *token)
263 struct substring s = ss_cstr (*s_);
267 c = ss_get_char (&s);
270 error (0, 0, _("syntax error parsing options for \"%s\" driver"),
274 else if (c == '\'' || c == '"')
280 c = ss_get_char (&s);
286 _("reached end of options inside quoted string "
287 "parsing options for \"%s\" driver"),
292 ds_put_char (token, c);
297 c = ss_get_char (&s);
339 while (ss_first (s) >= '0' && ss_first (s) <= '7')
340 out = out * 8 + (ss_get_char (&s) - '0');
345 while (isxdigit (ss_first (s)))
347 c = ss_get_char (&s);
352 out += tolower (c) - 'a' + 10;
356 error (0, 0, _("syntax error in string constant "
357 "parsing options for \"%s\" driver"),
361 ds_put_char (token, out);
369 ds_put_char (token, c);
372 if (c == EOF || c == '=' || isspace (c))
383 parse_options (const char *driver_name, char *options,
384 struct string_map *option_map)
386 struct string key = DS_EMPTY_INITIALIZER;
387 struct string value = DS_EMPTY_INITIALIZER;
391 options += strspn (options, CC_SPACES);
392 if (*options == '\0')
395 if (!get_option_token (&options, driver_name, &key))
398 options += strspn (options, CC_SPACES);
401 error (0, 0, _("syntax error expecting `=' "
402 "parsing options for driver \"%s\""),
408 options += strspn (options, CC_SPACES);
409 if (!get_option_token (&options, driver_name, &value))
412 if (string_map_contains (option_map, ds_cstr (&key)))
413 error (0, 0, _("driver \"%s\" defines option \"%s\" multiple times"),
414 driver_name, ds_cstr (&key));
416 string_map_insert (option_map, ds_cstr (&key), ds_cstr (&value));
424 trim_token (char *token)
430 /* Trim leading spaces. */
431 while (isspace ((unsigned char) *token))
434 /* Trim trailing spaces. */
435 end = strchr (token, '\0');
436 while (end > token && isspace ((unsigned char) end[-1]))
439 /* An empty token is a null token. */
446 static const struct output_driver_class *
447 find_output_class (const char *name)
449 const struct output_driver_class **classp;
451 for (classp = driver_classes; *classp != NULL; classp++)
452 if (!strcmp ((*classp)->name, name))
458 static struct output_driver *
459 create_driver (const char *driver_name, const char *class_name,
460 const char *device_type, struct string_map *options)
462 const struct output_driver_class *class;
463 enum output_device_type type;
464 struct output_driver *driver;
466 type = OUTPUT_DEVICE_UNKNOWN;
467 if (device_type != NULL && device_type[0] != '\0')
469 if (!strcmp (device_type, "listing"))
470 type = OUTPUT_DEVICE_LISTING;
471 else if (!strcmp (device_type, "screen"))
472 type = OUTPUT_DEVICE_SCREEN;
473 else if (!strcmp (device_type, "printer"))
474 type = OUTPUT_DEVICE_PRINTER;
476 error (0, 0, _("unknown device type `%s'"), device_type);
479 class = find_output_class (class_name);
481 driver = class->create (driver_name, type, options);
484 error (0, 0, _("unknown output driver class `%s'"), class_name);
488 string_map_destroy (options);
493 struct output_driver *
494 output_driver_create (const char *class_name, struct string_map *options)
496 return create_driver (class_name, class_name, NULL, options);
499 /* String LINE is in format:
500 DRIVERNAME:CLASSNAME:DEVICETYPE:OPTIONS
503 output_configure_driver (const char *line_)
505 char *save_ptr = NULL;
506 char *line = xstrdup (line_);
507 char *driver_name = trim_token (strtok_r (line, ":", &save_ptr));
508 char *class_name = trim_token (strtok_r (NULL, ":", &save_ptr));
509 char *device_type = trim_token (strtok_r (NULL, ":", &save_ptr));
510 char *options = trim_token (strtok_r (NULL, "", &save_ptr));
512 if (driver_name && class_name)
514 struct string_map option_map;
515 struct output_driver *driver;
517 string_map_init (&option_map);
519 parse_options (driver_name, options, &option_map);
521 driver = create_driver (driver_name, class_name,
522 device_type, &option_map);
524 output_driver_register (driver);
528 _("driver definition line missing driver name or class name"));
533 /* Display on stdout a list of all registered driver classes. */
535 output_list_classes (void)
537 const struct output_driver_class **classp;
539 printf (_("Driver classes:"));
540 for (classp = driver_classes; *classp != NULL; classp++)
541 printf (" %s", (*classp)->name);
546 driver_is_enabled (const struct output_driver *d)
548 return (1u << d->device_type) & enabled_device_types;
552 output_submit__ (struct output_item *item)
556 for (i = 0; i < n_drivers; i++)
558 struct output_driver *d = drivers[i];
559 if (driver_is_enabled (d))
560 d->class->submit (d, item);
563 output_item_unref (item);
566 /* Submits ITEM to the configured output drivers, and transfers ownership to
567 the output subsystem. */
569 output_submit (struct output_item *item)
571 if (is_text_item (item))
573 struct text_item *text = to_text_item (item);
574 switch (text_item_get_type (text))
576 case TEXT_ITEM_SYNTAX:
579 if (deferred_syntax != NULL)
580 output_submit__ (deferred_syntax);
581 deferred_syntax = item;
586 case TEXT_ITEM_COMMAND_OPEN:
587 output_submit__ (item);
588 if (deferred_syntax != NULL)
590 output_submit__ (deferred_syntax);
591 deferred_syntax = NULL;
596 case TEXT_ITEM_COMMAND_CLOSE:
605 output_submit__ (item);
608 /* Flushes output to screen devices, so that the user can see
609 output that doesn't fill up an entire page. */
615 for (i = 0; i < n_drivers; i++)
617 struct output_driver *d = drivers[i];
618 if (driver_is_enabled (d) && d->class->flush != NULL)
624 output_get_enabled_types (void)
626 return enabled_device_types;
630 output_set_enabled_types (unsigned int types)
632 enabled_device_types = types;
636 output_set_type_enabled (bool enable, enum output_device_type type)
638 unsigned int bit = 1u << type;
640 enabled_device_types |= bit;
642 enabled_device_types |= ~bit;
646 output_driver_init (struct output_driver *driver,
647 const struct output_driver_class *class,
648 const char *name, enum output_device_type type)
650 driver->class = class;
651 driver->name = xstrdup (name);
652 driver->device_type = type;
656 output_driver_destroy (struct output_driver *driver)
660 char *name = driver->name;
661 if (output_driver_is_registered (driver))
662 output_driver_unregister (driver);
663 if (driver->class->destroy)
664 driver->class->destroy (driver);
670 output_driver_get_name (const struct output_driver *driver)
676 output_driver_register (struct output_driver *driver)
678 assert (!output_driver_is_registered (driver));
679 if (n_drivers >= allocated_drivers)
680 drivers = x2nrealloc (drivers, &allocated_drivers, sizeof *drivers);
681 drivers[n_drivers++] = driver;
685 output_driver_unregister (struct output_driver *driver)
689 for (i = 0; i < n_drivers; i++)
690 if (drivers[i] == driver)
692 remove_element (drivers, n_drivers, sizeof *drivers, i);
699 output_driver_is_registered (const struct output_driver *driver)
703 for (i = 0; i < n_drivers; i++)
704 if (drivers[i] == driver)
709 /* Known driver classes. */
711 static const struct output_driver_class *driver_classes[] =