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 /* Increasing order of variable index. */
62 static struct ordering forward_positional_ordering = {1, 1};
64 static int compare_variables_given_ordering (const void *, const void *,
67 /* Explains how to modify the variables in a dictionary. */
68 struct var_modification
70 /* New variable ordering. */
71 struct variable **reorder_vars;
74 /* DROP/KEEP information. */
75 struct variable **drop_vars;
78 /* New variable names. */
79 struct variable **rename_vars;
84 static int rearrange_dict (struct dictionary *d,
85 const struct var_modification *vm);
87 /* Performs MODIFY VARS command. */
89 cmd_modify_vars (void)
91 /* Bits indicated whether we've already encountered a subcommand of
93 unsigned already_encountered = 0;
95 /* What we're gonna do to the active file. */
96 struct var_modification vm;
99 int ret_code = CMD_FAILURE;
103 lex_match_id ("MODIFY");
104 lex_match_id ("VARS");
106 vm.reorder_vars = NULL;
108 vm.rename_vars = NULL;
114 /* Parse each subcommand. */
118 if (lex_match_id ("REORDER"))
120 struct variable **v = NULL;
123 if (already_encountered & 1)
125 msg (SE, _("REORDER subcommand may be given at most once."));
128 already_encountered |= 1;
133 struct ordering ordering;
136 ordering.forward = ordering.positional = 1;
137 if (lex_match_id ("FORWARD"));
138 else if (lex_match_id ("BACKWARD"))
139 ordering.forward = 0;
140 if (lex_match_id ("POSITIONAL"));
141 else if (lex_match_id ("ALPHA"))
142 ordering.positional = 0;
144 if (lex_match (T_ALL) || token == '/' || token == '.')
148 msg (SE, _("Cannot specify ALL after specifying a set "
152 dict_get_vars (default_dict, &v, &nv, 1u << DC_SYSTEM);
156 if (!lex_match ('('))
158 msg (SE, _("`(' expected on REORDER subcommand."));
162 if (!parse_variables (default_dict, &v, &nv,
163 PV_APPEND | PV_NO_DUPLICATE))
168 if (!lex_match (')'))
170 msg (SE, _("`)' expected following variable names on "
171 "REORDER subcommand."));
176 sort (&v[prev_nv], nv - prev_nv, sizeof *v,
177 compare_variables_given_ordering, &ordering);
179 while (token != '/' && token != '.');
184 else if (lex_match_id ("RENAME"))
186 if (already_encountered & 2)
188 msg (SE, _("RENAME subcommand may be given at most once."));
191 already_encountered |= 2;
196 int prev_nv_1 = vm.rename_cnt;
197 int prev_nv_2 = vm.rename_cnt;
199 if (!lex_match ('('))
201 msg (SE, _("`(' expected on RENAME subcommand."));
204 if (!parse_variables (default_dict, &vm.rename_vars, &vm.rename_cnt,
205 PV_APPEND | PV_NO_DUPLICATE))
207 if (!lex_match ('='))
209 msg (SE, _("`=' expected between lists of new and old variable "
210 "names on RENAME subcommand."));
213 if (!parse_DATA_LIST_vars (&vm.new_names, &prev_nv_1, PV_APPEND))
215 if (prev_nv_1 != vm.rename_cnt)
217 msg (SE, _("Differing number of variables in old name list "
218 "(%d) and in new name list (%d)."),
219 vm.rename_cnt - prev_nv_2, prev_nv_1 - prev_nv_2);
220 for (i = 0; i < prev_nv_1; i++)
221 free (vm.new_names[i]);
226 if (!lex_match (')'))
228 msg (SE, _("`)' expected after variable lists on RENAME "
233 while (token != '.' && token != '/');
235 else if (lex_match_id ("KEEP"))
237 struct variable **keep_vars, **all_vars, **drop_vars;
238 int keep_cnt, all_cnt, drop_cnt;
240 if (already_encountered & 4)
242 msg (SE, _("KEEP subcommand may be given at most once. It may not"
243 "be given in conjunction with the DROP subcommand."));
246 already_encountered |= 4;
249 if (!parse_variables (default_dict, &keep_vars, &keep_cnt, PV_NONE))
252 /* Transform the list of variables to keep into a list of
253 variables to drop. First sort the keep list, then figure
254 out which variables are missing. */
255 sort (keep_vars, keep_cnt, sizeof *keep_vars,
256 compare_variables_given_ordering, &forward_positional_ordering);
258 dict_get_vars (default_dict, &all_vars, &all_cnt, 0);
260 drop_cnt = all_cnt - keep_cnt;
261 drop_vars = xmalloc (drop_cnt * sizeof *keep_vars);
262 if (set_difference (all_vars, all_cnt,
266 compare_variables_given_ordering,
267 &forward_positional_ordering)
274 vm.drop_vars = drop_vars;
275 vm.drop_cnt = drop_cnt;
277 else if (lex_match_id ("DROP"))
279 struct variable **drop_vars;
282 if (already_encountered & 4)
284 msg (SE, _("DROP subcommand may be given at most once. It may "
285 "not be given in conjunction with the KEEP "
289 already_encountered |= 4;
292 if (!parse_variables (default_dict, &drop_vars, &drop_cnt, PV_NONE))
294 vm.drop_vars = drop_vars;
295 vm.drop_cnt = drop_cnt;
297 else if (lex_match_id ("MAP"))
299 struct dictionary *temp = dict_clone (default_dict);
300 int success = rearrange_dict (temp, &vm);
303 /* FIXME: display new dictionary. */
310 msg (SE, _("Unrecognized subcommand name `%s'."), tokid);
312 msg (SE, _("Subcommand name expected."));
320 msg (SE, _("`/' or `.' expected."));
326 if (already_encountered & (1 | 4))
329 procedure (NULL, NULL, NULL);
332 if (!rearrange_dict (default_dict, &vm))
335 ret_code = CMD_SUCCESS;
338 free (vm.reorder_vars);
339 free (vm.rename_vars);
340 for (i = 0; i < vm.rename_cnt; i++)
341 free (vm.new_names[i]);
347 /* Compares A and B according to the settings in
348 ORDERING, returning a strcmp()-type result. */
350 compare_variables_given_ordering (const void *a_, const void *b_,
353 struct variable *const *pa = a_;
354 struct variable *const *pb = b_;
355 const struct variable *a = *pa;
356 const struct variable *b = *pb;
357 const struct ordering *ordering = ordering_;
360 if (ordering->positional)
361 result = a->index < b->index ? -1 : a->index > b->index;
363 result = strcmp (a->name, b->name);
364 if (!ordering->forward)
369 /* Pairs a variable with a new name. */
372 struct variable *var;
376 /* A algo_compare_func that compares new_name members in struct
377 var_renaming structures A and B. */
379 compare_var_renaming_by_new_name (const void *a_, const void *b_,
382 const struct var_renaming *a = a_;
383 const struct var_renaming *b = b_;
385 return strcmp (a->new_name, b->new_name);
388 /* Returns true if performing VM on dictionary D would not cause
389 problems such as duplicate variable names. Returns false
390 otherwise, and issues an error message. */
392 validate_var_modification (const struct dictionary *d,
393 const struct var_modification *vm)
395 /* Variable reordering can't be a problem, so we don't simulate
396 it. Variable renaming can cause duplicate names, but
397 dropping variables can eliminate them, so we simulate both
399 struct variable **all_vars;
400 struct variable **keep_vars;
401 struct variable **drop_vars;
402 size_t all_cnt, keep_cnt, drop_cnt;
404 struct var_renaming *var_renaming;
408 /* All variables, in index order. */
409 dict_get_vars (d, &all_vars, &all_cnt, 0);
411 /* Drop variables, in index order. */
412 drop_cnt = vm->drop_cnt;
413 drop_vars = xmalloc (drop_cnt * sizeof *drop_vars);
414 memcpy (drop_vars, vm->drop_vars, drop_cnt * sizeof *drop_vars);
415 sort (drop_vars, drop_cnt, sizeof *drop_vars,
416 compare_variables_given_ordering, &forward_positional_ordering);
418 /* Keep variables, in index order. */
419 keep_cnt = all_cnt - drop_cnt;
420 keep_vars = xmalloc (keep_cnt * sizeof *keep_vars);
421 if (set_difference (all_vars, all_cnt,
425 compare_variables_given_ordering,
426 &forward_positional_ordering) != keep_cnt)
429 /* Copy variables into var_renaming array. */
430 var_renaming = xmalloc (keep_cnt * sizeof *var_renaming);
431 for (i = 0; i < keep_cnt; i++)
433 var_renaming[i].var = keep_vars[i];
434 strcpy (var_renaming[i].new_name, keep_vars[i]->name);
437 /* Rename variables in var_renaming array. */
438 for (i = 0; i < vm->rename_cnt; i++)
440 struct variable *const *kv;
441 struct var_renaming *vr;
443 /* Get the var_renaming element. */
444 kv = binary_search (keep_vars, keep_cnt, sizeof *keep_vars,
446 compare_variables_given_ordering,
447 &forward_positional_ordering);
450 vr = var_renaming + (kv - keep_vars);
452 strcpy (vr->new_name, vm->new_names[i]);
455 /* Sort var_renaming array by new names and check for
457 sort (var_renaming, keep_cnt, sizeof *var_renaming,
458 compare_var_renaming_by_new_name, NULL);
459 valid = adjacent_find_equal (var_renaming, keep_cnt, sizeof *var_renaming,
460 compare_var_renaming_by_new_name, NULL) == NULL;
471 /* Reoders, removes, and renames variables in dictionary D
472 according to VM. Returns nonzero if successful, zero if there
473 would have been duplicate variable names if the modifications
474 had been carried out. In the latter case, the dictionary is
477 rearrange_dict (struct dictionary *d, const struct var_modification *vm)
479 char **rename_old_names;
481 struct variable **rename_vars;
482 char **rename_new_names;
487 /* Check whether the modifications will cause duplicate
489 if (!validate_var_modification (d, vm))
492 /* Record the old names of variables to rename. After
493 variables are deleted, we can't depend on the variables to
494 still exist, but we can still look them up by name. */
495 rename_old_names = xmalloc (vm->rename_cnt * sizeof *rename_old_names);
496 for (i = 0; i < vm->rename_cnt; i++)
497 rename_old_names[i] = xstrdup (vm->rename_vars[i]->name);
499 /* Reorder and delete variables. */
500 dict_reorder_vars (d, vm->reorder_vars, vm->reorder_cnt);
501 dict_delete_vars (d, vm->drop_vars, vm->drop_cnt);
503 /* Compose lists of variables to rename and their new names. */
504 rename_vars = xmalloc (vm->rename_cnt * sizeof *rename_vars);
505 rename_new_names = xmalloc (vm->rename_cnt * sizeof *rename_new_names);
507 for (i = 0; i < vm->rename_cnt; i++)
509 struct variable *var = dict_lookup_var (d, rename_old_names[i]);
513 rename_vars[rename_cnt] = var;
514 rename_new_names[rename_cnt] = vm->new_names[i];
519 if (dict_rename_vars (d, rename_vars, rename_new_names, rename_cnt,
524 for (i = 0; i < vm->rename_cnt; i++)
525 free (rename_old_names[i]);
526 free (rename_old_names);
528 free (rename_new_names);