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