Fix memory leak in AGGREGATE.
[pspp] / src / language / lexer / range-parser.c
1 #include <config.h>
2 #include "range-parser.h"
3 #include <stdbool.h>
4 #include <data/data-in.h>
5 #include <libpspp/message.h>
6 #include "lexer.h"
7 #include <libpspp/magic.h>
8 #include <libpspp/str.h>
9 #include <data/value.h>
10
11 #include "gettext.h"
12 #define _(msgid) gettext (msgid)
13 #define N_(msgid) msgid
14
15 static bool parse_number (double *, const struct fmt_spec *);
16
17 /* Parses and stores a numeric value, or a range of the form "x
18    THRU y".  Open-ended ranges may be specified as "LO(WEST) THRU
19    y" or "x THRU HI(GHEST)".  Sets *X and *Y to the range or the
20    value and returns success.
21
22    Numeric values are always accepted.  If F is nonnull, then
23    string values are also accepted, and converted to numeric
24    values using the specified format. */
25 bool
26 parse_num_range (double *x, double *y, const struct fmt_spec *f) 
27 {
28   if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
29     *x = LOWEST;
30   else if (!parse_number (x, f))
31     return false;
32
33   if (lex_match_id ("THRU")) 
34     {
35       if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
36         *y = HIGHEST;
37       else if (!parse_number (y, f))
38         return false;
39
40       if (*y < *x) 
41         {
42           double t;
43           msg (SW, _("Low end of range (%g) is below high end (%g).  "
44                      "The range will be treated as reversed."),
45                *x, *y);
46           t = *x;
47           *x = *y;
48           *y = t;
49         }
50       else if (*x == *y) 
51         msg (SW, _("Ends of range are equal (%g)."), *x);
52
53       return true;
54     }
55   else
56     {
57       if (*x == LOWEST) 
58         {
59           msg (SE, _("LO or LOWEST must be part of a range."));
60           return false;
61         }
62       *y = *x;
63     }
64   
65   return true;
66 }
67
68 /* Parses a number and stores it in *X.  Returns success.
69
70    Numeric values are always accepted.  If F is nonnull, then
71    string values are also accepted, and converted to numeric
72    values using the specified format. */
73 static bool
74 parse_number (double *x, const struct fmt_spec *f)
75 {
76   if (lex_is_number ()) 
77     {
78       *x = lex_number ();
79       lex_get ();
80       return true;
81     }
82   else if (token == T_STRING && f != NULL) 
83     {
84       struct data_in di;
85       union value v;
86       di.s = ds_data (&tokstr);
87       di.e = ds_end (&tokstr);
88       di.v = &v;
89       di.flags = 0;
90       di.f1 = 1;
91       di.f2 = ds_length (&tokstr);
92       di.format = *f;
93       data_in (&di);
94       lex_get ();
95       *x = v.f;
96       if (*x == SYSMIS)
97         {
98           lex_error (_("System-missing value is not valid here."));
99           return false;
100         }
101       return true;
102     }
103   else 
104     {
105       if (f != NULL)
106         lex_error (_("expecting number or data string"));
107       else
108         lex_force_num ();
109       return false; 
110     }
111 }