format: Make fmt_check() easier to translate.
[pspp] / src / data / format.c
index d0b87a503f198a8d7db58978abbf6c2fa27a6d06..f323424d0868fbf128629bbf845e7bb94726a813 100644 (file)
@@ -63,13 +63,13 @@ fmt_settings_uninit (struct fmt_settings *settings)
     fmt_number_style_destroy (settings->ccs[i]);
 }
 
-void
-fmt_settings_copy (struct fmt_settings *new, const struct fmt_settings *old)
+struct fmt_settings
+fmt_settings_copy (const struct fmt_settings *old)
 {
-  new->epoch = old->epoch;
-  new->decimal = old->decimal;
+  struct fmt_settings new = *old;
   for (int i = 0; i < FMT_N_CCS; i++)
-    new->ccs[i] = fmt_number_style_clone (old->ccs[i]);
+    new.ccs[i] = fmt_number_style_clone (old->ccs[i]);
+  return new;
 }
 
 static size_t
@@ -184,10 +184,7 @@ fmt_settings_set_cc (struct fmt_settings *settings, enum fmt_type type,
 struct fmt_spec
 fmt_for_input (enum fmt_type type, int w, int d)
 {
-  struct fmt_spec f;
-  f.type = type;
-  f.w = w;
-  f.d = d;
+  struct fmt_spec f = { .type = type, .w = w, .d = d };
   assert (fmt_check_input (&f));
   return f;
 }
@@ -197,10 +194,7 @@ fmt_for_input (enum fmt_type type, int w, int d)
 struct fmt_spec
 fmt_for_output (enum fmt_type type, int w, int d)
 {
-  struct fmt_spec f;
-  f.type = type;
-  f.w = w;
-  f.d = d;
+  struct fmt_spec f = { .type = type, .w = w, .d = d };
   assert (fmt_check_output (&f));
   return f;
 }
@@ -208,7 +202,8 @@ fmt_for_output (enum fmt_type type, int w, int d)
 /* Returns the output format specifier corresponding to input
    format specifier INPUT. */
 struct fmt_spec
-fmt_for_output_from_input (const struct fmt_spec *input)
+fmt_for_output_from_input (const struct fmt_spec *input,
+                           const struct fmt_settings *settings)
 {
   struct fmt_spec output;
 
@@ -237,7 +232,7 @@ fmt_for_output_from_input (const struct fmt_spec *input)
     case FMT_PCT:
       {
         const struct fmt_number_style *style =
-         settings_get_style (input->type);
+         fmt_settings_get_style (settings, input->type);
 
         output.w += fmt_affix_width (style);
         if (style->grouping != 0 && input->w - input->d >= 3)
@@ -344,14 +339,12 @@ fmt_default_for_width (int width)
 bool
 fmt_check (const struct fmt_spec *spec, enum fmt_use use)
 {
-  const char *io_fmt;
   char str[FMT_STRING_LEN_MAX + 1];
   int min_w, max_w, max_d;
 
   assert (is_fmt_type (spec->type));
   fmt_to_string (spec, str);
 
-  io_fmt = use == FMT_FOR_INPUT ? _("Input format") : _("Output format");
   if (use == FMT_FOR_INPUT && !fmt_usable_for_input (spec->type))
     {
       msg (SE, _("Format %s may not be used for input."), str);
@@ -361,8 +354,14 @@ fmt_check (const struct fmt_spec *spec, enum fmt_use use)
   if (spec->w % fmt_step_width (spec->type))
     {
       assert (fmt_step_width (spec->type) == 2);
-      msg (SE, _("%s specifies width %d, but %s requires an even width."),
-           str, spec->w, fmt_name (spec->type));
+      if (use == FMT_FOR_INPUT)
+        msg (SE, _("Input format %s specifies width %d, "
+                   "but %s requires an even width."),
+             str, spec->w, fmt_name (spec->type));
+      else
+        msg (SE, _("Output format %s specifies width %d, "
+                   "but %s requires an even width."),
+             str, spec->w, fmt_name (spec->type));
       return false;
     }
 
@@ -370,39 +369,80 @@ fmt_check (const struct fmt_spec *spec, enum fmt_use use)
   max_w = fmt_max_width (spec->type, use);
   if (spec->w < min_w || spec->w > max_w)
     {
-      msg (SE, _("%s %s specifies width %d, but "
-                 "%s requires a width between %d and %d."),
-           io_fmt, str, spec->w, fmt_name (spec->type), min_w, max_w);
+      if (use == FMT_FOR_INPUT)
+        msg (SE, _("Input format %s specifies width %d, but "
+                   "%s requires a width between %d and %d."),
+             str, spec->w, fmt_name (spec->type), min_w, max_w);
+      else
+        msg (SE, _("Output format %s specifies width %d, but "
+                   "%s requires a width between %d and %d."),
+             str, spec->w, fmt_name (spec->type), min_w, max_w);
       return false;
     }
 
   max_d = fmt_max_decimals (spec->type, spec->w, use);
   if (!fmt_takes_decimals (spec->type) && spec->d != 0)
     {
-      msg (SE, ngettext ("%s %s specifies %d decimal place, but "
-                         "%s does not allow any decimals.",
-                         "%s %s specifies %d decimal places, but "
-                         "%s does not allow any decimals.",
-                         spec->d),
-           io_fmt, str, spec->d, fmt_name (spec->type));
+      if (use == FMT_FOR_INPUT)
+        msg (SE, ngettext ("Input format %s specifies %d decimal place, but "
+                           "%s does not allow any decimals.",
+                           "Input format %s specifies %d decimal places, but "
+                           "%s does not allow any decimals.",
+                           spec->d),
+             str, spec->d, fmt_name (spec->type));
+      else
+        msg (SE, ngettext ("Output format %s specifies %d decimal place, but "
+                           "%s does not allow any decimals.",
+                           "Output format %s specifies %d decimal places, but "
+                           "%s does not allow any decimals.",
+                           spec->d),
+             str, spec->d, fmt_name (spec->type));
       return false;
     }
   else if (spec->d > max_d)
     {
       if (max_d > 0)
-        msg (SE, ngettext ("%s %s specifies %d decimal place, but "
-                           "the given width allows at most %d decimals.",
-                           "%s %s specifies %d decimal places, but "
-                           "the given width allows at most %d decimals.",
-                           spec->d),
-             io_fmt, str, spec->d, max_d);
+        {
+          if (use == FMT_FOR_INPUT)
+            msg (SE, ngettext ("Input format %s specifies %d decimal place, "
+                               "but the given width allows at most "
+                               "%d decimals.",
+                               "Input format %s specifies %d decimal places, "
+                               "but the given width allows at most "
+                               "%d decimals.",
+                               spec->d),
+                 str, spec->d, max_d);
+          else
+            msg (SE, ngettext ("Output format %s specifies %d decimal place, "
+                               "but the given width allows at most "
+                               "%d decimals.",
+                               "Output format %s specifies %d decimal places, "
+                               "but the given width allows at most "
+                               "%d decimals.",
+                               spec->d),
+                 str, spec->d, max_d);
+        }
       else
-        msg (SE, ngettext ("%s %s specifies %d decimal place, but "
-                           "the given width does not allow for any decimals.",
-                           "%s %s specifies %d decimal places, but "
-                           "the given width does not allow for any decimals.",
-                           spec->d),
-             io_fmt, str, spec->d);
+        {
+          if (use == FMT_FOR_INPUT)
+            msg (SE, ngettext ("Input format %s specifies %d decimal place, "
+                               "but the given width does not allow "
+                               "for any decimals.",
+                               "Input format %s specifies %d decimal places, "
+                               "but the given width does not allow "
+                               "for any decimals.",
+                               spec->d),
+                 str, spec->d);
+          else
+            msg (SE, ngettext ("Output format %s specifies %d decimal place, "
+                               "but the given width does not allow "
+                               "for any decimals.",
+                               "Output format %s specifies %d decimal places, "
+                               "but the given width does not allow "
+                               "for any decimals.",
+                               spec->d),
+                 str, spec->d);
+        }
       return false;
     }
 
@@ -1143,12 +1183,8 @@ fmt_clamp_width (struct fmt_spec *fmt, enum fmt_use use)
 static void
 fmt_clamp_decimals (struct fmt_spec *fmt, enum fmt_use use)
 {
-  int max_d;
-
-  max_d = fmt_max_decimals (fmt->type, fmt->w, use);
-  if (fmt->d < 0)
-    fmt->d = 0;
-  else if (fmt->d > max_d)
+  int max_d = fmt_max_decimals (fmt->type, fmt->w, use);
+  if (fmt->d > max_d)
     fmt->d = max_d;
 }
 \f
@@ -1156,7 +1192,7 @@ static struct fmt_affix
 fmt_affix_clone (const struct fmt_affix *old)
 {
   return (struct fmt_affix) {
-    .s = old->s ? xstrdup (old->s) : NULL,
+    .s = xstrdup_if_nonnull (old->s),
     .width = old->width,
   };
 }
@@ -1165,7 +1201,7 @@ fmt_affix_clone (const struct fmt_affix *old)
 static void
 fmt_affix_free (struct fmt_affix *affix)
 {
-  if (affix->s[0])
+  if (affix->s)
     free (affix->s);
 }
 
@@ -1239,6 +1275,34 @@ fmt_number_style_from_string (const char *s)
   return style;
 }
 
+static void
+format_cc (struct string *out, const char *in, char grouping)
+{
+  while (*in != '\0')
+    {
+      char c = *in++;
+      if (c == grouping || c == '\'')
+        ds_put_byte (out, '\'');
+      else if (c == '"')
+        ds_put_byte (out, '"');
+      ds_put_byte (out, c);
+    }
+}
+
+char *
+fmt_number_style_to_string (const struct fmt_number_style *cc)
+{
+  struct string out = DS_EMPTY_INITIALIZER;
+  format_cc (&out, cc->neg_prefix.s, cc->grouping);
+  ds_put_byte (&out, cc->grouping);
+  format_cc (&out, cc->prefix.s, cc->grouping);
+  ds_put_byte (&out, cc->grouping);
+  format_cc (&out, cc->suffix.s, cc->grouping);
+  ds_put_byte (&out, cc->grouping);
+  format_cc (&out, cc->neg_suffix.s, cc->grouping);
+  return ds_steal_cstr (&out);
+}
+
 struct fmt_number_style *
 fmt_number_style_clone (const struct fmt_number_style *old)
 {
@@ -1305,7 +1369,7 @@ get_fmt_desc (enum fmt_type type)
   return &formats[type];
 }
 
-const struct fmt_spec F_8_0 = {FMT_F, 8, 0};
-const struct fmt_spec F_8_2 = {FMT_F, 8, 2};
-const struct fmt_spec F_4_3 = {FMT_F, 4, 3};
-const struct fmt_spec F_5_1 = {FMT_F, 5, 1};
+const struct fmt_spec F_8_0 = { .type = FMT_F, .w = 8, .d = 0 };
+const struct fmt_spec F_8_2 = { .type = FMT_F, .w = 8, .d = 2 };
+const struct fmt_spec F_4_3 = { .type = FMT_F, .w = 4, .d = 3 };
+const struct fmt_spec F_5_1 = { .type = FMT_F, .w = 5, .d = 1 };