68d642a09c2ed3f9c355a061d168d5c4cf0d46f4
[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 "error.h"
25 #include "lexer.h"
26 #include "magic.h"
27 #include "str.h"
28 #include "var.h"
29
30 #include "debug-print.h"
31
32 /* Variables on MIS VAL. */
33 static struct variable **v;
34 static int nv;
35
36 /* Type of the variables on MIS VAL. */
37 static int type;
38
39 /* Width of string variables on MIS VAL. */
40 static size_t width;
41
42 /* Items to fill-in var structs with. */
43 static int miss_type;
44 static union value missing[3];
45
46 static int parse_varnames (void);
47 static int parse_numeric (void);
48 static int parse_alpha (void);
49
50 int
51 cmd_missing_values (void)
52 {
53   int i;
54
55   while (token != '.')
56     {
57       if (!parse_varnames ())
58         goto fail;
59
60       if (token != ')')
61         {
62           if ((type == NUMERIC && !parse_numeric ())
63               || (type == ALPHA && !parse_alpha ()))
64             goto fail;
65         }
66       else
67         miss_type = MISSING_NONE;
68
69       if (!lex_match (')'))
70         {
71           msg (SE, _("`)' expected after value specification."));
72           goto fail;
73         }
74
75       for (i = 0; i < nv; i++)
76         {
77           v[i]->miss_type = miss_type;
78           memcpy (v[i]->missing, missing, sizeof v[i]->missing);
79         }
80
81       lex_match ('/');
82       free (v);
83     }
84
85   return lex_end_of_command ();
86
87 fail:
88   free (v);
89   return CMD_PART_SUCCESS_MAYBE;
90 }
91
92 static int
93 parse_varnames (void)
94 {
95   int i;
96
97   if (!parse_variables (default_dict, &v, &nv, PV_SAME_TYPE))
98     return 0;
99   if (!lex_match ('('))
100     {
101       msg (SE, _("`(' expected after variable name%s."), nv > 1 ? "s" : "");
102       return 0;
103     }
104
105   type = v[0]->type;
106   if (type == NUMERIC)
107     return 1;
108
109   width = v[0]->width;
110   for (i = 1; i < nv; i++)
111     if (v[i]->type == ALPHA && v[i]->nv != 1)
112       {
113         msg (SE, _("Long string value specified."));
114         return 0;
115       }
116     else if (v[i]->type == ALPHA && (int) width != v[i]->width)
117       {
118         msg (SE, _("Short strings must be of equal width."));
119         return 0;
120       }
121
122   return 1;
123 }
124
125 /* Number or range? */
126 enum
127   {
128     MV_NOR_NOTHING,             /* Empty. */
129     MV_NOR_NUMBER,              /* Single number. */
130     MV_NOR_RANGE                /* Range. */
131   };
132
133 /* A single value or a range. */
134 struct num_or_range
135   {
136     int type;                   /* One of NOR_*. */
137     double d[2];                /* d[0]=lower bound or value, d[1]=upper bound. */
138   };
139
140 /* Parses something of the form <num>, or LO[WEST] THRU <num>, or
141    <num> THRU HI[GHEST], or <num> THRU <num>, and sets the appropriate
142    members of NOR.  Returns success. */
143 static int
144 parse_num_or_range (struct num_or_range * nor)
145 {
146   if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
147     {
148       nor->type = MV_NOR_RANGE;
149       if (!lex_force_match_id ("THRU"))
150         return 0;
151       if (!lex_force_num ())
152         return 0;
153       nor->d[0] = LOWEST;
154       nor->d[1] = tokval;
155     }
156   else if (lex_is_number ())
157     {
158       nor->d[0] = tokval;
159       lex_get ();
160
161       if (lex_match_id ("THRU"))
162         {
163           nor->type = MV_NOR_RANGE;
164           if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
165             nor->d[1] = HIGHEST;
166           else
167             {
168               if (!lex_force_num ())
169                 return 0;
170               nor->d[1] = tokval;
171               lex_get ();
172
173               if (nor->d[0] > nor->d[1])
174                 {
175                   msg (SE, _("Range %g THRU %g is not valid because %g is "
176                              "greater than %g."),
177                        nor->d[0], nor->d[1], nor->d[0], nor->d[1]);
178                   return 0;
179                 }
180             }
181         }
182       else
183         nor->type = MV_NOR_NUMBER;
184     }
185   else
186     return -1;
187
188   return 1;
189 }
190
191 /* Parses a set of numeric missing values and stores them into
192    `missing[]' and `miss_type' global variables. */
193 static int
194 parse_numeric (void)
195 {
196   struct num_or_range set[3];
197   int r;
198
199   set[1].type = set[2].type = MV_NOR_NOTHING;
200
201   /* Get first number or range. */
202   r = parse_num_or_range (&set[0]);
203   if (r < 1)
204     {
205       if (r == -1)
206         msg (SE, _("Number or range expected."));
207       return 0;
208     }
209
210   /* Get second and third optional number or range. */
211   lex_match (',');
212   r = parse_num_or_range (&set[1]);
213   if (r == 1)
214     {
215       lex_match (',');
216       r = parse_num_or_range (&set[2]);
217     }
218   if (r == 0)
219     return 0;
220
221   /* Force range, if present, into set[0]. */
222   if (set[1].type == MV_NOR_RANGE)
223     {
224       struct num_or_range t = set[1];
225       set[1] = set[0];
226       set[0] = t;
227     }
228   if (set[2].type == MV_NOR_RANGE)
229     {
230       struct num_or_range t = set[2];
231       set[2] = set[0];
232       set[0] = t;
233     }
234   
235   /* Ensure there's not more than one range, or one range
236      plus one value. */
237   if (set[1].type == MV_NOR_RANGE || set[2].type == MV_NOR_RANGE)
238     {
239       msg (SE, _("At most one range can exist in the missing values "
240                  "for any one variable."));
241       return 0;
242     }
243   if (set[0].type == MV_NOR_RANGE && set[2].type != MV_NOR_NOTHING)
244     {
245       msg (SE, _("At most one individual value can be missing along "
246                  "with one range."));
247       return 0;
248     }
249
250   /* Set missing[] from set[]. */
251   if (set[0].type == MV_NOR_RANGE)
252     {
253       int x = 0;
254
255       if (set[0].d[0] == LOWEST)
256         {
257           miss_type = MISSING_LOW;
258           missing[x++].f = set[0].d[1];
259         }
260       else if (set[0].d[1] == HIGHEST)
261         {
262           miss_type = MISSING_HIGH;
263           missing[x++].f = set[0].d[0];
264         }
265       else
266         {
267           miss_type = MISSING_RANGE;
268           missing[x++].f = set[0].d[0];
269           missing[x++].f = set[0].d[1];
270         }
271
272       if (set[1].type == MV_NOR_NUMBER)
273         {
274           miss_type += 3;
275           missing[x].f = set[1].d[0];
276         }
277     }
278   else
279     {
280       if (set[0].type == MV_NOR_NUMBER)
281         {
282           miss_type = MISSING_1;
283           missing[0].f = set[0].d[0];
284         }
285       if (set[1].type == MV_NOR_NUMBER)
286         {
287           miss_type = MISSING_2;
288           missing[1].f = set[1].d[0];
289         }
290       if (set[2].type == MV_NOR_NUMBER)
291         {
292           miss_type = MISSING_3;
293           missing[2].f = set[2].d[0];
294         }
295     }
296
297   return 1;
298 }
299
300 static int
301 parse_alpha (void)
302 {
303   for (miss_type = 0; token == T_STRING && miss_type < 3; miss_type++)
304     {
305       if (ds_length (&tokstr) != width)
306         {
307           msg (SE, _("String is not of proper length."));
308           return 0;
309         }
310       strncpy (missing[miss_type].s, ds_c_str (&tokstr), MAX_SHORT_STRING);
311       lex_get ();
312       lex_match (',');
313     }
314   if (miss_type < 1)
315     {
316       msg (SE, _("String expected."));
317       return 0;
318     }
319
320   return 1;
321 }
322
323 /* Copy the missing values from variable SRC to variable DEST. */
324 void
325 copy_missing_values (struct variable *dest, const struct variable *src)
326 {
327   static const int n_values[MISSING_COUNT] = 
328     {
329       0, 1, 2, 3, 2, 1, 1, 3, 2, 2,
330     };
331     
332   assert (dest->width == src->width);
333   assert (src->miss_type >= 0 && src->miss_type < MISSING_COUNT);
334   
335   {
336     int i;
337
338     dest->miss_type = src->miss_type;
339     for (i = 0; i < n_values[src->miss_type]; i++)
340       if (src->type == NUMERIC)
341         dest->missing[i].f = src->missing[i].f;
342       else
343         memcpy (dest->missing[i].s, src->missing[i].s, src->width);
344   }
345 }