string, then fields are never quoted.
@item @option{-O titles=@var{boolean}}
-Whether table titles should be printed. Default: @code{on}.
+Whether table titles (brief descriptions) should be printed. Default:
+@code{on}.
+
+@item @option{-O captions=@var{boolean}}
+Whether table captions (more extensive descriptions) should be
+printed. Default: on.
@end table
The CSV format used is an extension to that specified in RFC 4180:
Each table row is output on a separate line, and each column is output
as a field. The contents of a cell that spans multiple rows or
columns is output only for the top-left row and column; the rest are
-output as empty fields. When a table has a caption and captions are
-enabled, the caption is output just above the table as a single field
-prefixed by @samp{Table:}.
+output as empty fields.
+
+@item Titles
+When a table has a title and titles are enabled, the title is output
+just above the table as a single field prefixed by @samp{Table:}.
+
+@item Captions
+When a table has a caption and captions are enabled, the caption is
+output just below the table as a single field prefixed by
+@samp{Caption:}.
+
+@item Footnotes
+Within a table, footnote markers are output as bracketed letters
+following the cell's contents, e.g.@tie{}@samp{[a]}, @samp{[b]},
+@enddots{} The footnotes themselves are output following the body of
+the table, as a separate two-column table introduced with a line that
+says @samp{Footnotes:}. Each row in the table represent one footnote:
+the first column is the marker, the second column is the text.
@item Text
Text in output is printed as a field on a line by itself. The TITLE
/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2009-2011, 2013 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2009-2011, 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
casereader_destroy (group);
- table_item_submit (table_item_create (t, "Data List"));
+ table_item_submit (table_item_create (t, "Data List", NULL));
}
ok = casegrouper_destroy (grouper);
ok = proc_commit (ds) && ok;
describe_variable (dict_get_var (d, i),
DF_ALL & ~DF_AT_ATTRIBUTES));
- table_item_submit (table_item_create (table, NULL /* XXX */));
+ table_item_submit (table_item_create (table, NULL /* XXX */, NULL));
dict_destroy (d);
if (flags & ~DF_DICT_INDEX)
tab_vline (t, TAL_1, nc - 1, 0, r - 1);
#endif
- table_item_submit (table_item_create (table, NULL /* XXX */));
+ table_item_submit (table_item_create (table, NULL /* XXX */, NULL));
}
\f
static bool
{
if (count_attributes (set, flags))
table_item_submit (table_item_create (describe_attributes (set, flags),
- _("Custom data file attributes.")));
+ _("Custom data file attributes."),
+ NULL));
}
static struct table *
size_t n_encodings, n_strings, n_unique_strings;
size_t i, j;
struct tab_table *t;
- struct text_item *text;
struct pool *pool;
size_t row;
return;
}
- text = text_item_create_format (
- TEXT_ITEM_PARAGRAPH,
- _("The following table lists the encodings that can successfully read %s, "
- "by specifying the encoding name on the GET command's ENCODING "
- "subcommand. Encodings that yield identical text are listed "
- "together."), fh_get_name (h));
- text_item_submit (text);
-
t = tab_create (2, n_encodings + 1);
tab_title (t, _("Usable encodings for %s."), fh_get_name (h));
+ tab_caption (t, _("Encodings that can successfully read %s (by specifying "
+ "the encoding name on the GET command's ENCODING "
+ "subcommand). Encodings that yield identical text are "
+ "listed together."), fh_get_name (h));
tab_headers (t, 1, 0, 1, 0);
tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 1, n_encodings);
tab_hline (t, TAL_1, 0, 1, 1);
return;
}
- text = text_item_create_format (
- TEXT_ITEM_PARAGRAPH,
- _("The following table lists text strings in the file dictionary that "
- "the encodings above interpret differently, along with those "
- "interpretations."));
- text_item_submit (text);
-
t = tab_create (3, (n_encodings * n_unique_strings) + 1);
tab_title (t, _("%s encoded text strings."), fh_get_name (h));
+ tab_caption (t, _("Text strings in the file dictionary that the previously "
+ "listed encodings interpret differently, along with the "
+ "interpretations."));
tab_headers (t, 1, 0, 1, 0);
tab_box (t, TAL_1, TAL_1, -1, -1, 0, 0, 2, n_encodings * n_unique_strings);
tab_hline (t, TAL_1, 0, 2, 1);
{
struct table_item *table_item;
- table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+ table_item = table_item_create (table_from_string (TAB_LEFT, text),
+ NULL, NULL);
ascii_output_table_item (a, table_item);
table_item_unref (table_item);
}
struct table_item *table_item;
struct xr_rendering *r;
- table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+ table_item = table_item_create (table_from_string (TAB_LEFT, text),
+ NULL, NULL);
r = xr_rendering_create (xr, &table_item->output_item, cr);
table_item_unref (table_item);
struct table_item *table_item;
struct xr_render_fsm *fsm;
- table_item = table_item_create (table_from_string (TAB_LEFT, text), NULL);
+ table_item = table_item_create (table_from_string (TAB_LEFT, text),
+ NULL, NULL);
fsm = xr_render_table (xr, table_item);
table_item_unref (table_item);
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. */
char *command_name; /* Current command. */
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->n_items = 0;
{
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)
table_cell_free (&cell);
}
}
+
+ if (csv->captions && caption != NULL)
+ {
+ csv_output_field_format (csv, "Caption: %s", caption);
+ putc ('\n', csv->file);
+ }
}
static void
{
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;
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;
style == TAL_1 ? "thin solid" : "double");
}
+static void
+put_tfoot (struct html_driver *html, const struct table *t, bool *tfoot)
+{
+ if (!*tfoot)
+ {
+ fprintf (html->file, "<TFOOT><TR><TD COLSPAN=%d>", table_nc (t));
+ *tfoot = true;
+ }
+ else
+ fputs ("\n<BR>", html->file);
+}
+
static void
html_output_table (struct html_driver *html, 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 footnote_idx = 0;
+ bool tfoot = false;
int y;
fputs ("<TABLE>", html->file);
+ if (caption)
+ {
+ put_tfoot (html, t, &tfoot);
+ escape_string (html->file, caption, strlen (caption), " ", "<BR>");
+ }
footnote_idx = 0;
for (y = 0; y < table_nr (t); y++)
{
{
char marker[16];
- if (!footnote_idx)
- fprintf (html->file, "<TFOOT><TR><TD COLSPAN=%d>",
- table_nc (t));
- else
- fputs ("\n<BR>", html->file);
+ put_tfoot (html, t, &tfoot);
str_format_26adic (++footnote_idx, false, marker, sizeof marker);
fprintf (html->file, "<SUP>%s</SUP> ", marker);
escape_string (html->file, c->footnotes[i],
table_cell_free (&cell);
}
}
- if (footnote_idx)
- {
- fputs ("</TD></TR></TFOOT>\n", html->file);
- footnote_idx = 0;
- }
+ if (tfoot)
+ fputs ("</TD></TR></TFOOT>\n", html->file);
+ footnote_idx = 0;
fputs ("<TBODY VALIGN=\"TOP\">\n", html->file);
write_table (struct odt_driver *odt, const struct table_item *item)
{
const struct table *tab = table_item_get_table (item);
+ const char *caption = table_item_get_caption (item);
const char *title = table_item_get_title (item);
int r, c;
}
xmlTextWriterEndElement (odt->content_wtr); /* table */
+
+ /* Write a caption for the table */
+ if (caption != NULL)
+ {
+ xmlTextWriterStartElement (odt->content_wtr, _xml("text:h"));
+ xmlTextWriterWriteFormatAttribute (odt->content_wtr,
+ _xml("text:outline-level"), "%d", 2);
+ xmlTextWriterWriteString (odt->content_wtr,
+ _xml (table_item_get_caption (item)) );
+ xmlTextWriterEndElement (odt->content_wtr);
+ }
+
}
static void
struct render_break y_break;
};
-static void
+static const struct render_page *
render_pager_add_table (struct render_pager *p, struct table *table)
{
+ struct render_page *page;
+
if (p->n_pages >= p->allocated_pages)
p->pages = x2nrealloc (p->pages, &p->allocated_pages, sizeof *p->pages);
- p->pages[p->n_pages++] = render_page_create (p->params, table);
+ page = p->pages[p->n_pages++] = render_page_create (p->params, table);
+ return page;
}
static void
render_pager_create (const struct render_params *params,
const struct table_item *table_item)
{
+ const char *caption = table_item_get_caption (table_item);
+ const char *title = table_item_get_title (table_item);
+ const struct render_page *body_page;
struct render_pager *p;
- const char *title;
p = xzalloc (sizeof *p);
p->params = params;
- title = table_item_get_title (table_item);
+ /* Title. */
if (title)
render_pager_add_table (p, table_from_string (TAB_LEFT, title));
- render_pager_add_table (p, table_ref (table_item_get_table (table_item)));
- add_footnote_page (p, p->pages[p->n_pages - 1]);
+
+ /* Body. */
+ body_page = render_pager_add_table (p, table_ref (table_item_get_table (
+ table_item)));
+
+ /* Caption. */
+ if (caption)
+ render_pager_add_table (p, table_from_string (TAB_LEFT, caption));
+
+ /* Footnotes. */
+ add_footnote_page (p, body_page);
render_pager_start_page (p);
table_set_nr (&t->table, nr);
t->title = NULL;
+ t->caption = NULL;
t->cf = nc;
t->cc = pool_calloc (t->container, nr * nc, sizeof *t->cc);
t->ct = pool_malloc (t->container, nr * nc);
va_end (args);
}
+/* Set the caption of table T to CAPTION, which is formatted as if
+ passed to printf(). */
+void
+tab_caption (struct tab_table *t, const char *caption, ...)
+{
+ va_list args;
+
+ free (t->caption);
+ va_start (args, caption);
+ t->caption = xvasprintf (caption, args);
+ va_end (args);
+}
+
/* Easy, type-safe way to submit a tab table to som. */
void
tab_submit (struct tab_table *t)
{
- table_item_submit (table_item_create (&t->table, t->title));
+ table_item_submit (table_item_create (&t->table, t->title, t->caption));
}
\f
/* Editing. */
struct tab_table *t = tab_cast (table);
free (t->title);
t->title = NULL;
+ free (t->caption);
+ t->caption = NULL;
pool_destroy (t->container);
}
Some of the features of this type of table are obsolete but have not yet
been removed, because some code still uses them. These features are:
- - The title. The title is a property of the table_item (see
- output/table-item.h) in which a table is embedded, not a property of
+ - The title and caption. These are properties of the table_item (see
+ output/table-item.h) in which a table is embedded, not properties of
the table itself.
- Row and columns offsets (via tab_offset(), tab_next_row()). This
struct table table;
struct pool *container;
- /* Table title, or a null pointer if no title has been set.
-
- The table title is properly part of struct table_item, not struc*/
- char *title;
+ /* Table title and caption, or null. */
+ char *title, *caption;
int cf; /* Column factor for indexing purposes. */
/* Table contents.
void tab_headers (struct tab_table *, int l, int r, int t, int b);
void tab_title (struct tab_table *, const char *, ...)
PRINTF_FORMAT (2, 3);
+void tab_caption (struct tab_table *, const char *, ...)
+ PRINTF_FORMAT (2, 3);
void tab_submit (struct tab_table *);
/* Rules. */
#include "gl/xalloc.h"
/* Initializes ITEM as a table item for rendering TABLE. The new table item
- initially has the specified TITLE, which may be NULL if no title is yet
- available. The caller retains ownership of TITLE. */
+ initially has the specified TITLE and CAPTION, which may each be NULL. The
+ caller retains ownership of TITLE and CAPTION. */
struct table_item *
-table_item_create (struct table *table, const char *title)
+table_item_create (struct table *table, const char *title, const char *caption)
{
struct table_item *item = xmalloc (sizeof *item);
output_item_init (&item->output_item, &table_item_class);
item->table = table;
item->title = title != NULL ? xstrdup (title) : NULL;
+ item->caption = caption != NULL ? xstrdup (caption) : NULL;
return item;
}
item->title = title != NULL ? xstrdup (title) : NULL;
}
+/* Returns ITEM's caption, which is a null pointer if no caption has been
+ set. */
+const char *
+table_item_get_caption (const struct table_item *item)
+{
+ return item->caption;
+}
+
+/* Sets ITEM's caption to CAPTION, replacing any previous caption. Specify
+ NULL for CAPTION to clear any caption from ITEM. The caller retains
+ ownership of CAPTION.
+
+ This function may only be used on a table_item that is unshared. */
+void
+table_item_set_caption (struct table_item *item, const char *caption)
+{
+ assert (!table_item_is_shared (item));
+ free (item->caption);
+ item->caption = caption != NULL ? xstrdup (caption) : NULL;
+}
+
/* Submits TABLE_ITEM to the configured output drivers, and transfers ownership
to the output subsystem. */
void
{
struct table_item *item = to_table_item (output_item);
free (item->title);
+ free (item->caption);
table_unref (item->table);
free (item);
}
/* Table items.
A table item is a subclass of an output item (see output-item.h) that
- contains a table (see table.h) and some formatting properties (currently
- just a title). */
+ contains a table (see table.h) and some formatting properties. Currently
+ the formatting properties are an optional title (a brief description
+ typically displayed above the table) and an optional caption (a more verbose
+ description typically displayed below the table). */
#include "libpspp/compiler.h"
#include "output/output-item.h"
struct output_item output_item; /* Superclass. */
struct table *table; /* The table to be rendered. */
char *title; /* May be null if there is no title. */
+ char *caption; /* May be null if there is no caption. */
};
-struct table_item *table_item_create (struct table *, const char *title);
+struct table_item *table_item_create (struct table *, const char *title,
+ const char *caption);
const struct table *table_item_get_table (const struct table_item *);
const char *table_item_get_title (const struct table_item *);
void table_item_set_title (struct table_item *, const char *);
+
+const char *table_item_get_caption (const struct table_item *);
+void table_item_set_caption (struct table_item *, const char *);
\f
/* This boilerplate for table_item, a subclass of output_item, was
autogenerated by mk-class-boilerplate. */
struct table *
table_create_nested (struct table *inner)
{
- return table_create_nested_item (table_item_create (inner, NULL));
+ return table_create_nested_item (table_item_create (inner, NULL, NULL));
}
/* Creates and returns a table with a single cell that contains INNER.
table = tables[n_tables - 1];
if (transpose)
table = table_transpose (table);
- table_item_submit (table_item_create (table, NULL));
+ table_item_submit (table_item_create (table, NULL, NULL));
}
else
draw (input);
error (1, 0, "unexpected subtable modifier \"%c\"", *text);
}
tab_subtable (tab, c, r, c + cs - 1, r + rs - 1, opt,
- table_item_create (table, NULL));
+ table_item_create (table, NULL, NULL));
}
else
{