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? */
63 CNT_ERROR, /* Invalid value. */
64 CNT_SINGLE, /* Single value. */
65 CNT_HIGH, /* x >= a. */
66 CNT_LOW, /* x <= a. */
67 CNT_RANGE, /* a <= x <= b. */
68 CNT_ANY, /* Count any. */
69 CNT_SENTINEL /* List terminator. */
86 struct counting *next;
88 /* variables to count */
93 int missing; /* (numeric only)
94 0=don't count missing,
96 2=count system- and user-missing */
97 union /* Criterion values. */
107 struct cnt_var_info *next;
109 struct variable *d; /* Destination variable. */
110 char n[9]; /* Name of dest var. */
112 struct counting *c; /* The counting specifications. */
117 struct trns_header h;
118 struct cnt_var_info *specs;
123 static trns_proc_func count_trns_proc;
124 static trns_free_func count_trns_free;
126 static int parse_numeric_criteria (struct counting *);
127 static int parse_string_criteria (struct counting *);
132 struct cnt_var_info *cnt; /* Specification currently being parsed. */
133 struct counting *c; /* Counting currently being parsed. */
134 int ret; /* Return value from parsing function. */
135 struct count_trns *trns; /* Transformation. */
136 struct cnt_var_info *head; /* First counting in chain. */
138 /* Parses each slash-delimited specification. */
139 head = cnt = xmalloc (sizeof *cnt);
142 /* Initialize this struct cnt_var_info to ensure proper cleanup. */
147 /* Get destination struct variable, or at least its name. */
148 if (!lex_force_id ())
150 cnt->d = dict_lookup_var (default_dict, tokid);
153 if (cnt->d->type == ALPHA)
155 msg (SE, _("Destination cannot be a string variable."));
160 strcpy (cnt->n, tokid);
163 if (!lex_force_match ('='))
166 c = cnt->c = xmalloc (sizeof *c);
171 if (!parse_variables (default_dict, &c->v, &c->n,
172 PV_DUPLICATE | PV_SAME_TYPE))
175 if (!lex_force_match ('('))
178 ret = (c->v[0]->type == NUMERIC
179 ? parse_numeric_criteria
180 : parse_string_criteria) (c);
184 if (token == '/' || token == '.')
187 c = c->next = xmalloc (sizeof *c);
193 if (!lex_force_match ('/'))
195 cnt = cnt->next = xmalloc (sizeof *cnt);
198 /* Create all the nonexistent destination variables. */
199 for (cnt = head; cnt; cnt = cnt->next)
202 /* It's valid, though motivationally questionable, to count to
203 the same dest var more than once. */
204 cnt->d = dict_lookup_var (default_dict, cnt->n);
207 cnt->d = dict_create_var_assert (default_dict, cnt->n, 0);
210 trns = xmalloc (sizeof *trns);
211 trns->h.proc = count_trns_proc;
212 trns->h.free = count_trns_free;
214 add_transformation ((struct trns_header *) trns);
222 count_trns_free ((struct trns_header *) & t);
227 /* Parses a set of numeric criterion values. */
229 parse_numeric_criteria (struct counting * c)
242 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
245 cur = &c->crit.n[n++];
250 if (lex_match_id ("THRU"))
254 if (!lex_force_num ())
257 cur->type = CNT_RANGE;
262 msg (SE, _("%g THRU %g is not a valid range. The "
263 "number following THRU must be at least "
264 "as big as the number preceding THRU."),
269 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
270 cur->type = CNT_HIGH;
278 cur->type = CNT_SINGLE;
280 else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
282 if (!lex_force_match_id ("THRU"))
290 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
298 else if (lex_match_id ("SYSMIS"))
303 else if (lex_match_id ("MISSING"))
316 c->crit.n[n].type = CNT_SENTINEL;
320 /* Parses a set of string criteria values. The skeleton is the same
321 as parse_numeric_criteria(). */
323 parse_string_criteria (struct counting * c)
332 for (i = 0; i < c->n; i++)
333 if (c->v[i]->width > len)
334 len = c->v[i]->width;
343 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
346 if (!lex_force_string ())
348 cur = &c->crit.s[n++];
349 cur->type = CNT_SINGLE;
350 cur->s = malloc (len + 1);
351 st_pad_copy (cur->s, ds_c_str (&tokstr), len + 1);
359 c->crit.s[n].type = CNT_SENTINEL;
363 /* Transformation. */
365 /* Counts the number of values in case C matching counting CNT. */
367 count_numeric (struct counting * cnt, struct ccase * c)
372 for (i = 0; i < cnt->n; i++)
376 /* Extract the variable value and eliminate missing values. */
377 double cmp = case_num (c, cnt->v[i]->fv);
380 if (cnt->missing >= 1)
384 if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
390 /* Try to find the value in the list. */
391 for (num = cnt->crit.n;; num++)
413 if (cmp < num->a || cmp > num->b)
430 /* Counts the number of values in case C matching counting CNT. */
432 count_string (struct counting * cnt, struct ccase * c)
437 for (i = 0; i < cnt->n; i++)
441 /* Extract the variable value, variable width. */
442 for (str = cnt->crit.s;; str++)
448 if (memcmp (case_str (c, cnt->v[i]->fv), str->s,
463 /* Performs the COUNT transformation T on case C. */
465 count_trns_proc (struct trns_header * trns, struct ccase * c,
468 struct cnt_var_info *info;
469 struct counting *cnt;
472 for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
475 for (cnt = info->c; cnt; cnt = cnt->next)
476 if (cnt->v[0]->type == NUMERIC)
477 counter += count_numeric (cnt, c);
479 counter += count_string (cnt, c);
480 case_data_rw (c, info->d->fv)->f = counter;
485 /* Destroys all dynamic data structures associated with T. */
487 count_trns_free (struct trns_header * t)
489 struct cnt_var_info *iter, *next;
491 for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
493 struct counting *i, *n;
495 for (i = iter->c; i; i = n)
499 if (i->v[0]->type == NUMERIC)
505 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)