treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp] / src / language / tests / float-format.c
index fed19479d2fe8043ee1a060e88b49b2fc4221c3e..e1d91168b0cac391f788fd87d09738355c1a0cd5 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2006 Free Software Foundation, Inc.
+   Copyright (C) 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
 
 #include <config.h>
 
-#include <libpspp/float-format.h>
+#include "libpspp/float-format.h"
 
-#include "gettext.h"
 #include <inttypes.h>
+#include <limits.h>
+#include <unistr.h>
 
-#include <language/command.h>
-#include <language/lexer/lexer.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
-#include <libpspp/str.h>
-
-#define _(msgid) gettext (msgid)
+#include "language/command.h"
+#include "language/lexer/lexer.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/message.h"
+#include "libpspp/str.h"
 
 /* Maximum supported size of a floating-point number, in bytes. */
 #define FP_MAX_SIZE 32
@@ -61,7 +61,7 @@ static const struct assoc fp_formats[] =
     {"X", FLOAT_HEX},
     {"FP", FLOAT_FP},
   };
-static const size_t format_cnt = sizeof fp_formats / sizeof *fp_formats;
+static const size_t n_formats = sizeof fp_formats / sizeof *fp_formats;
 
 /* Parses a floating-point format name into *FORMAT,
    and returns success. */
