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