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