treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp] / src / language / tests / float-format.c
index 817246bc8167dbcd0df48fcca125e951b109c320..e1d91168b0cac391f788fd87d09738355c1a0cd5 100644 (file)
 
 #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,34 +136,47 @@ 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, T_LPAREN)
           || !lex_force_string (lexer))
         return false;
 
-      length = ss_length (lex_tokss (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, ss_data (lex_tokss (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_CAST_BUG (char *,fp->data), lex_tokcstr (lexer), sizeof fp->data);
+          memcpy (fp->data, s.string, s.length);
         }
 
       lex_get (lexer);
@@ -235,26 +275,26 @@ 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.");
           return CMD_FAILURE;
         }
-      if (!parse_fp (lexer, &fp[fp_cnt++]))
+      if (!parse_fp (lexer, &fp[n_fps++]))
         return CMD_FAILURE;
 
-      if (lex_token (lexer) == T_ENDCMD && fp_cnt > 1)
+      if (lex_token (lexer) == T_ENDCMD && n_fps > 1)
         break;
       else if (!lex_force_match (lexer, T_EQUALS))
         return CMD_FAILURE;
 
-      if (fp_cnt == 1)
+      if (n_fps == 1)
         {
           if (lex_match (lexer, T_EQUALS))
             bijective = true;
@@ -279,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;
     }
@@ -288,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;
     }