+ struct pivot_value *pv = pivot_value_new_var_value (
+ var, &(union value) { .f = number });
+ pivot_value_format (pv, NULL, s);
+ pivot_value_destroy (pv);
+}
+
+static void
+ctables_category_format_string (struct substring string,
+ const struct variable *var, struct string *out)
+{
+ int width = var_get_width (var);
+ char *s = xmalloc (width);
+ buf_copy_rpad (s, width, string.string, string.length, ' ');
+ struct pivot_value *pv = pivot_value_new_var_value (
+ var, &(union value) { .s = CHAR_CAST (uint8_t *, s) });
+ pivot_value_format (pv, NULL, out);
+ pivot_value_destroy (pv);
+ free (s);
+}
+
+static bool
+ctables_category_format_label (const struct ctables_category *cat,
+ const struct variable *var,
+ struct string *s)
+{
+ switch (cat->type)
+ {
+ case CCT_NUMBER:
+ ctables_category_format_number (cat->number, var, s);
+ return true;
+
+ case CCT_STRING:
+ ctables_category_format_string (cat->string, var, s);
+ return true;
+
+ case CCT_NRANGE:
+ ctables_category_format_number (cat->nrange[0], var, s);
+ ds_put_format (s, " THRU ");
+ ctables_category_format_number (cat->nrange[1], var, s);
+ return true;
+
+ case CCT_SRANGE:
+ ctables_category_format_string (cat->srange[0], var, s);
+ ds_put_format (s, " THRU ");
+ ctables_category_format_string (cat->srange[1], var, s);
+ return true;
+
+ case CCT_MISSING:
+ ds_put_cstr (s, "MISSING");
+ return true;
+
+ case CCT_OTHERNM:
+ ds_put_cstr (s, "OTHERNM");
+ return true;
+
+ case CCT_POSTCOMPUTE:
+ ds_put_format (s, "&%s", cat->pc->name);
+ return true;
+
+ case CCT_TOTAL:
+ case CCT_SUBTOTAL:
+ ds_put_cstr (s, cat->total_label);
+ return true;
+
+ case CCT_VALUE:
+ case CCT_LABEL:
+ case CCT_FUNCTION:
+ case CCT_EXCLUDED_MISSING:
+ return false;
+ }
+
+ return false;