test NEGPAREN & friends
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 5 Aug 2022 00:40:51 +0000 (17:40 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 5 Aug 2022 00:40:51 +0000 (17:40 -0700)
src/language/stats/ctables.c
tests/language/stats/ctables.at

index 64c399bcbcd27a70634c398cd58ce554abb8e88f..461007c555db92673236ba5beb192d59862ee2e2 100644 (file)
@@ -4358,6 +4358,37 @@ ctables_cell_calculate_postcompute (const struct ctables_section *s,
   return ctables_pcexpr_evaluate (&ctx, pc->expr);
 }
 
+static char *
+ctables_format (double d, const struct fmt_spec *format,
+                const struct fmt_settings *settings)
+{
+  const union value v = { .f = d };
+  char *s = data_out_stretchy (&v, "UTF-8", format, settings, NULL);
+
+  /* The custom-currency specifications for NEQUAL, PAREN, and PCTPAREN don't
+     produce the results we want for negative numbers, putting the negative
+     sign in the wrong spot, before the prefix instead of after it.  We can't,
+     in fact, produce the desired results using a custom-currency
+     specification.  Instead, we postprocess the output, moving the negative
+     sign into place:
+
+         NEQUAL:   "-N=3"  => "N=-3"
+         PAREN:    "-(3)"  => "(-3)"
+         PCTPAREN: "-(3%)" => "(-3%)"
+
+     This transformation doesn't affect NEGPAREN. */
+  char *minus_src = strchr (s, '-');
+  if (minus_src && (minus_src == s || minus_src[-1] != 'E'))
+    {
+      char *n_equals = strstr (s, "N=");
+      char *lparen = strchr (s, '(');
+      char *minus_dst = n_equals ? n_equals + 1 : lparen;
+      if (minus_dst)
+        move_element (s, minus_dst - s + 1, 1, minus_src - s, minus_dst - s);
+    }
+  return s;
+}
+
 static void
 ctables_table_output (struct ctables *ct, struct ctables_table *t)
 {
@@ -4684,12 +4715,8 @@ ctables_table_output (struct ctables *ct, struct ctables_table *t)
               else if (d == SYSMIS && ct->missing)
                 value = pivot_value_new_user_text (ct->missing, SIZE_MAX);
               else if (is_ctables_format)
-                {
-                  char *s = data_out_stretchy (&(union value) { .f = d },
-                                               "UTF-8", &format,
-                                               &ct->ctables_formats, NULL);
-                  value = pivot_value_new_user_text_nocopy (s);
-                }
+                value = pivot_value_new_user_text_nocopy (
+                  ctables_format (d, &format, &ct->ctables_formats));
               else
                 {
                   value = pivot_value_new_number (d);
index 171e92f83cc5a801c3c0237706a52a07c9c848ec..9109b7c034395d7107846bf4a84131b62958cf95 100644 (file)
@@ -16,7 +16,6 @@ dnl   * Date values
 dnl   * THRU (numeric ranges)
 dnl   * OTHERNM
 dnl - Date/time variables and values
-dnl - Special formats for summary functions: NEGPAREN, NEQUAL, PAREN, PCTPAREN.
 dnl - TITLES: )DATE, )TIME, )TABLE.
 dnl - Test PCOMPUTE:
 dnl   * PCOMPUTE for more than one kind of summary (e.g. [COUNT, ROWPCT]).
@@ -2397,3 +2396,21 @@ maximumColumnWidth="192"
 minimumColumnWidth="96"
 ])
 AT_CLEANUP
+
+AT_SETUP([CTABLES special formats])
+AT_KEYWORDS([NEGPAREN NEQUAL PAREN PCTPAREN])
+AT_CHECK([ln $top_srcdir/examples/nhtsa.sav . || cp $top_srcdir/examples/nhtsa.sav .])
+AT_DATA([ctables.sps],
+[[GET 'nhtsa.sav'.
+COMPUTE x = qnd3 - 4.
+CTABLES /TABLE x[MINIMUM NEGPAREN8.1, MINIMUM NEQUAL8.1, MINIMUM PAREN8.1, MINIMUM PCTPAREN8.1, MAXIMUM NEGPAREN8.1, MAXIMUM NEQUAL8.1, MAXIMUM PAREN8.1, MAXIMUM PCTPAREN8.1].
+]])
+AT_CHECK([pspp ctables.sps -O box=unicode], [0], [dnl
+                           Custom Tables
+╭─┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────╮
+│ │Minimum│Minimum│Minimum│Minimum│Maximum│Maximum│Maximum│Maximum│
+├─┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┤
+│x│(3.0)  │N=-3.0 │(-3.0) │(-3.0%)│8.0    │N=8.0  │(8.0)  │(8.0%) │
+╰─┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────╯
+])
+AT_CLEANUP