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? */
62 CNT_ERROR, /* Invalid value. */
63 CNT_SINGLE, /* Single value. */
64 CNT_HIGH, /* x >= a. */
65 CNT_LOW, /* x <= a. */
66 CNT_RANGE, /* a <= x <= b. */
67 CNT_ANY, /* Count any. */
68 CNT_SENTINEL /* List terminator. */
85 struct counting *next;
87 /* variables to count */
92 int missing; /* (numeric only)
93 0=don't count missing,
95 2=count system- and user-missing */
96 union /* Criterion values. */
106 struct cnt_var_info *next;
108 struct variable *d; /* Destination variable. */
109 char n[9]; /* Name of dest var. */
111 struct counting *c; /* The counting specifications. */
116 struct trns_header h;
117 struct cnt_var_info *specs;
122 static trns_proc_func count_trns_proc;
123 static trns_free_func count_trns_free;
125 static int parse_numeric_criteria (struct counting *);
126 static int parse_string_criteria (struct counting *);
131 struct cnt_var_info *cnt; /* Specification currently being parsed. */
132 struct counting *c; /* Counting currently being parsed. */
133 int ret; /* Return value from parsing function. */
134 struct count_trns *trns; /* Transformation. */
135 struct cnt_var_info *head; /* First counting in chain. */
137 /* Parses each slash-delimited specification. */
138 head = cnt = xmalloc (sizeof *cnt);
141 /* Initialize this struct cnt_var_info to ensure proper cleanup. */
146 /* Get destination struct variable, or at least its name. */
147 if (!lex_force_id ())
149 cnt->d = dict_lookup_var (default_dict, tokid);
152 if (cnt->d->type == ALPHA)
154 msg (SE, _("Destination cannot be a string variable."));
159 strcpy (cnt->n, tokid);
162 if (!lex_force_match ('='))
165 c = cnt->c = xmalloc (sizeof *c);
170 if (!parse_variables (default_dict, &c->v, &c->n,
171 PV_DUPLICATE | PV_SAME_TYPE))
174 if (!lex_force_match ('('))
177 ret = (c->v[0]->type == NUMERIC
178 ? parse_numeric_criteria
179 : parse_string_criteria) (c);
183 if (token == '/' || token == '.')
186 c = c->next = xmalloc (sizeof *c);
192 if (!lex_force_match ('/'))
194 cnt = cnt->next = xmalloc (sizeof *cnt);
197 /* Create all the nonexistent destination variables. */
198 for (cnt = head; cnt; cnt = cnt->next)
201 /* It's valid, though motivationally questionable, to count to
202 the same dest var more than once. */
203 cnt->d = dict_lookup_var (default_dict, cnt->n);
206 cnt->d = dict_create_var_assert (default_dict, cnt->n, 0);
209 trns = xmalloc (sizeof *trns);
210 trns->h.proc = count_trns_proc;
211 trns->h.free = count_trns_free;
213 add_transformation ((struct trns_header *) trns);
221 count_trns_free ((struct trns_header *) & t);
226 /* Parses a set of numeric criterion values. */
228 parse_numeric_criteria (struct counting * c)
241 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_num));
244 cur = &c->crit.n[n++];
249 if (lex_match_id ("THRU"))
253 if (!lex_force_num ())
256 cur->type = CNT_RANGE;
261 msg (SE, _("%g THRU %g is not a valid range. The "
262 "number following THRU must be at least "
263 "as big as the number preceding THRU."),
268 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
269 cur->type = CNT_HIGH;
277 cur->type = CNT_SINGLE;
279 else if (lex_match_id ("LO") || lex_match_id ("LOWEST"))
281 if (!lex_force_match_id ("THRU"))
289 else if (lex_match_id ("HI") || lex_match_id ("HIGHEST"))
297 else if (lex_match_id ("SYSMIS"))
302 else if (lex_match_id ("MISSING"))
315 c->crit.n[n].type = CNT_SENTINEL;
319 /* Parses a set of string criteria values. The skeleton is the same
320 as parse_numeric_criteria(). */
322 parse_string_criteria (struct counting * c)
331 for (i = 0; i < c->n; i++)
332 if (c->v[i]->width > len)
333 len = c->v[i]->width;
342 c->crit.n = xrealloc (c->crit.n, m * sizeof (struct cnt_str));
345 if (!lex_force_string ())
347 cur = &c->crit.s[n++];
348 cur->type = CNT_SINGLE;
349 cur->s = malloc (len + 1);
350 st_pad_copy (cur->s, ds_value (&tokstr), len + 1);
358 c->crit.s[n].type = CNT_SENTINEL;
362 /* Transformation. */
364 /* Counts the number of values in case C matching counting CNT. */
366 count_numeric (struct counting * cnt, struct ccase * c)
375 for (i = 0; i < cnt->n; i++)
377 /* Extract the variable value and eliminate missing values. */
378 cmp = c->data[cnt->v[i]->fv].f;
381 if (cnt->missing >= 1)
385 if (cnt->missing >= 2 && is_num_user_missing (cmp, cnt->v[i]))
391 /* Try to find the value in the list. */
392 for (num = cnt->crit.n;; num++)
414 if (cmp < num->a || cmp > num->b)
431 /* Counts the number of values in case C matching counting CNT. */
433 count_string (struct counting * cnt, struct ccase * c)
444 for (i = 0; i < cnt->n; i++)
446 /* Extract the variable value, variable width. */
447 cmp = c->data[cnt->v[i]->fv].s;
448 len = cnt->v[i]->width;
450 for (str = cnt->crit.s;; str++)
456 if (memcmp (cmp, str->s, len))
470 /* Performs the COUNT transformation T on case C. */
472 count_trns_proc (struct trns_header * trns, struct ccase * c,
475 struct cnt_var_info *info;
476 struct counting *cnt;
479 for (info = ((struct count_trns *) trns)->specs; info; info = info->next)
482 for (cnt = info->c; cnt; cnt = cnt->next)
483 if (cnt->v[0]->type == NUMERIC)
484 counter += count_numeric (cnt, c);
486 counter += count_string (cnt, c);
487 c->data[info->d->fv].f = counter;
492 /* Destroys all dynamic data structures associated with T. */
494 count_trns_free (struct trns_header * t)
496 struct cnt_var_info *iter, *next;
498 for (iter = ((struct count_trns *) t)->specs; iter; iter = next)
500 struct counting *i, *n;
502 for (i = iter->c; i; i = n)
506 if (i->v[0]->type == NUMERIC)
512 for (s = i->crit.s; s->type != CNT_SENTINEL; s++)