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
20 /* AIX requires this to be the first thing in the file. */
23 #define alloca __builtin_alloca
31 #ifndef alloca /* predefined by HP cc +Olibcalls */
40 #include "algorithm.h"
42 #include "bitvector.h"
52 /* FIXME: should change weighting variable, etc. */
53 /* These control the ordering produced by
54 compare_variables_given_ordering(). */
57 int forward; /* 1=FORWARD, 0=BACKWARD. */
58 int positional; /* 1=POSITIONAL, 0=ALPHA. */
61 static int compare_variables_given_ordering (const void *, const void *,
64 /* Explains how to modify the variables in a dictionary in conjunction
65 with the p.mfv field of `variable'. */
66 struct var_modification
68 /* REORDER information. */
69 struct variable **reorder_list;
71 /* RENAME information. */
72 struct variable **old_names;
76 /* DROP/KEEP information. */
77 int n_drop; /* Number of variables being dropped. */
80 static struct dictionary *rearrange_dict (struct dictionary *d,
81 struct var_modification *vm,
84 /* Performs MODIFY VARS command. */
86 cmd_modify_vars (void)
88 /* Bits indicated whether we've already encountered a subcommand of
90 unsigned already_encountered = 0;
92 /* What we're gonna do to the active file. */
93 struct var_modification vm;
95 lex_match_id ("MODIFY");
96 lex_match_id ("VARS");
98 vm.reorder_list = NULL;
104 /* Parse each subcommand. */
108 if (lex_match_id ("REORDER"))
110 struct variable **v = NULL;
113 if (already_encountered & 1)
115 msg (SE, _("REORDER subcommand may be given at most once."));
118 already_encountered |= 1;
123 struct ordering ordering;
126 ordering.forward = ordering.positional = 1;
127 if (lex_match_id ("FORWARD"));
128 else if (lex_match_id ("BACKWARD"))
129 ordering.forward = 0;
130 if (lex_match_id ("POSITIONAL"));
131 else if (lex_match_id ("ALPHA"))
132 ordering.positional = 0;
134 if (lex_match (T_ALL) || token == '/' || token == '.')
138 msg (SE, _("Cannot specify ALL after specifying a set "
142 fill_all_vars (&v, &nv, FV_NO_SYSTEM);
146 if (!lex_match ('('))
148 msg (SE, _("`(' expected on REORDER subcommand."));
152 if (!parse_variables (&default_dict, &v, &nv,
153 PV_APPEND | PV_NO_DUPLICATE))
158 if (!lex_match (')'))
160 msg (SE, _("`)' expected following variable names on "
161 "REORDER subcommand."));
166 sort (&v[prev_nv], nv - prev_nv, sizeof *v,
167 compare_variables_given_ordering, &ordering);
169 while (token != '/' && token != '.');
171 if (nv != default_dict.nvar)
173 size_t nbytes = DIV_RND_UP (default_dict.nvar, 8);
174 unsigned char *bits = local_alloc (nbytes);
177 memset (bits, 0, nbytes);
178 for (i = 0; i < nv; i++)
179 SET_BIT (bits, v[i]->index);
180 v = xrealloc (v, sizeof *v * default_dict.nvar);
181 for (i = 0; i < default_dict.nvar; i++)
182 if (!TEST_BIT (bits, i))
183 v[nv++] = default_dict.var[i];
189 else if (lex_match_id ("RENAME"))
191 if (already_encountered & 2)
193 msg (SE, _("RENAME subcommand may be given at most once."));
196 already_encountered |= 2;
201 int prev_nv_1 = vm.n_rename;
202 int prev_nv_2 = vm.n_rename;
204 if (!lex_match ('('))
206 msg (SE, _("`(' expected on RENAME subcommand."));
209 if (!parse_variables (&default_dict, &vm.old_names, &vm.n_rename,
210 PV_APPEND | PV_NO_DUPLICATE))
212 if (!lex_match ('='))
214 msg (SE, _("`=' expected between lists of new and old variable "
215 "names on RENAME subcommand."));
218 if (!parse_DATA_LIST_vars (&vm.new_names, &prev_nv_1, PV_APPEND))
220 if (prev_nv_1 != vm.n_rename)
224 msg (SE, _("Differing number of variables in old name list "
225 "(%d) and in new name list (%d)."),
226 vm.n_rename - prev_nv_2, prev_nv_1 - prev_nv_2);
227 for (i = 0; i < prev_nv_1; i++)
228 free (&vm.new_names[i]);
229 free (&vm.new_names);
233 if (!lex_match (')'))
235 msg (SE, _("`)' expected after variable lists on RENAME "
240 while (token != '.' && token != '/');
242 else if (lex_match_id ("KEEP"))
244 struct ordering ordering;
245 struct variable **keep_vars;
250 if (already_encountered & 4)
252 msg (SE, _("KEEP subcommand may be given at most once. It may not"
253 "be given in conjunction with the DROP subcommand."));
256 already_encountered |= 4;
259 if (!parse_variables (&default_dict, &keep_vars, &nv, PV_NONE))
262 /* Transform the list of variables to keep into a list of
263 variables to drop. First sort the keep list, then figure
264 out which variables are missing. */
265 ordering.forward = ordering.positional = 1;
266 sort (keep_vars, nv, sizeof *keep_vars,
267 compare_variables_given_ordering, &ordering);
269 vm.n_drop = default_dict.nvar - nv;
272 for (i = 0; i < nv; i++)
274 while (counter < keep_vars[i]->index)
275 default_dict.var[counter++]->p.mfv.drop_this_var = 1;
276 default_dict.var[counter++]->p.mfv.drop_this_var = 0;
279 default_dict.var[counter++]->p.mfv.drop_this_var = 1;
283 else if (lex_match_id ("DROP"))
285 struct variable **drop_vars;
289 if (already_encountered & 4)
291 msg (SE, _("DROP subcommand may be given at most once. It may not"
292 "be given in conjunction with the KEEP subcommand."));
295 already_encountered |= 4;
298 if (!parse_variables (&default_dict, &drop_vars, &nv, PV_NONE))
300 for (i = 0; i < default_dict.nvar; i++)
301 default_dict.var[i]->p.mfv.drop_this_var = 0;
302 for (i = 0; i < nv; i++)
303 drop_vars[i]->p.mfv.drop_this_var = 1;
307 else if (lex_match_id ("MAP"))
309 struct dictionary *new_dict = rearrange_dict (&default_dict, &vm, 0);
312 /* FIXME: display new dictionary. */
317 msg (SE, _("Unrecognized subcommand name `%s'."), tokid);
319 msg (SE, _("Subcommand name expected."));
327 msg (SE, _("`/' or `.' expected."));
336 if (already_encountered & (1 | 4))
339 procedure (NULL, NULL, NULL);
342 if (NULL == rearrange_dict (&default_dict, &vm, 1))
345 free (vm.reorder_list);
347 for (i = 0; i < vm.n_rename; i++)
348 free (vm.new_names[i]);
358 free (vm.reorder_list);
360 for (i = 0; i < vm.n_rename; i++)
361 free (vm.new_names[i]);
367 /* Compares A and B according to the settings in
368 ORDERING, returning a strcmp()-type result. */
370 compare_variables_given_ordering (const void *a_, const void *b_,
373 struct variable *const *pa = a_;
374 struct variable *const *pb = b_;
375 const struct variable *a = *pa;
376 const struct variable *b = *pb;
377 const struct ordering *ordering = ordering_;
380 if (ordering->positional)
381 result = a->index < b->index ? -1 : a->index > b->index;
383 result = strcmp (a->name, b->name);
384 if (!ordering->forward)
389 /* (Possibly) rearranges variables and (possibly) removes some
390 variables and (possibly) renames some more variables in dictionary
391 D. There are two modes of operation, distinguished by the value of
394 If PERMANENT is nonzero, then the dictionary is modified in place.
395 Returns the new dictionary on success or NULL if there would have
396 been duplicate variable names in the resultant dictionary (in this
397 case the dictionary has not been modified).
399 If PERMANENT is zero, then the dictionary is copied to a new
400 dictionary structure that retains most of the same deep structure
401 as D. The p.mfv.new_name field of each variable is set to what
402 would become the variable's new name if PERMANENT were nonzero.
403 Returns the new dictionary. */
404 static struct dictionary *
405 rearrange_dict (struct dictionary * d, struct var_modification * vm, int permanent)
407 struct dictionary *n;
409 struct variable **save_var;
411 /* Linked list of variables for deletion. */
412 struct variable *head, *tail;
416 /* First decide what dictionary to modify. */
419 n = xmalloc (sizeof *n);
426 /* Perform first half of renaming. */
429 for (i = 0; i < d->nvar; i++)
430 d->var[i]->p.mfv.new_name[0] = 0;
431 d->var = xmalloc (sizeof *d->var * d->nvar);
434 for (i = 0; i < d->nvar; i++)
435 strcpy (d->var[i]->p.mfv.new_name, d->var[i]->name);
436 for (i = 0; i < vm->n_rename; i++)
437 strcpy (vm->old_names[i]->p.mfv.new_name, vm->new_names[i]);
439 /* Copy the variable list, reordering if appropriate. */
440 if (vm->reorder_list)
441 memcpy (n->var, vm->reorder_list, sizeof *n->var * d->nvar);
443 for (i = 0; i < d->nvar; i++)
444 n->var[i] = d->var[i];
446 /* Drop all the unwanted variables. */
452 n->nvar = d->nvar - vm->n_drop;
453 for (i = j = 0; i < n->nvar; i++)
455 while (n->var[j]->p.mfv.drop_this_var != 0)
459 /* If this is permanent, then we have to keep a list
460 of all the dropped variables because they must be
461 free()'d, but can't be until we know that there
462 aren't any duplicate variable names. */
464 tail = tail->p.mfv.next = n->var[j];
466 head = tail = n->var[j];
470 n->var[i] = n->var[j++];
473 tail->p.mfv.next = NULL;
476 /* Check for duplicate variable names if appropriate. */
477 if (permanent && vm->n_rename)
479 struct ordering ordering;
482 if (vm->reorder_list)
483 v = vm->reorder_list; /* Reuse old buffer if possible. */
485 v = xmalloc (sizeof *v * n->nvar);
486 memcpy (v, n->var, sizeof *v * n->nvar);
487 ordering.forward = 1;
488 ordering.positional = 0;
489 sort (v, n->nvar, sizeof *v,
490 compare_variables_given_ordering, &ordering);
491 for (i = 1; i < n->nvar; i++)
492 if (!strcmp (n->var[i]->name, n->var[i - 1]->name))
494 msg (SE, _("Duplicate variable name `%s' after renaming."),
496 if (vm->reorder_list == NULL)
501 if (vm->reorder_list == NULL)
505 /* Delete unwanted variables and finalize renaming if
509 /* Delete dropped variables for good. */
510 for (; head; head = tail)
512 tail = head->p.mfv.next;
513 clear_variable (n, head);
517 /* Remove names from all renamed variables. */
519 for (i = 0; i < n->nvar; i++)
520 if (n->var[i]->p.mfv.new_name[0])
522 hsh_force_delete (n->name_tab, n->var[i]);
524 tail = tail->p.mfv.next = n->var[i];
526 head = tail = n->var[i];
529 tail->p.mfv.next = NULL;
531 /* Put names onto renamed variables. */
532 for (; head; head = head->p.mfv.next)
534 strcpy (head->name, head->p.mfv.new_name);
535 hsh_force_insert (n->name_tab, head);
539 /* As a final step the index fields must be redone. */
540 for (i = 0; i < n->nvar; i++)
541 n->var[i]->index = i;