Got rid of "struct long_vec", envector(), devector(), etc.
[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 == NULL) 
224           cnt->d = dict_create_var_assert (default_dict, cnt->n, 0);
225       }
226
227 #if DEBUGGING
228   debug_print ();
229 #endif
230
231   trns = xmalloc (sizeof *trns);
232   trns->h.proc = count_trns_proc;
233   trns->h.free = count_trns_free;
234   trns->specs = head;
235   add_transformation ((struct trns_header *) trns);
236
237   return CMD_SUCCESS;
238
239 fail:
240   {
241     struct count_trns t;
242     t.specs = head;
243     count_trns_free ((struct trns_header *) & t);
244     return CMD_FAILURE;
245   }
246 }
247
248 /* Parses a set of numeric criterion values. */
249 static int
250 parse_numeric_criteria (struct counting * c)
251 {
252   int n = 0;
253   int m = 0;
254
255   c->crit.n = 0;
256   c->missing = 0;
257   for (;;)
258     {
259       struct cnt_num *cur;
260       if (n >= m - 1)
261         {
262           m += 16;
263           c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
264         }
265
266       cur = &c->crit.n[n++];
267       if (token == T_NUM)
268         {
269           cur->a = tokval;
270           lex_get ();
271           if (lex_match_id ("THRU"))
272             {
273               if (token == T_NUM)
274                 {
275                   if (!lex_force_num ())
276                     return 0;
277                   cur->b = tokval;
278                   cur->type = CNT_RANGE;
279                   lex_get ();
280
281                   if (cur->a > cur->b)
282                     {
283                       msg (SE, _("%g THRU %g is not a valid range.  The "
284                                  "number following THRU must be at least "
285                                  "as big as the number preceding THRU."),
286                            cur->a, cur->b);
287                       return 0;
288                     }
289                 }
290               else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
291                 cur->type = CNT_HIGH;
292               else
293                 {
294                   lex_error (NULL);
295                   return 0;
296                 }
297             }
298           else
299             cur->type = CNT_SINGLE;
300         }
301       else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
302         {
303           if (!lex_force_match_id ("THRU"))
304             return 0;
305           if (token == T_NUM)
306             {
307               cur->type = CNT_LOW;
308               cur->a = tokval;
309               lex_get ();
310             }
311           else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
312             cur->type = CNT_ANY;
313           else
314             {
315               lex_error (NULL);
316               return 0;
317             }
318         }
319       else if (lex_match_id ("SYSMIS"))
320         {
321           if (c->missing < 1)
322             c->missing = 1;
323         }
324       else if (lex_match_id ("MISSING"))
325         c->missing = 2;
326       else
327         {
328           lex_error (NULL);
329           return 0;
330         }
331
332       lex_match (',');
333       if (lex_match (')'))
334         break;
335     }
336
337   c->crit.n[n].type = CNT_SENTINEL;
338   return 1;
339 }
340
341 /* Parses a set of string criteria values.  The skeleton is the same
342    as parse_numeric_criteria(). */
343 static int
344 parse_string_criteria (struct counting * c)
345 {
346   int len = 0;
347
348   int n = 0;
349   int m = 0;
350
351   int i;
352
353   for (i = 0; i < c->n; i++)
354     if (c->v[i]->width > len)
355       len = c->v[i]->width;
356
357   c->crit.n = 0;
358   for (;;)
359     {
360       struct cnt_str *cur;
361       if (n >= m - 1)
362         {
363           m += 16;
364           c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
365         }
366
367       if (!lex_force_string ())
368         return 0;
369       cur = &c->crit.s[n++];
370       cur->type = CNT_SINGLE;
371       cur->s = malloc (len + 1);
372       st_pad_copy (cur->s, ds_value (&tokstr), len + 1);
373       lex_get ();
374
375       lex_match (',');
376       if (lex_match (')'))
377         break;
378     }
379
380   c->crit.s[n].type = CNT_SENTINEL;
381   return 1;
382 }
383 \f
384 /* Transformation. */
385
386 /* Counts the number of values in case C matching counting CNT. */
387 static inline int
388 count_numeric (struct counting * cnt, struct ccase * c)
389 {
390   int counter = 0;
391
392   struct cnt_num *num;
393
394   double cmp;
395   int i;
396
397   for (i = 0; i < cnt->n; i++)
398     {
399       /* Extract the variable value and eliminate missing values. */
400       cmp = c->data[cnt->v[i]->fv].f;
401       if (cmp == SYSMIS)
402         {
403           if (cnt->missing >= 1)
404             counter++;
405           continue;
406         }
407       if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
408         {
409           counter++;
410           continue;
411         }
412
413       /* Try to find the value in the list. */
414       for (num = cnt->crit.n;; num++)
415         switch (num->type)
416           {
417           case CNT_ERROR:
418             assert (0);
419             break;
420           case CNT_SINGLE:
421             if (approx_ne (cmp, num->a))
422               break;
423             counter++;
424             goto done;
425           case CNT_HIGH:
426             if (approx_lt (cmp, num->a))
427               break;
428             counter++;
429             goto done;
430           case CNT_LOW:
431             if (approx_gt (cmp, num->a))
432               break;
433             counter++;
434             goto done;
435           case CNT_RANGE:
436             if (approx_lt (cmp, num->a) || approx_gt (cmp, num->b))
437               break;
438             counter++;
439             goto done;
440           case CNT_ANY:
441             counter++;
442             goto done;
443           case CNT_SENTINEL:
444             goto done;
445           default:
446             assert (0);
447           }
448     done: ;
449     }
450   return counter;
451 }
452
453 /* Counts the number of values in case C matching counting CNT. */
454 static inline int
455 count_string (struct counting * cnt, struct ccase * c)
456 {
457   int counter = 0;
458
459   struct cnt_str *str;
460
461   char *cmp;
462   int len;
463
464   int i;
465
466   for (i = 0; i < cnt->n; i++)
467     {
468       /* Extract the variable value, variable width. */
469       cmp = c->data[cnt->v[i]->fv].s;
470       len = cnt->v[i]->width;
471
472       for (str = cnt->crit.s;; str++)
473         switch (str->type)
474           {
475           case CNT_ERROR:
476             assert (0);
477           case CNT_SINGLE:
478             if (memcmp (cmp, str->s, len))
479               break;
480             counter++;
481             goto done;
482           case CNT_SENTINEL:
483             goto done;
484           default:
485             assert (0);
486           }
487     done: ;
488     }
489   return counter;
490 }
491
492 /* Performs the COUNT transformation T on case C. */
493 static int
494 count_trns_proc (struct trns_header * trns, struct ccase * c)
495 {
496   struct cnt_var_info *info;
497   struct counting *cnt;
498   int counter;
499
500   for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
501     {
502       counter = 0;
503       for (cnt = info->c; cnt; cnt = cnt->next)
504         if (cnt->v[0]->type == NUMERIC)
505           counter += count_numeric (cnt, c);
506         else
507           counter += count_string (cnt, c);
508       c->data[info->d->fv].f = counter;
509     }
510   return -1;
511 }
512
513 /* Destroys all dynamic data structures associated with T. */
514 static void
515 count_trns_free (struct trns_header * t)
516 {
517   struct cnt_var_info *iter, *next;
518
519   for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
520     {
521       struct counting *i, *n;
522
523       for (i = iter->c; i; i = n)
524         {
525           if (i->n && i->v)
526             {
527               if (i->v[0]->type == NUMERIC)
528                 free (i->crit.n);
529               else
530                 {
531                   struct cnt_str *s;
532
533                   for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
534                     free (s->s);
535                   free (i->crit.s);
536                 }
537             }
538           free (i->v);
539
540           n = i->next;
541           free (i);
542         }
543
544       next = iter->next;
545       free (iter);
546     }
547 }
548 \f
549 /* Debugging. */
550
551 #if DEBUGGING
552 static void
553 debug_print (void)
554 {
555   struct cnt_var_info *iter;
556   struct counting *i;
557   int j;
558
559   printf ("COUNT\n");
560   for (iter = head; iter; iter = iter->next)
561     {
562       printf ("  %s=", iter->d->name);
563       for (i = iter->c; i; i = i->next)
564         {
565           for (j = 0; j < i->n; j++)
566             printf ("%s%s", j ? " " : "", i->v[j]->name);
567           printf (" (");
568           if (i->v[0]->type == NUMERIC)
569             {
570               struct cnt_num *n;
571
572               if (i->missing == 2)
573                 printf ("MISSING");
574               else if (i->missing == 1)
575                 printf ("SYSMIS");
576               else
577                 assert (i->missing == 0);
578
579               for (n = i->crit.n; n->type != CNT_SENTINEL; n++)
580                 {
581                   if (i->missing && n != i->crit.n)
582                     printf (",");
583                   switch (n->type)
584                     {
585                     case CNT_SINGLE:
586                       printf ("%g", n->a);
587                       break;
588                     case CNT_HIGH:
589                       printf ("%g THRU HIGH", n->a);
590                       break;
591                     case CNT_LOW:
592                       printf ("LOW THRU %g", n->a);
593                       break;
594                     case CNT_RANGE:
595                       printf ("%g THRU %g", n->a, n->b);
596                       break;
597                     case CNT_ANY:
598                       printf ("LOW THRU HIGH");
599                       break;
600                     default:
601                       printf ("<ERROR %d>", n->type);
602                       break;
603                     }
604                 }
605             }
606           else
607             {
608               struct cnt_str *s;
609
610               for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
611                 {
612                   if (s != i->crit.s)
613                     printf (",");
614                   if (s->type == CNT_SINGLE)
615                     printf ("'%s'", s->s);
616                   else
617                     printf ("<ERROR %d>", s->type);
618                 }
619             }
620           printf (")  ");
621         }
622       printf ("\n");
623     }
624 }
625 #endif /* DEBUGGING */