PANGO_UNDERLINE_SINGLE));
}
- const struct pivot_value *value = cell->value;
- if (value->n_footnotes || value->n_subscripts)
+ const struct pivot_value_ex *ex = pivot_value_ex (cell->value);
+ if (ex->n_footnotes || ex->n_subscripts)
{
size_t subscript_ofs = ds_length (&body);
- for (size_t i = 0; i < value->n_subscripts; i++)
+ for (size_t i = 0; i < ex->n_subscripts; i++)
{
if (i)
ds_put_byte (&body, ',');
- ds_put_cstr (&body, value->subscripts[i]);
+ ds_put_cstr (&body, ex->subscripts[i]);
}
size_t footnote_ofs = ds_length (&body);
size_t n_footnotes = 0;
- for (size_t i = 0; i < value->n_footnotes; i++)
+ for (size_t i = 0; i < ex->n_footnotes; i++)
{
const struct pivot_footnote *f
- = pt->footnotes[value->footnote_indexes[i]];
+ = pt->footnotes[ex->footnote_indexes[i]];
if (f->show)
{
if (n_footnotes++)
/* Allow footnote markers to occupy the right margin. That way, numbers
in the column are still aligned. */
- if (value->n_footnotes && halign == TABLE_HALIGN_RIGHT)
+ if (ex->n_footnotes && halign == TABLE_HALIGN_RIGHT)
{
/* Measure the width of the footnote marker, so we know how much we
need to make room for. */
PANGO_ATTR_INDEX_TO_TEXT_END);
add_attr (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL),
subscript_ofs, PANGO_ATTR_INDEX_TO_TEXT_END);
- if (value->n_subscripts)
+ if (ex->n_subscripts)
add_attr (attrs, pango_attr_rise_new (-3000), subscript_ofs,
footnote_ofs - subscript_ofs);
- if (value->n_footnotes)
+ if (ex->n_footnotes)
{
bool superscript = pt->look->footnote_marker_superscripts;
add_attr (attrs, pango_attr_rise_new (superscript ? 3000 : -3000),
escape_string (html->file, s, " ", "<br>");
ds_destroy (&body);
- if (cell->value->n_subscripts)
+ const struct pivot_value_ex *ex = pivot_value_ex (cell->value);
+ if (ex->n_subscripts)
{
fputs ("<sub>", html->file);
- for (size_t i = 0; i < cell->value->n_subscripts; i++)
+ for (size_t i = 0; i < ex->n_subscripts; i++)
{
if (i)
putc (',', html->file);
- escape_string (html->file, cell->value->subscripts[i],
- " ", "<br>");
+ escape_string (html->file, ex->subscripts[i], " ", "<br>");
}
fputs ("</sub>", html->file);
}
- if (cell->value->n_footnotes > 0)
+ if (ex->n_footnotes > 0)
{
fputs ("<sup>", html->file);
size_t n_footnotes = 0;
- for (size_t i = 0; i < cell->value->n_footnotes; i++)
+ for (size_t i = 0; i < ex->n_footnotes; i++)
{
const struct pivot_footnote *f
- = pt->footnotes[cell->value->footnote_indexes[i]];
+ = pt->footnotes[ex->footnote_indexes[i]];
if (f->show)
{
if (n_footnotes++ > 0)
xmlTextWriterWriteString (odt->content_wtr, _xml (ds_cstr (&body)));
ds_destroy (&body);
- write_footnotes (odt, pt, cell->value->footnote_indexes,
- cell->value->n_footnotes);
+ const struct pivot_value_ex *ex = pivot_value_ex (cell->value);
+ write_footnotes (odt, pt, ex->footnote_indexes, ex->n_footnotes);
}
static void
{
if (subtype == TEXT_ITEM_SYNTAX || subtype == TEXT_ITEM_LOG)
{
- if (!value->font_style)
+ struct pivot_value_ex *ex = pivot_value_ex_rw (value);
+ if (!ex->font_style)
{
- value->font_style = xmalloc (sizeof *value->font_style);
- *value->font_style = (struct font_style) FONT_STYLE_INITIALIZER;
+ ex->font_style = xmalloc (sizeof *value->ex->font_style);
+ *ex->font_style = (struct font_style) FONT_STYLE_INITIALIZER;
}
- free (value->font_style->typeface);
- value->font_style->typeface = xstrdup ("Monospaced");
+ free (ex->font_style->typeface);
+ ex->font_style->typeface = xstrdup ("Monospaced");
}
struct output_item *item = xzalloc (sizeof *item);
if (ds != ss
|| (ds != TEXT_ITEM_SYNTAX && ds != TEXT_ITEM_LOG)
|| strcmp (output_item_get_label (dst), output_item_get_label (src))
- || !nullable_font_style_equal (dc->font_style, sc->font_style)
- || (dc->font_style && dc->font_style->markup)
+ || !nullable_font_style_equal (dc->ex ? dc->ex->font_style : NULL,
+ sc->ex ? sc->ex->font_style : NULL)
+ || (dc->ex && dc->ex->font_style && dc->ex->font_style->markup)
|| sc->type != PIVOT_VALUE_TEXT
|| dc->type != PIVOT_VALUE_TEXT)
return false;
if (x == cell.d[H][0] && y == cell.d[V][0])
{
- for (size_t i = 0; i < cell.value->n_footnotes; i++)
+ const struct pivot_value_ex *ex = pivot_value_ex (cell.value);
+ for (size_t i = 0; i < ex->n_footnotes; i++)
{
- size_t idx = cell.value->footnote_indexes[i];
+ size_t idx = ex->footnote_indexes[i];
assert (idx < pt->n_footnotes);
if (!refs[idx] && pt->footnotes[idx]->show)
break;
case PIVOT_VALUE_TEXT:
- if (value->font_style && value->font_style->markup)
+ if (value->ex && value->ex->font_style && value->ex->font_style->markup)
get_text_from_markup (value->text.local, out);
else
ds_put_cstr (out, value->text.local);
{
bool numeric = pivot_value_format_body (value, pt, out);
- if (value->n_subscripts)
+ const struct pivot_value_ex *ex = value->ex;
+ if (ex)
{
- for (size_t i = 0; i < value->n_subscripts; i++)
- ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]);
- }
+ if (ex->n_subscripts)
+ {
+ for (size_t i = 0; i < ex->n_subscripts; i++)
+ ds_put_format (out, "%c%s", i ? ',' : '_', ex->subscripts[i]);
+ }
- for (size_t i = 0; i < value->n_footnotes; i++)
- {
- ds_put_byte (out, '[');
+ for (size_t i = 0; i < ex->n_footnotes; i++)
+ {
+ ds_put_byte (out, '[');
- size_t idx = value->footnote_indexes[i];
- const struct pivot_footnote *f = pt->footnotes[idx];
- pivot_footnote_format_marker (f, pt, out);
+ size_t idx = ex->footnote_indexes[i];
+ const struct pivot_footnote *f = pt->footnotes[idx];
+ pivot_footnote_format_marker (f, pt, out);
- ds_put_byte (out, ']');
+ ds_put_byte (out, ']');
+ }
}
return numeric;
return NULL;
struct pivot_value *new = xmemdup (old, sizeof *new);
- if (old->font_style)
- {
- new->font_style = xmalloc (sizeof *new->font_style);
- font_style_copy (NULL, new->font_style, old->font_style);
- }
- if (old->cell_style)
- new->cell_style = xmemdup (old->cell_style, sizeof *new->cell_style);
- if (old->n_subscripts)
- {
- new->subscripts = xnmalloc (old->n_subscripts, sizeof *new->subscripts);
- for (size_t i = 0; i < old->n_subscripts; i++)
- new->subscripts[i] = xstrdup (old->subscripts[i]);
- }
- if (old->n_footnotes)
- new->footnote_indexes = xmemdup (
- old->footnote_indexes, old->n_footnotes * sizeof *new->footnote_indexes);
+ if (old->ex)
+ new->ex = pivot_value_ex_clone (old->ex);
switch (new->type)
{
{
if (value)
{
- font_style_uninit (value->font_style);
- free (value->font_style);
- free (value->cell_style);
- free (value->footnote_indexes);
-
- for (size_t i = 0; i < value->n_subscripts; i++)
- free (value->subscripts[i]);
- free (value->subscripts);
-
+ pivot_value_ex_destroy (value->ex);
switch (value->type)
{
case PIVOT_VALUE_NUMERIC:
const struct cell_style *base_cell_style,
struct table_area_style *area)
{
- 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);
+ const struct pivot_value_ex *ex = pivot_value_ex (value);
+ font_style_copy (NULL, &area->font_style,
+ ex->font_style ? ex->font_style : base_font_style);
+ area->cell_style = *(ex->cell_style ? ex->cell_style : base_cell_style);
}
/* Copies AREA into VALUE's style. */
pivot_value_set_font_style (struct pivot_value *value,
const struct font_style *font_style)
{
- if (value->font_style)
- font_style_uninit (value->font_style);
+ struct pivot_value_ex *ex = pivot_value_ex_rw (value);
+ if (ex->font_style)
+ font_style_uninit (ex->font_style);
else
- value->font_style = xmalloc (sizeof *value->font_style);
- font_style_copy (NULL, value->font_style, font_style);
+ ex->font_style = xmalloc (sizeof *ex->font_style);
+ font_style_copy (NULL, ex->font_style, font_style);
}
void
pivot_value_set_cell_style (struct pivot_value *value,
const struct cell_style *cell_style)
{
- if (!value->cell_style)
- value->cell_style = xmalloc (sizeof *value->cell_style);
- *value->cell_style = *cell_style;
+ struct pivot_value_ex *ex = pivot_value_ex_rw (value);
+ if (!ex->cell_style)
+ ex->cell_style = xmalloc (sizeof *ex->cell_style);
+ *ex->cell_style = *cell_style;
}
void
pivot_value_add_footnote (struct pivot_value *v,
const struct pivot_footnote *footnote)
{
+ struct pivot_value_ex *ex = pivot_value_ex_rw (v);
+
/* Some legacy tables include numerous duplicate footnotes. Suppress
them. */
- for (size_t i = 0; i < v->n_footnotes; i++)
- if (v->footnote_indexes[i] == footnote->idx)
+ for (size_t i = 0; i < ex->n_footnotes; i++)
+ if (ex->footnote_indexes[i] == footnote->idx)
return;
- v->footnote_indexes = xrealloc (
- v->footnote_indexes, (v->n_footnotes + 1) * sizeof *v->footnote_indexes);
- v->footnote_indexes[v->n_footnotes++] = footnote->idx;
+ ex->footnote_indexes = xrealloc (
+ ex->footnote_indexes,
+ (ex->n_footnotes + 1) * sizeof *ex->footnote_indexes);
+ ex->footnote_indexes[ex->n_footnotes++] = footnote->idx;
pivot_value_sort_footnotes (v);
}
void
pivot_value_sort_footnotes (struct pivot_value *v)
{
- if (v->n_footnotes > 1)
- qsort (v->footnote_indexes, v->n_footnotes, sizeof *v->footnote_indexes,
- compare_footnote_indexes);
+ if (v->ex && v->ex->n_footnotes > 1)
+ qsort (v->ex->footnote_indexes, v->ex->n_footnotes,
+ sizeof *v->ex->footnote_indexes, compare_footnote_indexes);
}
/* If VALUE is a numeric value, and RC is a result class such as
pivot_table_use_rc (table, rc,
&value->numeric.format, &value->numeric.honor_small);
}
+\f
+/* pivot_value_ex. */
+
+struct pivot_value_ex *
+pivot_value_ex_rw (struct pivot_value *value)
+{
+ if (!value->ex)
+ value->ex = xzalloc (sizeof *value->ex);
+ return value->ex;
+}
+
+struct pivot_value_ex *
+pivot_value_ex_clone (const struct pivot_value_ex *old)
+{
+ struct font_style *font_style = NULL;
+ if (old->font_style)
+ {
+ font_style = xmalloc (sizeof *font_style);
+ font_style_copy (NULL, font_style, old->font_style);
+ }
+ char **subscripts = NULL;
+ if (old->n_subscripts)
+ {
+ subscripts = xnmalloc (old->n_subscripts, sizeof *subscripts);
+ for (size_t i = 0; i < old->n_subscripts; i++)
+ subscripts[i] = xstrdup (old->subscripts[i]);
+ }
+
+ struct pivot_value_ex *new = xmalloc (sizeof *new);
+ *new = (struct pivot_value_ex) {
+ .font_style = font_style,
+ .cell_style = (old->cell_style
+ ? xmemdup (old->cell_style, sizeof *new->cell_style)
+ : NULL),
+ .subscripts = subscripts,
+ .n_subscripts = old->n_subscripts,
+ .footnote_indexes = (
+ old->n_footnotes
+ ? xmemdup (old->footnote_indexes,
+ old->n_footnotes * sizeof *new->footnote_indexes)
+ : NULL),
+ .n_footnotes = old->n_footnotes
+ };
+ return new;
+}
+
+void
+pivot_value_ex_destroy (struct pivot_value_ex *ex)
+{
+ if (ex)
+ {
+ font_style_uninit (ex->font_style);
+ free (ex->font_style);
+ free (ex->cell_style);
+ free (ex->footnote_indexes);
+
+ for (size_t i = 0; i < ex->n_subscripts; i++)
+ free (ex->subscripts[i]);
+ free (ex->subscripts);
+ }
+}
*/
struct pivot_value
{
- struct font_style *font_style;
- struct cell_style *cell_style;
-
- char **subscripts;
- size_t n_subscripts;
-
- size_t *footnote_indexes;
- size_t n_footnotes;
-
+ struct pivot_value_ex *ex;
union
{
enum pivot_value_type type;
void pivot_argument_copy (struct pivot_argument *,
const struct pivot_argument *);
\f
+/* Extra styling for a pivot_value.
+
+ This is logically part of pivot_value itself. It is broken into a separate
+ structure to save memory because it is rarely used. */
+struct pivot_value_ex
+ {
+ struct font_style *font_style;
+ struct cell_style *cell_style;
+
+ char **subscripts;
+ size_t n_subscripts;
+
+ size_t *footnote_indexes;
+ size_t n_footnotes;
+ };
+
+static inline const struct pivot_value_ex *
+pivot_value_ex (const struct pivot_value *value)
+{
+ static const struct pivot_value_ex empty_ex = { .font_style = NULL };
+ return value->ex ? value->ex : &empty_ex;
+}
+
+struct pivot_value_ex *pivot_value_ex_rw (struct pivot_value *);
+struct pivot_value_ex *pivot_value_ex_clone (const struct pivot_value_ex *);
+void pivot_value_ex_destroy (struct pivot_value_ex *);
+\f
/* One piece of data within a pivot table. */
struct pivot_cell
{
{
if (sf)
{
- if (sf->reset > 0)
+ if (sf->reset > 0 && value->ex)
{
- free (value->footnote_indexes);
- value->footnote_indexes = NULL;
- value->n_footnotes = 0;
+ free (value->ex->footnote_indexes);
+ value->ex->footnote_indexes = NULL;
+ value->ex->n_footnotes = 0;
}
struct fmt_spec format = { .w = 0 };
}
if (fg || bg)
{
+ const struct pivot_value_ex *ex = pivot_value_ex (value);
struct table_area_style area;
pivot_value_get_style (
value,
- value->font_style ? value->font_style : &base_area_style->font_style,
- value->cell_style ? value->cell_style : &base_area_style->cell_style,
+ ex->font_style ? ex->font_style : &base_area_style->font_style,
+ ex->cell_style ? ex->cell_style : &base_area_style->cell_style,
&area);
decode_spvdx_style_incremental (fg, bg, &area);
pivot_value_set_style (value, &area);
if (value->type == PIVOT_VALUE_NUMERIC
&& value->numeric.x == SYSMIS
- && !value->n_footnotes)
+ && !pivot_value_ex (value)->n_footnotes)
{
/* Apparently, system-missing values are just empty cells? */
pivot_value_destroy (value);
{
if (vm->n_subscripts)
{
- out->n_subscripts = vm->n_subscripts;
- out->subscripts = xnmalloc (vm->n_subscripts,
- sizeof *out->subscripts);
+ struct pivot_value_ex *ex = pivot_value_ex_rw (out);
+ ex->n_subscripts = vm->n_subscripts;
+ ex->subscripts = xnmalloc (vm->n_subscripts, sizeof *ex->subscripts);
for (size_t i = 0; i < vm->n_subscripts; i++)
- out->subscripts[i] = to_utf8 (vm->subscripts[i], encoding);
+ ex->subscripts[i] = to_utf8 (vm->subscripts[i], encoding);
}
if (vm->n_refs)
{
- out->footnote_indexes = xnmalloc (vm->n_refs,
- sizeof *out->footnote_indexes);
+ struct pivot_value_ex *ex = pivot_value_ex_rw (out);
+ ex->footnote_indexes = xnmalloc (vm->n_refs,
+ sizeof *ex->footnote_indexes);
+
for (size_t i = 0; i < vm->n_refs; i++)
{
uint16_t idx = vm->refs[i];
idx, table->n_footnotes);
}
- out->footnote_indexes[out->n_footnotes++] = idx;
+ ex->footnote_indexes[ex->n_footnotes++] = idx;
}
pivot_value_sort_footnotes (out);
}
if (vm->style_pair)
{
+ struct pivot_value_ex *ex = pivot_value_ex_rw (out);
error = decode_spvlb_font_style (vm->style_pair->font_style,
- encoding, &out->font_style);
+ encoding, &ex->font_style);
if (!error)
error = decode_spvlb_cell_style (vm->style_pair->cell_style,
- &out->cell_style);
+ &ex->cell_style);
if (error)
{
pivot_value_destroy (out);
put_value_mod (struct buf *buf, const struct pivot_value *value,
const char *template)
{
- if (value->n_footnotes || value->n_subscripts
- || template || value->font_style || value->cell_style)
+ if ((value->ex
+ && (value->ex->n_footnotes
+ || value->ex->n_subscripts
+ || value->ex->font_style
+ || value->ex->cell_style))
+ || template)
{
+ const struct pivot_value_ex *ex = pivot_value_ex (value);
put_byte (buf, 0x31);
/* Footnotes. */
- put_u32 (buf, value->n_footnotes);
- for (size_t i = 0; i < value->n_footnotes; i++)
- put_u16 (buf, value->footnote_indexes[i]);
+ put_u32 (buf, ex->n_footnotes);
+ for (size_t i = 0; i < ex->n_footnotes; i++)
+ put_u16 (buf, ex->footnote_indexes[i]);
/* Subscripts. */
- put_u32 (buf, value->n_subscripts);
- for (size_t i = 0; i < value->n_subscripts; i++)
- put_string (buf, value->subscripts[i]);
+ put_u32 (buf, ex->n_subscripts);
+ for (size_t i = 0; i < ex->n_subscripts; i++)
+ put_string (buf, ex->subscripts[i]);
/* Template and style. */
uint32_t v3_start = start_count (buf);
put_string (buf, template);
}
end_count_u32 (buf, template_string_start);
- put_style_pair (buf, value->font_style, value->cell_style);
+ put_style_pair (buf, ex->font_style, ex->cell_style);
end_count_u32 (buf, v3_start);
}
else
{
struct font_style *font_style = xmalloc (sizeof *font_style);
char *text = decode_embedded_html (ct->html->node_.raw, font_style);
+
struct pivot_value *value = xmalloc (sizeof *value);
*value = (struct pivot_value) {
- .font_style = font_style,
.text = {
.type = PIVOT_VALUE_TEXT,
.local = text,
.user_provided = true,
},
};
+ pivot_value_ex_rw (value)->font_style = font_style;
struct output_item *item = text_item_create_value (TEXT_ITEM_LOG,
value, NULL);
else
{
const struct pivot_value *v = cc ? cc : &empty_value;
+ const struct pivot_value_ex *ex = pivot_value_ex (v);
*cell = (struct table_cell) {
.d = { [H] = { x, x + 1 }, [V] = { y, y + 1 } },
.options = opt,
.value = v,
- .font_style = v->font_style ? v->font_style : &style->font_style,
- .cell_style = v->cell_style ? v->cell_style : &style->cell_style,
+ .font_style = ex->font_style ? ex->font_style : &style->font_style,
+ .cell_style = ex->cell_style ? ex->cell_style : &style->cell_style,
};
}
static void
tex_put_footnote_markers (struct tex_driver *tex,
const struct pivot_table *pt,
- const size_t *footnote_indexes,
- size_t n_footnotes)
+ const struct pivot_value_ex *ex)
{
size_t n_visible = 0;
- for (size_t i = 0; i < n_footnotes; i++)
+ for (size_t i = 0; i < ex->n_footnotes; i++)
{
- const struct pivot_footnote *f = pt->footnotes[footnote_indexes[i]];
+ const struct pivot_footnote *f = pt->footnotes[ex->footnote_indexes[i]];
if (f->show)
{
if (!n_visible++)
tex_escape_string (tex, ds_cstr (&s), false);
ds_destroy (&s);
- tex_put_footnote_markers (tex, pt,
- cell->value->footnote_indexes,
- cell->value->n_footnotes);
+ tex_put_footnote_markers (tex, pt, pivot_value_ex (cell->value));
}
static void
tex_escape_string (tex, ds_cstr (&s), true);
ds_destroy (&s);
- tex_put_footnote_markers (tex, pt, cell.value->footnote_indexes,
- cell.value->n_footnotes);
+ tex_put_footnote_markers (tex, pt, pivot_value_ex (cell.value));
if (halign == TABLE_HALIGN_CENTER || halign == TABLE_HALIGN_RIGHT)
{
shipout (&tex->token_list, "}");
if (lex_match_id (lexer, "SUBSCRIPTS"))
{
lex_match (lexer, T_EQUALS);
- size_t allocated_subscripts = value->n_subscripts;
+
+ struct pivot_value_ex *ex = pivot_value_ex_rw (value);
+ size_t allocated_subscripts = ex->n_subscripts;
while (lex_token (lexer) == T_STRING)
{
- if (value->n_subscripts >= allocated_subscripts)
- value->subscripts = x2nrealloc (value->subscripts,
- &allocated_subscripts,
- sizeof *value->subscripts);
+ if (ex->n_subscripts >= allocated_subscripts)
+ ex->subscripts = x2nrealloc (ex->subscripts, &allocated_subscripts,
+ sizeof *ex->subscripts);
- value->subscripts[value->n_subscripts++] = xstrdup (
- lex_tokcstr (lexer));
+ ex->subscripts[ex->n_subscripts++] = xstrdup (lex_tokcstr (lexer));
lex_get (lexer);
}
return;
{
lex_match (lexer, T_EQUALS);
- if (!value->font_style)
+ struct pivot_value_ex *ex = pivot_value_ex_rw (value);
+ if (!ex->font_style)
{
- value->font_style = xmalloc (sizeof *value->font_style);
- font_style_copy (NULL, value->font_style, &base_style->font_style);
+ ex->font_style = xmalloc (sizeof *ex->font_style);
+ font_style_copy (NULL, ex->font_style, &base_style->font_style);
}
- read_font_style (lexer, value->font_style);
+ read_font_style (lexer, ex->font_style);
return;
}
{
lex_match (lexer, T_EQUALS);
- if (!value->cell_style)
+ struct pivot_value_ex *ex = pivot_value_ex_rw (value);
+ if (!ex->cell_style)
{
- value->cell_style = xmalloc (sizeof *value->cell_style);
- *value->cell_style = base_style->cell_style;
+ ex->cell_style = xmalloc (sizeof *ex->cell_style);
+ *ex->cell_style = base_style->cell_style;
}
- read_cell_style (lexer, value->cell_style);
+ read_cell_style (lexer, ex->cell_style);
return;
}