+static bool
+is_at_name (const char *name)
+{
+ return name[0] == '@' || (name[0] == '$' && name[1] == '@');
+}
+
+static size_t
+count_attributes (const struct attrset *set, int flags)
+{
+ struct attrset_iterator i;
+ struct attribute *attr;
+ size_t n_attrs;
+
+ n_attrs = 0;
+ for (attr = attrset_first (set, &i); attr != NULL;
+ attr = attrset_next (set, &i))
+ if (flags & DF_AT_ATTRIBUTES || !is_at_name (attribute_get_name (attr)))
+ n_attrs += attribute_get_n_values (attr);
+ return n_attrs;
+}
+
+static void
+display_attributes (struct tab_table *t, const struct attrset *set, int flags,
+ int c, int r)
+{
+ struct attrset_iterator i;
+ struct attribute *attr;
+
+ for (attr = attrset_first (set, &i); attr != NULL;
+ attr = attrset_next (set, &i))
+ {
+ const char *name = attribute_get_name (attr);
+ size_t n_values;
+ size_t i;
+
+ if (!(flags & DF_AT_ATTRIBUTES) && is_at_name (name))
+ continue;
+
+ n_values = attribute_get_n_values (attr);
+ for (i = 0; i < n_values; i++)
+ {
+ if (n_values > 1)
+ tab_text_format (t, c, r, TAB_LEFT, "%s[%d]", name, i + 1);
+ else
+ tab_text (t, c, r, TAB_LEFT, name);
+ tab_text (t, c + 1, r, TAB_LEFT, attribute_get_value (attr, i));
+ r++;
+ }
+ }
+}
+
+static void
+display_data_file_attributes (struct attrset *set, int flags)
+{
+ 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, 0);
+ 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_columns (t, TAB_COL_DOWN, 1);
+ tab_dim (t, tab_natural_dimensions, NULL);
+ 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)