Fixed blank replacement
[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   size_t nv;
43
44   int retval = CMD_PART_SUCCESS_MAYBE;
45   bool deferred_errors = false;
46
47   while (token != '.')
48     {
49       size_t i;
50
51       if (!parse_variables (default_dict, &v, &nv, PV_NONE)) 
52         goto done;
53
54       if (!lex_match ('('))
55         {
56           lex_error (_("expecting `('"));
57           goto done;
58         }
59
60       for (i = 0; i < nv; i++)
61         mv_init (&v[i]->miss, v[i]->width);
62
63       if (!lex_match (')')) 
64         {
65           struct missing_values mv;
66
67           for (i = 0; i < nv; i++)
68             if (v[i]->type != v[0]->type)
69               {
70                 const struct variable *n = v[0]->type == NUMERIC ? v[0] : v[i];
71                 const struct variable *s = v[0]->type == NUMERIC ? v[i] : v[0];
72                 msg (SE, _("Cannot mix numeric variables (e.g. %s) and "
73                            "string variables (e.g. %s) within a single list."),
74                      n->name, s->name);
75                 goto done;
76               }
77
78           if (v[0]->type == NUMERIC) 
79             {
80               mv_init (&mv, 0);
81               while (!lex_match (')'))
82                 {
83                   double x;
84
85                   if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
86                     x = LOWEST;
87                   else if (!parse_number (&x, &v[0]->print))
88                     goto done;
89
90                   if (lex_match_id ("THRU")) 
91                     {
92                       double y;
93                       
94                       if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
95                         y = HIGHEST;
96                       else if (!parse_number (&y, &v[0]->print))
97                         goto done;
98
99                       if (x == LOWEST && y == HIGHEST)
100                         {
101                           msg (SE, _("LO THRU HI is an invalid range."));
102                           deferred_errors = true;
103                         }
104                       else if (!mv_add_num_range (&mv, x, y))
105                         deferred_errors = true;
106                     }
107                   else
108                     {
109                       if (x == LOWEST) 
110                         {
111                           msg (SE, _("LO or LOWEST must be part of a range."));
112                           deferred_errors = true;
113                         }
114                       else if (!mv_add_num (&mv, x))
115                         deferred_errors = true;
116                     }
117
118                   lex_match (',');
119                 }
120             }
121           else 
122             {
123               mv_init (&mv, MAX_SHORT_STRING);
124               while (!lex_match (')')) 
125                 {
126                   if (!lex_force_string ())
127                     {
128                       deferred_errors = true;
129                       break;
130                     }
131
132                   if (ds_length (&tokstr) > MAX_SHORT_STRING) 
133                     {
134                       ds_truncate (&tokstr, MAX_SHORT_STRING);
135                       msg (SE, _("Truncating missing value to short string "
136                                  "length (%d characters)."),
137                            MAX_SHORT_STRING);
138                     }
139                   else
140                     ds_rpad (&tokstr, MAX_SHORT_STRING, ' ');
141
142                   if (!mv_add_str (&mv, ds_data (&tokstr)))
143                     deferred_errors = true;
144
145                   lex_get ();
146                   lex_match (',');
147                 }
148             }
149           
150           for (i = 0; i < nv; i++) 
151             {
152               if (!mv_is_resizable (&mv, v[i]->width)) 
153                 {
154                   msg (SE, _("Missing values provided are too long to assign "
155                              "to variable of width %d."),
156                        v[i]->width);
157                   deferred_errors = true;
158                 }
159               else 
160                 {
161                   mv_copy (&v[i]->miss, &mv);
162                   mv_resize (&v[i]->miss, v[i]->width);
163                 }
164             }
165         }
166
167       lex_match ('/');
168       free (v);
169       v = NULL;
170     }
171   retval = lex_end_of_command ();
172   
173  done:
174   free (v);
175   if (deferred_errors)
176     retval = CMD_PART_SUCCESS_MAYBE;
177   return retval;
178 }
179
180 static bool
181 parse_number (double *x, const struct fmt_spec *f)
182 {
183   if (lex_is_number ()) 
184     {
185       *x = lex_number ();
186       lex_get ();
187       return true;
188     }
189   else if (token == T_STRING) 
190     {
191       struct data_in di;
192       union value v;
193       di.s = ds_data (&tokstr);
194       di.e = ds_end (&tokstr);
195       di.v = &v;
196       di.flags = 0;
197       di.f1 = 1;
198       di.f2 = ds_length (&tokstr);
199       di.format = *f;
200       data_in (&di);
201       lex_get ();
202       *x = v.f;
203       return true;
204     }
205   else 
206     {
207       lex_error (_("expecting number or data string"));
208       return false; 
209     }
210 }
211