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