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