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