X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Foutput%2Fpivot-table.c;h=f8f917d9dd1d965b3d5b2830b725c7c12004eee1;hb=cee6f0eb54144da7034566fa1bcdcee22337ae6a;hp=85ac16d09c1bf2f311bdc7a02dd3cd8c8b8f0c14;hpb=34cb3b49aed3f145ccf68f083041e493cc5fc924;p=pspp diff --git a/src/output/pivot-table.c b/src/output/pivot-table.c index 85ac16d09c..f8f917d9dd 100644 --- a/src/output/pivot-table.c +++ b/src/output/pivot-table.c @@ -18,6 +18,8 @@ #include "output/pivot-table.h" +#include +#include #include #include @@ -746,11 +748,11 @@ struct result_class /* Formats for most of the result classes. */ static struct result_class result_classes[] = { - { PIVOT_RC_INTEGER, { FMT_F, 40, 0 } }, - { PIVOT_RC_PERCENT, { FMT_PCT, 40, 1 } }, - { PIVOT_RC_CORRELATION, { FMT_F, 40, 3 } }, - { PIVOT_RC_SIGNIFICANCE, { FMT_F, 40, 3 } }, - { PIVOT_RC_RESIDUAL, { FMT_F, 40, 2 } }, + { PIVOT_RC_INTEGER, { .type = FMT_F, .w = 40, .d = 0 } }, + { PIVOT_RC_PERCENT, { .type = FMT_PCT, .w = 40, .d = 1 } }, + { PIVOT_RC_CORRELATION, { .type = FMT_F, .w = 40, .d = 3 } }, + { PIVOT_RC_SIGNIFICANCE, { .type = FMT_F, .w = 40, .d = 3 } }, + { PIVOT_RC_RESIDUAL, { .type = FMT_F, .w = 40, .d = 2 } }, { PIVOT_RC_COUNT, { 0, 0, 0 } }, { PIVOT_RC_OTHER, { 0, 0, 0 } }, }; @@ -863,20 +865,20 @@ pivot_table_create (const char *title) struct pivot_table * pivot_table_create__ (struct pivot_value *title, const char *subtype) { - struct pivot_table *table = xzalloc (sizeof *table); - table->ref_cnt = 1; - table->show_title = true; - table->show_caption = true; - table->weight_format = (struct fmt_spec) { FMT_F, 40, 0 }; - table->title = title; - table->subtype = subtype ? pivot_value_new_text (subtype) : NULL; - table->command_c = output_get_command_name (); - table->look = pivot_table_look_ref (pivot_table_look_get_default ()); - table->settings = fmt_settings_copy (settings_get_fmt_settings ()); - table->small = settings_get_small (); - - hmap_init (&table->cells); - + struct pivot_table *table = xmalloc (sizeof *table); + *table = (struct pivot_table) { + .ref_cnt = 1, + .show_title = true, + .show_caption = true, + .weight_format = (struct fmt_spec) { .type = FMT_F, .w = 40 }, + .title = title, + .subtype = subtype ? pivot_value_new_text (subtype) : NULL, + .command_c = xstrdup_if_nonempty (output_get_command_name ()), + .look = pivot_table_look_ref (pivot_table_look_get_default ()), + .settings = fmt_settings_copy (settings_get_fmt_settings ()), + .small = settings_get_small (), + .cells = HMAP_INITIALIZER (table->cells), + }; return table; } @@ -911,12 +913,6 @@ pivot_table_ref (const struct pivot_table *table_) return table; } -static char * -xstrdup_if_nonnull (const char *s) -{ - return s ? xstrdup (s) : NULL; -} - static struct pivot_table_sizing clone_sizing (const struct pivot_table_sizing *s) { @@ -972,7 +968,7 @@ clone_category (struct pivot_category *old, .extra_depth = old->extra_depth, .subs = (old->n_subs - ? xzalloc (old->n_subs * sizeof *new->subs) + ? xcalloc (old->n_subs, sizeof *new->subs) : NULL), .n_subs = old->n_subs, .allocated_subs = old->n_subs, @@ -1010,9 +1006,9 @@ clone_dimension (struct pivot_dimension *old, struct pivot_table *new_pt) .axis_type = old->axis_type, .level = old->level, .top_index = old->top_index, - .data_leaves = xzalloc (old->n_leaves * sizeof *new->data_leaves), - .presentation_leaves = xzalloc (old->n_leaves - * sizeof *new->presentation_leaves), + .data_leaves = xcalloc (old->n_leaves , sizeof *new->data_leaves), + .presentation_leaves = xcalloc (old->n_leaves + , sizeof *new->presentation_leaves), .n_leaves = old->n_leaves, .allocated_leaves = old->n_leaves, .hide_all_labels = old->hide_all_labels, @@ -1195,6 +1191,43 @@ pivot_table_is_shared (const struct pivot_table *table) return table->ref_cnt > 1; } +static void +pivot_table_set_value__ (struct pivot_value **dstp, struct pivot_value *src) +{ + pivot_value_destroy (*dstp); + *dstp = src; +} + +/* Changes the title of TABLE to TITLE. Takes ownership of TITLE. */ +void +pivot_table_set_title (struct pivot_table *table, struct pivot_value *title) +{ + pivot_table_set_value__ (&table->title, title); +} + +/* Changes the subtype of TABLE to SUBTYPE. Takes ownership of SUBTYPE. */ +void +pivot_table_set_subtype (struct pivot_table *table, struct pivot_value *subtype) +{ + pivot_table_set_value__ (&table->subtype, subtype); +} + +/* Changes the corner text of TABLE to CORNER_TEXT. Takes ownership of + CORNER_TEXT. */ +void +pivot_table_set_corner_text (struct pivot_table *table, + struct pivot_value *corner_text) +{ + pivot_table_set_value__ (&table->corner_text, corner_text); +} + +/* Changes the caption of TABLE to CAPTION. Takes ownership of CAPTION. */ +void +pivot_table_set_caption (struct pivot_table *table, struct pivot_value *caption) +{ + pivot_table_set_value__ (&table->caption, caption); +} + /* Swaps axes A and B in TABLE. */ void pivot_table_swap_axes (struct pivot_table *table, @@ -1943,6 +1976,8 @@ compose_headings (const struct pivot_table *pt, static void free_headings (const struct pivot_axis *axis, char ***headings) { + if (!headings) + return; for (size_t i = 0; i < axis->label_depth; i++) { for (size_t j = 0; j < axis->extent; j++) @@ -2098,21 +2133,30 @@ pivot_table_dump (const struct pivot_table *table, int indentation) size_t *row_enumeration = pivot_table_enumerate_axis ( table, PIVOT_AXIS_ROW, layer_indexes, table->look->omit_empty, NULL); + /* Print column headings. + + Ordinarily the test for nonnull 'column_headings' would be + unnecessary, because 'column_headings' is null only if the axis's + label_depth is 0, but there is a special case for the column axis only + in pivot_table_assign_label_depth(). */ char ***column_headings = compose_headings ( table, &table->axes[PIVOT_AXIS_COLUMN], column_enumeration); - for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++) + if (column_headings) { - indent (indentation + 1); - for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++) + for (size_t y = 0; y < table->axes[PIVOT_AXIS_COLUMN].label_depth; y++) { - if (x) - fputs ("; ", stdout); - if (column_headings[y][x]) - fputs (column_headings[y][x], stdout); + indent (indentation + 1); + for (size_t x = 0; x < table->axes[PIVOT_AXIS_COLUMN].extent; x++) + { + if (x) + fputs ("; ", stdout); + if (column_headings && column_headings[y] && column_headings[y][x]) + fputs (column_headings[y][x], stdout); + } + putchar ('\n'); } - putchar ('\n'); + free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings); } - free_headings (&table->axes[PIVOT_AXIS_COLUMN], column_headings); indent (indentation + 1); printf ("-----------------------------------------------\n"); @@ -2301,6 +2345,33 @@ interpret_show (enum settings_value_show global_show, : global_show); } +/* Appends to OUT the actual text content from the given Pango MARKUP. */ +static void +get_text_from_markup (const char *markup, struct string *out) +{ + xmlParserCtxt *parser = xmlCreatePushParserCtxt (NULL, NULL, NULL, 0, NULL); + if (!parser) + { + ds_put_cstr (out, markup); + return; + } + + xmlParseChunk (parser, "", strlen (""), false); + xmlParseChunk (parser, markup, strlen (markup), false); + xmlParseChunk (parser, "", strlen (""), true); + + if (parser->wellFormed) + { + xmlChar *s = xmlNodeGetContent (xmlDocGetRootElement (parser->myDoc)); + ds_put_cstr (out, CHAR_CAST (char *, s)); + xmlFree (s); + } + else + ds_put_cstr (out, markup); + xmlFreeDoc (parser->myDoc); + xmlFreeParserCtxt (parser); +} + /* Appends a text representation of the body of VALUE to OUT. Settings on PT control whether variable and value labels are included. @@ -2388,7 +2459,10 @@ pivot_value_format_body (const struct pivot_value *value, break; case PIVOT_VALUE_TEXT: - ds_put_cstr (out, value->text.local); + if (value->ex && value->ex->font_style && value->ex->font_style->markup) + get_text_from_markup (value->text.local, out); + else + ds_put_cstr (out, value->text.local); break; case PIVOT_VALUE_TEMPLATE: @@ -2414,21 +2488,25 @@ pivot_value_format (const struct pivot_value *value, { bool numeric = pivot_value_format_body (value, pt, out); - if (value->n_subscripts) + const struct pivot_value_ex *ex = value->ex; + if (ex) { - for (size_t i = 0; i < value->n_subscripts; i++) - ds_put_format (out, "%c%s", i ? ',' : '_', value->subscripts[i]); - } + if (ex->n_subscripts) + { + for (size_t i = 0; i < ex->n_subscripts; i++) + ds_put_format (out, "%c%s", i ? ',' : '_', ex->subscripts[i]); + } - for (size_t i = 0; i < value->n_footnotes; i++) - { - ds_put_byte (out, '['); + for (size_t i = 0; i < ex->n_footnotes; i++) + { + ds_put_byte (out, '['); - size_t idx = value->footnote_indexes[i]; - const struct pivot_footnote *f = pt->footnotes[idx]; - pivot_footnote_format_marker (f, pt, out); + size_t idx = ex->footnote_indexes[i]; + const struct pivot_footnote *f = pt->footnotes[idx]; + pivot_footnote_format_marker (f, pt, out); - ds_put_byte (out, ']'); + ds_put_byte (out, ']'); + } } return numeric; @@ -2451,6 +2529,7 @@ pivot_value_to_string_defaults (const struct pivot_value *value) static const struct pivot_table pt = { .show_values = SETTINGS_VALUE_SHOW_DEFAULT, .show_variables = SETTINGS_VALUE_SHOW_DEFAULT, + .settings = FMT_SETTINGS_INIT, }; return pivot_value_to_string (value, &pt); } @@ -2462,22 +2541,8 @@ pivot_value_clone (const struct pivot_value *old) return NULL; 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->cell_style = xmemdup (old->cell_style, sizeof *new->cell_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->footnote_indexes = xmemdup ( - old->footnote_indexes, old->n_footnotes * sizeof *new->footnote_indexes); + if (old->ex) + new->ex = pivot_value_ex_clone (old->ex); switch (new->type) { @@ -2530,15 +2595,7 @@ pivot_value_destroy (struct pivot_value *value) { if (value) { - font_style_uninit (value->font_style); - free (value->font_style); - free (value->cell_style); - free (value->footnote_indexes); - - for (size_t i = 0; i < value->n_subscripts; i++) - free (value->subscripts[i]); - free (value->subscripts); - + pivot_value_ex_destroy (value->ex); switch (value->type) { case PIVOT_VALUE_NUMERIC: @@ -2590,12 +2647,10 @@ pivot_value_get_style (struct pivot_value *value, const struct cell_style *base_cell_style, struct table_area_style *area) { - font_style_copy (NULL, &area->font_style, (value->font_style - ? value->font_style - : base_font_style)); - area->cell_style = *(value->cell_style - ? value->cell_style - : base_cell_style); + const struct pivot_value_ex *ex = pivot_value_ex (value); + font_style_copy (NULL, &area->font_style, + ex->font_style ? ex->font_style : base_font_style); + area->cell_style = *(ex->cell_style ? ex->cell_style : base_cell_style); } /* Copies AREA into VALUE's style. */ @@ -2611,20 +2666,22 @@ void pivot_value_set_font_style (struct pivot_value *value, const struct font_style *font_style) { - if (value->font_style) - font_style_uninit (value->font_style); + struct pivot_value_ex *ex = pivot_value_ex_rw (value); + if (ex->font_style) + font_style_uninit (ex->font_style); else - value->font_style = xmalloc (sizeof *value->font_style); - font_style_copy (NULL, value->font_style, font_style); + ex->font_style = xmalloc (sizeof *ex->font_style); + font_style_copy (NULL, ex->font_style, font_style); } void pivot_value_set_cell_style (struct pivot_value *value, const struct cell_style *cell_style) { - if (!value->cell_style) - value->cell_style = xmalloc (sizeof *value->cell_style); - *value->cell_style = *cell_style; + struct pivot_value_ex *ex = pivot_value_ex_rw (value); + if (!ex->cell_style) + ex->cell_style = xmalloc (sizeof *ex->cell_style); + *ex->cell_style = *cell_style; } void @@ -2665,8 +2722,8 @@ pivot_value_new_user_text_nocopy (char *text) { struct pivot_value *value = xmalloc (sizeof *value); *value = (struct pivot_value) { - .type = PIVOT_VALUE_TEXT, .text = { + .type = PIVOT_VALUE_TEXT, .local = text, .c = text, .id = text, @@ -2684,9 +2741,9 @@ pivot_value_new_user_text_nocopy (char *text) that pivot_value_new_variable() should be used for variable names). For strings that are part of the PSPP user interface, such as names of procedures, statistics, annotations, error messages, etc., use - pivot_value_new_text().j + pivot_value_new_text(). - The caller retains ownership of TEXT.*/ + The caller retains ownership of TEXT. */ struct pivot_value * pivot_value_new_user_text (const char *text, size_t length) { @@ -2708,8 +2765,8 @@ pivot_value_new_text (const char *text) struct pivot_value *value = xmalloc (sizeof *value); *value = (struct pivot_value) { - .type = PIVOT_VALUE_TEXT, .text = { + .type = PIVOT_VALUE_TEXT, .local = local, .c = c, .id = c, @@ -2720,7 +2777,7 @@ pivot_value_new_text (const char *text) } /* Same as pivot_value_new_text() but its argument is a printf()-like format - string. */ + string. The format string should generally be enclosed in N_(). */ struct pivot_value * PRINTF_FORMAT (1, 2) pivot_value_new_text_format (const char *format, ...) { @@ -2735,8 +2792,8 @@ pivot_value_new_text_format (const char *format, ...) struct pivot_value *value = xmalloc (sizeof *value); *value = (struct pivot_value) { - .type = PIVOT_VALUE_TEXT, .text = { + .type = PIVOT_VALUE_TEXT, .local = local, .c = c, .id = xstrdup (c), @@ -2757,8 +2814,10 @@ pivot_value_new_number (double x) { struct pivot_value *value = xmalloc (sizeof *value); *value = (struct pivot_value) { - .type = PIVOT_VALUE_NUMERIC, - .numeric = { .x = x, }, + .numeric = { + .type = PIVOT_VALUE_NUMERIC, + .x = x + }, }; return value; } @@ -2768,7 +2827,7 @@ struct pivot_value * pivot_value_new_integer (double x) { struct pivot_value *value = pivot_value_new_number (x); - value->numeric.format = (struct fmt_spec) { FMT_F, 40, 0 }; + value->numeric.format = (struct fmt_spec) { .type = FMT_F, .w = 40 }; return value; } @@ -2807,7 +2866,7 @@ struct pivot_value * pivot_value_new_value (const union value *value, int width, const struct fmt_spec *format, const char *encoding) { - struct pivot_value *pv = xzalloc (sizeof *pv); + struct pivot_value *pv = XZALLOC (struct pivot_value); if (width > 0) { char *s = recode_string (UTF8, encoding, CHAR_CAST (char *, value->s), @@ -2833,13 +2892,22 @@ pivot_value_new_value (const union value *value, int width, /* Returns a new pivot_value for VARIABLE. */ struct pivot_value * pivot_value_new_variable (const struct variable *variable) +{ + return pivot_value_new_variable__ (var_get_name (variable), + var_get_label (variable)); +} + +/* Returns a new pivot_value for a variable with the given NAME and optional + LABEL. */ +struct pivot_value * +pivot_value_new_variable__ (const char *name, const char *label) { struct pivot_value *value = xmalloc (sizeof *value); *value = (struct pivot_value) { - .type = PIVOT_VALUE_VARIABLE, .variable = { - .var_name = xstrdup (var_get_name (variable)), - .var_label = xstrdup_if_nonempty (var_get_label (variable)), + .type = PIVOT_VALUE_VARIABLE, + .var_name = xstrdup (name), + .var_label = xstrdup_if_nonempty (label), }, }; return value; @@ -2850,15 +2918,18 @@ void pivot_value_add_footnote (struct pivot_value *v, const struct pivot_footnote *footnote) { + struct pivot_value_ex *ex = pivot_value_ex_rw (v); + /* Some legacy tables include numerous duplicate footnotes. Suppress them. */ - for (size_t i = 0; i < v->n_footnotes; i++) - if (v->footnote_indexes[i] == footnote->idx) + for (size_t i = 0; i < ex->n_footnotes; i++) + if (ex->footnote_indexes[i] == footnote->idx) return; - v->footnote_indexes = xrealloc ( - v->footnote_indexes, (v->n_footnotes + 1) * sizeof *v->footnote_indexes); - v->footnote_indexes[v->n_footnotes++] = footnote->idx; + ex->footnote_indexes = xrealloc ( + ex->footnote_indexes, + (ex->n_footnotes + 1) * sizeof *ex->footnote_indexes); + ex->footnote_indexes[ex->n_footnotes++] = footnote->idx; pivot_value_sort_footnotes (v); } @@ -2879,9 +2950,9 @@ compare_footnote_indexes (const void *a_, const void *b_) void pivot_value_sort_footnotes (struct pivot_value *v) { - if (v->n_footnotes > 1) - qsort (v->footnote_indexes, v->n_footnotes, sizeof *v->footnote_indexes, - compare_footnote_indexes); + if (v->ex && v->ex->n_footnotes > 1) + qsort (v->ex->footnote_indexes, v->ex->n_footnotes, + sizeof *v->ex->footnote_indexes, compare_footnote_indexes); } /* If VALUE is a numeric value, and RC is a result class such as @@ -2894,4 +2965,66 @@ pivot_value_set_rc (const struct pivot_table *table, struct pivot_value *value, pivot_table_use_rc (table, rc, &value->numeric.format, &value->numeric.honor_small); } + +/* pivot_value_ex. */ + +struct pivot_value_ex * +pivot_value_ex_rw (struct pivot_value *value) +{ + if (!value->ex) + value->ex = xzalloc (sizeof *value->ex); + return value->ex; +} + +struct pivot_value_ex * +pivot_value_ex_clone (const struct pivot_value_ex *old) +{ + struct font_style *font_style = NULL; + if (old->font_style) + { + font_style = xmalloc (sizeof *font_style); + font_style_copy (NULL, font_style, old->font_style); + } + + char **subscripts = NULL; + if (old->n_subscripts) + { + subscripts = xnmalloc (old->n_subscripts, sizeof *subscripts); + for (size_t i = 0; i < old->n_subscripts; i++) + subscripts[i] = xstrdup (old->subscripts[i]); + } + + struct pivot_value_ex *new = xmalloc (sizeof *new); + *new = (struct pivot_value_ex) { + .font_style = font_style, + .cell_style = (old->cell_style + ? xmemdup (old->cell_style, sizeof *new->cell_style) + : NULL), + .subscripts = subscripts, + .n_subscripts = old->n_subscripts, + .footnote_indexes = ( + old->n_footnotes + ? xmemdup (old->footnote_indexes, + old->n_footnotes * sizeof *new->footnote_indexes) + : NULL), + .n_footnotes = old->n_footnotes + }; + return new; +} +void +pivot_value_ex_destroy (struct pivot_value_ex *ex) +{ + if (ex) + { + font_style_uninit (ex->font_style); + free (ex->font_style); + free (ex->cell_style); + free (ex->footnote_indexes); + + for (size_t i = 0; i < ex->n_subscripts; i++) + free (ex->subscripts[i]); + free (ex->subscripts); + free (ex); + } +}