@@ -70,7 +70,7 @@ parse_float_format (struct lexer *lexer, enum float_format *format)
 {
   size_t i;
 
-  for (i = 0; i < format_cnt; i++)
+  for (i = 0; i < n_formats; i++)
     if (lex_match_id (lexer, fp_formats[i].name))
       {
         *format = fp_formats[i].format;
@@ -86,13 +86,39 @@ get_float_format_name (enum float_format format)
 {
   size_t i;
 
-  for (i = 0; i < format_cnt; i++)
+  for (i = 0; i < n_formats; i++)
     if (fp_formats[i].format == format)
       return fp_formats[i].name;
 
   NOT_REACHED ();
 }
 
+/* Returns the integer value of (hex) digit C. */
+static int
+digit_value (int c)
+{
+  switch (c)
+    {
+    case '0': return 0;
+    case '1': return 1;
+    case '2': return 2;
+    case '3': return 3;
+    case '4': return 4;
+    case '5': return 5;
+    case '6': return 6;
+    case '7': return 7;
+    case '8': return 8;
+    case '9': return 9;
+    case 'a': case 'A': return 10;
+    case 'b': case 'B': return 11;
+    case 'c': case 'C': return 12;
+    case 'd': case 'D': return 13;
+    case 'e': case 'E': return 14;
+    case 'f': case 'F': return 15;
+    default: return INT_MAX;
+    }
+}
+
 /* Parses a number in the form FORMAT(STRING), where FORMAT is
    the name of the format and STRING gives the number's
    representation.  Also supports ordinary floating-point numbers
@@ -100,6 +126,7 @@ get_float_format_name (enum float_format format)
 static bool
 parse_fp (struct lexer *lexer, struct fp *fp)
 {
+  memset (fp, 0, sizeof *fp);
   if (lex_is_number (lexer))
     {
       double number = lex_number (lexer);
@@ -109,38 +136,51 @@ parse_fp (struct lexer *lexer, struct fp *fp)
     }
   else if (lex_token (lexer) == T_ID)
     {
-      size_t length;
+      struct substring s;
 
       if (!parse_float_format (lexer, &fp->format)
-          || !lex_force_match (lexer, '(')
+          || !lex_force_match (lexer, T_LPAREN)
           || !lex_force_string (lexer))
         return false;
 
-      length = ds_length (lex_tokstr (lexer));
+      s = lex_tokss (lexer);
       if (fp->format != FLOAT_HEX)
         {
-          if (length != float_get_size (fp->format))
+          size_t i;
+
+          if (s.length != float_get_size (fp->format) * 2)
             {
-              msg (SE, _("%zu-byte string needed but %zu-byte string "
-                         "supplied."),
-                   float_get_size (fp->format), length);
+              msg (SE, "%zu-byte string needed but %zu-byte string "
+                   "supplied.", float_get_size (fp->format), s.length);
               return false;
             }
-          assert (length <= sizeof fp->data);
-          memcpy (fp->data, ds_data (lex_tokstr (lexer)), length);
+          assert (s.length / 2 <= sizeof fp->data);
+          for (i = 0; i < s.length / 2; i++)
+            {
+              int hi = digit_value (s.string[i * 2]);
+              int lo = digit_value (s.string[i * 2 + 1]);
+
+              if (hi >= 16 || lo >= 16)
+                {
+                  msg (SE, "Invalid hex digit in string.");
+                  return false;
+                }
+
+              fp->data[i] = hi * 16 + lo;
+            }
         }
       else
         {
-          if (length >= sizeof fp->data)
+          if (s.length >= sizeof fp->data)
             {
-              msg (SE, _("Hexadecimal floating constant too long."));
+              msg (SE, "Hexadecimal floating constant too long.");
               return false;
             }
-          strncpy ((char *) fp->data, ds_cstr (lex_tokstr (lexer)), sizeof fp->data);
+          memcpy (fp->data, s.string, s.length);
         }
 
       lex_get (lexer);
-      if (!lex_force_match (lexer, ')'))
+      if (!lex_force_match (lexer, T_RPAREN))
         return false;
     }
   else
@@ -197,9 +237,8 @@ mismatch (const struct fp *from, const struct fp *to, char *result,
       make_printable (to->format, to->data, to_size, expected,
                       sizeof expected);
       make_printable (to->format, result, to_size, actual, sizeof actual);
-      msg (SE,
-           _("%s conversion of %s from %s to %s should have produced %s "
-             "but actually produced %s."),
+      msg (SE, "%s conversion of %s from %s to %s should have produced %s "
+           "but actually produced %s.",
            conversion_type,
            original, get_float_format_name (from->format),
            get_float_format_name (to->format), expected,
@@ -236,28 +275,28 @@ int
 cmd_debug_float_format (struct lexer *lexer, struct dataset *ds UNUSED)
 {
   struct fp fp[16];
-  size_t fp_cnt = 0;
+  size_t n_fps = 0;
   bool bijective = false;
   bool ok;
 
   for (;;)
     {
-      if (fp_cnt >= sizeof fp / sizeof *fp)
+      if (n_fps >= sizeof fp / sizeof *fp)
         {
-          msg (SE, _("Too many values in single command."));
+          msg (SE, "Too many values in single command.");
           return CMD_FAILURE;
         }
-      if (!parse_fp (lexer, &fp[fp_cnt++]))
+      if (!parse_fp (lexer, &fp[n_fps++]))
         return CMD_FAILURE;
 
-      if (lex_token (lexer) == '.' && fp_cnt > 1)
+      if (lex_token (lexer) == T_ENDCMD && n_fps > 1)
         break;
-      else if (!lex_force_match (lexer, '='))
+      else if (!lex_force_match (lexer, T_EQUALS))
         return CMD_FAILURE;
 
-      if (fp_cnt == 1)
+      if (n_fps == 1)
         {
-          if (lex_match (lexer, '='))
+          if (lex_match (lexer, T_EQUALS))
             bijective = true;
           else if (lex_match (lexer, T_GT))
             bijective = false;
@@ -269,7 +308,7 @@ cmd_debug_float_format (struct lexer *lexer, struct dataset *ds UNUSED)
         }
       else
         {
-          if ((bijective && !lex_force_match (lexer, '='))
+          if ((bijective && !lex_force_match (lexer, T_EQUALS))
               || (!bijective && !lex_force_match (lexer, T_GT)))
             return CMD_FAILURE;
         }
@@ -280,8 +319,8 @@ cmd_debug_float_format (struct lexer *lexer, struct dataset *ds UNUSED)
     {
       size_t i, j;
 
-      for (i = 0; i < fp_cnt; i++)
-        for (j = 0; j < fp_cnt; j++)
+      for (i = 0; i < n_fps; i++)
+        for (j = 0; j < n_fps; j++)
           if (!verify_conversion (&fp[i], &fp[j]))
             ok = false;
     }
@@ -289,7 +328,7 @@ cmd_debug_float_format (struct lexer *lexer, struct dataset *ds UNUSED)
     {
       size_t i;
 
-      for (i = 1; i < fp_cnt; i++)
+      for (i = 1; i < n_fps; i++)
         if (!verify_conversion (&fp[i - 1], &fp[i]))
           ok = false;
     }