fixed constness
[pspp-builds.git] / src / mis-val.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
5    This program is free software; you can redistribute it and/or
6    modify it under the terms of the GNU General Public License as
7    published by the Free Software Foundation; either version 2 of the
8    License, or (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301, USA. */
19
20 #include <config.h>
21 #include "error.h"
22 #include <stdlib.h>
23 #include "command.h"
24 #include "data-in.h"
25 #include "error.h"
26 #include "lexer.h"
27 #include "magic.h"
28 #include "str.h"
29 #include "var.h"
30
31 #include "gettext.h"
32 #define _(msgid) gettext (msgid)
33
34 #include "debug-print.h"
35
36 static bool parse_number (double *, const struct fmt_spec *);
37
38 int
39 cmd_missing_values (void)
40 {
41   struct variable **v;
42   int nv;
43
44   int retval = CMD_PART_SUCCESS_MAYBE;
45   bool deferred_errors = false;
46
47   while (token != '.')
48     {
49       int i;
50       
51
52       if (!parse_variables (default_dict, &v, &nv, PV_NONE)) 
53         goto done;
54
55       if (!lex_match ('('))
56         {
57           lex_error (_("expecting `('"));
58           goto done;
59         }
60
61       for (i = 0; i < nv; i++)
62         mv_init (&v[i]->miss, v[i]->width);
63
64       if (!lex_match (')')) 
65         {
66           struct missing_values mv;
67
68           for (i = 0; i < nv; i++)
69             if (v[i]->type != v[0]->type)
70               {
71                 const struct variable *n = v[0]->type == NUMERIC ? v[0] : v[i];
72                 const struct variable *s = v[0]->type == NUMERIC ? v[i] : v[0];
73                 msg (SE, _("Cannot mix numeric variables (e.g. %s) and "
74                            "string variables (e.g. %s) within a single list."),
75                      n->name, s->name);
76                 goto done;
77               }
78
79           if (v[0]->type == NUMERIC) 
80             {
81               mv_init (&mv, 0);
82               while (!lex_match (')'))
83                 {
84                   double x;
85
86                   if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
87                     x = LOWEST;
88                   else if (!parse_number (&x, &v[0]->print))
89                     goto done;
90
91                   if (lex_match_id ("THRU")) 
92                     {
93                       double y;
94                       
95                       if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
96                         y = HIGHEST;
97                       else if (!parse_number (&y, &v[0]->print))
98                         goto done;
99
100                       if (x == LOWEST && y == HIGHEST)
101                         {
102                           msg (SE, _("LO THRU HI is an invalid range."));
103                           deferred_errors = true;
104                         }
105                       else if (!mv_add_num_range (&mv, x, y))
106                         deferred_errors = true;
107                     }
108                   else
109                     {
110                       if (x == LOWEST) 
111                         {
112                           msg (SE, _("LO or LOWEST must be part of a range."));
113                           deferred_errors = true;
114                         }
115                       else if (!mv_add_num (&mv, x))
116                         deferred_errors = true;
117                     }
118
119                   lex_match (',');
120                 }
121             }
122           else 
123             {
124               mv_init (&mv, MAX_SHORT_STRING);
125               while (!lex_match (')')) 
126                 {
127                   if (!lex_force_string ())
128                     {
129                       deferred_errors = true;
130                       break;
131                     }
132
133                   if (ds_length (&tokstr) > MAX_SHORT_STRING) 
134                     {
135                       ds_truncate (&tokstr, MAX_SHORT_STRING);
136                       msg (SE, _("Truncating missing value to short string "
137                                  "length (%d characters)."),
138                            MAX_SHORT_STRING);
139                     }
140                   else
141                     ds_rpad (&tokstr, MAX_SHORT_STRING, ' ');
142
143                   if (!mv_add_str (&mv, ds_data (&tokstr)))
144                     deferred_errors = true;
145
146                   lex_get ();
147                   lex_match (',');
148                 }
149             }
150           
151           for (i = 0; i < nv; i++) 
152             {
153               if (!mv_is_resizable (&mv, v[i]->width)) 
154                 {
155                   msg (SE, _("Missing values provided are too long to assign "
156                              "to variable of width %d."),
157                        v[i]->width);
158                   deferred_errors = true;
159                 }
160               else 
161                 {
162                   mv_copy (&v[i]->miss, &mv);
163                   mv_resize (&v[i]->miss, v[i]->width);
164                 }
165             }
166         }
167
168       lex_match ('/');
169       free (v);
170       v = NULL;
171     }
172   retval = lex_end_of_command ();
173   
174  done:
175   free (v);
176   if (deferred_errors)
177     retval = CMD_PART_SUCCESS_MAYBE;
178   return retval;
179 }
180
181 static bool
182 parse_number (double *x, const struct fmt_spec *f)
183 {
184   if (lex_is_number ()) 
185     {
186       *x = lex_number ();
187       lex_get ();
188       return true;
189     }
190   else if (token == T_STRING) 
191     {
192       struct data_in di;
193       union value v;
194       di.s = ds_data (&tokstr);
195       di.e = ds_end (&tokstr);
196       di.v = &v;
197       di.flags = 0;
198       di.f1 = 1;
199       di.f2 = ds_length (&tokstr);
200       di.format = *f;
201       data_in (&di);
202       lex_get ();
203       *x = v.f;
204       return true;
205     }
206   else 
207     {
208       lex_error (_("expecting number or data string"));
209       return false; 
210     }
211 }
212