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
30 /* Implementation details:
32 The S?SS manuals do not specify the order that COUNT subcommands are
33 performed in. Experiments, however, have shown that they are performed
34 in the order that they are specified in, rather than simultaneously.
35 So, with the two variables A and B, and the two cases,
41 the command COUNT A=A B (1) / B=A B (2) will produce the following
48 rather than the results that would be produced if subcommands were
55 Perhaps simultaneity could be implemented as an option. On the
56 other hand, what good are the above commands? */
58 #include "debug-print.h"
64 CNT_ERROR, /* Invalid value. */
65 CNT_SINGLE, /* Single value. */
66 CNT_HIGH, /* x >= a. */
67 CNT_LOW, /* x <= a. */
68 CNT_RANGE, /* a <= x <= b. */
69 CNT_ANY, /* Count any. */
70 CNT_SENTINEL /* List terminator. */
87 struct counting *next;
89 /* variables to count */
94 int missing; /* (numeric only)
95 0=don't count missing,
97 2=count system- and user-missing */
98 union /* Criterion values. */
108 struct cnt_var_info *next;
110 struct variable *d; /* Destination variable. */
111 char n[9]; /* Name of dest var. */
113 struct counting *c; /* The counting specifications. */
118 struct trns_header h;
119 struct cnt_var_info *specs;
123 static void debug_print (void);
126 /* First counting in chain. */
127 static struct cnt_var_info *head;
131 static int count_trns_proc (struct trns_header *, struct ccase *);
132 static void count_trns_free (struct trns_header *);
134 static int parse_numeric_criteria (struct counting *);
135 static int parse_string_criteria (struct counting *);
140 /* Specification currently being parsed. */
141 struct cnt_var_info *cnt;
143 /* Counting currently being parsed. */
146 /* Return value from parsing function. */
149 /* Transformation. */
150 struct count_trns *trns;
152 lex_match_id ("COUNT");
154 /* Parses each slash-delimited specification. */
155 head = cnt = xmalloc (sizeof *cnt);
158 /* Initialize this struct cnt_var_info to ensure proper cleanup. */
163 /* Get destination struct variable, or at least its name. */
164 if (!lex_force_id ())
166 cnt->d = dict_lookup_var (default_dict, tokid);
169 if (cnt->d->type == ALPHA)
171 msg (SE, _("Destination cannot be a string variable."));
176 strcpy (cnt->n, tokid);
179 if (!lex_force_match ('='))
182 c = cnt->c = xmalloc (sizeof *c);
187 if (!parse_variables (default_dict, &c->v, &c->n,
188 PV_DUPLICATE | PV_SAME_TYPE))
191 if (!lex_force_match ('('))
194 ret = (c->v[0]->type == NUMERIC
195 ? parse_numeric_criteria
196 : parse_string_criteria) (c);
200 if (token == '/' || token == '.')
203 c = c->next = xmalloc (sizeof *c);
209 if (!lex_force_match ('/'))
211 cnt = cnt->next = xmalloc (sizeof *cnt);
214 /* Create all the nonexistent destination variables. */
215 for (cnt = head; cnt; cnt = cnt->next)
218 /* It's valid, though motivationally questionable, to count to
219 the same dest var more than once. */
220 cnt->d = dict_lookup_var (default_dict, cnt->n);
223 cnt->d = dict_create_var_assert (default_dict, cnt->n, 0);
230 trns = xmalloc (sizeof *trns);
231 trns->h.proc = count_trns_proc;
232 trns->h.free = count_trns_free;
234 add_transformation ((struct trns_header *) trns);
242 count_trns_free ((struct trns_header *) & t);
247 /* Parses a set of numeric criterion values. */
249 parse_numeric_criteria (struct counting * c)
262 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
265 cur = &c->crit.n[n++];
270 if (lex_match_id ("THRU"))
274 if (!lex_force_num ())
277 cur->type = CNT_RANGE;
282 msg (SE, _("%g THRU %g is not a valid range. The "
283 "number following THRU must be at least "
284 "as big as the number preceding THRU."),
289 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
290 cur->type = CNT_HIGH;
298 cur->type = CNT_SINGLE;
300 else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
302 if (!lex_force_match_id ("THRU"))
310 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
318 else if (lex_match_id ("SYSMIS"))
323 else if (lex_match_id ("MISSING"))
336 c->crit.n[n].type = CNT_SENTINEL;
340 /* Parses a set of string criteria values. The skeleton is the same
341 as parse_numeric_criteria(). */
343 parse_string_criteria (struct counting * c)
352 for (i = 0; i < c->n; i++)
353 if (c->v[i]->width > len)
354 len = c->v[i]->width;
363 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
366 if (!lex_force_string ())
368 cur = &c->crit.s[n++];
369 cur->type = CNT_SINGLE;
370 cur->s = malloc (len + 1);
371 st_pad_copy (cur->s, ds_value (&tokstr), len + 1);
379 c->crit.s[n].type = CNT_SENTINEL;
383 /* Transformation. */
385 /* Counts the number of values in case C matching counting CNT. */
387 count_numeric (struct counting * cnt, struct ccase * c)
396 for (i = 0; i < cnt->n; i++)
398 /* Extract the variable value and eliminate missing values. */
399 cmp = c->data[cnt->v[i]->fv].f;
402 if (cnt->missing >= 1)
406 if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
412 /* Try to find the value in the list. */
413 for (num = cnt->crit.n;; num++)
435 if (cmp < num->a || cmp > num->b)
452 /* Counts the number of values in case C matching counting CNT. */
454 count_string (struct counting * cnt, struct ccase * c)
465 for (i = 0; i < cnt->n; i++)
467 /* Extract the variable value, variable width. */
468 cmp = c->data[cnt->v[i]->fv].s;
469 len = cnt->v[i]->width;
471 for (str = cnt->crit.s;; str++)
477 if (memcmp (cmp, str->s, len))
491 /* Performs the COUNT transformation T on case C. */
493 count_trns_proc (struct trns_header * trns, struct ccase * c)
495 struct cnt_var_info *info;
496 struct counting *cnt;
499 for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
502 for (cnt = info->c; cnt; cnt = cnt->next)
503 if (cnt->v[0]->type == NUMERIC)
504 counter += count_numeric (cnt, c);
506 counter += count_string (cnt, c);
507 c->data[info->d->fv].f = counter;
512 /* Destroys all dynamic data structures associated with T. */
514 count_trns_free (struct trns_header * t)
516 struct cnt_var_info *iter, *next;
518 for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
520 struct counting *i, *n;
522 for (i = iter->c; i; i = n)
526 if (i->v[0]->type == NUMERIC)
532 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
554 struct cnt_var_info *iter;
559 for (iter = head; iter; iter = iter->next)
561 printf (" %s=", iter->d->name);
562 for (i = iter->c; i; i = i->next)
564 for (j = 0; j < i->n; j++)
565 printf ("%s%s", j ? " " : "", i->v[j]->name);
567 if (i->v[0]->type == NUMERIC)
573 else if (i->missing == 1)
576 assert (i->missing == 0);
578 for (n = i->crit.n; n->type != CNT_SENTINEL; n++)
580 if (i->missing && n != i->crit.n)
588 printf ("%g THRU HIGH", n->a);
591 printf ("LOW THRU %g", n->a);
594 printf ("%g THRU %g", n->a, n->b);
597 printf ("LOW THRU HIGH");
600 printf ("<ERROR %d>", n->type);
609 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
613 if (s->type == CNT_SINGLE)
614 printf ("'%s'", s->s);
616 printf ("<ERROR %d>", s->type);
624 #endif /* DEBUGGING */