1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2005, 2006, 2009, 2010, 2011, 2014 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "value-parser.h"
24 #include "data/data-in.h"
25 #include "data/format.h"
26 #include "data/value.h"
27 #include "language/lexer/lexer.h"
28 #include "libpspp/cast.h"
29 #include "libpspp/i18n.h"
30 #include "libpspp/message.h"
31 #include "libpspp/str.h"
34 #define _(msgid) gettext (msgid)
35 #define N_(msgid) msgid
37 static bool parse_number (struct lexer *, double *, const enum fmt_type *);
39 /* Parses and stores a numeric value, or a range of the form "x
40 THRU y". Open-ended ranges may be specified as "LO(WEST) THRU
41 y" or "x THRU HI(GHEST)". Sets *X and *Y to the range or the
42 value and returns success.
44 Numeric values are always accepted. If FORMAT is nonnull,
45 then string values are also accepted, and converted to numeric
46 values using *FORMAT. */
48 parse_num_range (struct lexer *lexer,
49 double *x, double *y, const enum fmt_type *format)
51 int start_ofs = lex_ofs (lexer);
53 if (lex_match_id (lexer, "LO") || lex_match_id (lexer, "LOWEST"))
55 else if (!parse_number (lexer, x, format))
58 if (lex_match_id (lexer, "THRU"))
60 if (lex_match_id (lexer, "HI") || lex_match_id (lexer, "HIGHEST"))
62 else if (!parse_number (lexer, y, format))
68 lex_ofs_msg (lexer, SW, start_ofs, lex_ofs (lexer) - 1,
69 ("The high end of the range (%.*g) is below the low end "
70 "(%.*g). The range will be treated as if reversed."),
71 DBL_DIG + 1, *y, DBL_DIG + 1, *x);
77 lex_ofs_msg (lexer, SW, start_ofs, lex_ofs (lexer) - 1,
78 _("Ends of range are equal (%.*g)."), DBL_DIG + 1, *x);
86 lex_next_msg (lexer, SW, -1, -1,
87 _("%s or %s must be part of a range."),
97 /* Parses a number and stores it in *X. Returns success.
99 Numeric values are always accepted. If FORMAT is nonnull,
100 then string values are also accepted, and converted to numeric
101 values using *FORMAT. */
103 parse_number (struct lexer *lexer, double *x, const enum fmt_type *format)
105 if (lex_is_string (lexer) && format != NULL)
109 assert (fmt_get_category (*format) != FMT_CAT_STRING);
111 if (!data_in_msg (lex_tokss (lexer), "UTF-8", *format,
112 settings_get_fmt_settings (), &v, 0, NULL))
119 lex_next_error (lexer, -1, -1,
120 _("System-missing value is not valid here."));
126 if (lex_force_num (lexer))
128 *x = lex_number (lexer);
136 /* Parses the current token from LEXER into value V, which must already have
137 been initialized with the specified VAR's WIDTH. Returns true if
138 successful, false otherwise. */
140 parse_value (struct lexer *lexer, union value *v, const struct variable *var)
142 int width = var_get_width (var);
145 struct fmt_spec format = var_get_print_format (var);
146 return parse_number (lexer, &v->f, &format.type);
148 else if (lex_force_string (lexer))
150 struct substring out;
151 if (recode_pedantically (var_get_encoding (var), "UTF-8",
152 lex_tokss (lexer), NULL, &out))
154 lex_error (lexer, _("This string is not representable in the "
155 "dataset encoding."));
158 if (out.length > width)
160 lex_error (lexer, _("This %zu-byte string is too long for "
161 "variable %s with width %d."),
162 out.length, var_get_name (var), width);
167 value_copy_buf_rpad (v, width, CHAR_CAST (const uint8_t *, out.string),