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
34 /*#define DEBUGGING 1 */
35 #include "debug-print.h"
37 /* FIXME: This module is less than ideally efficient, both in space
38 and time. If anyone cares, it would be a good project. */
40 /* FIXME: Implement PRINT subcommand. */
42 /* Explains how to recode one value. `from' must be first element. */
45 union value from; /* Original value. */
46 double to; /* Recoded value. */
49 /* Explains how to recode an AUTORECODE variable. */
52 struct variable *src; /* Source variable. */
53 struct variable *dest; /* Target variable. */
54 struct hsh_table *items; /* Hash table of `freq's. */
57 /* AUTORECODE transformation. */
58 struct autorecode_trns
61 struct pool *owner; /* Contains AUTORECODE specs. */
62 struct arc_spec *arc; /* AUTORECODE specifications. */
63 int n_arc; /* Number of specifications. */
66 /* Source and target variables, hash table translator. */
67 static struct variable **v_src;
68 static struct variable **v_dest;
69 static struct hsh_table **h_trans;
72 /* Pool for allocation of hash table entries. */
73 static struct pool *hash_pool;
79 static int autorecode_trns_proc (struct trns_header *, struct ccase *);
80 static void autorecode_trns_free (struct trns_header *);
81 static int autorecode_proc_func (struct ccase *);
82 static int compare_alpha_value (const void *, const void *, void *);
83 static unsigned hash_alpha_value (const void *, void *);
84 static int compare_numeric_value (const void *, const void *, void *);
85 static unsigned hash_numeric_value (const void *, void *);
86 static void recode (void);
88 /* Performs the AUTORECODE procedure. */
102 lex_match_id ("AUTORECODE");
103 lex_match_id ("VARIABLES");
105 if (!parse_variables (&default_dict, &v_src, &nv_src, PV_NO_DUPLICATE))
107 if (!lex_force_match_id ("INTO"))
110 if (!parse_DATA_LIST_vars (&n_dest, &nv_dest, PV_NONE))
112 if (nv_dest != nv_src)
114 msg (SE, _("Number of source variables (%d) does not match number "
115 "of target variables (%d)."), nv_src, nv_dest);
118 while (lex_match ('/'))
119 if (lex_match_id ("DESCENDING"))
121 else if (lex_match_id ("PRINT"))
125 lex_error (_("expecting end of command"));
129 for (i = 0; i < nv_dest; i++)
133 if (is_varname (n_dest[i]))
135 msg (SE, _("Target variable %s duplicates existing variable %s."),
136 n_dest[i], n_dest[i]);
139 for (j = 0; j < i; j++)
140 if (!strcmp (n_dest[i], n_dest[j]))
142 msg (SE, _("Duplicate variable name %s among target variables."),
148 hash_pool = pool_create ();
150 v_dest = xmalloc (sizeof *v_dest * nv_dest);
151 h_trans = xmalloc (sizeof *h_trans * nv_dest);
152 for (i = 0; i < nv_dest; i++)
153 if (v_src[i]->type == ALPHA)
154 h_trans[i] = hsh_create (10, compare_alpha_value,
155 hash_alpha_value, NULL,
156 (void *) v_src[i]->width);
158 h_trans[i] = hsh_create (10, compare_numeric_value,
159 hash_numeric_value, NULL, NULL);
161 procedure (NULL, autorecode_proc_func, NULL);
163 for (i = 0; i < nv_dest; i++)
165 v_dest[i] = force_create_variable (&default_dict, n_dest[i], NUMERIC, 0);
179 for (i = 0; i < nv_src; i++)
180 hsh_destroy (h_trans[i]);
181 for (i = 0; i < nv_dest; i++)
188 /* AUTORECODE transformation. */
193 struct autorecode_trns *t;
194 struct pool *arc_pool;
197 arc_pool = pool_create ();
198 t = xmalloc (sizeof *t);
199 t->h.proc = autorecode_trns_proc;
200 t->h.free = autorecode_trns_free;
202 t->arc = pool_alloc (arc_pool, sizeof *t->arc * nv_src);
204 for (i = 0; i < nv_src; i++)
206 struct arc_spec *spec = &t->arc[i];
207 void **p = hsh_sort (h_trans[i], NULL);
208 int count = hsh_count (h_trans[i]);
211 spec->src = v_src[i];
212 spec->dest = v_dest[i];
214 if (v_src[i]->type == ALPHA)
215 spec->items = hsh_create (2 * count, compare_alpha_value,
216 hash_alpha_value, NULL,
217 (void *) v_src[i]->width);
219 spec->items = hsh_create (2 * count, compare_numeric_value,
220 hash_numeric_value, NULL, NULL);
222 for (j = 0; *p; p++, j++)
224 struct arc_item *item = pool_alloc (arc_pool, sizeof *item);
226 memcpy (&item->from, *p, sizeof (union value));
227 if (v_src[i]->type == ALPHA)
228 item->from.c = pool_strdup (arc_pool, item->from.c);
229 item->to = !descend ? j + 1 : count - j;
230 force_hsh_insert (spec->items, item);
233 hsh_destroy (h_trans[i]);
236 pool_destroy (hash_pool);
237 add_transformation ((struct trns_header *) t);
241 autorecode_trns_proc (struct trns_header * trns, struct ccase * c)
243 struct autorecode_trns *t = (struct autorecode_trns *) trns;
246 for (i = 0; i < t->n_arc; i++)
248 struct arc_spec *spec = &t->arc[i];
249 struct arc_item *item;
251 if (spec->src->type == NUMERIC)
252 item = force_hsh_find (spec->items, &c->data[spec->src->fv].f);
256 v.c = c->data[spec->src->fv].s;
257 item = force_hsh_find (spec->items, &v);
260 c->data[spec->dest->fv].f = item->to;
266 autorecode_trns_free (struct trns_header * trns)
268 struct autorecode_trns *t = (struct autorecode_trns *) trns;
271 for (i = 0; i < t->n_arc; i++)
272 hsh_destroy (t->arc[i].items);
273 pool_destroy (t->owner);
276 /* AUTORECODE procedure. */
279 compare_alpha_value (const void *a, const void *b, void *len)
281 return memcmp (((union value *) a)->c, ((union value *) b)->c, (int) len);
285 hash_alpha_value (const void *a, void *len)
287 return hashpjw_d (((union value *) a)->c, &((union value *) a)->c[(int) len]);
291 compare_numeric_value (const void *pa, const void *pb, void *foobar unused)
293 double a = ((union value *) pa)->f, b = ((union value *) pb)->f;
294 return a > b ? 1 : (a < b ? -1 : 0);
298 hash_numeric_value (const void *a, void *len unused)
300 return hashpjw_d ((char *) &((union value *) a)->f,
301 (char *) &(&((union value *) a)->f)[1]);
305 autorecode_proc_func (struct ccase * c)
309 for (i = 0; i < nv_src; i++)
315 if (v_src[i]->type == NUMERIC)
317 v.f = c->data[v_src[i]->fv].f;
318 vpp = (union value **) hsh_probe (h_trans[i], &v);
321 vp = pool_alloc (hash_pool, sizeof (union value));
328 v.c = c->data[v_src[i]->fv].s;
329 vpp = (union value **) hsh_probe (h_trans[i], &v);
332 vp = pool_alloc (hash_pool, sizeof (union value));
334 memset (vp, 0, sizeof (union value));
336 vp->c = pool_strdup (hash_pool, v.c);