/* 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
{"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. */
{
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;
return true;
}
- lex_error (lexer, "expecting floating-point format identifier");
+ lex_error (lexer, "Syntax error expecting floating-point format identifier.");
return false;
}
{
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
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);
}
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
/* Renders SRC, which contains SRC_SIZE bytes of a floating-point
number in the given FORMAT, as relatively human-readable
null-terminated string in the DST_SIZE bytes in DST. DST_SIZE
- must be be large enough to hold the output. */
+ must be large enough to hold the output. */
static void
make_printable (enum float_format format, const void *src_, size_t src_size,
char *dst, size_t dst_size)
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,
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;
}
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;
}
{
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;
}
{
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;
}