/* 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
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, _("%d-byte string needed but %d-byte string supplied."),
- (int) float_get_size (fp->format), (int) 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
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,
{
if (fp_cnt >= 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++]))
return CMD_FAILURE;
- if (lex_token (lexer) == '.' && fp_cnt > 1)
+ if (lex_token (lexer) == T_ENDCMD && fp_cnt > 1)
break;
- else if (!lex_force_match (lexer, '='))
+ else if (!lex_force_match (lexer, T_EQUALS))
return CMD_FAILURE;
if (fp_cnt == 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;
}