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);
144 return parse_number (lexer, &v->f, &var_get_print_format (var)->type);
145 else if (lex_force_string (lexer))
147 struct substring out;
148 if (recode_pedantically (var_get_encoding (var), "UTF-8",
149 lex_tokss (lexer), NULL, &out))
151 lex_error (lexer, _("This string is not representable in the "
152 "dataset encoding."));
155 if (out.length > width)
157 lex_error (lexer, _("This %zu-byte string is too long for "
158 "variable %s with width %d."),
159 out.length, var_get_name (var), width);
164 value_copy_buf_rpad (v, width, CHAR_CAST (const uint8_t *, out.string),