/* PSPP - a program for statistical analysis.
- Copyright (C) 2009 Free Software Foundation, Inc.
+ Copyright (C) 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 <errno.h>
#include <stdlib.h>
-#include <data/file-name.h>
-#include <libpspp/assertion.h>
-#include <libpspp/compiler.h>
-#include <libpspp/string-map.h>
-#include <output/text-item.h>
-#include <output/driver-provider.h>
-#include <output/options.h>
-#include <output/table-item.h>
-#include <output/table-provider.h>
+#include "data/file-name.h"
+#include "libpspp/assertion.h"
+#include "libpspp/compiler.h"
+#include "libpspp/message.h"
+#include "libpspp/string-map.h"
+#include "output/text-item.h"
+#include "output/driver-provider.h"
+#include "output/options.h"
+#include "output/message-item.h"
+#include "output/table-item.h"
+#include "output/table-provider.h"
#include "gl/error.h"
#include "gl/xalloc.h"
{
struct output_driver driver;
- char *separator; /* Comma or tab. */
+ char *separator; /* Field separator (usually comma or tab). */
+ char *quote_set; /* Characters that force quoting. */
+ bool captions; /* Print table captions? */
char *file_name; /* Output file name. */
+ char *command_name; /* Current command. */
FILE *file; /* Output file. */
- bool reported_error; /* Reported file open error? */
+ int n_items; /* Number of items output so far. */
};
+static const struct output_driver_class csv_driver_class;
+
static struct csv_driver *
csv_driver_cast (struct output_driver *driver)
{
- assert (driver->class == &csv_class);
+ assert (driver->class == &csv_driver_class);
return UP_CAST (driver, struct csv_driver, driver);
}
}
static struct output_driver *
-csv_create (const char *name, enum output_device_type device_type,
+csv_create (const char *file_name, enum settings_output_devices device_type,
struct string_map *o)
{
struct output_driver *d;
csv = xzalloc (sizeof *csv);
d = &csv->driver;
- output_driver_init (&csv->driver, &csv_class, name, device_type);
+ output_driver_init (&csv->driver, &csv_driver_class, file_name, device_type);
csv->separator = parse_string (opt (d, o, "separator", ","));
- csv->file_name = parse_string (opt (d, o, "output-file", "pspp.csv"));
- csv->file = NULL;
- csv->reported_error = false;
+ csv->quote_set = xasprintf ("\"\n\r\t%s", csv->separator);
+ csv->captions = parse_boolean (opt (d, o, "captions", "true"));
+ csv->file_name = xstrdup (file_name);
+ csv->file = fn_open (csv->file_name, "w");
+ csv->n_items = 0;
+
+ if (csv->file == NULL)
+ {
+ error (0, errno, _("error opening output file `%s'"), csv->file_name);
+ output_driver_destroy (d);
+ return NULL;
+ }
return d;
}
{
struct csv_driver *csv = csv_driver_cast (driver);
+ if (csv->file != NULL)
+ fn_close (csv->file_name, csv->file);
+
free (csv->separator);
+ free (csv->quote_set);
free (csv->file_name);
- if (csv->file != NULL)
- fclose (csv->file);
free (csv);
}
}
static void
-csv_output_field (FILE *file, const char *field)
+csv_output_field (struct csv_driver *csv, const char *field)
{
while (*field == ' ')
field++;
- if (field[strcspn (field, "\"\n\r,\t")])
+ if (field[strcspn (field, csv->quote_set)])
{
const char *p;
- putc ('"', file);
+ putc ('"', csv->file);
for (p = field; *p != '\0'; p++)
{
if (*p == '"')
- putc ('"', file);
- putc (*p, file);
+ putc ('"', csv->file);
+ putc (*p, csv->file);
}
- putc ('"', file);
+ putc ('"', csv->file);
}
else
- fputs (field, file);
+ fputs (field, csv->file);
}
static void
-csv_output_field_format (FILE *file, const char *format, ...)
+csv_output_field_format (struct csv_driver *csv, const char *format, ...)
PRINTF_FORMAT (2, 3);
static void
-csv_output_field_format (FILE *file, const char *format, ...)
+csv_output_field_format (struct csv_driver *csv, const char *format, ...)
{
va_list args;
char *s;
s = xvasprintf (format, args);
va_end (args);
- csv_output_field (file, s);
+ csv_output_field (csv, s);
free (s);
}
-static bool
-csv_open_file (struct csv_driver *csv)
+static void
+csv_put_separator (struct csv_driver *csv)
{
- if (csv->file == NULL)
- {
- csv->file = fn_open (csv->file_name, "w");
- if (csv->file == NULL)
- {
- if (!csv->reported_error)
- error (0, errno, _("csv: opening output file \"%s\""),
- csv->file_name);
- csv->reported_error = true;
- return false;
- }
- }
- else
+ if (csv->n_items++ > 0)
putc ('\n', csv->file);
-
- return true;
}
static void
{
struct csv_driver *csv = csv_driver_cast (driver);
+ output_driver_track_current_command (output_item, &csv->command_name);
+
if (is_table_item (output_item))
{
struct table_item *table_item = to_table_item (output_item);
const struct table *t = table_item_get_table (table_item);
int x, y;
- if (!csv_open_file (csv))
- return;
+ csv_put_separator (csv);
- if (caption != NULL)
+ if (csv->captions && caption != NULL)
{
- csv_output_field_format (csv->file, "Table: %s", caption);
+ csv_output_field_format (csv, "Table: %s", caption);
putc ('\n', csv->file);
}
fputs (csv->separator, csv->file);
if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0])
- csv_output_field (csv->file, "");
+ csv_output_field (csv, "");
else
- csv_output_field (csv->file, cell.contents);
+ csv_output_field (csv, cell.contents);
table_cell_free (&cell);
}
|| type == TEXT_ITEM_SYNTAX)
return;
- csv_open_file (csv);
+ csv_put_separator (csv);
switch (type)
{
case TEXT_ITEM_TITLE:
- csv_output_field_format (csv->file, "Title: %s", text);
+ csv_output_field_format (csv, "Title: %s", text);
break;
case TEXT_ITEM_SUBTITLE:
- csv_output_field_format (csv->file, "Subtitle: %s", text);
+ csv_output_field_format (csv, "Subtitle: %s", text);
break;
default:
- csv_output_field (csv->file, text);
+ csv_output_field (csv, text);
break;
}
putc ('\n', csv->file);
}
+ 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, csv->command_name);
+ csv_put_separator (csv);
+ csv_output_field (csv, s);
+ free (s);
+ putc ('\n', csv->file);
+ }
}
-const struct output_driver_class csv_class =
+struct output_driver_factory csv_driver_factory = { "csv", csv_create };
+
+static const struct output_driver_class csv_driver_class =
{
"csv",
- csv_create,
csv_destroy,
csv_submit,
csv_flush,