1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
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.
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.
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
31 /* Implementation details:
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,
42 the command COUNT A=A B (1) / B=A B (2) will produce the following
49 rather than the results that would be produced if subcommands were
56 Perhaps simultaneity could be implemented as an option. On the
57 other hand, what good are the above commands? */
59 #include "debug-print.h"
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. */
88 struct counting *next;
90 /* variables to count */
95 int missing; /* (numeric only)
96 0=don't count missing,
98 2=count system- and user-missing */
99 union /* Criterion values. */
109 struct cnt_var_info *next;
111 struct variable *d; /* Destination variable. */
112 char n[9]; /* Name of dest var. */
114 struct counting *c; /* The counting specifications. */
119 struct trns_header h;
120 struct cnt_var_info *specs;
124 static void debug_print (void);
127 /* First counting in chain. */
128 static struct cnt_var_info *head;
132 static int count_trns_proc (struct trns_header *, struct ccase *);
133 static void count_trns_free (struct trns_header *);
135 static int parse_numeric_criteria (struct counting *);
136 static int parse_string_criteria (struct counting *);
141 /* Specification currently being parsed. */
142 struct cnt_var_info *cnt;
144 /* Counting currently being parsed. */
147 /* Return value from parsing function. */
150 /* Transformation. */
151 struct count_trns *trns;
153 lex_match_id ("COUNT");
155 /* Parses each slash-delimited specification. */
156 head = cnt = xmalloc (sizeof *cnt);
159 /* Initialize this struct cnt_var_info to ensure proper cleanup. */
164 /* Get destination struct variable, or at least its name. */
165 if (!lex_force_id ())
167 cnt->d = dict_lookup_var (default_dict, tokid);
170 if (cnt->d->type == ALPHA)
172 msg (SE, _("Destination cannot be a string variable."));
177 strcpy (cnt->n, tokid);
180 if (!lex_force_match ('='))
183 c = cnt->c = xmalloc (sizeof *c);
188 if (!parse_variables (default_dict, &c->v, &c->n,
189 PV_DUPLICATE | PV_SAME_TYPE))
192 if (!lex_force_match ('('))
195 ret = (c->v[0]->type == NUMERIC
196 ? parse_numeric_criteria
197 : parse_string_criteria) (c);
201 if (token == '/' || token == '.')
204 c = c->next = xmalloc (sizeof *c);
210 if (!lex_force_match ('/'))
212 cnt = cnt->next = xmalloc (sizeof *cnt);
215 /* Create all the nonexistent destination variables. */
216 for (cnt = head; cnt; cnt = cnt->next)
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);
224 cnt->d = dict_create_var_assert (default_dict, cnt->n, 0);
231 trns = xmalloc (sizeof *trns);
232 trns->h.proc = count_trns_proc;
233 trns->h.free = count_trns_free;
235 add_transformation ((struct trns_header *) trns);
243 count_trns_free ((struct trns_header *) & t);
248 /* Parses a set of numeric criterion values. */
250 parse_numeric_criteria (struct counting * c)
263 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
266 cur = &c->crit.n[n++];
271 if (lex_match_id ("THRU"))
275 if (!lex_force_num ())
278 cur->type = CNT_RANGE;
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."),
290 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
291 cur->type = CNT_HIGH;
299 cur->type = CNT_SINGLE;
301 else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
303 if (!lex_force_match_id ("THRU"))
311 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
319 else if (lex_match_id ("SYSMIS"))
324 else if (lex_match_id ("MISSING"))
337 c->crit.n[n].type = CNT_SENTINEL;
341 /* Parses a set of string criteria values. The skeleton is the same
342 as parse_numeric_criteria(). */
344 parse_string_criteria (struct counting * c)
353 for (i = 0; i < c->n; i++)
354 if (c->v[i]->width > len)
355 len = c->v[i]->width;
364 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
367 if (!lex_force_string ())
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);
380 c->crit.s[n].type = CNT_SENTINEL;
384 /* Transformation. */
386 /* Counts the number of values in case C matching counting CNT. */
388 count_numeric (struct counting * cnt, struct ccase * c)
397 for (i = 0; i < cnt->n; i++)
399 /* Extract the variable value and eliminate missing values. */
400 cmp = c->data[cnt->v[i]->fv].f;
403 if (cnt->missing >= 1)
407 if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
413 /* Try to find the value in the list. */
414 for (num = cnt->crit.n;; num++)
421 if (approx_ne (cmp, num->a))
426 if (approx_lt (cmp, num->a))
431 if (approx_gt (cmp, num->a))
436 if (approx_lt (cmp, num->a) || approx_gt (cmp, num->b))
453 /* Counts the number of values in case C matching counting CNT. */
455 count_string (struct counting * cnt, struct ccase * c)
466 for (i = 0; i < cnt->n; i++)
468 /* Extract the variable value, variable width. */
469 cmp = c->data[cnt->v[i]->fv].s;
470 len = cnt->v[i]->width;
472 for (str = cnt->crit.s;; str++)
478 if (memcmp (cmp, str->s, len))
492 /* Performs the COUNT transformation T on case C. */
494 count_trns_proc (struct trns_header * trns, struct ccase * c)
496 struct cnt_var_info *info;
497 struct counting *cnt;
500 for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
503 for (cnt = info->c; cnt; cnt = cnt->next)
504 if (cnt->v[0]->type == NUMERIC)
505 counter += count_numeric (cnt, c);
507 counter += count_string (cnt, c);
508 c->data[info->d->fv].f = counter;
513 /* Destroys all dynamic data structures associated with T. */
515 count_trns_free (struct trns_header * t)
517 struct cnt_var_info *iter, *next;
519 for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
521 struct counting *i, *n;
523 for (i = iter->c; i; i = n)
527 if (i->v[0]->type == NUMERIC)
533 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
555 struct cnt_var_info *iter;
560 for (iter = head; iter; iter = iter->next)
562 printf (" %s=", iter->d->name);
563 for (i = iter->c; i; i = i->next)
565 for (j = 0; j < i->n; j++)
566 printf ("%s%s", j ? " " : "", i->v[j]->name);
568 if (i->v[0]->type == NUMERIC)
574 else if (i->missing == 1)
577 assert (i->missing == 0);
579 for (n = i->crit.n; n->type != CNT_SENTINEL; n++)
581 if (i->missing && n != i->crit.n)
589 printf ("%g THRU HIGH", n->a);
592 printf ("LOW THRU %g", n->a);
595 printf ("%g THRU %g", n->a, n->b);
598 printf ("LOW THRU HIGH");
601 printf ("<ERROR %d>", n->type);
610 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
614 if (s->type == CNT_SINGLE)
615 printf ("'%s'", s->s);
617 printf ("<ERROR %d>", s->type);
625 #endif /* DEBUGGING */