format: Optimize fmt_from_io().
[pspp] / src / data / format.c
index a319a182ccf7fb14ef3dba0abe94ea03a56910b7..3907016cf4dac66ba021694b175e96ef67b2761a 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2010 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
@@ -408,6 +408,61 @@ fmt_resize (struct fmt_spec *fmt, int width)
       /* Still numeric. */
     }
 }
+
+/* Adjusts FMT's width and decimal places to be valid for an
+   input format (if FOR_INPUT) or an output format (if
+   !FOR_INPUT).  */
+void
+fmt_fix (struct fmt_spec *fmt, bool for_input)
+{
+  int min_w, max_w;
+  int max_d;
+
+  /* Clamp width to those allowed by format. */
+  min_w = fmt_min_width (fmt->type, for_input);
+  max_w = fmt_max_width (fmt->type, for_input);
+  if (fmt->w < min_w)
+    fmt->w = min_w;
+  else if (fmt->w > max_w)
+    fmt->w = max_w;
+
+  /* First, if FMT has more decimal places than allowed, attempt
+     to increase FMT's width until that number of decimal places
+     can be achieved. */
+  if (fmt->d > fmt_max_decimals (fmt->type, fmt->w, for_input))
+    {
+      int w;
+      for (w = fmt->w; w <= max_w; w++)
+        if (fmt_max_decimals (fmt->type, w, for_input) >= fmt->d)
+          {
+            fmt->w = w;
+            break;
+          }
+    }
+
+  /* Clamp decimals to those allowed by format and width. */
+  max_d = fmt_max_decimals (fmt->type, fmt->w, for_input);
+  if (fmt->d < 0)
+    fmt->d = 0;
+  else if (fmt->d > max_d)
+    fmt->d = max_d;
+}
+
+/* Adjusts FMT's width and decimal places to be valid for an
+   input format.  */
+void
+fmt_fix_input (struct fmt_spec *fmt)
+{
+  fmt_fix (fmt, true);
+}
+
+/* Adjusts FMT's width and decimal places to be valid for an
+   output format.  */
+void
+fmt_fix_output (struct fmt_spec *fmt)
+{
+  fmt_fix (fmt, false);
+}
 \f
 /* Describes a display format. */
 struct fmt_desc
@@ -717,15 +772,16 @@ fmt_to_io (enum fmt_type type)
 bool
 fmt_from_io (int io, enum fmt_type *fmt_type)
 {
-  enum fmt_type type;
-
-  for (type = 0; type < FMT_NUMBER_OF_FORMATS; type++)
-    if (get_fmt_desc (type)->io == io)
-      {
-        *fmt_type = type;
-        return true;
-      }
-  return false;
+  switch (io)
+    {
+#define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY)     \
+    case IO:                                          \
+      *fmt_type = FMT_##NAME;                           \
+      return true;
+#include "format.def"
+    default:
+      return false;
+    }
 }
 
 /* Returns true if TYPE may be used as an input format,
@@ -923,3 +979,5 @@ get_fmt_desc (enum fmt_type type)
   assert (is_fmt_type (type));
   return &formats[type];
 }
+
+const struct fmt_spec F_8_0 = {FMT_F, 8, 0};