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? */
61 #include "debug-print.h"
67 CNT_ERROR, /* Invalid value. */
68 CNT_SINGLE, /* Single value. */
69 CNT_HIGH, /* x >= a. */
70 CNT_LOW, /* x <= a. */
71 CNT_RANGE, /* a <= x <= b. */
72 CNT_ANY, /* Count any. */
73 CNT_SENTINEL /* List terminator. */
90 struct counting *next;
92 /* variables to count */
97 int missing; /* (numeric only)
98 0=don't count missing,
100 2=count system- and user-missing */
101 union /* Criterion values. */
111 struct cnt_var_info *next;
113 struct variable *d; /* Destination variable. */
114 char n[9]; /* Name of dest var. */
116 struct counting *c; /* The counting specifications. */
121 struct trns_header h;
122 struct cnt_var_info *specs;
126 static void debug_print (void);
129 /* First counting in chain. */
130 static struct cnt_var_info *head;
134 static int count_trns_proc (struct trns_header *, struct ccase *);
135 static void count_trns_free (struct trns_header *);
137 static int parse_numeric_criteria (struct counting *);
138 static int parse_string_criteria (struct counting *);
140 int cmd_count (void);
143 internal_cmd_count (void)
145 int code = cmd_count ();
150 count_trns_free ((struct trns_header *) & c);
158 /* Specification currently being parsed. */
159 struct cnt_var_info *cnt;
161 /* Counting currently being parsed. */
164 /* Return value from parsing function. */
167 /* Transformation. */
168 struct count_trns *trns;
170 lex_match_id ("COUNT");
172 /* Parses each slash-delimited specification. */
173 head = cnt = xmalloc (sizeof *cnt);
176 /* Initialize this struct cnt_var_info to ensure proper cleanup. */
181 /* Get destination struct variable, or at least its name. */
182 if (!lex_force_id ())
184 cnt->d = find_variable (tokid);
187 if (cnt->d->type == ALPHA)
189 msg (SE, _("Destination cannot be a string variable."));
194 strcpy (cnt->n, tokid);
197 if (!lex_force_match ('='))
200 c = cnt->c = xmalloc (sizeof *c);
205 if (!parse_variables (NULL, &c->v, &c->n, PV_DUPLICATE | PV_SAME_TYPE))
208 if (!lex_force_match ('('))
211 ret = (c->v[0]->type == NUMERIC
212 ? parse_numeric_criteria
213 : parse_string_criteria) (c);
217 if (token == '/' || token == '.')
220 c = c->next = xmalloc (sizeof *c);
226 if (!lex_force_match ('/'))
228 cnt = cnt->next = xmalloc (sizeof *cnt);
231 /* Create all the nonexistent destination variables. */
232 for (cnt = head; cnt; cnt = cnt->next)
235 /* It's legal, though motivationally questionable, to count to
236 the same dest var more than once. */
237 cnt->d = find_variable (cnt->n);
240 cnt->d = force_create_variable (&default_dict, cnt->n, NUMERIC, 0);
247 trns = xmalloc (sizeof *trns);
248 trns->h.proc = count_trns_proc;
249 trns->h.free = count_trns_free;
251 add_transformation ((struct trns_header *) trns);
259 count_trns_free ((struct trns_header *) & t);
264 /* Parses a set of numeric criterion values. */
266 parse_numeric_criteria (struct counting * c)
279 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
282 cur = &c->crit.n[n++];
287 if (lex_match_id ("THRU"))
291 if (!lex_force_num ())
294 cur->type = CNT_RANGE;
299 msg (SE, _("%g THRU %g is not a valid range. The "
300 "number following THRU must be at least "
301 "as big as the number preceding THRU."),
306 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
307 cur->type = CNT_HIGH;
315 cur->type = CNT_SINGLE;
317 else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
319 if (!lex_force_match_id ("THRU"))
327 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
335 else if (lex_match_id ("SYSMIS"))
340 else if (lex_match_id ("MISSING"))
353 c->crit.n[n].type = CNT_SENTINEL;
357 /* Parses a set of string criteria values. The skeleton is the same
358 as parse_numeric_criteria(). */
360 parse_string_criteria (struct counting * c)
369 for (i = 0; i < c->n; i++)
370 if (c->v[i]->width > len)
371 len = c->v[i]->width;
380 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
383 if (!lex_force_string ())
385 cur = &c->crit.s[n++];
386 cur->type = CNT_SINGLE;
387 cur->s = malloc (len + 1);
388 st_pad_copy (cur->s, ds_value (&tokstr), len + 1);
396 c->crit.s[n].type = CNT_SENTINEL;
400 /* Transformation. */
402 /* Counts the number of values in case C matching counting CNT. */
404 count_numeric (struct counting * cnt, struct ccase * c)
413 for (i = 0; i < cnt->n; i++)
415 /* Extract the variable value and eliminate missing values. */
416 cmp = c->data[cnt->v[i]->fv].f;
419 if (cnt->missing >= 1)
423 if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
429 /* Try to find the value in the list. */
430 for (num = cnt->crit.n;; num++)
437 if (approx_ne (cmp, num->a))
442 if (approx_lt (cmp, num->a))
447 if (approx_gt (cmp, num->a))
452 if (approx_lt (cmp, num->a) || approx_gt (cmp, num->b))
469 /* Counts the number of values in case C matching counting CNT. */
471 count_string (struct counting * cnt, struct ccase * c)
482 for (i = 0; i < cnt->n; i++)
484 /* Extract the variable value, variable width. */
485 cmp = c->data[cnt->v[i]->fv].s;
486 len = cnt->v[i]->width;
488 for (str = cnt->crit.s;; str++)
494 if (memcmp (cmp, str->s, len))
508 /* Performs the COUNT transformation T on case C. */
510 count_trns_proc (struct trns_header * trns, struct ccase * c)
512 struct cnt_var_info *info;
513 struct counting *cnt;
516 for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
519 for (cnt = info->c; cnt; cnt = cnt->next)
520 if (cnt->v[0]->type == NUMERIC)
521 counter += count_numeric (cnt, c);
523 counter += count_string (cnt, c);
524 c->data[info->d->fv].f = counter;
529 /* Destroys all dynamic data structures associated with T. */
531 count_trns_free (struct trns_header * t)
533 struct cnt_var_info *iter, *next;
535 for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
537 struct counting *i, *n;
539 for (i = iter->c; i; i = n)
543 if (i->v[0]->type == NUMERIC)
549 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
571 struct cnt_var_info *iter;
576 for (iter = head; iter; iter = iter->next)
578 printf (" %s=", iter->d->name);
579 for (i = iter->c; i; i = i->next)
581 for (j = 0; j < i->n; j++)
582 printf ("%s%s", j ? " " : "", i->v[j]->name);
584 if (i->v[0]->type == NUMERIC)
590 else if (i->missing == 1)
593 assert (i->missing == 0);
595 for (n = i->crit.n; n->type != CNT_SENTINEL; n++)
597 if (i->missing && n != i->crit.n)
605 printf ("%g THRU HIGH", n->a);
608 printf ("LOW THRU %g", n->a);
611 printf ("%g THRU %g", n->a, n->b);
614 printf ("LOW THRU HIGH");
617 printf ("<ERROR %d>", n->type);
626 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)
630 if (s->type == CNT_SINGLE)
631 printf ("'%s'", s->s);
633 printf ("<ERROR %d>", s->type);
641 #endif /* DEBUGGING */