test NEGPAREN & friends
[pspp] / src / language / stats / ctables.c
index 5393c1b838b5343bc4eb71433c0246c130d26eac..461007c555db92673236ba5beb192d59862ee2e2 100644 (file)
@@ -905,102 +905,9 @@ ctables_function_availability (enum ctables_summary_function f)
 static bool
 ctables_summary_function_is_count (enum ctables_summary_function f)
 {
-  switch (f)
-    {
-    case CTSF_COUNT:
-    case CTSF_ECOUNT:
-    case CTSF_ROWPCT_COUNT:
-    case CTSF_COLPCT_COUNT:
-    case CTSF_TABLEPCT_COUNT:
-    case CTSF_SUBTABLEPCT_COUNT:
-    case CTSF_LAYERPCT_COUNT:
-    case CTSF_LAYERROWPCT_COUNT:
-    case CTSF_LAYERCOLPCT_COUNT:
-    case CTSF_UCOUNT:
-    case CTSF_UROWPCT_COUNT:
-    case CTSF_UCOLPCT_COUNT:
-    case CTSF_UTABLEPCT_COUNT:
-    case CTSF_USUBTABLEPCT_COUNT:
-    case CTSF_ULAYERPCT_COUNT:
-    case CTSF_ULAYERROWPCT_COUNT:
-    case CTSF_ULAYERCOLPCT_COUNT:
-      return true;
-
-    case CTSF_ROWPCT_VALIDN:
-    case CTSF_COLPCT_VALIDN:
-    case CTSF_TABLEPCT_VALIDN:
-    case CTSF_SUBTABLEPCT_VALIDN:
-    case CTSF_LAYERPCT_VALIDN:
-    case CTSF_LAYERROWPCT_VALIDN:
-    case CTSF_LAYERCOLPCT_VALIDN:
-    case CTSF_ROWPCT_TOTALN:
-    case CTSF_COLPCT_TOTALN:
-    case CTSF_TABLEPCT_TOTALN:
-    case CTSF_SUBTABLEPCT_TOTALN:
-    case CTSF_LAYERPCT_TOTALN:
-    case CTSF_LAYERROWPCT_TOTALN:
-    case CTSF_LAYERCOLPCT_TOTALN:
-    case CTSF_MAXIMUM:
-    case CTSF_MEAN:
-    case CTSF_MEDIAN:
-    case CTSF_MINIMUM:
-    case CTSF_MISSING:
-    case CTSF_MODE:
-    case CTSF_PTILE:
-    case CTSF_RANGE:
-    case CTSF_SEMEAN:
-    case CTSF_STDDEV:
-    case CTSF_SUM:
-    case CSTF_TOTALN:
-    case CTSF_ETOTALN:
-    case CTSF_VALIDN:
-    case CTSF_EVALIDN:
-    case CTSF_VARIANCE:
-    case CTSF_ROWPCT_SUM:
-    case CTSF_COLPCT_SUM:
-    case CTSF_TABLEPCT_SUM:
-    case CTSF_SUBTABLEPCT_SUM:
-    case CTSF_LAYERPCT_SUM:
-    case CTSF_LAYERROWPCT_SUM:
-    case CTSF_LAYERCOLPCT_SUM:
-    case CTSF_UROWPCT_VALIDN:
-    case CTSF_UCOLPCT_VALIDN:
-    case CTSF_UTABLEPCT_VALIDN:
-    case CTSF_USUBTABLEPCT_VALIDN:
-    case CTSF_ULAYERPCT_VALIDN:
-    case CTSF_ULAYERROWPCT_VALIDN:
-    case CTSF_ULAYERCOLPCT_VALIDN:
-    case CTSF_UROWPCT_TOTALN:
-    case CTSF_UCOLPCT_TOTALN:
-    case CTSF_UTABLEPCT_TOTALN:
-    case CTSF_USUBTABLEPCT_TOTALN:
-    case CTSF_ULAYERPCT_TOTALN:
-    case CTSF_ULAYERROWPCT_TOTALN:
-    case CTSF_ULAYERCOLPCT_TOTALN:
-    case CTSF_UMEAN:
-    case CTSF_UMEDIAN:
-    case CTSF_UMISSING:
-    case CTSF_UMODE:
-    case CTSF_UPTILE:
-    case CTSF_USEMEAN:
-    case CTSF_USTDDEV:
-    case CTSF_USUM:
-    case CSTF_UTOTALN:
-    case CTSF_UVALIDN:
-    case CTSF_UVARIANCE:
-    case CTSF_UROWPCT_SUM:
-    case CTSF_UCOLPCT_SUM:
-    case CTSF_UTABLEPCT_SUM:
-    case CTSF_USUBTABLEPCT_SUM:
-    case CTSF_ULAYERPCT_SUM:
-    case CTSF_ULAYERROWPCT_SUM:
-    case CTSF_ULAYERCOLPCT_SUM:
-      return false;
-  }
-  NOT_REACHED ();
+  return f == CTSF_COUNT || f == CTSF_ECOUNT || f == CTSF_UCOUNT;
 }
 
-
 static bool
 parse_ctables_summary_function (struct lexer *lexer,
                                 enum ctables_summary_function *f)
@@ -4451,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)
 {
@@ -4777,17 +4715,14 @@ 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);
                   value->numeric.format = format;
                 }
+              /* XXX should text values be right-justified? */
               pivot_table_put (pt, dindexes, n_dindexes, value);
             }
         }