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);
225 cnt->d = dict_create_var (default_dict, cnt->n, 0);
226 assert (cnt->d != NULL);
234 trns = xmalloc (sizeof *trns);
235 trns->h.proc = count_trns_proc;
236 trns->h.free = count_trns_free;
238 add_transformation ((struct trns_header *) trns);
246 count_trns_free ((struct trns_header *) & t);
251 /* Parses a set of numeric criterion values. */
253 parse_numeric_criteria (struct counting * c)
266 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
269 cur = &c->crit.n[n++];
274 if (lex_match_id ("THRU"))
278 if (!lex_force_num ())
281 cur->type = CNT_RANGE;
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."),
293 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
294 cur->type = CNT_HIGH;
302 cur->type = CNT_SINGLE;
304 else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
306 if (!lex_force_match_id ("THRU"))
314 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
322 else if (lex_match_id ("SYSMIS"))
327 else if (lex_match_id ("MISSING"))
340 c->crit.n[n].type = CNT_SENTINEL;
344 /* Parses a set of string criteria values. The skeleton is the same
345 as parse_numeric_criteria(). */
347 parse_string_criteria (struct counting * c)
356 for (i = 0; i < c->n; i++)
357 if (c->v[i]->width > len)
358 len = c->v[i]->width;
367 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
370 if (!lex_force_string ())
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);
383 c->crit.s[n].type = CNT_SENTINEL;
387 /* Transformation. */
389 /* Counts the number of values in case C matching counting CNT. */
391 count_numeric (struct counting * cnt, struct ccase * c)
400 for (i = 0; i < cnt->n; i++)
402 /* Extract the variable value and eliminate missing values. */
403 cmp = c->data[cnt->v[i]->fv].f;
406 if (cnt->missing >= 1)
410 if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
416 /* Try to find the value in the list. */
417 for (num = cnt->crit.n;; num++)
424 if (approx_ne (cmp, num->a))
429 if (approx_lt (cmp, num->a))
434 if (approx_gt (cmp, num->a))
439 if (approx_lt (cmp, num->a) || approx_gt (cmp, num->b))
456 /* Counts the number of values in case C matching counting CNT. */
458 count_string (struct counting * cnt, struct ccase * c)
469 for (i = 0; i < cnt->n; i++)
471 /* Extract the variable value, variable width. */
472 cmp = c->data[cnt->v[i]->fv].s;
473 len = cnt->v[i]->width;
475 for (str = cnt->crit.s;; str++)
481 if (memcmp (cmp, str->s, len))
495 /* Performs the COUNT transformation T on case C. */
497 count_trns_proc (struct trns_header * trns, struct ccase * c)
499 struct cnt_var_info *info;
500 struct counting *cnt;
503 for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
506 for (cnt = info->c; cnt; cnt = cnt->next)
507 if (cnt->v[0]->type == NUMERIC)
508 counter += count_numeric (cnt, c);
510 counter += count_string (cnt, c);
511 c->data[info->d->fv].f = counter;
516 /* Destroys all dynamic data structures associated with T. */
518 count_trns_free (struct trns_header * t)
520 struct cnt_var_info *iter, *next;
522 for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
524 struct counting *i, *n;
526 for (i = iter->c; i; i = n)
530 if (i->v[0]->type == NUMERIC)
536 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
558 struct cnt_var_info *iter;
563 for (iter = head; iter; iter = iter->next)
565 printf (" %s=", iter->d->name);
566 for (i = iter->c; i; i = i->next)
568 for (j = 0; j < i->n; j++)
569 printf ("%s%s", j ? " " : "", i->v[j]->name);
571 if (i->v[0]->type == NUMERIC)
577 else if (i->missing == 1)
580 assert (i->missing == 0);
582 for (n = i->crit.n; n->type != CNT_SENTINEL; n++)
584 if (i->missing && n != i->crit.n)
592 printf ("%g THRU HIGH", n->a);
595 printf ("LOW THRU %g", n->a);
598 printf ("%g THRU %g", n->a, n->b);
601 printf ("LOW THRU HIGH");
604 printf ("<ERROR %d>", n->type);
613 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
617 if (s->type == CNT_SINGLE)
618 printf ("'%s'", s->s);
620 printf ("<ERROR %d>", s->type);
628 #endif /* DEBUGGING */