Automatically infer variables' measurement level from format and data.
[pspp] / src / data / settings.c
index b98a1351ac0eee0855222b9c341c1f04ec0da54f..c70635cec03fc06da0dd7c472a8da626e2010fd6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2007, 2009, 2010, 2011, 2015 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 #include <config.h>
-#include "settings.h"
+
+#include "data/settings.h"
+
 #include <assert.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <stdlib.h>
-#include <time.h>
-#include "format.h"
-#include "value.h"
-#include "xalloc.h"
-#include <data/case.h>
-#include <libpspp/i18n.h>
-#include <libpspp/integer-format.h>
-#include <libpspp/message.h>
-
-#include "error.h"
-#include "minmax.h"
+
+#include "data/case.h"
+#include "data/format.h"
+#include "data/value.h"
+#include "libpspp/i18n.h"
+#include "libpspp/integer-format.h"
+#include "libpspp/message.h"
+
+#include "gl/minmax.h"
+#include "gl/xalloc.h"
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
 
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-static int global_algorithm = ENHANCED;
-
 struct settings
 {
   /* Integer format used for IB and PIB input. */
 struct settings
 {
   /* Integer format used for IB and PIB input. */
@@ -49,11 +48,13 @@ struct settings
   /* Format of reals in output (SET WRB). */
   enum float_format output_float_format;
 
   /* Format of reals in output (SET WRB). */
   enum float_format output_float_format;
 
-  int *viewlength;
-  int *viewwidth;
+  /* MATRIX...END MATRIX settings. */
+  enum settings_mdisplay mdisplay;
+
+  int viewlength;
+  int viewwidth;
   bool safer_mode;
   bool include;
   bool safer_mode;
   bool include;
-  int epoch;
   bool route_errors_to_terminal;
   bool route_errors_to_listing;
   bool scompress;
   bool route_errors_to_terminal;
   bool route_errors_to_listing;
   bool scompress;
@@ -61,82 +62,137 @@ struct settings
   double blanks;
   int max_messages[MSG_N_SEVERITIES];
   bool printback;
   double blanks;
   int max_messages[MSG_N_SEVERITIES];
   bool printback;
-  bool mprint;
+
+  /* Macro settings. */
+  bool mexpand;                 /* Expand macros? */
+  bool mprint;                  /* Print macro expansions? */
+  int miterate;                 /* Maximum iterations of !FOR. */
+  int mnest;                    /* Maximum nested macro expansion levels. */
+
   int mxloops;
   int mxloops;
-  bool nulline;
-  char endcmd;
   size_t workspace;
   struct fmt_spec default_format;
   bool testing_mode;
   size_t workspace;
   struct fmt_spec default_format;
   bool testing_mode;
+  int fuzzbits;
+  int scalemin;
 
   int cmd_algorithm;
 
   int cmd_algorithm;
-  int *algorithm;
+  int global_algorithm;
   int syntax;
 
   int syntax;
 
-  struct fmt_settings *styles;
+  struct fmt_settings styles;
+  double small;
 
   enum settings_output_devices output_routing[SETTINGS_N_OUTPUT_TYPES];
 
   enum settings_output_devices output_routing[SETTINGS_N_OUTPUT_TYPES];
+
+  enum settings_value_show show_values;
+  enum settings_value_show show_variables;
 };
 
 static struct settings the_settings = {
 };
 
 static struct settings the_settings = {
-  INTEGER_NATIVE,               /* input_integer_format */
-  FLOAT_NATIVE_DOUBLE,          /* input_float_format */
-  INTEGER_NATIVE,               /* output_integer_format */
-  FLOAT_NATIVE_DOUBLE,          /* output_float_format */
-  NULL,                         /* viewlength */
-  NULL,                         /* viewwidth */
-  false,                        /* safer_mode */
-  true,                         /* include */
-  -1,                           /* epoch */
-  true,                         /* route_errors_to_terminal */
-  true,                         /* route_errors_to_listing */
-  true,                         /* scompress */
-  true,                         /* undefined */
-  SYSMIS,                       /* blanks */
-
-  /* max_messages */
-  {
-    100,                        /* MSG_S_ERROR */
-    100,                        /* MSG_S_WARNING */
-    100                         /* MSG_S_NOTE */
+  .input_integer_format = INTEGER_NATIVE,
+  .input_float_format = FLOAT_NATIVE_DOUBLE,
+  .output_integer_format = INTEGER_NATIVE,
+  .output_float_format = FLOAT_NATIVE_DOUBLE,
+  .mdisplay = SETTINGS_MDISPLAY_TEXT,
+  .viewlength = 24,
+  .viewwidth = 79,
+  .safer_mode = false,
+  .include = true,
+  .route_errors_to_terminal = true,
+  .route_errors_to_listing = true,
+  .scompress = true,
+  .undefined = true,
+  .blanks = SYSMIS,
+
+  .max_messages = {
+    [MSG_S_ERROR] = 100,
+    [MSG_S_WARNING] = 100,
+    [MSG_S_NOTE] = 100
   },
 
   },
 
-  true,                         /* printback */
-  true,                         /* mprint */
-  1,                            /* mxloops */
-  true,                         /* nulline */
-  '.',                          /* endcmd */
-  64L * 1024 * 1024,            /* workspace */
-  {FMT_F, 8, 2},                /* default_format */
-  false,                        /* testing_mode */
-  ENHANCED,                     /* cmd_algorithm */
-  &global_algorithm,            /* algorithm */
-  ENHANCED,                     /* syntax */
-  NULL,                         /* styles */
+  .printback = true,
+
+  .mexpand = true,
+  .mprint = false,
+  .miterate = 1000,
+  .mnest = 50,
+
+  .mxloops = 40,
+  .workspace = 64L * 1024 * 1024,
+  .default_format = { .type = FMT_F, .w = 8, .d = 2 },
+  .testing_mode = false,
+  .fuzzbits = 6,
+  .scalemin = 24,
+  .cmd_algorithm = ENHANCED,
+  .global_algorithm = ENHANCED,
+  .syntax = ENHANCED,
+  .styles = FMT_SETTINGS_INIT,
+  .small = .0001,
 
   /* output_routing */
 
   /* output_routing */
-  {SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
-   SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL,
-   0,
-   SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL}
-};
+  .output_routing = {
+#define LT (SETTINGS_DEVICE_LISTING | SETTINGS_DEVICE_TERMINAL)
+    [SETTINGS_OUTPUT_ERROR] = LT,
+    [SETTINGS_OUTPUT_NOTE] = LT,
+    [SETTINGS_OUTPUT_SYNTAX] = 0,
+    [SETTINGS_OUTPUT_RESULT] = LT
+#undef LT
+  },
 
 
-static void init_viewport ( int *, int *);
+  .show_values = SETTINGS_VALUE_SHOW_LABEL,
+  .show_variables = SETTINGS_VALUE_SHOW_LABEL,
+};
 
 
+/* Initializes the settings module. */
 void
 void
