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