X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fdriver.c;h=6f72ffe739aca687e07bfbd1bb4a92be5c1fd92d;hb=8a4ffde673c1bdfc687ff2a504036313f3595157;hp=203644584f162eade6f30663c26ffaa81625d58d;hpb=d0b91eae59319ab2756d0d43b9cb15eb9cd3c234;p=pspp diff --git a/src/output/driver.c b/src/output/driver.c index 203644584f..6f72ffe739 100644 --- a/src/output/driver.c +++ b/src/output/driver.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-9, 2000, 2007, 2009, 2010 Free Software Foundation, Inc. + Copyright (C) 1997-9, 2000, 2007, 2009, 2010, 2011, 2012, 2014 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ #include #include -#include "data/file-name.h" +#include "data/file-handle-def.h" #include "data/settings.h" #include "libpspp/array.h" #include "libpspp/assertion.h" @@ -38,29 +38,58 @@ #include "output/output-item.h" #include "output/text-item.h" -#include "gl/error.h" #include "gl/xalloc.h" #include "gl/xmemdup0.h" #include "gettext.h" #define _(msgid) gettext (msgid) +struct output_engine + { + struct llx_list drivers; /* Contains "struct output_driver"s. */ + struct string deferred_syntax; /* TEXT_ITEM_SYNTAX being accumulated. */ + }; + static const struct output_driver_factory *factories[]; -/* Drivers currently registered with output_driver_register(). */ -static struct llx_list drivers = LLX_INITIALIZER (drivers); +/* A stack of output engines.. */ +static struct output_engine *engine_stack; +static size_t n_stack, allocated_stack; + +static struct output_engine * +engine_stack_top (void) +{ + assert (n_stack > 0); + return &engine_stack[n_stack - 1]; +} -static struct output_item *deferred_syntax; -static bool in_command; +void +output_engine_push (void) +{ + struct output_engine *e; + + if (n_stack >= allocated_stack) + engine_stack = x2nrealloc (engine_stack, &allocated_stack, + sizeof *engine_stack); + + e = &engine_stack[n_stack++]; + llx_init (&e->drivers); + ds_init_empty (&e->deferred_syntax); +} void -output_close (void) +output_engine_pop (void) { - while (!llx_is_empty (&drivers)) + struct output_engine *e; + + assert (n_stack > 0); + e = &engine_stack[--n_stack]; + while (!llx_is_empty (&e->drivers)) { - struct output_driver *d = llx_pop_head (&drivers, &llx_malloc_mgr); + struct output_driver *d = llx_pop_head (&e->drivers, &llx_malloc_mgr); output_driver_destroy (d); } + ds_destroy (&e->deferred_syntax); } void @@ -73,11 +102,11 @@ output_get_supported_formats (struct string_set *formats) } static void -output_submit__ (struct output_item *item) +output_submit__ (struct output_engine *e, struct output_item *item) { struct llx *llx, *next; - for (llx = llx_head (&drivers); llx != llx_null (&drivers); llx = next) + for (llx = llx_head (&e->drivers); llx != llx_null (&e->drivers); llx = next) { struct output_driver *d = llx_data (llx); enum settings_output_type type; @@ -106,50 +135,39 @@ output_submit__ (struct output_item *item) } static void -flush_deferred_syntax (void) +flush_deferred_syntax (struct output_engine *e) { - if (deferred_syntax != NULL) + if (!ds_is_empty (&e->deferred_syntax)) { - output_submit__ (deferred_syntax); - deferred_syntax = NULL; + char *syntax = ds_steal_cstr (&e->deferred_syntax); + output_submit__ (e, text_item_super ( + text_item_create_nocopy (TEXT_ITEM_SYNTAX, syntax))); } } +static bool +is_syntax_item (const struct output_item *item) +{ + return (is_text_item (item) + && text_item_get_type (to_text_item (item)) == TEXT_ITEM_SYNTAX); +} + /* Submits ITEM to the configured output drivers, and transfers ownership to the output subsystem. */ void output_submit (struct output_item *item) { - if (is_text_item (item)) + struct output_engine *e = engine_stack_top (); + + if (is_syntax_item (item)) { - struct text_item *text = to_text_item (item); - switch (text_item_get_type (text)) - { - case TEXT_ITEM_SYNTAX: - if (!in_command) - { - flush_deferred_syntax (); - deferred_syntax = item; - return; - } - break; - - case TEXT_ITEM_COMMAND_OPEN: - output_submit__ (item); - flush_deferred_syntax (); - in_command = true; - return; - - case TEXT_ITEM_COMMAND_CLOSE: - in_command = false; - break; - - default: - break; - } + ds_put_cstr (&e->deferred_syntax, text_item_get_text (to_text_item (item))); + output_item_unref (item); + return; } - output_submit__ (item); + flush_deferred_syntax (e); + output_submit__ (e, item); } /* Flushes output to screen devices, so that the user can see @@ -157,9 +175,11 @@ output_submit (struct output_item *item) void output_flush (void) { + struct output_engine *e = engine_stack_top (); struct llx *llx; - for (llx = llx_head (&drivers); llx != llx_null (&drivers); + flush_deferred_syntax (e); + for (llx = llx_head (&e->drivers); llx != llx_null (&e->drivers); llx = llx_next (llx)) { struct output_driver *d = llx_data (llx); @@ -198,24 +218,41 @@ output_driver_get_name (const struct output_driver *driver) return driver->name; } +static struct output_engine * +output_driver_get_engine (const struct output_driver *driver) +{ + struct output_engine *e; + + for (e = engine_stack; e < &engine_stack[n_stack]; e++) + if (llx_find (llx_head (&e->drivers), llx_null (&e->drivers), driver)) + return e; + + return NULL; +} + void output_driver_register (struct output_driver *driver) { + struct output_engine *e = engine_stack_top (); + assert (!output_driver_is_registered (driver)); - llx_push_tail (&drivers, driver, &llx_malloc_mgr); + llx_push_tail (&e->drivers, driver, &llx_malloc_mgr); } void output_driver_unregister (struct output_driver *driver) { - llx_remove (llx_find (llx_head (&drivers), llx_null (&drivers), driver), + struct output_engine *e = output_driver_get_engine (driver); + + assert (e != NULL); + llx_remove (llx_find (llx_head (&e->drivers), llx_null (&e->drivers), driver), &llx_malloc_mgr); } bool output_driver_is_registered (const struct output_driver *driver) { - return llx_find (llx_head (&drivers), llx_null (&drivers), driver) != NULL; + return output_driver_get_engine (driver) != NULL; } /* Useful functions for output driver implementation. */ @@ -246,8 +283,10 @@ output_driver_track_current_command (const struct output_item *output_item, extern const struct output_driver_factory txt_driver_factory; extern const struct output_driver_factory list_driver_factory; extern const struct output_driver_factory html_driver_factory; -extern const struct output_driver_factory odt_driver_factory; extern const struct output_driver_factory csv_driver_factory; +#ifdef ODF_WRITE_SUPPORT +extern const struct output_driver_factory odt_driver_factory; +#endif #ifdef HAVE_CAIRO extern const struct output_driver_factory pdf_driver_factory; extern const struct output_driver_factory ps_driver_factory; @@ -259,8 +298,10 @@ static const struct output_driver_factory *factories[] = &txt_driver_factory, &list_driver_factory, &html_driver_factory, - &odt_driver_factory, &csv_driver_factory, +#ifdef ODF_WRITE_SUPPORT + &odt_driver_factory, +#endif #ifdef HAVE_CAIRO &pdf_driver_factory, &ps_driver_factory, @@ -302,16 +343,23 @@ output_driver_create (struct string_map *options) char *file_name; char *format; + format = string_map_find_and_delete (options, "format"); file_name = string_map_find_and_delete (options, "output-file"); - if (file_name == NULL) - file_name = xstrdup ("-"); - format = string_map_find_and_delete (options, "format"); if (format == NULL) { - const char *extension = strrchr (file_name, '.'); - format = xstrdup (extension != NULL ? extension + 1 : ""); + if (file_name != NULL) + { + const char *extension = strrchr (file_name, '.'); + format = xstrdup (extension != NULL ? extension + 1 : ""); + } + else + format = xstrdup ("txt"); } + f = find_factory (format); + + 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"); @@ -323,20 +371,21 @@ output_driver_create (struct string_map *options) device_type = SETTINGS_DEVICE_LISTING; else { - error (0, 0, _("%s is not a valid device type (the choices are " - "\"terminal\" and \"listing\")"), device_string); + 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 ()); - f = find_factory (format); - driver = f->create (file_name, device_type, options); + driver = f->create (fh, device_type, options); if (driver != NULL) { const struct string_map_node *node; const char *key; STRING_MAP_FOR_EACH_KEY (key, node, options) - error (0, 0, _("%s: unknown option \"%s\""), file_name, key); + msg (MW, _("%s: unknown option `%s'"), file_name, key); } string_map_clear (options);