-settings_init (int *width, int *length)
+settings_init (void)
 {
 {
-  init_viewport (width, length);
-  settings_set_epoch (-1);
-  the_settings.styles = fmt_settings_create ();
-
   settings_set_decimal_char (get_system_decimal ());
 }
 
   settings_set_decimal_char (get_system_decimal ());
 }
 
+/* Cleans up the settings module. */
 void
 settings_done (void)
 {
 void
 settings_done (void)
 {
-  fmt_settings_destroy (the_settings.styles);
+  settings_destroy (&the_settings);
+}
+
+static void
+settings_copy (struct settings *dst, const struct settings *src)
+{
+  *dst = *src;
+  dst->styles = fmt_settings_copy (&src->styles);
+}
+
+/* Returns a copy of the current settings. */
+struct settings *
+settings_get (void)
+{
+  struct settings *s = xmalloc (sizeof *s);
+  settings_copy (s, &the_settings);
+  return s;
+}
+
+/* Replaces the current settings by those in S.  The caller retains ownership
+   of S. */
+void
+settings_set (const struct settings *s)
+{
+  settings_destroy (&the_settings);
+  settings_copy (&the_settings, s);
+}
+
+/* Destroys S. */
+void
+settings_destroy (struct settings *s)
+{
+  if (s != NULL)
+    {
+      fmt_settings_uninit (&s->styles);
+      if (s != &the_settings)
+        free (s);
+    }
 }
 
 /* Returns the floating-point format used for RB and RBHEX
 }
 
 /* Returns the floating-point format used for RB and RBHEX
@@ -150,7 +206,7 @@ settings_get_input_float_format (void)
 /* Sets the floating-point format used for RB and RBHEX input to
    FORMAT. */
 void
 /* Sets the floating-point format used for RB and RBHEX input to
    FORMAT. */
 void
-settings_set_input_float_format ( enum float_format format)
+settings_set_input_float_format (enum float_format format)
 {
   the_settings.input_float_format = format;
 }
 {
   the_settings.input_float_format = format;
 }
@@ -165,7 +221,7 @@ settings_get_input_integer_format (void)
 /* Sets the integer format used for IB and PIB input to
    FORMAT. */
 void
 /* Sets the integer format used for IB and PIB input to
    FORMAT. */
 void
-settings_set_input_integer_format ( enum integer_format format)
+settings_set_input_integer_format (enum integer_format format)
 {
   the_settings.input_integer_format = format;
 }
 {
   the_settings.input_integer_format = format;
 }
@@ -194,7 +250,7 @@ settings_get_output_float_format (void)
 
 /* Sets the output float format to FLOAT_FORMAT. */
 void
 
 /* Sets the output float format to FLOAT_FORMAT. */
 void
-settings_set_output_float_format ( enum float_format float_format)
+settings_set_output_float_format (enum float_format float_format)
 {
   the_settings.output_float_format = float_format;
 }
 {
   the_settings.output_float_format = float_format;
 }
@@ -203,35 +259,28 @@ settings_set_output_float_format ( enum float_format float_format)
 int
 settings_get_viewlength (void)
 {
 int
 settings_get_viewlength (void)
 {
-  return *the_settings.viewlength;
+  return the_settings.viewlength;
 }
 
 /* Sets the view length. */
 void
 }
 
 /* Sets the view length. */
 void
-settings_set_viewlength ( int viewlength_)
+settings_set_viewlength (int viewlength_)
 {
 {
-  *the_settings.viewlength = viewlength_;
+  the_settings.viewlength = viewlength_;
 }
 
 /* Screen width. */
 int
 settings_get_viewwidth(void)
 {
 }
 
 /* Screen width. */
 int
 settings_get_viewwidth(void)
 {
-  return *the_settings.viewwidth;
+  return the_settings.viewwidth;
 }
 
 /* Sets the screen width. */
 void
 }
 
 /* Sets the screen width. */
 void
-settings_set_viewwidth ( int viewwidth_)
-{
-  *the_settings.viewwidth = viewwidth_;
-}
-
-static void
-init_viewport ( int  *width, int *length)
+settings_set_viewwidth (int viewwidth_)
 {
 {
-  the_settings.viewwidth = width;
-  the_settings.viewlength = length;
+  the_settings.viewwidth = viewwidth_;
 }
 
 /* Whether PSPP can erase and overwrite files. */
 }
 
 /* Whether PSPP can erase and overwrite files. */
@@ -257,33 +306,23 @@ settings_get_include (void)
 
 /* Set include file echo. */
 void
 
 /* Set include file echo. */
 void
-settings_set_include ( bool include)
+settings_set_include (bool include)
 {
   the_settings.include = include;
 }
 
 {
   the_settings.include = include;
 }
 
-/* What year to use as the start of the epoch. */
+/* Returns the year that starts the epoch. */
 int
 settings_get_epoch (void)
 {
 int
 settings_get_epoch (void)
 {
-  assert (the_settings.epoch >= 0);
-
-  return the_settings.epoch;
+  return the_settings.styles.epoch;
 }
 
 /* Sets the year that starts the epoch. */
 void
 }
 
 /* Sets the year that starts the epoch. */
 void
-settings_set_epoch ( int epoch)
+settings_set_epoch (int epoch)
 {
 {
-  if (epoch < 0)
-    {
-      time_t t = time (0);
-      struct tm *tm = localtime (&t);
-      epoch = (tm != NULL ? tm->tm_year + 1900 : 2000) - 69;
-    }
-
-  the_settings.epoch = epoch;
-  assert (the_settings.epoch >= 0);
+  the_settings.styles.epoch = epoch;
 }
 
 /* Compress system files by default? */
 }
 
 /* Compress system files by default? */
@@ -295,7 +334,7 @@ settings_get_scompression (void)
 
 /* Set system file default compression. */
 void
 
 /* Set system file default compression. */
 void
-settings_set_scompression ( bool scompress)
+settings_set_scompression (bool scompress)
 {
   the_settings.scompress = scompress;
 }
 {
   the_settings.scompress = scompress;
 }
@@ -309,7 +348,7 @@ settings_get_undefined (void)
 
 /* Set whether to warn on undefined values. */
 void
 
 /* Set whether to warn on undefined values. */
 void
-settings_set_undefined ( bool undefined)
+settings_set_undefined (bool undefined)
 {
   the_settings.undefined = undefined;
 }
 {
   the_settings.undefined = undefined;
 }
@@ -324,7 +363,7 @@ settings_get_blanks (void)
 /* Set the value that blank numeric fields are set to when read
    in. */
 void
 /* Set the value that blank numeric fields are set to when read
    in. */
 void
-settings_set_blanks ( double blanks)
+settings_set_blanks (double blanks)
 {
   the_settings.blanks = blanks;
 }
 {
   the_settings.blanks = blanks;
 }
@@ -341,9 +380,9 @@ settings_get_max_messages (enum msg_severity severity)
 
 /* Sets the maximum number of messages to show of the given SEVERITY before
    aborting to MAX.  (The value for MSG_S_WARNING is interpreted as maximum
 
 /* Sets the maximum number of messages to show of the given SEVERITY before
    aborting to MAX.  (The value for MSG_S_WARNING is interpreted as maximum
-   number of warnings and errors combined.)  In addition, in the case of 
+   number of warnings and errors combined.)  In addition, in the case of
    warnings the special value of zero indicates that no warnings are to be
    warnings the special value of zero indicates that no warnings are to be
-   issued. 
+   issued.
 */
 void
 settings_set_max_messages (enum msg_severity severity, int max)
 */
 void
 settings_set_max_messages (enum msg_severity severity, int max)
@@ -352,13 +391,13 @@ settings_set_max_messages (enum msg_severity severity, int max)
 
   if (severity == MSG_S_WARNING)
     {
 
   if (severity == MSG_S_WARNING)
     {
-      if ( max == 0)
+      if (max == 0)
        {
          msg (MW,
               _("MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."));
          msg_ui_disable_warnings (true);
        }
        {
          msg (MW,
               _("MXWARNS set to zero.  No further warnings will be given even when potentially problematic situations are encountered."));
          msg_ui_disable_warnings (true);
        }
-      else if ( the_settings.max_messages [MSG_S_WARNING] == 0)
+      else if (the_settings.max_messages [MSG_S_WARNING] == 0)
        {
          msg_ui_disable_warnings (false);
          the_settings.max_messages[MSG_S_WARNING] = max;
        {
          msg_ui_disable_warnings (false);
          the_settings.max_messages[MSG_S_WARNING] = max;
@@ -369,6 +408,20 @@ settings_set_max_messages (enum msg_severity severity, int max)
   the_settings.max_messages[severity] = max;
 }
 
   the_settings.max_messages[severity] = max;
 }
 
+/* Returns whether to expand macro invocations. */
+bool
+settings_get_mexpand (void)
+{
+  return the_settings.mexpand;
+}
+
+/* Sets whether to expand macro invocations. */
+void
+settings_set_mexpand (bool mexpand)
+{
+  the_settings.mexpand = mexpand;
+}
+
 /* Independent of get_printback, controls whether the commands
    generated by macro invocations are displayed. */
 bool
 /* Independent of get_printback, controls whether the commands
    generated by macro invocations are displayed. */
 bool
@@ -380,51 +433,52 @@ settings_get_mprint (void)
 /* Sets whether the commands generated by macro invocations are
    displayed. */
 void
 /* Sets whether the commands generated by macro invocations are
    displayed. */
 void
-settings_set_mprint ( bool mprint)
+settings_set_mprint (bool mprint)
 {
   the_settings.mprint = mprint;
 }
 
 {
   the_settings.mprint = mprint;
 }
 
-/* Implied limit of unbounded loop. */
+/* Returns the limit for loop iterations within a macro. */
 int
 int
-settings_get_mxloops (void)
+settings_get_miterate (void)
 {
 {
-  return the_settings.mxloops;
+  return the_settings.miterate;
 }
 
 }
 
-/* Set implied limit of unbounded loop. */
+/* Sets the limit for loop iterations within a macro. */
 void
 void
-settings_set_mxloops ( int mxloops)
+settings_set_miterate (int miterate)
 {
 {
-  the_settings.mxloops = mxloops;
+  the_settings.miterate = miterate;
 }
 
 }
 
-/* Whether a blank line is a command terminator. */
-bool
-settings_get_nulline (void)
+/* Returns the limit for recursion macro expansions. */
+int settings_get_mnest (void)
 {
 {
-  return the_settings.nulline;
+  return the_settings.mnest;
 }
 
 }
 
-/* Set whether a blank line is a command terminator. */
+/* Sets the limit for recursion macro expansions. */
 void
 void
-settings_set_nulline ( bool nulline)
+settings_set_mnest (int mnest)
 {
 {
-  the_settings.nulline = nulline;
+  the_settings.mnest = mnest;
 }
 
 }
 
-/* The character used to terminate commands. */
-char
-settings_get_endcmd (void)
+int settings_get_mxloops (void);
+void settings_set_mxloops (int);
+/* Implied limit of unbounded loop. */
+int
+settings_get_mxloops (void)
 {
 {
-  return the_settings.endcmd;
+  return the_settings.mxloops;
 }
 
 }
 
-/* Set the character used to terminate commands. */
+/* Set implied limit of unbounded loop. */
 void
 void
-settings_set_endcmd ( char endcmd)
+settings_set_mxloops (int mxloops)
 {
 {
-  the_settings.endcmd = endcmd;
+  the_settings.mxloops = mxloops;
 }
 
 /* Approximate maximum amount of memory to use for cases, in
 }
 
 /* Approximate maximum amount of memory to use for cases, in
@@ -448,7 +502,7 @@ settings_get_workspace_cases (const struct caseproto *proto)
    bytes. */
 
 void
    bytes. */
 
 void
-settings_set_workspace ( size_t workspace)
+settings_set_workspace (size_t workspace)
 {
   the_settings.workspace = workspace;
 }
 {
   the_settings.workspace = workspace;
 }
@@ -464,7 +518,7 @@ settings_get_format (void)
 /* Set default format for variables created by transformations
    and by DATA LIST {FREE,LIST}. */
 void
 /* Set default format for variables created by transformations
    and by DATA LIST {FREE,LIST}. */
 void
-settings_set_format ( const struct fmt_spec *default_format)
+settings_set_format (const struct fmt_spec *default_format)
 {
   the_settings.default_format = *default_format;
 }
 {
   the_settings.default_format = *default_format;
 }
@@ -479,38 +533,61 @@ settings_get_testing_mode (void)
 
 /* Set testing mode. */
 void
 
 /* Set testing mode. */
 void
-settings_set_testing_mode ( bool testing_mode)
+settings_set_testing_mode (bool testing_mode)
 {
   the_settings.testing_mode = testing_mode;
 }
 
 {
   the_settings.testing_mode = testing_mode;
 }
 
+int
+settings_get_fuzzbits (void)
+{
+  return the_settings.fuzzbits;
+}
+
+void
+settings_set_fuzzbits (int fuzzbits)
+{
+  the_settings.fuzzbits = fuzzbits;
+}
+
+int
+settings_get_scalemin (void)
+{
+  return the_settings.scalemin;
+}
+
+void
+settings_set_scalemin (int scalemin)
+{
+  the_settings.scalemin = scalemin;
+}
+
 /* Return the current algorithm setting */
 enum behavior_mode
 settings_get_algorithm (void)
 {
 /* Return the current algorithm setting */
 enum behavior_mode
 settings_get_algorithm (void)
 {
-  return *the_settings.algorithm;
+  return the_settings.cmd_algorithm;
 }
 
 /* Set the algorithm option globally. */
 void
 settings_set_algorithm (enum behavior_mode mode)
 {
 }
 
 /* Set the algorithm option globally. */
 void
 settings_set_algorithm (enum behavior_mode mode)
 {
-  global_algorithm = mode;
+  the_settings.global_algorithm = the_settings.cmd_algorithm = mode;
 }
 
 /* Set the algorithm option for this command only */
 void
 }
 
 /* Set the algorithm option for this command only */
 void
-settings_set_cmd_algorithm ( enum behavior_mode mode)
+settings_set_cmd_algorithm (enum behavior_mode mode)
 {
   the_settings.cmd_algorithm = mode;
 {
   the_settings.cmd_algorithm = mode;
-  the_settings.algorithm = &the_settings.cmd_algorithm;
 }
 
 /* Unset the algorithm option for this command */
 void
 unset_cmd_algorithm (void)
 {
 }
 
 /* Unset the algorithm option for this command */
 void
 unset_cmd_algorithm (void)
 {
-  the_settings.algorithm = &global_algorithm;
+  the_settings.cmd_algorithm = the_settings.global_algorithm;
 }
 
 /* Get the current syntax setting */
 }
 
 /* Get the current syntax setting */
@@ -522,90 +599,19 @@ settings_get_syntax (void)
 
 /* Set the syntax option */
 void
 
 /* Set the syntax option */
 void
-settings_set_syntax ( enum behavior_mode mode)
+settings_set_syntax (enum behavior_mode mode)
 {
   the_settings.syntax = mode;
 }
 
 \f
 {
   the_settings.syntax = mode;
 }
 
 \f
-
-/* Find the grouping characters in CC_STRING and set CC's
-   grouping and decimal members appropriately.  Returns true if
-   successful, false otherwise. */
-static bool
-find_cc_separators (const char *cc_string, struct fmt_number_style *cc)
-{
-  const char *sp;
-  int comma_cnt, dot_cnt;
-
-  /* Count commas and periods.  There must be exactly three of
-     one or the other, except that an apostrophe escapes a
-     following comma or period. */
-  comma_cnt = dot_cnt = 0;
-  for (sp = cc_string; *sp; sp++)
-    if (*sp == ',')
-      comma_cnt++;
-    else if (*sp == '.')
-      dot_cnt++;
-    else if (*sp == '\'' && (sp[1] == '.' || sp[1] == ',' || sp[1] == '\''))
-      sp++;
-
-  if ((comma_cnt == 3) == (dot_cnt == 3))
-    return false;
-
-  if (comma_cnt == 3)
-    {
-      cc->decimal = '.';
-      cc->grouping = ',';
-    }
-  else
-    {
-      cc->decimal = ',';
-      cc->grouping = '.';
-    }
-  return true;
-}
-
-/* Extracts a token from IN into AFFIX, using BUFFER for storage.  BUFFER must
-   have at least FMT_STYLE_AFFIX_MAX + 1 bytes of space.  Tokens are delimited
-   by GROUPING.  The token is truncated to at most FMT_STYLE_AFFIX_MAX bytes,
-   followed by a null terminator.  Returns the first character following the
-   token. */
-static const char *
-extract_cc_token (const char *in, int grouping, struct substring *affix,
-                  char buffer[FMT_STYLE_AFFIX_MAX + 1])
-{
-  size_t ofs = 0;
-
-  for (; *in != '\0' && *in != grouping; in++)
-    {
-      if (*in == '\'' && in[1] == grouping)
-        in++;
-      if (ofs < FMT_STYLE_AFFIX_MAX)
-        buffer[ofs++] = *in;
-    }
-  *affix = ss_buffer (buffer, ofs);
-
-  if (*in == grouping)
-    in++;
-  return in;
-}
-
 /* Sets custom currency specifier CC having name CC_NAME ('A' through
    'E') to correspond to the settings in CC_STRING. */
 bool
 settings_set_cc (const char *cc_string, enum fmt_type type)
 {
 /* Sets custom currency specifier CC having name CC_NAME ('A' through
    'E') to correspond to the settings in CC_STRING. */
 bool
 settings_set_cc (const char *cc_string, enum fmt_type type)
 {
-  char a[FMT_STYLE_AFFIX_MAX + 1];
-  char b[FMT_STYLE_AFFIX_MAX + 1];
-  char c[FMT_STYLE_AFFIX_MAX + 1];
-  char d[FMT_STYLE_AFFIX_MAX + 1];
-  struct fmt_number_style cc;
-
-  assert (fmt_get_category (type) == FMT_CAT_CUSTOM);
-
-  /* Determine separators. */
-  if (!find_cc_separators (cc_string, &cc))
+  struct fmt_number_style *style = fmt_number_style_from_string (cc_string);
+  if (!style)
     {
       msg (SE, _("%s: Custom currency string `%s' does not contain "
                  "exactly three periods or commas (or it contains both)."),
     {
       msg (SE, _("%s: Custom currency string `%s' does not contain "
                  "exactly three periods or commas (or it contains both)."),
@@ -613,36 +619,38 @@ settings_set_cc (const char *cc_string, enum fmt_type type)
       return false;
     }
 
       return false;
     }
 
-  cc_string = extract_cc_token (cc_string, cc.grouping, &cc.neg_prefix, a);
-  cc_string = extract_cc_token (cc_string, cc.grouping, &cc.prefix, b);
-  cc_string = extract_cc_token (cc_string, cc.grouping, &cc.suffix, c);
-  cc_string = extract_cc_token (cc_string, cc.grouping, &cc.neg_suffix, d);
-
-  fmt_settings_set_style (the_settings.styles, type, &cc);
-
+  fmt_settings_set_cc (&the_settings.styles, type, style);
   return true;
 }
 
   return true;
 }
 
-/* Returns the decimal point character for TYPE. */
-int
-settings_get_decimal_char (enum fmt_type type)
+void
+settings_set_decimal_char (char decimal)
 {
 {
-  return fmt_settings_get_style (the_settings.styles, type)->decimal;
+  the_settings.styles.decimal = decimal;
 }
 
 void
 }
 
 void
-settings_set_decimal_char (char decimal)
+settings_set_include_leading_zero (bool include_leading_zero)
+{
+  the_settings.styles.include_leading_zero = include_leading_zero;
+}
+
+const struct fmt_settings *
+settings_get_fmt_settings (void)
+{
+  return &the_settings.styles;
+}
+
+double
+settings_get_small (void)
 {
 {
-  fmt_settings_set_decimal (the_settings.styles, decimal);
+  return the_settings.small;
 }
 
 }
 
-/* Returns the number formatting style associated with the given
-   format TYPE. */
-const struct fmt_number_style *
-settings_get_style (enum fmt_type type)
+void
+settings_set_small (double small)
 {
 {
-  assert (is_fmt_type (type));
-  return fmt_settings_get_style (the_settings.styles, type);
+  the_settings.small = small;
 }
 
 /* Returns a string of the form "$#,###.##" according to FMT,
 }
 
 /* Returns a string of the form "$#,###.##" according to FMT,
@@ -657,22 +665,22 @@ settings_dollar_template (const struct fmt_spec *fmt)
 
   assert (fmt->type == FMT_DOLLAR);
 
 
   assert (fmt->type == FMT_DOLLAR);
 
-  fns = fmt_settings_get_style (the_settings.styles, fmt->type);
+  fns = fmt_settings_get_style (&the_settings.styles, fmt->type);
 
 
-  ds_put_char (&str, '$');
-  for (c = MAX (fmt->w - fmt->d - 1, 0); c > 0; )
+  ds_put_byte (&str, '$');
+  for (c = MAX (fmt->w - fmt->d - 1, 0); c > 0;)
     {
     {
-      ds_put_char (&str, '#');
+      ds_put_byte (&str, '#');
       if (--c % 4 == 0 && c > 0)
         {
       if (--c % 4 == 0 && c > 0)
         {
-          ds_put_char (&str, fns->grouping);
+          ds_put_byte (&str, fns->grouping);
           --c;
         }
     }
   if (fmt->d > 0)
     {
           --c;
         }
     }
   if (fmt->d > 0)
     {
-      ds_put_char (&str, fns->decimal);
-      ds_put_char_multiple (&str, '#', fmt->d);
+      ds_put_byte (&str, fns->decimal);
+      ds_put_byte_multiple (&str, '#', fmt->d);
     }
 
   return ds_cstr (&str);
     }
 
   return ds_cstr (&str);
@@ -692,3 +700,40 @@ settings_get_output_routing (enum settings_output_type type)
   assert (type < SETTINGS_N_OUTPUT_TYPES);
   return the_settings.output_routing[type] | SETTINGS_DEVICE_UNFILTERED;
 }
   assert (type < SETTINGS_N_OUTPUT_TYPES);
   return the_settings.output_routing[type] | SETTINGS_DEVICE_UNFILTERED;
 }
+
+enum settings_value_show
+settings_get_show_values (void)
+{
+  return the_settings.show_values;
+}
+
+void
+settings_set_show_values (enum settings_value_show s)
+{
+  the_settings.show_values = s;
+}
+
+
+enum settings_value_show
+settings_get_show_variables (void)
+{
+  return the_settings.show_variables;
+}
+
+void
+settings_set_show_variables (enum settings_value_show s)
+{
+  the_settings.show_variables = s;
+}
+
+enum settings_mdisplay
+settings_get_mdisplay (void)
+{
+  return the_settings.mdisplay;
+}
+
+void
+settings_set_mdisplay (enum settings_mdisplay mdisplay)
+{
+  the_settings.mdisplay = mdisplay;
+}