+ struct tab_table *t;
+ size_t n_attrs;
+
+ n_attrs = count_attributes (set, flags);
+ if (!n_attrs)
+ return;
+
+ t = tab_create (2, n_attrs + 1);
+ tab_headers (t, 0, 0, 1, 0);
+ tab_box (t, TAL_1, TAL_1, -1, TAL_1, 0, 0, tab_nc (t) - 1, tab_nr (t) - 1);
+ tab_hline (t, TAL_2, 0, 1, 1);
+ tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Attribute"));
+ tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Value"));
+ display_attributes (t, set, flags, 0, 1);
+ tab_title (t, "Custom data file attributes.");
+ tab_submit (t);
+}
+
+/* Puts a description of variable V into table T starting at row
+ R. The variable will be described in the format given by
+ FLAGS. Returns the next row available for use in the
+ table. */
+static int
+describe_variable (const struct variable *v, struct tab_table *t, int r,
+ int pc, int flags)
+{
+ size_t n_attrs = 0;
+ int need_rows;
+
+ /* Make sure that enough rows are allocated. */
+ need_rows = 1;
+ if (flags & ~(DF_DICT_INDEX | DF_VARIABLE_LABELS))
+ need_rows += 15;
+ if (flags & DF_VALUE_LABELS)
+ need_rows += val_labs_count (var_get_value_labels (v));
+ if (flags & (DF_ATTRIBUTES | DF_AT_ATTRIBUTES))
+ {
+ n_attrs = count_attributes (var_get_attributes (v), flags);
+ need_rows += n_attrs;
+ }
+ if (r + need_rows > tab_nr (t))
+ {
+ int nr = MAX (r + need_rows, tab_nr (t) * 2);
+ tab_realloc (t, -1, nr);
+ }