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 *);
138 int cmd_count (void);
141 internal_cmd_count (void)
143 int code = cmd_count ();
148 count_trns_free ((struct trns_header *) & c);
156 /* Specification currently being parsed. */
157 struct cnt_var_info *cnt;
159 /* Counting currently being parsed. */
162 /* Return value from parsing function. */
165 /* Transformation. */
166 struct count_trns *trns;
168 lex_match_id ("COUNT");
170 /* Parses each slash-delimited specification. */
171 head = cnt = xmalloc (sizeof *cnt);
174 /* Initialize this struct cnt_var_info to ensure proper cleanup. */
179 /* Get destination struct variable, or at least its name. */
180 if (!lex_force_id ())
182 cnt->d = find_variable (tokid);
185 if (cnt->d->type == ALPHA)
187 msg (SE, _("Destination cannot be a string variable."));
192 strcpy (cnt->n, tokid);
195 if (!lex_force_match ('='))
198 c = cnt->c = xmalloc (sizeof *c);
203 if (!parse_variables (NULL, &c->v, &c->n, PV_DUPLICATE | PV_SAME_TYPE))
206 if (!lex_force_match ('('))
209 ret = (c->v[0]->type == NUMERIC
210 ? parse_numeric_criteria
211 : parse_string_criteria) (c);
215 if (token == '/' || token == '.')
218 c = c->next = xmalloc (sizeof *c);
224 if (!lex_force_match ('/'))
226 cnt = cnt->next = xmalloc (sizeof *cnt);
229 /* Create all the nonexistent destination variables. */
230 for (cnt = head; cnt; cnt = cnt->next)
233 /* It's legal, though motivationally questionable, to count to
234 the same dest var more than once. */
235 cnt->d = find_variable (cnt->n);
238 cnt->d = force_create_variable (&default_dict, cnt->n, NUMERIC, 0);
245 trns = xmalloc (sizeof *trns);
246 trns->h.proc = count_trns_proc;
247 trns->h.free = count_trns_free;
249 add_transformation ((struct trns_header *) trns);
257 count_trns_free ((struct trns_header *) & t);
262 /* Parses a set of numeric criterion values. */
264 parse_numeric_criteria (struct counting * c)
277 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
280 cur = &c->crit.n[n++];
285 if (lex_match_id ("THRU"))
289 if (!lex_force_num ())
292 cur->type = CNT_RANGE;
297 msg (SE, _("%g THRU %g is not a valid range. The "
298 "number following THRU must be at least "
299 "as big as the number preceding THRU."),
304 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
305 cur->type = CNT_HIGH;
313 cur->type = CNT_SINGLE;
315 else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
317 if (!lex_force_match_id ("THRU"))
325 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
333 else if (lex_match_id ("SYSMIS"))
338 else if (lex_match_id ("MISSING"))
351 c->crit.n[n].type = CNT_SENTINEL;
355 /* Parses a set of string criteria values. The skeleton is the same
356 as parse_numeric_criteria(). */
358 parse_string_criteria (struct counting * c)
367 for (i = 0; i < c->n; i++)
368 if (c->v[i]->width > len)
369 len = c->v[i]->width;
378 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
381 if (!lex_force_string ())
383 cur = &c->crit.s[n++];
384 cur->type = CNT_SINGLE;
385 cur->s = malloc (len + 1);
386 st_pad_copy (cur->s, ds_value (&tokstr), len + 1);
394 c->crit.s[n].type = CNT_SENTINEL;
398 /* Transformation. */
400 /* Counts the number of values in case C matching counting CNT. */
402 count_numeric (struct counting * cnt, struct ccase * c)
411 for (i = 0; i < cnt->n; i++)
413 /* Extract the variable value and eliminate missing values. */
414 cmp = c->data[cnt->v[i]->fv].f;
417 if (cnt->missing >= 1)
421 if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
427 /* Try to find the value in the list. */
428 for (num = cnt->crit.n;; num++)
435 if (approx_ne (cmp, num->a))
440 if (approx_lt (cmp, num->a))
445 if (approx_gt (cmp, num->a))
450 if (approx_lt (cmp, num->a) || approx_gt (cmp, num->b))
467 /* Counts the number of values in case C matching counting CNT. */
469 count_string (struct counting * cnt, struct ccase * c)
480 for (i = 0; i < cnt->n; i++)
482 /* Extract the variable value, variable width. */
483 cmp = c->data[cnt->v[i]->fv].s;
484 len = cnt->v[i]->width;
486 for (str = cnt->crit.s;; str++)
492 if (memcmp (cmp, str->s, len))
506 /* Performs the COUNT transformation T on case C. */
508 count_trns_proc (struct trns_header * trns, struct ccase * c)
510 struct cnt_var_info *info;
511 struct counting *cnt;
514 for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
517 for (cnt = info->c; cnt; cnt = cnt->next)
518 if (cnt->v[0]->type == NUMERIC)
519 counter += count_numeric (cnt, c);
521 counter += count_string (cnt, c);
522 c->data[info->d->fv].f = counter;
527 /* Destroys all dynamic data structures associated with T. */
529 count_trns_free (struct trns_header * t)
531 struct cnt_var_info *iter, *next;
533 for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
535 struct counting *i, *n;
537 for (i = iter->c; i; i = n)
541 if (i->v[0]->type == NUMERIC)
547 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
569 struct cnt_var_info *iter;
574 for (iter = head; iter; iter = iter->next)
576 printf (" %s=", iter->d->name);
577 for (i = iter->c; i; i = i->next)
579 for (j = 0; j < i->n; j++)
580 printf ("%s%s", j ? " " : "", i->v[j]->name);
582 if (i->v[0]->type == NUMERIC)
588 else if (i->missing == 1)
591 assert (i->missing == 0);
593 for (n = i->crit.n; n->type != CNT_SENTINEL; n++)
595 if (i->missing && n != i->crit.n)
603 printf ("%g THRU HIGH", n->a);
606 printf ("LOW THRU %g", n->a);
609 printf ("%g THRU %g", n->a, n->b);
612 printf ("LOW THRU HIGH");
615 printf ("<ERROR %d>", n->type);
624 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
628 if (s->type == CNT_SINGLE)
629 printf ("'%s'", s->s);
631 printf ("<ERROR %d>", s->type);
639 #endif /* DEBUGGING */