Get rid of static var in COUNT.
[pspp-builds.git] / src / count.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 "alloc.h"
24 #include "command.h"
25 #include "error.h"
26 #include "lexer.h"
27 #include "str.h"
28 #include "var.h"
29
30 /* Implementation details:
31
32    The S?SS manuals do not specify the order that COUNT subcommands are
33    performed in.  Experiments, however, have shown that they are performed
34    in the order that they are specified in, rather than simultaneously.
35    So, with the two variables A and B, and the two cases,
36
37    A B
38    1 2
39    2 1
40
41    the command COUNT A=A B (1) / B=A B (2) will produce the following
42    results,
43
44    A B
45    1 1
46    1 0
47
48    rather than the results that would be produced if subcommands were
49    simultaneous:
50
51    A B
52    1 1
53    1 1
54
55    Perhaps simultaneity could be implemented as an option.  On the
56    other hand, what good are the above commands?  */
57 \f
58 /* Definitions. */
59
60 enum
61   {
62     CNT_ERROR,                  /* Invalid value. */
63     CNT_SINGLE,                 /* Single value. */
64     CNT_HIGH,                   /* x >= a. */
65     CNT_LOW,                    /* x <= a. */
66     CNT_RANGE,                  /* a <= x <= b. */
67     CNT_ANY,                    /* Count any. */
68     CNT_SENTINEL                /* List terminator. */
69   };
70
71 struct cnt_num
72   {
73     int type;
74     double a, b;
75   };
76
77 struct cnt_str
78   {
79     int type;
80     char *s;
81   };
82
83 struct counting
84   {
85     struct counting *next;
86
87     /* variables to count */
88     struct variable **v;
89     int n;
90
91     /* values to count */
92     int missing;                /* (numeric only)
93                                    0=don't count missing,
94                                    1=count SYSMIS,
95                                    2=count system- and user-missing */
96     union                       /* Criterion values. */
97       {
98         struct cnt_num *n;
99         struct cnt_str *s;
100       }
101     crit;
102   };
103
104 struct cnt_var_info
105   {
106     struct cnt_var_info *next;
107
108     struct variable *d;         /* Destination variable. */
109     char n[9];                  /* Name of dest var. */
110
111     struct counting *c;         /* The counting specifications. */
112   };
113
114 struct count_trns
115   {
116     struct trns_header h;
117     struct cnt_var_info *specs;
118   };
119 \f
120 /* Parser. */
121
122 static trns_proc_func count_trns_proc;
123 static trns_free_func count_trns_free;
124
125 static int parse_numeric_criteria (struct counting *);
126 static int parse_string_criteria (struct counting *);
127
128 int
129 cmd_count (void)
130 {
131   struct cnt_var_info *cnt;     /* Specification currently being parsed. */
132   struct counting *c;           /* Counting currently being parsed. */
133   int ret;                      /* Return value from parsing function. */
134   struct count_trns *trns;      /* Transformation. */
135   struct cnt_var_info *head;    /* First counting in chain. */
136
137   lex_match_id ("COUNT");
138
139   /* Parses each slash-delimited specification. */
140   head = cnt = xmalloc (sizeof *cnt);
141   for (;;)
142     {
143       /* Initialize this struct cnt_var_info to ensure proper cleanup. */
144       cnt->next = NULL;
145       cnt->d = NULL;
146       cnt->c = NULL;
147
148       /* Get destination struct variable, or at least its name. */
149       if (!lex_force_id ())
150         goto fail;
151       cnt->d = dict_lookup_var (default_dict, tokid);
152       if (cnt->d)
153         {
154           if (cnt->d->type == ALPHA)
155             {
156               msg (SE, _("Destination cannot be a string variable."));
157               goto fail;
158             }
159         }
160       else
161         strcpy (cnt->n, tokid);
162
163       lex_get ();
164       if (!lex_force_match ('='))
165         goto fail;
166
167       c = cnt->c = xmalloc (sizeof *c);
168       for (;;)
169         {
170           c->next = NULL;
171           c->v = NULL;
172           if (!parse_variables (default_dict, &c->v, &c->n,
173                                 PV_DUPLICATE | PV_SAME_TYPE))
174             goto fail;
175
176           if (!lex_force_match ('('))
177             goto fail;
178
179           ret = (c->v[0]->type == NUMERIC
180                  ? parse_numeric_criteria
181                  : parse_string_criteria) (c);
182           if (!ret)
183             goto fail;
184
185           if (token == '/' || token == '.')
186             break;
187
188           c = c->next = xmalloc (sizeof *c);
189         }
190
191       if (token == '.')
192         break;
193
194       if (!lex_force_match ('/'))
195         goto fail;
196       cnt = cnt->next = xmalloc (sizeof *cnt);
197     }
198
199   /* Create all the nonexistent destination variables. */
200   for (cnt = head; cnt; cnt = cnt->next)
201     if (!cnt->d)
202       {
203         /* It's valid, though motivationally questionable, to count to
204            the same dest var more than once. */
205         cnt->d = dict_lookup_var (default_dict, cnt->n);
206
207         if (cnt->d == NULL) 
208           cnt->d = dict_create_var_assert (default_dict, cnt->n, 0);
209       }
210
211   trns = xmalloc (sizeof *trns);
212   trns->h.proc = count_trns_proc;
213   trns->h.free = count_trns_free;
214   trns->specs = head;
215   add_transformation ((struct trns_header *) trns);
216
217   return CMD_SUCCESS;
218
219 fail:
220   {
221     struct count_trns t;
222     t.specs = head;
223     count_trns_free ((struct trns_header *) & t);
224     return CMD_FAILURE;
225   }
226 }
227
228 /* Parses a set of numeric criterion values. */
229 static int
230 parse_numeric_criteria (struct counting * c)
231 {
232   int n = 0;
233   int m = 0;
234
235   c->crit.n = 0;
236   c->missing = 0;
237   for (;;)
238     {
239       struct cnt_num *cur;
240       if (n >= m - 1)
241         {
242           m += 16;
243           c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
244         }
245
246       cur = &c->crit.n[n++];
247       if (token == T_NUM)
248         {
249           cur->a = tokval;
250           lex_get ();
251           if (lex_match_id ("THRU"))
252             {
253               if (token == T_NUM)
254                 {
255                   if (!lex_force_num ())
256                     return 0;
257                   cur->b = tokval;
258                   cur->type = CNT_RANGE;
259                   lex_get ();
260
261                   if (cur->a > cur->b)
262                     {
263                       msg (SE, _("%g THRU %g is not a valid range.  The "
264                                  "number following THRU must be at least "
265                                  "as big as the number preceding THRU."),
266                            cur->a, cur->b);
267                       return 0;
268                     }
269                 }
270               else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
271                 cur->type = CNT_HIGH;
272               else
273                 {
274                   lex_error (NULL);
275                   return 0;
276                 }
277             }
278           else
279             cur->type = CNT_SINGLE;
280         }
281       else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
282         {
283           if (!lex_force_match_id ("THRU"))
284             return 0;
285           if (token == T_NUM)
286             {
287               cur->type = CNT_LOW;
288               cur->a = tokval;
289               lex_get ();
290             }
291           else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
292             cur->type = CNT_ANY;
293           else
294             {
295               lex_error (NULL);
296               return 0;
297             }
298         }
299       else if (lex_match_id ("SYSMIS"))
300         {
301           if (c->missing < 1)
302             c->missing = 1;
303         }
304       else if (lex_match_id ("MISSING"))
305         c->missing = 2;
306       else
307         {
308           lex_error (NULL);
309           return 0;
310         }
311
312       lex_match (',');
313       if (lex_match (')'))
314         break;
315     }
316
317   c->crit.n[n].type = CNT_SENTINEL;
318   return 1;
319 }
320
321 /* Parses a set of string criteria values.  The skeleton is the same
322    as parse_numeric_criteria(). */
323 static int
324 parse_string_criteria (struct counting * c)
325 {
326   int len = 0;
327
328   int n = 0;
329   int m = 0;
330
331   int i;
332
333   for (i = 0; i < c->n; i++)
334     if (c->v[i]->width > len)
335       len = c->v[i]->width;
336
337   c->crit.n = 0;
338   for (;;)
339     {
340       struct cnt_str *cur;
341       if (n >= m - 1)
342         {
343           m += 16;
344           c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
345         }
346
347       if (!lex_force_string ())
348         return 0;
349       cur = &c->crit.s[n++];
350       cur->type = CNT_SINGLE;
351       cur->s = malloc (len + 1);
352       st_pad_copy (cur->s, ds_value (&tokstr), len + 1);
353       lex_get ();
354
355       lex_match (',');
356       if (lex_match (')'))
357         break;
358     }
359
360   c->crit.s[n].type = CNT_SENTINEL;
361   return 1;
362 }
363 \f
364 /* Transformation. */
365
366 /* Counts the number of values in case C matching counting CNT. */
367 static inline int
368 count_numeric (struct counting * cnt, struct ccase * c)
369 {
370   int counter = 0;
371
372   struct cnt_num *num;
373
374   double cmp;
375   int i;
376
377   for (i = 0; i < cnt->n; i++)
378     {
379       /* Extract the variable value and eliminate missing values. */
380       cmp = c->data[cnt->v[i]->fv].f;
381       if (cmp == SYSMIS)
382         {
383           if (cnt->missing >= 1)
384             counter++;
385           continue;
386         }
387       if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
388         {
389           counter++;
390           continue;
391         }
392
393       /* Try to find the value in the list. */
394       for (num = cnt->crit.n;; num++)
395         switch (num->type)
396           {
397           case CNT_ERROR:
398             assert (0);
399             break;
400           case CNT_SINGLE:
401             if (cmp != num->a)
402               break;
403             counter++;
404             goto done;
405           case CNT_HIGH:
406             if (cmp < num->a)
407               break;
408             counter++;
409             goto done;
410           case CNT_LOW:
411             if (cmp > num->a)
412               break;
413             counter++;
414             goto done;
415           case CNT_RANGE:
416             if (cmp < num->a || cmp > num->b)
417               break;
418             counter++;
419             goto done;
420           case CNT_ANY:
421             counter++;
422             goto done;
423           case CNT_SENTINEL:
424             goto done;
425           default:
426             assert (0);
427           }
428     done: ;
429     }
430   return counter;
431 }
432
433 /* Counts the number of values in case C matching counting CNT. */
434 static inline int
435 count_string (struct counting * cnt, struct ccase * c)
436 {
437   int counter = 0;
438
439   struct cnt_str *str;
440
441   char *cmp;
442   int len;
443
444   int i;
445
446   for (i = 0; i < cnt->n; i++)
447     {
448       /* Extract the variable value, variable width. */
449       cmp = c->data[cnt->v[i]->fv].s;
450       len = cnt->v[i]->width;
451
452       for (str = cnt->crit.s;; str++)
453         switch (str->type)
454           {
455           case CNT_ERROR:
456             assert (0);
457           case CNT_SINGLE:
458             if (memcmp (cmp, str->s, len))
459               break;
460             counter++;
461             goto done;
462           case CNT_SENTINEL:
463             goto done;
464           default:
465             assert (0);
466           }
467     done: ;
468     }
469   return counter;
470 }
471
472 /* Performs the COUNT transformation T on case C. */
473 static int
474 count_trns_proc (struct trns_header * trns, struct ccase * c,
475                  int case_num UNUSED)
476 {
477   struct cnt_var_info *info;
478   struct counting *cnt;
479   int counter;
480
481   for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
482     {
483       counter = 0;
484       for (cnt = info->c; cnt; cnt = cnt->next)
485         if (cnt->v[0]->type == NUMERIC)
486           counter += count_numeric (cnt, c);
487         else
488           counter += count_string (cnt, c);
489       c->data[info->d->fv].f = counter;
490     }
491   return -1;
492 }
493
494 /* Destroys all dynamic data structures associated with T. */
495 static void
496 count_trns_free (struct trns_header * t)
497 {
498   struct cnt_var_info *iter, *next;
499
500   for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
501     {
502       struct counting *i, *n;
503
504       for (i = iter->c; i; i = n)
505         {
506           if (i->n && i->v)
507             {
508               if (i->v[0]->type == NUMERIC)
509                 free (i->crit.n);
510               else
511                 {
512                   struct cnt_str *s;
513
514                   for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
515                     free (s->s);
516                   free (i->crit.s);
517                 }
518             }
519           free (i->v);
520
521           n = i->next;
522           free (i);
523         }
524
525       next = iter->next;
526       free (iter);
527     }
528 }