#include "data/variable.h"
#include "libpspp/hash-functions.h"
#include "libpspp/i18n.h"
+#include "output/driver.h"
#include "gl/c-ctype.h"
#include "gl/intprops.h"
}
}
+const struct table_area_style *
+pivot_area_get_default_style (enum pivot_area area)
+{
+#define STYLE(BOLD, H, V, L, R, T, B) { \
+ .cell_style = { \
+ .halign = TABLE_HALIGN_##H, \
+ .valign = TABLE_VALIGN_##V, \
+ .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
+ [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
+ }, \
+ .font_style = { \
+ .bold = BOLD, \
+ .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
+ .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
+ .size = 9, \
+ .typeface = (char *) "Sans Serif", \
+ }, \
+ }
+ static const struct table_area_style default_area_styles[PIVOT_N_AREAS] = {
+ [PIVOT_AREA_TITLE] = STYLE(true, CENTER, CENTER, 8,11,1,8),
+ [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
+ [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
+ [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
+ [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
+ [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
+ [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
+ [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
+ };
+#undef STYLE
+
+ return &default_area_styles[area];
+}
+
+void
+pivot_border_get_default_style (enum pivot_border border,
+ struct table_border_style *style)
+{
+ static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
+ [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
+ };
+ *style = (struct table_border_style) {
+ .stroke = default_strokes[border],
+ .color = CELL_COLOR_BLACK,
+ };
+}
+
/* Returns the name of BORDER. */
const char *
pivot_border_to_string (enum pivot_border border)
}
}
\f
+/* Pivot table looks. */
+
+void
+pivot_table_look_init (struct pivot_table_look *look)
+{
+ memset (look, 0, sizeof *look);
+
+ look->omit_empty = true;
+ look->row_labels_in_corner = true;
+ look->width_ranges[TABLE_HORZ][0] = 36;
+ look->width_ranges[TABLE_HORZ][1] = 72;
+ look->width_ranges[TABLE_VERT][0] = 36;
+ look->width_ranges[TABLE_VERT][1] = 120;
+
+ for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+ table_area_style_copy (NULL, &look->areas[i],
+ pivot_area_get_default_style (i));
+
+ static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
+ [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
+ [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
+ [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
+ [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
+ };
+ for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
+ look->borders[i] = (struct table_border_style) {
+ .stroke = default_strokes[i],
+ .color = CELL_COLOR_BLACK,
+ };
+}
+
+void
+pivot_table_look_uninit (struct pivot_table_look *look)
+{
+ free (look->name);
+
+ for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+ table_area_style_uninit (&look->areas[i]);
+
+ free (look->continuation);
+}
+
+static char *
+xstrdup_if_nonempty (const char *s)
+{
+ return s && s[0] ? xstrdup (s) : NULL;
+}
+
+void
+pivot_table_look_copy (struct pivot_table_look *dst,
+ const struct pivot_table_look *src)
+{
+ *dst = *src;
+ dst->name = xstrdup_if_nonempty (src->name);
+ for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+ table_area_style_copy (NULL, &dst->areas[i], &src->areas[i]);
+ dst->continuation = xstrdup_if_nonempty (src->continuation);
+}
+\f
/* Axes. */
/* Returns the name of AXIS_TYPE. */
axis->dimensions, (axis->n_dimensions + 1) * sizeof *axis->dimensions);
axis->dimensions[axis->n_dimensions++] = d;
- /* XXX extent and label_depth need to be calculated later. */
+ if (axis_type == PIVOT_AXIS_LAYER)
+ {
+ free (table->current_layer);
+ table->current_layer = xcalloc (axis[PIVOT_AXIS_LAYER].n_dimensions,
+ sizeof *table->current_layer);
+ }
+
+ /* axis->extent and axis->label_depth will be calculated later. */
return d;
}
return rc != NULL;
}
\f
-/* One piece of data within a pivot table. */
-struct pivot_cell
- {
- struct hmap_node hmap_node; /* In struct pivot_table's 'cells' hmap. */
- struct pivot_value *value;
- unsigned int idx[]; /* One index per table dimension. */
- };
-
/* Pivot tables. */
/* Creates and returns a new pivot table with the given TITLE. TITLE should be
a text string marked for translation but not actually translated yet,
- e.g. N_("Descriptive Statistics").
+ e.g. N_("Descriptive Statistics"). The un-translated text string is used as
+ the pivot table's subtype.
Operations commonly performed on the new pivot_table:
This function is a shortcut for pivot_table_create__() for the most common
case. Use pivot_table_create__() directly if the title should be some kind
- of value other than an ordinary text string.
+ of value other than an ordinary text string, or if the subtype should be
+different from the title.
See the large comment at the top of pivot-table.h for general advice on
creating pivot tables. */
struct pivot_table *
pivot_table_create (const char *title)
{
- return pivot_table_create__ (pivot_value_new_text (title));
+ return pivot_table_create__ (pivot_value_new_text (title), title);
}
-/* Creates and returns a new pivot table with the given TITLE.
+/* Creates and returns a new pivot table with the given TITLE, and takes
+ ownership of TITLE. The new pivot table's subtype is SUBTYPE, which
+ should be an untranslated English string that describes the contents of
+ the table at a high level without being specific about the variables or
+ other context involved.
Operations commonly performed on the new pivot_table:
See the large comment at the top of pivot-table.h for general advice on
creating pivot tables. */
struct pivot_table *
-pivot_table_create__ (struct pivot_value *title)
+pivot_table_create__ (struct pivot_value *title, const char *subtype)
{
struct pivot_table *table = xzalloc (sizeof *table);
+ table->ref_cnt = 1;
+ table->show_caption = true;
table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 };
table->title = title;
+ table->subtype = subtype ? pivot_value_new_text (subtype) : NULL;
+ table->command_c = output_get_command_name ();
- /* Set default area styles. */
-#define STYLE(BOLD, H, V, L, R, T, B) { \
- .cell_style = { \
- .halign = TABLE_HALIGN_##H, \
- .valign = TABLE_VALIGN_##V, \
- .margin = { [TABLE_HORZ][0] = L, [TABLE_HORZ][1] = R, \
- [TABLE_VERT][0] = T, [TABLE_VERT][1] = B }, \
- }, \
- .font_style = { \
- .bold = BOLD, \
- .fg = { [0] = CELL_COLOR_BLACK, [1] = CELL_COLOR_BLACK}, \
- .bg = { [0] = CELL_COLOR_WHITE, [1] = CELL_COLOR_WHITE}, \
- }, \
- }
- static const struct area_style default_area_styles[PIVOT_N_AREAS] = {
- [PIVOT_AREA_TITLE] = STYLE( true, CENTER, CENTER, 8,11,1,8),
- [PIVOT_AREA_CAPTION] = STYLE(false, LEFT, TOP, 8,11,1,1),
- [PIVOT_AREA_FOOTER] = STYLE(false, LEFT, TOP, 11, 8,2,3),
- [PIVOT_AREA_CORNER] = STYLE(false, LEFT, BOTTOM, 8,11,1,1),
- [PIVOT_AREA_COLUMN_LABELS] = STYLE(false, CENTER, BOTTOM, 8,11,1,3),
- [PIVOT_AREA_ROW_LABELS] = STYLE(false, LEFT, TOP, 8,11,1,3),
- [PIVOT_AREA_DATA] = STYLE(false, MIXED, TOP, 8,11,1,1),
- [PIVOT_AREA_LAYERS] = STYLE(false, LEFT, BOTTOM, 8,11,1,3),
- };
-#undef STYLE
- for (size_t i = 0; i < PIVOT_N_AREAS; i++)
- table->areas[i] = default_area_styles[i];
-
- /* Set default border styles. */
- static const enum table_stroke default_strokes[PIVOT_N_BORDERS] = {
- [PIVOT_BORDER_TITLE] = TABLE_STROKE_NONE,
- [PIVOT_BORDER_OUTER_LEFT] = TABLE_STROKE_NONE,
- [PIVOT_BORDER_OUTER_TOP] = TABLE_STROKE_NONE,
- [PIVOT_BORDER_OUTER_RIGHT] = TABLE_STROKE_NONE,
- [PIVOT_BORDER_OUTER_BOTTOM] = TABLE_STROKE_NONE,
- [PIVOT_BORDER_INNER_LEFT] = TABLE_STROKE_THICK,
- [PIVOT_BORDER_INNER_TOP] = TABLE_STROKE_THICK,
- [PIVOT_BORDER_INNER_RIGHT] = TABLE_STROKE_THICK,
- [PIVOT_BORDER_INNER_BOTTOM] = TABLE_STROKE_THICK,
- [PIVOT_BORDER_DATA_LEFT] = TABLE_STROKE_THICK,
- [PIVOT_BORDER_DATA_TOP] = TABLE_STROKE_THICK,
- [PIVOT_BORDER_DIM_ROW_HORZ] = TABLE_STROKE_SOLID,
- [PIVOT_BORDER_DIM_ROW_VERT] = TABLE_STROKE_NONE,
- [PIVOT_BORDER_DIM_COL_HORZ] = TABLE_STROKE_SOLID,
- [PIVOT_BORDER_DIM_COL_VERT] = TABLE_STROKE_SOLID,
- [PIVOT_BORDER_CAT_ROW_HORZ] = TABLE_STROKE_NONE,
- [PIVOT_BORDER_CAT_ROW_VERT] = TABLE_STROKE_NONE,
- [PIVOT_BORDER_CAT_COL_HORZ] = TABLE_STROKE_SOLID,
- [PIVOT_BORDER_CAT_COL_VERT] = TABLE_STROKE_SOLID,
- };
- for (size_t i = 0; i < PIVOT_N_BORDERS; i++)
- table->borders[i] = (struct table_border_style) {
- .stroke = default_strokes[i],
- .color = CELL_COLOR_BLACK,
- };
+ pivot_table_look_init (&table->look);
- table->row_labels_in_corner = true;
hmap_init (&table->cells);
return table;
pivot_table_create_for_text (struct pivot_value *title,
struct pivot_value *content)
{
- struct pivot_table *table = pivot_table_create__ (title);
+ struct pivot_table *table = pivot_table_create__ (title, "Error");
struct pivot_dimension *d = pivot_dimension_create (
table, PIVOT_AXIS_ROW, N_("Error"));
return table;
}
-/* Destroys TABLE and frees everything it points to. */
+/* Increases TABLE's reference count, indicating that it has an additional
+ owner. A pivot table that is shared among multiple owners must not be
+ modified. */
+struct pivot_table *
+pivot_table_ref (const struct pivot_table *table_)
+{
+ struct pivot_table *table = CONST_CAST (struct pivot_table *, table_);
+ table->ref_cnt++;
+ return table;
+}
+
+/* Decreases TABLE's reference count, indicating that it has one fewer owner.
+ If TABLE no longer has any owners, it is freed. */
void
-pivot_table_destroy (struct pivot_table *table)
+pivot_table_unref (struct pivot_table *table)
{
if (!table)
return;
+ assert (table->ref_cnt > 0);
+ if (--table->ref_cnt)
+ return;
free (table->current_layer);
- free (table->table_look);
+ pivot_table_look_uninit (&table->look);
for (int i = 0; i < TABLE_N_AXES; i++)
pivot_table_sizing_uninit (&table->sizing[i]);
- free (table->continuation);
-
for (int i = 0; i < sizeof table->ccs / sizeof *table->ccs; i++)
free (table->ccs[i]);
pivot_value_destroy (table->corner_text);
pivot_value_destroy (table->caption);
- for (size_t i = 0; i < PIVOT_N_AREAS; i++)
- area_style_uninit (&table->areas[i]);
-
for (size_t i = 0; i < table->n_dimensions; i++)
pivot_dimension_destroy (table->dimensions[i]);
free (table->dimensions);
free (table);
}
+/* Returns true if TABLE has more than one owner. A pivot table that is shared
+ among multiple owners must not be modified. */
+bool
+pivot_table_is_shared (const struct pivot_table *table)
+{
+ return table->ref_cnt > 1;
+}
+
+const struct pivot_table_look *
+pivot_table_get_look (const struct pivot_table *table)
+{
+ return &table->look;
+}
+
+void
+pivot_table_set_look (struct pivot_table *table,
+ const struct pivot_table_look *look)
+{
+ pivot_table_look_uninit (&table->look);
+ pivot_table_look_copy (&table->look, look);
+}
+
/* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
WV, which should be the weight variable for the dictionary whose data or
statistics are being put into TABLE.
return pivot_value_new_user_text (text, -1);
}
-/* Creates or modifies a footnote in TABLE with 0-based number IDX. If MARKER
- is nonnull, sets the footnote's marker; if CONTENT is nonnull, sets the
- footnote's content. */
+/* Creates or modifies a footnote in TABLE with 0-based number IDX (and creates
+ all lower indexes as a side effect). If MARKER is nonnull, sets the
+ footnote's marker; if CONTENT is nonnull, sets the footnote's content. */
struct pivot_footnote *
pivot_table_create_footnote__ (struct pivot_table *table, size_t idx,
struct pivot_value *marker,
struct pivot_footnote *f = xmalloc (sizeof *f);
f->idx = table->n_footnotes;
f->marker = pivot_make_default_footnote_marker (
- f->idx, table->show_numeric_markers);
+ f->idx, table->look.show_numeric_markers);
f->content = NULL;
+ f->show = true;
table->footnotes[table->n_footnotes++] = f;
}
axis->n_dimensions), 1),
sizeof *enumeration);
size_t *p = enumeration;
- size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
+ size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
size_t *axis_indexes;
PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
p += axis->n_dimensions;
}
+ if (omit_empty && p == enumeration)
+ {
+ PIVOT_AXIS_FOR_EACH (axis_indexes, axis)
+ {
+ memcpy (p, axis_indexes, axis->n_dimensions * sizeof *p);
+ p += axis->n_dimensions;
+ }
+ }
*p = SIZE_MAX;
if (n)
*n = (p - enumeration) / axis->n_dimensions;
{
pivot_axis_assign_label_depth (table, PIVOT_AXIS_COLUMN, false);
if (pivot_axis_assign_label_depth (
- table, PIVOT_AXIS_ROW, (table->row_labels_in_corner
+ table, PIVOT_AXIS_ROW, (table->look.row_labels_in_corner
&& !table->corner_text))
&& table->axes[PIVOT_AXIS_COLUMN].label_depth == 0)
table->axes[PIVOT_AXIS_COLUMN].label_depth = 1;
}
static void
-area_style_dump (enum pivot_area area, const struct area_style *a,
- int indentation)
+table_area_style_dump (enum pivot_area area, const struct table_area_style *a,
+ int indentation)
{
indent (indentation);
printf ("%s: ", pivot_area_to_string (area));
return headings;
}
+static void
+free_headings (const struct pivot_axis *axis, char ***headings)
+{
+ for (size_t i = 0; i < axis->label_depth; i++)
+ {
+ for (size_t j = 0; j < axis->extent; j++)
+ free (headings[i][j]);
+ free (headings[i]);
+ }
+ free (headings);
+}
+
+static void
+pivot_table_sizing_dump (const char *name,
+ const int width_ranges[2],
+ const struct pivot_table_sizing *s,
+ int indentation)
+{
+ indent (indentation);
+ printf ("%ss: min=%d, max=%d\n", name, width_ranges[0], width_ranges[1]);
+ if (s->n_widths)
+ {
+ indent (indentation + 1);
+ printf ("%s widths:", name);
+ for (size_t i = 0; i < s->n_widths; i++)
+ printf (" %d", s->widths[i]);
+ printf ("\n");
+ }
+ if (s->n_breaks)
+ {
+ indent (indentation + 1);
+ printf ("break after %ss:", name);
+ for (size_t i = 0; i < s->n_breaks; i++)
+ printf (" %zu", s->breaks[i]);
+ printf ("\n");
+ }
+ if (s->n_keeps)
+ {
+ indent (indentation + 1);
+ printf ("keep %ss together:", name);
+ for (size_t i = 0; i < s->n_keeps; i++)
+ printf (" [%zu,%zu]",
+ s->keeps[i].ofs,
+ s->keeps[i].ofs + s->keeps[i].n - 1);
+ printf ("\n");
+ }
+}
+
void
pivot_table_dump (const struct pivot_table *table, int indentation)
{
pivot_table_dump_string (table->dataset, "dataset", indentation);
pivot_table_dump_string (table->datafile, "datafile", indentation);
pivot_table_dump_string (table->notes, "notes", indentation);
- pivot_table_dump_string (table->table_look, "table-look", indentation);
+ pivot_table_dump_string (table->look.name, "table-look", indentation);
if (table->date)
{
indent (indentation);
- printf ("date: %s", ctime (&table->date)); /* XXX thread unsafe */
+
+ struct tm *tm = localtime (&table->date);
+ printf ("date: %d-%02d-%02d %d:%02d:%02d\n", tm->tm_year + 1900,
+ tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
}
+ indent (indentation);
+ printf ("sizing:\n");
+ pivot_table_sizing_dump ("column", table->look.width_ranges[TABLE_HORZ],
+ &table->sizing[TABLE_HORZ], indentation + 1);
+ pivot_table_sizing_dump ("row", table->look.width_ranges[TABLE_VERT],
+ &table->sizing[TABLE_VERT], indentation + 1);
+
indent (indentation);
printf ("areas:\n");
for (enum pivot_area area = 0; area < PIVOT_N_AREAS; area++)
- area_style_dump (area, &table->areas[area], indentation + 1);
+ table_area_style_dump (area, &table->look.areas[area], indentation + 1);
indent (indentation);
printf ("borders:\n");
for (enum pivot_border border = 0; border < PIVOT_N_BORDERS; border++)
- table_border_style_dump (border, &table->borders[border], indentation + 1);
+ table_border_style_dump (border, &table->look.borders[border],
+ indentation + 1);
for (size_t i = 0; i < table->n_dimensions; i++)
pivot_dimension_dump (table->dimensions[i], indentation);
/* Presentation and data indexes. */
- size_t *dindexes = xcalloc (table->n_dimensions, sizeof *dindexes);
+ size_t *dindexes = XCALLOC (table->n_dimensions, size_t);
const struct pivot_axis *layer_axis = &table->axes[PIVOT_AXIS_LAYER];
if (layer_axis->n_dimensions)
fputs (" =", stdout);
struct pivot_value **names = xnmalloc (layer_axis->label_depth,
- sizeof *names);
+ sizeof *names);
size_t n_names = 0;
for (const struct pivot_category *c
= d->presentation_leaves[layer_indexes[i]];
names[n_names++] = c->name;
}
- for (size_t i = n_names; i-- > 0; )
+ for (size_t i = n_names; i-- > 0;)
{
putchar (' ');
pivot_value_dump (names[i]);
putchar ('\n');
size_t *column_enumeration = pivot_table_enumerate_axis (
- table, PIVOT_AXIS_COLUMN, layer_indexes, table->omit_empty, NULL);
+ table, PIVOT_AXIS_COLUMN, layer_indexes, table->look.omit_empty, NULL);
size_t *row_enumeration = pivot_table_enumerate_axis (
- table, PIVOT_AXIS_ROW, layer_indexes, table->omit_empty, NULL);
+ table, PIVOT_AXIS_ROW, layer_indexes, table->look.omit_empty, NULL);
char ***column_headings = compose_headings (
&table->axes[PIVOT_AXIS_COLUMN], column_enumeration,
}
putchar ('\n');
}
+ free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings);
indent (indentation + 1);
printf ("-----------------------------------------------\n");
free (column_enumeration);
free (row_enumeration);
+ free_headings (&table->axes[PIVOT_AXIS_ROW], row_headings);
}
pivot_table_dump_value (table->caption, "caption", indentation);
putchar ('\n');
}
+ free (dindexes);
settings_set_decimal_char (old_decimal);
}
\f
break;
case PIVOT_VALUE_TEMPLATE:
- pivot_format_template (out, value->template.s, value->template.args,
+ pivot_format_template (out, value->template.local, value->template.args,
value->template.n_args, show_values,
show_variables);
break;
enum settings_value_show show_variables,
struct string *out)
{
- pivot_value_format_body ( value, show_values, show_variables, out);
+ pivot_value_format_body (value, show_values, show_variables, out);
- if (value->subscript)
- ds_put_format (out, "_%s", value->subscript);
+ if (value->n_subscripts)
+ {
+ for (size_t i = 0; i < value->n_subscripts; i++)
+ ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
+ }
if (value->superscript)
ds_put_format (out, "^%s", value->superscript);
them. */
free (value->footnotes);
+ for (size_t i = 0; i < value->n_subscripts; i++)
+ free (value->subscripts[i]);
+ free (value->subscripts);
+
+ free (value->superscript);
+
switch (value->type)
{
case PIVOT_VALUE_NUMERIC:
break;
case PIVOT_VALUE_TEMPLATE:
- free (value->template.s);
+ free (value->template.local);
+ if (value->template.id != value->template.local)
+ free (value->template.id);
for (size_t i = 0; i < value->template.n_args; i++)
pivot_argument_uninit (&value->template.args[i]);
free (value->template.args);
DEFAULT_STYLE for the parts of the style that VALUE doesn't override. */
void
pivot_value_get_style (struct pivot_value *value,
- const struct area_style *default_style,
- struct area_style *area)
+ const struct font_style *base_font_style,
+ const struct cell_style *base_cell_style,
+ struct table_area_style *area)
{
- font_style_copy (&area->font_style, (value->font_style
- ? value->font_style
- : &default_style->font_style));
- area->cell_style = (value->cell_style
- ? *value->cell_style
- : default_style->cell_style);
+ font_style_copy (NULL, &area->font_style, (value->font_style
+ ? value->font_style
+ : base_font_style));
+ area->cell_style = *(value->cell_style
+ ? value->cell_style
+ : base_cell_style);
}
/* Copies AREA into VALUE's style. */
void
pivot_value_set_style (struct pivot_value *value,
- const struct area_style *area)
+ const struct table_area_style *area)
{
if (value->font_style)
font_style_uninit (value->font_style);
else
value->font_style = xmalloc (sizeof *value->font_style);
- font_style_copy (value->font_style, &area->font_style);
+ font_style_copy (NULL, value->font_style, &area->font_style);
if (!value->cell_style)
value->cell_style = xmalloc (sizeof *value->cell_style);
}
}
+/* Creates and returns a new pivot_value whose contents is the null-terminated
+ string TEXT. Takes ownership of TEXT.
+
+ This function is for text strings provided by the user (with the exception
+ that pivot_value_new_variable() should be used for variable names). For
+ strings that are part of the PSPP user interface, such as names of
+ procedures, statistics, annotations, error messages, etc., use
+ pivot_value_new_text(). */
struct pivot_value *
pivot_value_new_user_text_nocopy (char *text)
{
return value;
}
+/* Creates and returns a new pivot_value whose contents is the LENGTH bytes of
+ TEXT. Use SIZE_MAX if TEXT is null-teriminated and its length is not known
+ in advance.
+
+ This function is for text strings provided by the user (with the exception
+ that pivot_value_new_variable() should be used for variable names). For
+ strings that are part of the PSPP user interface, such as names of
+ procedures, statistics, annotations, error messages, etc., use
+ pivot_value_new_text().j
+
+ The caller retains ownership of TEXT.*/
struct pivot_value *
pivot_value_new_user_text (const char *text, size_t length)
{
xmemdup0 (text, length != SIZE_MAX ? length : strlen (text)));
}
-/* TEXT should be a translatable string, but not actually translated yet,
- e.g. enclosed in N_(). */
+/* Creates and returns new pivot_value whose contents is TEXT, which should be
+ a translatable string, but not actually translated yet, e.g. enclosed in
+ N_(). This function is for text strings that are part of the PSPP user
+ interface, such as names of procedures, statistics, annotations, error
+ messages, etc. For strings that come from the user, use
+ pivot_value_new_user_text(). */
struct pivot_value *
pivot_value_new_text (const char *text)
{
return value;
}
-/* FORMAT should be a translatable string, but not actually translated yet,
- e.g. enclosed in N_(). */
+/* Same as pivot_value_new_text() but its argument is a printf()-like format
+ string. */
struct pivot_value * PRINTF_FORMAT (1, 2)
pivot_value_new_text_format (const char *format, ...)
{
return value;
}
-static char *
-xstrdup_if_nonempty (const char *s)
-{
- return s && s[0] ? xstrdup (s) : NULL;
-}
-
/* Returns a new pivot_value that represents X.
The format to use for X is unspecified. Usually the easiest way to specify
struct pivot_value *pv = xzalloc (sizeof *pv);
if (width > 0)
{
- char *s = recode_string (UTF8, encoding,
- CHAR_CAST (char *, value_str (value, width)),
+ char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s),
width);
size_t n = strlen (s);
while (n > 0 && s[n - 1] == ' ')
/* Attaches a reference to FOOTNOTE to V. */
void
pivot_value_add_footnote (struct pivot_value *v,
- struct pivot_footnote *footnote)
+ const struct pivot_footnote *footnote)
{
+ /* Some legacy tables include numerous duplicate footnotes. Suppress
+ them. */
+ for (size_t i = 0; i < v->n_footnotes; i++)
+ if (v->footnotes[i] == footnote)
+ return;
+
v->footnotes = xrealloc (v->footnotes,
(v->n_footnotes + 1) * sizeof *v->footnotes);
v->footnotes[v->n_footnotes++] = footnote;
/* If VALUE is a numeric value, and RC is a result class such as
PIVOT_RC_COUNT, changes VALUE's format to the result class's. */
void
-pivot_value_set_rc (struct pivot_table *table, struct pivot_value *value,
+pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value,
const char *rc)
{
if (value->type == PIVOT_VALUE_NUMERIC)