1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2010, 2011,
3 2019 Free Software Foundation, Inc.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU 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, see <http://www.gnu.org/licenses/>. */
20 #include "language/data-io/trim.h"
24 #include "data/dictionary.h"
25 #include "data/variable.h"
26 #include "language/lexer/lexer.h"
27 #include "language/lexer/variable-parser.h"
28 #include "libpspp/message.h"
30 #include "gl/xalloc.h"
33 #define _(msgid) gettext (msgid)
35 /* Commands that read and write system files share a great deal
36 of common syntactic structure for rearranging and dropping
37 variables. This function parses this syntax and modifies DICT
38 appropriately. If RELAX is true, then the modified dictionary
39 need not conform to the usual variable name rules. Returns
40 true on success, false on failure. */
42 parse_dict_trim (struct lexer *lexer, struct dictionary *dict, bool relax)
44 if (lex_match_id (lexer, "MAP"))
49 else if (lex_match_id (lexer, "DROP"))
50 return parse_dict_drop (lexer, dict);
51 else if (lex_match_id (lexer, "KEEP"))
52 return parse_dict_keep (lexer, dict);
53 else if (lex_match_id (lexer, "RENAME"))
54 return parse_dict_rename (lexer, dict, relax);
57 lex_error (lexer, _("expecting a valid subcommand"));
62 /* Parses and performs the RENAME subcommand of GET, SAVE, and
63 related commands. If RELAX is true, then the new variable
64 names need not conform to the normal dictionary rules.
67 parse_dict_rename (struct lexer *lexer, struct dictionary *dict,
70 struct variable **oldvars = NULL;
73 char **newnames = NULL;
74 lex_match (lexer, T_EQUALS);
76 while (lex_token (lexer) != T_SLASH && lex_token (lexer) != T_ENDCMD)
84 bool paren = lex_match (lexer, T_LPAREN);
86 if (!parse_variables (lexer, dict, &oldvars, &n_oldvars, PV_NO_DUPLICATE))
89 if (!lex_force_match (lexer, T_EQUALS))
92 newnames = xmalloc (sizeof *newnames * n_oldvars);
93 while (lex_token (lexer) == T_ID || lex_token (lexer) == T_STRING)
95 if (n_newvars >= n_oldvars)
97 const char *new_name = lex_tokcstr (lexer);
98 if (!relax && ! id_is_plausible (new_name, true))
101 if (dict_lookup_var (dict, new_name) != NULL)
103 msg (SE, _("Cannot rename %s as %s because there already exists "
104 "a variable named %s. To rename variables with "
105 "overlapping names, use a single RENAME subcommand "
106 "such as `/RENAME (A=B)(B=C)(C=A)', or equivalently, "
107 "`/RENAME (A B C=B C A)'."),
108 var_get_name (oldvars[n_newvars]), new_name, new_name);
111 newnames[n_newvars] = strdup (new_name);
115 if (n_newvars != n_oldvars)
117 msg (SE, _("Number of variables on left side of `=' (%zu) does not "
118 "match number of variables on right side (%zu), in "
119 "parenthesized group %d of RENAME subcommand."),
120 n_newvars, n_oldvars, group);
125 if (!lex_force_match (lexer, T_RPAREN))
129 if (!dict_rename_vars (dict, oldvars, newnames, n_newvars, &errname))
132 _("Requested renaming duplicates variable name %s."),
137 for (int i = 0; i < n_newvars; ++i)
147 for (int i = 0; i < n_newvars; ++i)
154 /* Parses and performs the DROP subcommand of GET, SAVE, and
156 Returns true if successful, false on failure.*/
158 parse_dict_drop (struct lexer *lexer, struct dictionary *dict)
163 lex_match (lexer, T_EQUALS);
164 if (!parse_variables (lexer, dict, &v, &nv, PV_NONE))
166 dict_delete_vars (dict, v, nv);
169 if (dict_get_var_cnt (dict) == 0)
171 msg (SE, _("Cannot DROP all variables from dictionary."));
177 /* Parses and performs the KEEP subcommand of GET, SAVE, and
179 Returns true if successful, false on failure.*/
181 parse_dict_keep (struct lexer *lexer, struct dictionary *dict)
187 lex_match (lexer, T_EQUALS);
188 if (!parse_variables (lexer, dict, &v, &nv, PV_NONE))
191 /* Move the specified variables to the beginning. */
192 dict_reorder_vars (dict, v, nv);
194 /* Delete the remaining variables. */
195 v = xnrealloc (v, dict_get_var_cnt (dict) - nv, sizeof *v);
196 for (i = nv; i < dict_get_var_cnt (dict); i++)
197 v[i - nv] = dict_get_var (dict, i);
198 dict_delete_vars (dict, v, dict_get_var_cnt (dict) - nv);