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