/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2007, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2007, 2009, 2010 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
#include <data/settings.h>
#include <libpspp/assertion.h>
#include <libpspp/compiler.h>
+#include <libpspp/message.h>
#include <libpspp/start-date.h>
#include <libpspp/string-map.h>
#include <libpspp/version.h>
#include <output/cairo.h>
#include <output/chart-item-provider.h>
-#include "output/options.h"
+#include <output/message-item.h>
+#include <output/options.h>
#include <output/tab.h>
#include <output/text-item.h>
#include <output/driver-provider.h>
struct output_driver driver;
/* User parameters. */
- bool append; /* Append if output-file already exists? */
+ bool append; /* Append if output file already exists? */
bool headers; /* Print headers at top of page? */
bool paginate; /* Insert formfeeds? */
bool squeeze_blank_lines; /* Squeeze multiple blank lines into one? */
enum emphasis_style emphasis; /* How to emphasize text. */
- int tab_width; /* Width of a tab; 0 not to use tabs. */
char *chart_file_name; /* Name of files used for charts. */
int width; /* Page width. */
char *init; /* Device initialization string. */
/* Internal state. */
+ char *command_name;
char *title;
char *subtitle;
char *file_name; /* Output file name. */
FILE *file; /* Output file. */
- bool reported_error; /* Reported file open error? */
+ bool error; /* Output error? */
int page_number; /* Current page number. */
struct ascii_line *lines; /* Page content. */
int allocated_lines; /* Number of lines allocated. */
int y;
};
+static const struct output_driver_class ascii_driver_class;
+
+static void ascii_submit (struct output_driver *, const struct output_item *);
+
static int vertical_margins (const struct ascii_driver *);
static const char *get_default_box (int right, int bottom, int left, int top);
static int parse_page_size (struct driver_option *);
static void ascii_close_page (struct ascii_driver *);
-static void ascii_open_page (struct ascii_driver *);
+static bool ascii_open_page (struct ascii_driver *);
static void ascii_draw_line (void *, int bb[TABLE_N_AXES][2],
enum render_line_style styles[TABLE_N_AXES][2]);
static struct ascii_driver *
ascii_driver_cast (struct output_driver *driver)
{
- assert (driver->class == &ascii_class);
+ assert (driver->class == &ascii_driver_class);
return UP_CAST (driver, struct ascii_driver, driver);
}
}
static struct output_driver *
-ascii_create (const char *name, enum output_device_type device_type,
+ascii_create (const char *file_name, enum settings_output_devices device_type,
struct string_map *o)
{
struct output_driver *d;
a = xzalloc (sizeof *a);
d = &a->driver;
- output_driver_init (&a->driver, &ascii_class, name, device_type);
+ output_driver_init (&a->driver, &ascii_driver_class, file_name, device_type);
a->append = parse_boolean (opt (d, o, "append", "false"));
- a->headers = parse_boolean (opt (d, o, "headers", "true"));
- a->paginate = parse_boolean (opt (d, o, "paginate", "true"));
- a->squeeze_blank_lines = parse_boolean (opt (d, o, "squeeze", "false"));
- a->emphasis = parse_enum (opt (d, o, "emphasis", "bold"),
+ a->headers = parse_boolean (opt (d, o, "headers", "false"));
+ a->paginate = parse_boolean (opt (d, o, "paginate", "false"));
+ a->squeeze_blank_lines = parse_boolean (opt (d, o, "squeeze", "true"));
+ a->emphasis = parse_enum (opt (d, o, "emphasis", "none"),
"bold", EMPH_BOLD,
"underline", EMPH_UNDERLINE,
"none", EMPH_NONE,
(char *) NULL);
- a->tab_width = parse_int (opt (d, o, "tab-width", "0"), 8, INT_MAX);
-
- if (parse_enum (opt (d, o, "chart-type", "png"),
- "png", true,
- "none", false,
- (char *) NULL))
- a->chart_file_name = parse_chart_file_name (opt (d, o, "chart-files",
- "pspp-#.png"));
- else
- a->chart_file_name = NULL;
- a->top_margin = parse_int (opt (d, o, "top-margin", "2"), 0, INT_MAX);
- a->bottom_margin = parse_int (opt (d, o, "bottom-margin", "2"), 0, INT_MAX);
+ a->chart_file_name = parse_chart_file_name (opt (d, o, "charts", file_name));
+
+ a->top_margin = parse_int (opt (d, o, "top-margin", "0"), 0, INT_MAX);
+ a->bottom_margin = parse_int (opt (d, o, "bottom-margin", "0"), 0, INT_MAX);
a->width = parse_page_size (opt (d, o, "width", "79"));
paper_length = parse_page_size (opt (d, o, "length", "66"));
}
a->init = parse_string (opt (d, o, "init", ""));
+ a->command_name = NULL;
a->title = xstrdup ("");
a->subtitle = xstrdup ("");
- a->file_name = parse_string (opt (d, o, "output-file", "pspp.list"));
+ a->file_name = xstrdup (file_name);
a->file = NULL;
- a->reported_error = false;
+ a->error = false;
a->page_number = 0;
a->lines = NULL;
a->allocated_lines = 0;
if (a->file != NULL)
fn_close (a->file_name, a->file);
+ free (a->command_name);
free (a->title);
free (a->subtitle);
free (a->file_name);
}
static void
-ascii_submit (struct output_driver *driver,
- const struct output_item *output_item)
+ascii_output_table_item (struct ascii_driver *a,
+ const struct table_item *table_item)
{
- struct ascii_driver *a = ascii_driver_cast (driver);
- if (is_table_item (output_item))
+ const char *caption = table_item_get_caption (table_item);
+ struct render_params params;
+ struct render_page *page;
+ struct render_break x_break;
+ int caption_height;
+ int i;
+
+ update_page_size (a, false);
+
+ if (caption != NULL)
{
- struct table_item *table_item = to_table_item (output_item);
- const char *caption = table_item_get_caption (table_item);
- struct render_params params;
- struct render_page *page;
- struct render_break x_break;
- int caption_height;
- int i;
+ /* XXX doesn't do well with very large captions */
+ struct table_cell cell;
+ ascii_init_caption_cell (caption, &cell);
+ caption_height = ascii_measure_cell_height (a, &cell, a->width);
+ }
+ else
+ caption_height = 0;
+
+ params.draw_line = ascii_draw_line;
+ params.measure_cell_width = ascii_measure_cell_width;
+ params.measure_cell_height = ascii_measure_cell_height;
+ params.draw_cell = ascii_draw_cell,
+ params.aux = a;
+ params.size[H] = a->width;
+ params.size[V] = a->length - caption_height;
+ params.font_size[H] = 1;
+ params.font_size[V] = 1;
+ for (i = 0; i < RENDER_N_LINES; i++)
+ {
+ int width = i == RENDER_LINE_NONE ? 0 : 1;
+ params.line_widths[H][i] = width;
+ params.line_widths[V][i] = width;
+ }
- update_page_size (a, false);
+ if (a->file == NULL && !ascii_open_page (a))
+ return;
- if (caption != NULL)
- {
- /* XXX doesn't do well with very large captions */
- struct table_cell cell;
- ascii_init_caption_cell (caption, &cell);
- caption_height = ascii_measure_cell_height (a, &cell, a->width);
- }
- else
- caption_height = 0;
-
- params.draw_line = ascii_draw_line;
- params.measure_cell_width = ascii_measure_cell_width;
- params.measure_cell_height = ascii_measure_cell_height;
- params.draw_cell = ascii_draw_cell,
- params.aux = a;
- params.size[H] = a->width;
- params.size[V] = a->length - caption_height;
- params.font_size[H] = 1;
- params.font_size[V] = 1;
- for (i = 0; i < RENDER_N_LINES; i++)
+ page = render_page_create (¶ms, table_item_get_table (table_item));
+ for (render_break_init (&x_break, page, H);
+ render_break_has_next (&x_break); )
+ {
+ struct render_page *x_slice;
+ struct render_break y_break;
+
+ x_slice = render_break_next (&x_break, a->width);
+ for (render_break_init (&y_break, x_slice, V);
+ render_break_has_next (&y_break); )
{
- int width = i == RENDER_LINE_NONE ? 0 : 1;
- params.line_widths[H][i] = width;
- params.line_widths[V][i] = width;
- }
+ struct render_page *y_slice;
+ int space;
- if (a->file == NULL)
- ascii_open_page (a);
+ if (a->y > 0)
+ a->y++;
- page = render_page_create (¶ms, table_item_get_table (table_item));
- for (render_break_init (&x_break, page, H);
- render_break_has_next (&x_break); )
- {
- struct render_page *x_slice;
- struct render_break y_break;
+ space = a->length - a->y - caption_height;
+ if (render_break_next_size (&y_break) > space)
+ {
+ assert (a->y > 0);
+ ascii_close_page (a);
+ if (!ascii_open_page (a))
+ return;
+ continue;
+ }
- x_slice = render_break_next (&x_break, a->width);
- for (render_break_init (&y_break, x_slice, V);
- render_break_has_next (&y_break); )
+ y_slice = render_break_next (&y_break, space);
+ if (caption_height)
{
- struct render_page *y_slice;
- int space;
-
- if (a->y > 0)
- a->y++;
-
- space = a->length - a->y - caption_height;
- if (render_break_next_size (&y_break) > space)
- {
- assert (a->y > 0);
- ascii_close_page (a);
- ascii_open_page (a);
- continue;
- }
-
- y_slice = render_break_next (&y_break, space);
- if (caption_height)
- {
- struct table_cell cell;
- int bb[TABLE_N_AXES][2];
-
- ascii_init_caption_cell (caption, &cell);
- bb[H][0] = 0;
- bb[H][1] = a->width;
- bb[V][0] = 0;
- bb[V][1] = caption_height;
- ascii_draw_cell (a, &cell, bb, bb);
- a->y += caption_height;
- caption_height = 0;
- }
- render_page_draw (y_slice);
- a->y += render_page_get_size (y_slice, V);
- render_page_unref (y_slice);
+ struct table_cell cell;
+ int bb[TABLE_N_AXES][2];
+
+ ascii_init_caption_cell (caption, &cell);
+ bb[H][0] = 0;
+ bb[H][1] = a->width;
+ bb[V][0] = 0;
+ bb[V][1] = caption_height;
+ ascii_draw_cell (a, &cell, bb, bb);
+ a->y += caption_height;
+ caption_height = 0;
}
- render_break_destroy (&y_break);
+ render_page_draw (y_slice);
+ a->y += render_page_get_size (y_slice, V);
+ render_page_unref (y_slice);
}
- render_break_destroy (&x_break);
+ render_break_destroy (&y_break);
}
+ render_break_destroy (&x_break);
+}
+
+static void
+ascii_output_text (struct ascii_driver *a, const char *text)
+{
+ struct table_item *table_item;
+
+ table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+ ascii_output_table_item (a, table_item);
+ table_item_unref (table_item);
+}
+
+static void
+ascii_submit (struct output_driver *driver,
+ const struct output_item *output_item)
+{
+ struct ascii_driver *a = ascii_driver_cast (driver);
+
+ output_driver_track_current_command (output_item, &a->command_name);
+
+ if (a->error)
+ return;
+
+ if (is_table_item (output_item))
+ ascii_output_table_item (a, to_table_item (output_item));
+#ifdef HAVE_CAIRO
else if (is_chart_item (output_item) && a->chart_file_name != NULL)
{
struct chart_item *chart_item = to_chart_item (output_item);
free (file_name);
}
}
+#endif /* HAVE_CAIRO */
else if (is_text_item (output_item))
{
const struct text_item *text_item = to_text_item (output_item);
break;
default:
- {
- struct table_item *item;
-
- item = table_item_create (table_from_string (0, text), NULL);
- ascii_submit (&a->driver, &item->output_item);
- table_item_unref (item);
- }
+ ascii_output_text (a, text);
break;
}
}
+ else if (is_message_item (output_item))
+ {
+ const struct message_item *message_item = to_message_item (output_item);
+ const struct msg *msg = message_item_get_msg (message_item);
+ char *s = msg_to_string (msg, a->command_name);
+ ascii_output_text (a, s);
+ free (s);
+ }
}
-const struct output_driver_class ascii_class =
+const struct output_driver_factory txt_driver_factory =
+ { "txt", ascii_create };
+const struct output_driver_factory list_driver_factory =
+ { "list", ascii_create };
+
+static const struct output_driver_class ascii_driver_class =
{
- "ascii",
- ascii_create,
+ "text",
ascii_destroy,
ascii_submit,
ascii_flush,
\f
/* ascii_close_page () and support routines. */
-static void
+static bool
ascii_open_page (struct ascii_driver *a)
{
int i;
+ if (a->error)
+ return false;
+
if (a->file == NULL)
{
a->file = fn_open (a->file_name, a->append ? "a" : "w");
}
else
{
- /* Report the error to the user and complete
- initialization. If we do not finish initialization,
- then calls to other driver functions will segfault
- later. It would be better to simply drop the driver
- entirely, but we do not have a convenient mechanism
- for this (yet). */
- if (!a->reported_error)
- error (0, errno, _("ascii: opening output file \"%s\""),
- a->file_name);
- a->reported_error = true;
+ error (0, errno, _("ascii: opening output file \"%s\""),
+ a->file_name);
+ a->error = true;
+ return false;
}
}
for (i = 0; i < a->length; i++)
a->lines[i].n_chars = 0;
+
+ return true;
}
/* Writes LINE to A's output file. */
bool any_blank;
int i, y;
+ a->y = 0;
if (a->file == NULL)
return;
putc ('\n', a->file);
if (a->paginate)
putc ('\f', a->file);
-
- a->y = 0;
}