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