From ec2799682bc9aeefb092b7204f419fb46547b8b6 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 3 Jul 2022 10:16:54 -0700 Subject: [PATCH] )TABLE, )DATE, )TIME --- doc/statistics.texi | 2 +- src/language/stats/ctables.c | 99 +++++++++++++++++++++++++++++++-- tests/language/stats/ctables.at | 6 +- 3 files changed, 99 insertions(+), 8 deletions(-) diff --git a/doc/statistics.texi b/doc/statistics.texi index 5b8b841933..4966d6afb8 100644 --- a/doc/statistics.texi +++ b/doc/statistics.texi @@ -923,7 +923,7 @@ where each @i{axis} may be empty or take one of the following forms: @i{axis} + @i{axis} @i{axis} > @i{axis} (@i{axis}) -@i{axis} @t{(}@i{summary} [@i{string}] [@i{format}]@t{)} +@i{axis} @t{[}@i{summary} [@i{string}] [@i{format}]@t{]} @end display The following subcommands precede the first @code{TABLE} subcommand diff --git a/src/language/stats/ctables.c b/src/language/stats/ctables.c index 497969a057..072b9f83a8 100644 --- a/src/language/stats/ctables.c +++ b/src/language/stats/ctables.c @@ -31,6 +31,7 @@ #include "language/command.h" #include "language/lexer/format-parser.h" #include "language/lexer/lexer.h" +#include "language/lexer/token.h" #include "language/lexer/variable-parser.h" #include "libpspp/array.h" #include "libpspp/assertion.h" @@ -1730,7 +1731,6 @@ parse_category_string (const struct ctables_category *cat, struct substring s, struct dictionary *dict, enum fmt_type format, double *n) { - printf ("parse %.*s as %s\n", (int) s.length, s.string, fmt_name (format)); union value v; char *error = data_in (s, dict_get_encoding (dict), format, settings_get_fmt_settings (), &v, 0, NULL); @@ -3302,7 +3302,6 @@ ctables_cell_insert (struct ctables_section *s, if (var_missing) is_missing = true; - printf ("ctables_cell_insert %s: ", var_get_name (var)); cats[a][i] = ctables_categories_match ( s->table->categories[var_get_dict_index (var)], value, var); if (!cats[a][i]) @@ -3687,7 +3686,7 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t) pivot_table_set_caption ( pt, pivot_value_new_user_text (t->caption, SIZE_MAX)); if (t->corner) - pivot_table_set_caption ( + pivot_table_set_corner_text ( pt, pivot_value_new_user_text (t->corner, SIZE_MAX)); bool summary_dimension = (t->summary_axis != t->slabels_axis @@ -5082,6 +5081,92 @@ error: return false; } +static void +put_strftime (struct string *out, time_t now, const char *format) +{ + const struct tm *tm = localtime (&now); + char value[128]; + strftime (value, sizeof value, format, tm); + ds_put_cstr (out, value); +} + +static bool +skip_prefix (struct substring *s, struct substring prefix) +{ + if (ss_starts_with (*s, prefix)) + { + ss_advance (s, prefix.length); + return true; + } + else + return false; +} + +static void +put_table_expression (struct string *out, struct lexer *lexer, + struct dictionary *dict, int expr_start, int expr_end) +{ + size_t nest = 0; + for (int ofs = expr_start; ofs < expr_end; ofs++) + { + const struct token *t = lex_ofs_token (lexer, ofs); + if (t->type == T_LBRACK) + nest++; + else if (t->type == T_RBRACK && nest > 0) + nest--; + else if (nest > 0) + { + /* Nothing. */ + } + else if (t->type == T_ID) + { + const struct variable *var + = dict_lookup_var (dict, t->string.string); + const char *label = var ? var_get_label (var) : NULL; + ds_put_cstr (out, label ? label : t->string.string); + } + else + { + if (ofs != expr_start && t->type != T_RPAREN && ds_last (out) != ' ') + ds_put_byte (out, ' '); + + char *repr = lex_ofs_representation (lexer, ofs, ofs); + ds_put_cstr (out, repr); + free (repr); + + if (ofs + 1 != expr_end && t->type != T_LPAREN) + ds_put_byte (out, ' '); + } + } +} + +static void +put_title_text (struct string *out, struct substring in, time_t now, + struct lexer *lexer, struct dictionary *dict, + int expr_start, int expr_end) +{ + for (;;) + { + size_t chunk = ss_find_byte (in, ')'); + ds_put_substring (out, ss_head (in, chunk)); + ss_advance (&in, chunk); + if (ss_is_empty (in)) + return; + + if (skip_prefix (&in, ss_cstr (")DATE"))) + put_strftime (out, now, "%x"); + else if (skip_prefix (&in, ss_cstr (")TIME"))) + put_strftime (out, now, "%X"); + else if (skip_prefix (&in, ss_cstr (")TABLE"))) + put_table_expression (out, lexer, dict, expr_start, expr_end); + else + { + ds_put_byte (out, ')'); + ss_advance (&in, 1); + } + } +} + int cmd_ctables (struct lexer *lexer, struct dataset *ds) { @@ -5104,6 +5189,8 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) .postcomputes = HMAP_INITIALIZER (ct->postcomputes), }; + time_t now = time (NULL); + struct ctf { enum fmt_type type; @@ -5371,6 +5458,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) ct->tables[ct->n_tables++] = t; lex_match (lexer, T_EQUALS); + int expr_start = lex_ofs (lexer); if (!ctables_axis_parse (lexer, dataset_dict (ds), ct, t, PIVOT_AXIS_ROW)) goto error; if (lex_match (lexer, T_BY)) @@ -5386,6 +5474,7 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) goto error; } } + int expr_end = lex_ofs (lexer); if (!t->axes[PIVOT_AXIS_ROW] && !t->axes[PIVOT_AXIS_COLUMN] && !t->axes[PIVOT_AXIS_LAYER]) @@ -5574,7 +5663,9 @@ cmd_ctables (struct lexer *lexer, struct dataset *ds) { if (!ds_is_empty (&s)) ds_put_byte (&s, ' '); - ds_put_substring (&s, lex_tokss (lexer)); + put_title_text (&s, lex_tokss (lexer), now, + lexer, dataset_dict (ds), + expr_start, expr_end); lex_get (lexer); } free (*textp); diff --git a/tests/language/stats/ctables.at b/tests/language/stats/ctables.at index 0923769b0b..a5ae1eebf0 100644 --- a/tests/language/stats/ctables.at +++ b/tests/language/stats/ctables.at @@ -12,10 +12,7 @@ dnl * U-prefix for unweighted summaries. dnl * .LCL and .UCL suffixes. dnl * .SE suffixes. dnl - CATEGORIES: -dnl * String values -dnl * Date values dnl * Data-dependent sorting. -dnl - TITLES: )DATE, )TIME, )TABLE. dnl - PCOMPUTE: dnl * multi-dimensional dnl * MISSING, OTHERNM @@ -36,6 +33,8 @@ dnl - EMPTY=INCLUDE For string ranges. dnl - Summary functions: dnl * Separate summary functions for totals and subtotals. dnl - CATEGORIES: +dnl * String values +dnl * Date values dnl * THRU (numeric ranges) dnl * THRU (string ranges) dnl * OTHERNM @@ -46,6 +45,7 @@ dnl * MISSING. dnl - HIDESMALLCOUNTS. dnl - Date/time variables and values dnl - Special formats for summary functions: NEGPAREN, NEQUAL, PAREN, PCTPAREN. +dnl - TITLES: )DATE, )TIME, )TABLE. dnl dnl Not for v1: dnl - Multiple response sets -- 2.30.2