+static char *
+xstrdup_if_nonnull (const char *s)
+{
+ return s ? xstrdup (s) : NULL;
+}
+
+struct pivot_value *
+pivot_value_clone (const struct pivot_value *old)
+{
+ 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->font_style = xmemdup (old->font_style, sizeof *new->font_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->footnotes = xmemdup (old->footnotes,
+ old->n_footnotes * sizeof *new->footnotes);
+
+ switch (new->type)
+ {
+ case PIVOT_VALUE_NUMERIC:
+ new->numeric.var_name = xstrdup_if_nonnull (new->numeric.var_name);
+ new->numeric.value_label = xstrdup_if_nonnull (new->numeric.value_label);
+ break;
+
+ case PIVOT_VALUE_STRING:
+ new->string.s = xstrdup (new->string.s);
+ new->string.var_name = xstrdup_if_nonnull (new->string.var_name);
+ new->string.value_label = xstrdup_if_nonnull (new->string.value_label);
+ break;
+
+ case PIVOT_VALUE_VARIABLE:
+ new->variable.var_name = xstrdup_if_nonnull (new->variable.var_name);
+ new->variable.var_label = xstrdup_if_nonnull (new->variable.var_label);
+ break;
+
+ case PIVOT_VALUE_TEXT:
+ new->text.local = xstrdup (old->text.local);
+ new->text.c = (old->text.c == old->text.local ? new->text.local
+ : xstrdup (old->text.c));
+ new->text.id = (old->text.id == old->text.local ? new->text.local
+ : old->text.id == old->text.c ? new->text.c
+ : xstrdup (old->text.id));
+ break;
+
+ case PIVOT_VALUE_TEMPLATE:
+ new->template.local = xstrdup (old->template.local);
+ new->template.id = (old->template.id == old->template.local
+ ? new->template.local
+ : xstrdup (old->template.id));
+ new->template.args = xmalloc (new->template.n_args
+ * sizeof *new->template.args);
+ for (size_t i = 0; i < old->template.n_args; i++)
+ pivot_argument_copy (&new->template.args[i],
+ &old->template.args[i]);
+ break;
+
+ default:
+ NOT_REACHED ();
+ }
+ return new;
+}
+