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