#include "data/settings.h"
#include "data/value.h"
#include "data/variable.h"
+#include "data/file-name.h"
#include "libpspp/hash-functions.h"
#include "libpspp/i18n.h"
#include "output/driver.h"
+#include "output/spv/spv-table-look.h"
#include "gl/c-ctype.h"
+#include "gl/configmake.h"
#include "gl/intprops.h"
#include "gl/minmax.h"
+#include "gl/relocatable.h"
#include "gl/xalloc.h"
#include "gl/xmemdup0.h"
#include "gl/xsize.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. */
+static const struct pivot_table_look *
+default_look (const struct pivot_table_look *new)
+{
+ static struct pivot_table_look *look;
+ if (new)
+ {
+ pivot_table_look_unref (look);
+ look = pivot_table_look_ref (new);
+ }
+ else if (!look)
+ {
+ char *error = pivot_table_look_read ("default.stt", &look);
+ if (error)
+ {
+ free (error);
+ look = pivot_table_look_ref (pivot_table_look_builtin_default ());
+ }
+ }
+ return look;
+}
+
+const struct pivot_table_look *
+pivot_table_look_get_default (void)
+{
+ return default_look (NULL);
+}
+
void
-pivot_table_look_init (struct pivot_table_look *look)
+pivot_table_look_set_default (const struct pivot_table_look *look)
{
- memset (look, 0, sizeof *look);
+ default_look (look);
+}
- look->omit_empty = false;
- 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;
+char * WARN_UNUSED_RESULT
+pivot_table_look_read (const char *name, struct pivot_table_look **lookp)
+{
+ *lookp = NULL;
- 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,
+ /* Construct search path. */
+ const char *path[4];
+ size_t n = 0;
+ path[n++] = ".";
+ const char *home = getenv ("HOME");
+ char *allocated = NULL;
+ if (home != NULL)
+ path[n++] = allocated = xasprintf ("%s/.pspp/looks", home);
+ char *allocated2;
+ path[n++] = relocate2 (PKGDATADIR "/looks", &allocated2);
+ path[n++] = NULL;
+
+ /* Search path. */
+ char *file = fn_search_path (name, (char **) path);
+ if (!file)
+ {
+ char *name2 = xasprintf ("%s.stt", name);
+ file = fn_search_path (name2, (char **) path);
+ free (name2);
+ }
+ free (allocated);
+ free (allocated2);
+ if (!file)
+ return xasprintf ("%s: not found", name);
+
+ /* Read file. */
+ char *error = spv_table_look_read (file, lookp);
+ free (file);
+ return error;
+}
+
+const struct pivot_table_look *
+pivot_table_look_builtin_default (void)
+{
+ static struct pivot_table_look look = {
+ .ref_cnt = 1,
+
+ .omit_empty = true,
+ .row_labels_in_corner = true,
+ .width_ranges = {
+ [TABLE_HORZ] = { 36, 72 },
+ [TABLE_VERT] = { 36, 120 },
+ },
+
+ .areas = {
+#define AREA(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", \
+ }, \
+ }
+ [PIVOT_AREA_TITLE] = AREA(true, CENTER, CENTER, 8,11,1,8),
+ [PIVOT_AREA_CAPTION] = AREA(false, LEFT, TOP, 8,11,1,1),
+ [PIVOT_AREA_FOOTER] = AREA(false, LEFT, TOP, 11, 8,2,3),
+ [PIVOT_AREA_CORNER] = AREA(false, LEFT, BOTTOM, 8,11,1,1),
+ [PIVOT_AREA_COLUMN_LABELS] = AREA(false, CENTER, BOTTOM, 8,11,1,3),
+ [PIVOT_AREA_ROW_LABELS] = AREA(false, LEFT, TOP, 8,11,1,3),
+ [PIVOT_AREA_DATA] = AREA(false, MIXED, TOP, 8,11,1,1),
+ [PIVOT_AREA_LAYERS] = AREA(false, LEFT, BOTTOM, 8,11,1,3),
+#undef AREA
+ },
+
+ .borders = {
+#define BORDER(STROKE) { .stroke = STROKE, .color = CELL_COLOR_BLACK }
+ [PIVOT_BORDER_TITLE] = BORDER(TABLE_STROKE_NONE),
+ [PIVOT_BORDER_OUTER_LEFT] = BORDER(TABLE_STROKE_NONE),
+ [PIVOT_BORDER_OUTER_TOP] = BORDER(TABLE_STROKE_NONE),
+ [PIVOT_BORDER_OUTER_RIGHT] = BORDER(TABLE_STROKE_NONE),
+ [PIVOT_BORDER_OUTER_BOTTOM] = BORDER(TABLE_STROKE_NONE),
+ [PIVOT_BORDER_INNER_LEFT] = BORDER(TABLE_STROKE_THICK),
+ [PIVOT_BORDER_INNER_TOP] = BORDER(TABLE_STROKE_THICK),
+ [PIVOT_BORDER_INNER_RIGHT] = BORDER(TABLE_STROKE_THICK),
+ [PIVOT_BORDER_INNER_BOTTOM] = BORDER(TABLE_STROKE_THICK),
+ [PIVOT_BORDER_DATA_LEFT] = BORDER(TABLE_STROKE_THICK),
+ [PIVOT_BORDER_DATA_TOP] = BORDER(TABLE_STROKE_THICK),
+ [PIVOT_BORDER_DIM_ROW_HORZ] = BORDER(TABLE_STROKE_SOLID),
+ [PIVOT_BORDER_DIM_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
+ [PIVOT_BORDER_DIM_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
+ [PIVOT_BORDER_DIM_COL_VERT] = BORDER(TABLE_STROKE_SOLID),
+ [PIVOT_BORDER_CAT_ROW_HORZ] = BORDER(TABLE_STROKE_NONE),
+ [PIVOT_BORDER_CAT_ROW_VERT] = BORDER(TABLE_STROKE_NONE),
+ [PIVOT_BORDER_CAT_COL_HORZ] = BORDER(TABLE_STROKE_SOLID),
+ [PIVOT_BORDER_CAT_COL_VERT] = BORDER(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,
- };
+
+ return &look;
}
-void
-pivot_table_look_uninit (struct pivot_table_look *look)
+struct pivot_table_look *
+pivot_table_look_new_builtin_default (void)
{
- free (look->name);
+ return pivot_table_look_unshare (
+ pivot_table_look_ref (pivot_table_look_builtin_default ()));
+}
- for (size_t i = 0; i < PIVOT_N_AREAS; i++)
- table_area_style_uninit (&look->areas[i]);
+struct pivot_table_look *
+pivot_table_look_ref (const struct pivot_table_look *look_)
+{
+ assert (look_->ref_cnt > 0);
- free (look->continuation);
+ struct pivot_table_look *look = CONST_CAST (struct pivot_table_look *, look_);
+ look->ref_cnt++;
+ return look;
}
static char *
return s && s[0] ? xstrdup (s) : NULL;
}
-void
-pivot_table_look_copy (struct pivot_table_look *dst,
- const struct pivot_table_look *src)
+struct pivot_table_look *
+pivot_table_look_unshare (struct pivot_table_look *old)
{
- *dst = *src;
- dst->name = xstrdup_if_nonempty (src->name);
+ assert (old->ref_cnt > 0);
+ if (old->ref_cnt == 1)
+ return old;
+
+ pivot_table_look_unref (old);
+
+ struct pivot_table_look *new = xmemdup (old, sizeof *old);
+ new->ref_cnt = 1;
+ new->name = xstrdup_if_nonempty (old->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);
+ table_area_style_copy (NULL, &new->areas[i], &old->areas[i]);
+ new->continuation = xstrdup_if_nonempty (old->continuation);
+
+ return new;
+}
+
+void
+pivot_table_look_unref (struct pivot_table_look *look)
+{
+ if (look)
+ {
+ assert (look->ref_cnt > 0);
+ if (!--look->ref_cnt)
+ {
+ free (look->name);
+ for (size_t i = 0; i < PIVOT_N_AREAS; i++)
+ table_area_style_uninit (&look->areas[i]);
+ free (look->continuation);
+ free (look);
+ }
+ }
}
\f
/* Axes. */
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:
-
- - If empty rows or columns should not be displayed, set ->omit_empty to
- true.
-
- - Set the format to use for "count" values with pivot_table_set_weight_var()
- or pivot_table_set_weight_format().
-
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, or if the subtype should be
-different from the title.
+ different from the title.
See the large comment at the top of pivot-table.h for general advice on
creating pivot tables. */
}
/* 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:
+ 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.
- - If empty rows or columns should not be displayed, set ->omit_empty to
- true.
-
- - Set the format to use for "count" values with pivot_table_set_weight_var()
- or pivot_table_set_weight_format().
+ TITLE and SUBTYPE may be NULL, but in that case the client must add them
+ later because they are both mandatory for a pivot table.
See the large comment at the top of pivot-table.h for general advice on
creating pivot tables. */
{
struct pivot_table *table = xzalloc (sizeof *table);
table->ref_cnt = 1;
+ table->show_title = true;
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 ();
-
- pivot_table_look_init (&table->look);
+ table->look = pivot_table_look_ref (pivot_table_look_get_default ());
hmap_init (&table->cells);
return;
free (table->current_layer);
- pivot_table_look_uninit (&table->look);
+ pivot_table_look_unref (table->look);
for (int i = 0; i < TABLE_N_AXES; i++)
pivot_table_sizing_uninit (&table->sizing[i]);
pivot_value_destroy (table->subtype);
pivot_value_destroy (table->corner_text);
pivot_value_destroy (table->caption);
+ free (table->notes);
for (size_t i = 0; i < table->n_dimensions; i++)
pivot_dimension_destroy (table->dimensions[i]);
const struct pivot_table_look *
pivot_table_get_look (const struct pivot_table *table)
{
- return &table->look;
+ 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);
+ pivot_table_look_unref (table->look);
+ table->look = pivot_table_look_ref (look);
}
/* Sets the format used for PIVOT_RC_COUNT cells to the one used for variable
struct pivot_value *value)
{
assert (n == table->n_dimensions);
+ for (size_t i = 0; i < n; i++)
+ assert (dindexes[i] < table->dimensions[i]->n_leaves);
if (value->type == PIVOT_VALUE_NUMERIC && !value->numeric.format.w)
{
struct pivot_footnote *f = xmalloc (sizeof *f);
f->idx = table->n_footnotes;
f->marker = pivot_make_default_footnote_marker (
- f->idx, table->look.show_numeric_markers);
+ f->idx, table->look->show_numeric_markers);
f->content = NULL;
f->show = true;
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->look.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;
pivot_axis_assign_label_depth (table, PIVOT_AXIS_LAYER, false);
}
\f
-/* Footnotes. */
-
-\f
-\f
static void
indent (int indentation)
{
settings_set_decimal_char (table->decimal);
pivot_table_dump_value (table->title, "title", indentation);
+ pivot_table_dump_value (table->subtype, "subtype", indentation);
pivot_table_dump_string (table->command_c, "command", 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->look.name, "table-look", indentation);
+ pivot_table_dump_string (table->look->name, "table-look", indentation);
if (table->date)
{
indent (indentation);
indent (indentation);
printf ("sizing:\n");
- pivot_table_sizing_dump ("column", table->look.width_ranges[TABLE_HORZ],
+ 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],
+ 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++)
- table_area_style_dump (area, &table->look.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->look.borders[border],
+ table_border_style_dump (border, &table->look->borders[border],
indentation + 1);
for (size_t i = 0; i < table->n_dimensions; i++)
pivot_value_dump (d->root->name);
fputs (" =", stdout);
- struct pivot_value **names = xnmalloc (layer_axis->label_depth,
- sizeof *names);
+ struct pivot_value **names = xnmalloc (d->n_leaves, sizeof *names);
size_t n_names = 0;
for (const struct pivot_category *c
= d->presentation_leaves[layer_indexes[i]];
putchar ('\n');
size_t *column_enumeration = pivot_table_enumerate_axis (
- table, PIVOT_AXIS_COLUMN, layer_indexes, table->look.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->look.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,
/* Appends a text representation of VALUE to OUT. SHOW_VALUES and
SHOW_VARIABLES control whether variable and value labels are included.
- Subscripts and superscripts and footnotes are included. */
+ Subscripts and footnotes are included. */
void
pivot_value_format (const struct pivot_value *value,
enum settings_value_show show_values,
ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
}
- if (value->superscript)
- ds_put_format (out, "^%s", value->superscript);
-
for (size_t i = 0; i < value->n_footnotes; i++)
{
ds_put_byte (out, '^');
free (value->subscripts[i]);
free (value->subscripts);
- free (value->superscript);
-
switch (value->type)
{
case PIVOT_VALUE_NUMERIC: