- struct table *table;
- struct string s;
-
- ds_init_empty (&s);
-
- /* Variable label. */
- if (flags & DF_VARIABLE_LABELS && var_has_label (v))
- {
- if (flags & ~(DF_DICT_INDEX | DF_VARIABLE_LABELS))
- ds_put_format (&s, _("Label: %s\n"), var_get_label (v));
- else
- ds_put_format (&s, "%s\n", var_get_label (v));
- }
-
- /* Print/write format, or print and write formats. */
- if (flags & DF_FORMATS)
- {
- const struct fmt_spec *print = var_get_print_format (v);
- const struct fmt_spec *write = var_get_write_format (v);
- char str[FMT_STRING_LEN_MAX + 1];
-
- if (fmt_equal (print, write))
- ds_put_format (&s, _("Format: %s\n"), fmt_to_string (print, str));
- else
- {
- ds_put_format (&s, _("Print Format: %s\n"),
- fmt_to_string (print, str));
- ds_put_format (&s, _("Write Format: %s\n"),
- fmt_to_string (write, str));
- }
- }
-
- /* Measurement level, role, display width, alignment. */
- if (flags & DF_MEASURE)
- ds_put_format (&s, _("Measure: %s\n"),
- measure_to_string (var_get_measure (v)));
-
- if (flags & DF_ROLE)
- ds_put_format (&s, _("Role: %s\n"), var_role_to_string (var_get_role (v)));
-
-
- if (flags & DF_ALIGNMENT)
- ds_put_format (&s, _("Display Alignment: %s\n"),
- alignment_to_string (var_get_alignment (v)));
-
- if (flags & DF_WIDTH)
- ds_put_format (&s, _("Display Width: %d\n"), var_get_display_width (v));
-
- /* Missing values if any. */
- if (flags & DF_MISSING_VALUES && var_has_missing_values (v))
- {
- const struct missing_values *mv = var_get_missing_values (v);
- int cnt = 0;
- int i;
-
- ds_put_cstr (&s, _("Missing Values: "));
-
- if (mv_has_range (mv))
- {
- double x, y;
- mv_get_range (mv, &x, &y);
- if (x == LOWEST)
- ds_put_format (&s, "LOWEST THRU %.*g", DBL_DIG + 1, y);
- else if (y == HIGHEST)
- ds_put_format (&s, "%.*g THRU HIGHEST", DBL_DIG + 1, x);
- else
- ds_put_format (&s, "%.*g THRU %.*g",
- DBL_DIG + 1, x,
- DBL_DIG + 1, y);
- cnt++;
- }
- for (i = 0; i < mv_n_values (mv); i++)
- {
- const union value *value = mv_get_value (mv, i);
- if (cnt++ > 0)
- ds_put_cstr (&s, "; ");
- if (var_is_numeric (v))
- ds_put_format (&s, "%.*g", DBL_DIG + 1, value->f);
- else
- {
- int width = var_get_width (v);
- int mv_width = MIN (width, MV_MAX_STRING);
-
- ds_put_byte (&s, '"');
- memcpy (ds_put_uninit (&s, mv_width),
- value_str (value, width), mv_width);
- ds_put_byte (&s, '"');
- }
- }
- ds_put_byte (&s, '\n');
- }
-
- ds_chomp_byte (&s, '\n');
-
- table = (ds_is_empty (&s)
- ? NULL
- : table_from_string (TAB_LEFT, ds_cstr (&s)));
- ds_destroy (&s);
-
- /* Value labels. */
- if (flags & DF_VALUE_LABELS && var_has_value_labels (v))
- table = table_vpaste (table, table_create_nested (describe_value_labels (v)));
-
- if (flags & (DF_ATTRIBUTES | DF_AT_ATTRIBUTES))
- {
- struct attrset *attrs = var_get_attributes (v);
-
- if (count_attributes (attrs, flags))
- table = table_vpaste (
- table, table_create_nested (describe_attributes (attrs, flags)));
- }
-
- if (table == NULL)
- table = table_from_string (TAB_LEFT, "");
-
- table = table_hpaste (table_from_string (0, var_get_name (v)),
- table_stomp (table));
- if (flags & DF_DICT_INDEX)
- {
- char s[INT_BUFSIZE_BOUND (size_t)];
+ size_t n_attributes = count_attributes (dict_attrset, flags);
+ for (size_t i = 0; i < n_vars; i++)
+ n_attributes += count_attributes (var_get_attributes (vars[i]), flags);
+ if (!n_attributes)
+ return;
+
+ struct tab_table *t = tab_create (3, n_attributes + 1);
+ tab_title (t, "%s", _("Variable and Dataset Attributes"));
+ tab_headers (t, 0, 0, 1, 0);
+ tab_hline (t, TAL_2, 0, 2, 1);
+ tab_text (t, 0, 0, TAB_LEFT | TAT_TITLE, _("Variable"));
+ tab_text (t, 1, 0, TAB_LEFT | TAT_TITLE, _("Name"));
+ tab_text (t, 2, 0, TAB_LEFT | TAT_TITLE, _("Value"));