data-in: Eliminate "implied_decimals" parameter from data_in().
[pspp] / src / language / lexer / value-parser.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2005, 2006, 2009, 2010 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include "value-parser.h"
20
21 #include <stdbool.h>
22
23 #include "data/data-in.h"
24 #include "data/format.h"
25 #include "data/value.h"
26 #include "language/lexer/lexer.h"
27 #include "libpspp/cast.h"
28 #include "libpspp/message.h"
29 #include "libpspp/str.h"
30
31 #include "gettext.h"
32 #define _(msgid) gettext (msgid)
33 #define N_(msgid) msgid
34
35 static bool parse_number (struct lexer *, double *, const enum fmt_type *);
36
37 /* Parses and stores a numeric value, or a range of the form "x
38    THRU y".  Open-ended ranges may be specified as "LO(WEST) THRU
39    y" or "x THRU HI(GHEST)".  Sets *X and *Y to the range or the
40    value and returns success.
41
42    Numeric values are always accepted.  If FORMAT is nonnull,
43    then string values are also accepted, and converted to numeric
44    values using *FORMAT. */
45 bool
46 parse_num_range (struct lexer *lexer,
47                  double *x, double *y, const enum fmt_type *format)
48 {
49   if (lex_match_id (lexer, "LO") || lex_match_id (lexer, "LOWEST"))
50     *x = LOWEST;
51   else if (!parse_number (lexer, x, format))
52     return false;
53
54   if (lex_match_id (lexer, "THRU"))
55     {
56       if (lex_match_id (lexer, "HI") || lex_match_id (lexer, "HIGHEST"))
57         *y = HIGHEST;
58       else if (!parse_number (lexer, y, format))
59         return false;
60
61       if (*y < *x)
62         {
63           double t;
64           msg (SW, _("Low end of range (%g) is below high end (%g).  "
65                      "The range will be treated as reversed."),
66                *x, *y);
67           t = *x;
68           *x = *y;
69           *y = t;
70         }
71       else if (*x == *y)
72         msg (SW, _("Ends of range are equal (%g)."), *x);
73
74       return true;
75     }
76   else
77     {
78       if (*x == LOWEST)
79         {
80           msg (SE, _("LO or LOWEST must be part of a range."));
81           return false;
82         }
83       *y = *x;
84     }
85
86   return true;
87 }
88
89 /* Parses a number and stores it in *X.  Returns success.
90
91    Numeric values are always accepted.  If FORMAT is nonnull,
92    then string values are also accepted, and converted to numeric
93    values using *FORMAT. */
94 static bool
95 parse_number (struct lexer *lexer, double *x, const enum fmt_type *format)
96 {
97   if (lex_is_number (lexer))
98     {
99       *x = lex_number (lexer);
100       lex_get (lexer);
101       return true;
102     }
103   else if (lex_is_string (lexer) && format != NULL)
104     {
105       union value v;
106       assert (! (fmt_get_category (*format) & ( FMT_CAT_STRING )));
107       data_in (ds_ss (lex_tokstr (lexer)), LEGACY_NATIVE, *format, 0, 0,
108                NULL, &v, 0);
109       lex_get (lexer);
110       *x = v.f;
111       if (*x == SYSMIS)
112         {
113           msg (SE, _("System-missing value is not valid here."));
114           return false;
115         }
116       return true;
117     }
118   else
119     {
120       if (format != NULL)
121         lex_error (lexer, _("expecting number or data string"));
122       else
123         lex_force_num (lexer);
124       return false;
125     }
126 }
127
128 /* Parses the current token from LEXER into value V, which must
129    already have been initialized with the specified WIDTH.
130    Returns true if successful, false otherwise. */
131 bool
132 parse_value (struct lexer *lexer, union value *v, int width)
133 {
134   if (width == 0)
135     {
136       if (!lex_force_num (lexer))
137         return false;
138       v->f = lex_tokval (lexer);
139     }
140   else if (lex_force_string (lexer))
141     {
142       const char *s = ds_cstr (lex_tokstr (lexer));
143       value_copy_str_rpad (v, width, CHAR_CAST_BUG (const uint8_t *, s), ' ');
144     }
145   else
146     return false;
147
148   lex_get (lexer);
149
150   return true;
151 }