X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fcsv.c;h=455584914e7c4a470e8c506640880d6b94bad1f7;hb=d6cbbc8d634fa91f050661355139a4e4697e99ab;hp=9be53c8b0f0c92716fc0fe397e23289f7c0a0847;hpb=93ec42221da8b677420bf11435e0d24d0503601b;p=pspp diff --git a/src/output/csv.c b/src/output/csv.c index 9be53c8b0f..455584914e 100644 --- a/src/output/csv.c +++ b/src/output/csv.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2009, 2010, 2012, 2013 Free Software Foundation, Inc. + Copyright (C) 2009, 2010, 2012, 2013, 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 @@ -20,6 +20,7 @@ #include #include "data/file-name.h" +#include "data/file-handle-def.h" #include "libpspp/assertion.h" #include "libpspp/compiler.h" #include "libpspp/message.h" @@ -46,9 +47,10 @@ struct csv_driver char *separator; /* Field separator (usually comma or tab). */ int quote; /* Quote character (usually ' or ") or 0. */ char *quote_set; /* Characters that force quoting. */ + bool titles; /* Print table titles? */ bool captions; /* Print table captions? */ - char *file_name; /* Output file name. */ + struct file_handle *handle; char *command_name; /* Current command. */ FILE *file; /* Output file. */ int n_items; /* Number of items output so far. */ @@ -71,7 +73,7 @@ opt (struct output_driver *d, struct string_map *options, const char *key, } static struct output_driver * -csv_create (const char *file_name, enum settings_output_devices device_type, +csv_create (struct file_handle *fh, enum settings_output_devices device_type, struct string_map *o) { struct output_driver *d; @@ -80,21 +82,22 @@ csv_create (const char *file_name, enum settings_output_devices device_type, csv = xzalloc (sizeof *csv); d = &csv->driver; - output_driver_init (&csv->driver, &csv_driver_class, file_name, device_type); + output_driver_init (&csv->driver, &csv_driver_class, fh_get_file_name (fh), device_type); csv->separator = parse_string (opt (d, o, "separator", ",")); quote = parse_string (opt (d, o, "quote", "\"")); csv->quote = quote[0]; free (quote); csv->quote_set = xasprintf ("\n\r\t%s%c", csv->separator, csv->quote); + csv->titles = parse_boolean (opt (d, o, "titles", "true")); csv->captions = parse_boolean (opt (d, o, "captions", "true")); - csv->file_name = xstrdup (file_name); - csv->file = fn_open (csv->file_name, "w"); + csv->handle = fh; + csv->file = fn_open (fh, "w"); csv->n_items = 0; if (csv->file == NULL) { - msg_error (errno, _("error opening output file `%s'"), csv->file_name); + msg_error (errno, _("error opening output file `%s'"), fh_get_file_name (fh)); output_driver_destroy (d); return NULL; } @@ -108,11 +111,11 @@ csv_destroy (struct output_driver *driver) struct csv_driver *csv = csv_driver_cast (driver); if (csv->file != NULL) - fn_close (csv->file_name, csv->file); + fn_close (csv->handle, csv->file); free (csv->separator); free (csv->quote_set); - free (csv->file_name); + fh_unref (csv->handle); free (csv); } @@ -147,6 +150,20 @@ csv_output_field (struct csv_driver *csv, const char *field) fputs (field, csv->file); } +static void PRINTF_FORMAT (2, 3) +csv_output_field_format (struct csv_driver *csv, const char *format, ...) +{ + va_list args; + char *s; + + va_start (args, format); + s = xvasprintf (format, args); + va_end (args); + + csv_output_field (csv, s); + free (s); +} + static void csv_put_field (struct csv_driver *csv, struct string *s, const char *field) { @@ -172,10 +189,19 @@ csv_put_field (struct csv_driver *csv, struct string *s, const char *field) static void csv_output_subtable (struct csv_driver *csv, struct string *s, - const struct table *t) + const struct table_item *item) { + const struct table *t = table_item_get_table (item); + const char *title = table_item_get_title (item); + const char *caption = table_item_get_caption (item); int y, x; + if (csv->titles && title != NULL) + { + csv_output_field_format (csv, "Table: %s", title); + putc ('\n', csv->file); + } + for (y = 0; y < table_nr (t); y++) { if (y > 0) @@ -217,24 +243,12 @@ csv_output_subtable (struct csv_driver *csv, struct string *s, table_cell_free (&cell); } } -} - -static void -csv_output_field_format (struct csv_driver *csv, const char *format, ...) - PRINTF_FORMAT (2, 3); -static void -csv_output_field_format (struct csv_driver *csv, const char *format, ...) -{ - va_list args; - char *s; - - va_start (args, format); - s = xvasprintf (format, args); - va_end (args); - - csv_output_field (csv, s); - free (s); + if (csv->captions && caption != NULL) + { + csv_output_field_format (csv, "Caption: %s", caption); + putc ('\n', csv->file); + } } static void @@ -255,18 +269,21 @@ csv_submit (struct output_driver *driver, if (is_table_item (output_item)) { struct table_item *table_item = to_table_item (output_item); + const char *title = table_item_get_title (table_item); const char *caption = table_item_get_caption (table_item); const struct table *t = table_item_get_table (table_item); + int footnote_idx; int x, y; csv_put_separator (csv); - if (csv->captions && caption != NULL) + if (csv->titles && title != NULL) { - csv_output_field_format (csv, "Table: %s", caption); + csv_output_field_format (csv, "Table: %s", title); putc ('\n', csv->file); } + footnote_idx = 0; for (y = 0; y < table_nr (t); y++) { for (x = 0; x < table_nc (t); x++) @@ -280,7 +297,9 @@ csv_submit (struct output_driver *driver, if (x != cell.d[TABLE_HORZ][0] || y != cell.d[TABLE_VERT][0]) csv_output_field (csv, ""); - else if (cell.n_contents == 1 && cell.contents[0].text != NULL) + else if (cell.n_contents == 1 + && cell.contents[0].text != NULL + && cell.contents[0].n_footnotes == 0) csv_output_field (csv, cell.contents[0].text); else { @@ -290,13 +309,25 @@ csv_submit (struct output_driver *driver, ds_init_empty (&s); for (i = 0; i < cell.n_contents; i++) { + const struct cell_contents *c = &cell.contents[i]; + int j; + if (i > 0) ds_put_cstr (&s, "\n\n"); - if (cell.contents[i].text != NULL) - ds_put_cstr (&s, cell.contents[i].text); + if (c->text != NULL) + ds_put_cstr (&s, c->text); else - csv_output_subtable (csv, &s, cell.contents[i].table); + csv_output_subtable (csv, &s, c->table); + + for (j = 0; j < c->n_footnotes; j++) + { + char marker[16]; + + str_format_26adic (++footnote_idx, false, + marker, sizeof marker); + ds_put_format (&s, "[%s]", marker); + } } csv_output_field (csv, ds_cstr (&s)); ds_destroy (&s); @@ -306,6 +337,49 @@ csv_submit (struct output_driver *driver, } putc ('\n', csv->file); } + + if (csv->captions && caption != NULL) + { + csv_output_field_format (csv, "Caption: %s", caption); + putc ('\n', csv->file); + } + + if (footnote_idx) + { + size_t i; + + fputs ("\nFootnotes:\n", csv->file); + + footnote_idx = 0; + for (y = 0; y < table_nr (t); y++) + { + struct table_cell cell; + for (x = 0; x < table_nc (t); x = cell.d[TABLE_HORZ][1]) + { + table_get_cell (t, x, y, &cell); + + if (x == cell.d[TABLE_HORZ][0] && y == cell.d[TABLE_VERT][0]) + for (i = 0; i < cell.n_contents; i++) + { + const struct cell_contents *c = &cell.contents[i]; + int j; + + for (j = 0; j < c->n_footnotes; j++) + { + char marker[16]; + + str_format_26adic (++footnote_idx, false, + marker, sizeof marker); + csv_output_field (csv, marker); + fputs (csv->separator, csv->file); + csv_output_field (csv, c->footnotes[j]); + putc ('\n', csv->file); + } + } + table_cell_free (&cell); + } + } + } } else if (is_text_item (output_item)) {