1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2010, 2011, 2013, 2016 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "data/case-map.h"
22 #include "data/casereader.h"
23 #include "data/casewriter.h"
24 #include "data/csv-file-writer.h"
25 #include "data/dataset.h"
26 #include "data/dictionary.h"
27 #include "data/file-name.h"
28 #include "data/format.h"
29 #include "data/settings.h"
30 #include "language/command.h"
31 #include "language/commands/file-handle.h"
32 #include "language/commands/trim.h"
33 #include "language/lexer/lexer.h"
34 #include "libpspp/message.h"
38 #define _(msgid) gettext (msgid)
39 #define N_(msgid) (msgid)
42 cmd_save_translate (struct lexer *lexer, struct dataset *ds)
44 enum { CSV_FILE = 1, TAB_FILE } type = 0;
46 struct dictionary *dict = dict_clone (dataset_dict (ds));
47 dict_set_names_must_be_ids (dict, false);
49 struct case_map_stage *stage = case_map_stage_create (dict);
50 dict_delete_scratch_vars (dict);
52 struct file_handle *handle = NULL;
56 bool retain_unselected = true;
57 bool recode_user_missing = false;
58 bool include_var_names = false;
59 bool use_value_labels = false;
60 bool use_print_formats = false;
61 char decimal = settings_get_fmt_settings ()->decimal;
65 int outfile_start = 0;
68 while (lex_token (lexer) != T_ENDCMD)
70 if (!lex_force_match (lexer, T_SLASH))
73 if (lex_match_id (lexer, "OUTFILE"))
75 outfile_start = lex_ofs (lexer) - 1;
78 lex_sbc_only_once (lexer, "OUTFILE");
82 lex_match (lexer, T_EQUALS);
84 handle = fh_parse (lexer, FH_REF_FILE, NULL);
87 outfile_end = lex_ofs (lexer) - 1;
89 else if (lex_match_id (lexer, "TYPE"))
93 lex_sbc_only_once (lexer, "TYPE");
97 lex_match (lexer, T_EQUALS);
98 if (lex_match_id (lexer, "CSV"))
100 else if (lex_match_id (lexer, "TAB"))
104 lex_error_expecting (lexer, "CSV", "TAB");
108 else if (lex_match_id (lexer, "REPLACE"))
110 else if (lex_match_id (lexer, "FIELDNAMES"))
111 include_var_names = true;
112 else if (lex_match_id (lexer, "MISSING"))
114 lex_match (lexer, T_EQUALS);
115 if (lex_match_id (lexer, "IGNORE"))
116 recode_user_missing = false;
117 else if (lex_match_id (lexer, "RECODE"))
118 recode_user_missing = true;
121 lex_error_expecting (lexer, "IGNORE", "RECODE");
125 else if (lex_match_id (lexer, "CELLS"))
127 lex_match (lexer, T_EQUALS);
128 if (lex_match_id (lexer, "VALUES"))
129 use_value_labels = false;
130 else if (lex_match_id (lexer, "LABELS"))
131 use_value_labels = true;
134 lex_error_expecting (lexer, "VALUES", "LABELS");
138 else if (lex_match_id (lexer, "TEXTOPTIONS"))
140 lex_match (lexer, T_EQUALS);
143 if (lex_match_id (lexer, "DELIMITER"))
145 lex_match (lexer, T_EQUALS);
146 if (!lex_force_string (lexer))
148 /* XXX should support multibyte UTF-8 delimiters */
149 if (ss_length (lex_tokss (lexer)) != 1)
151 lex_error (lexer, _("The %s string must contain exactly "
152 "one character."), "DELIMITER");
155 delimiter = ss_first (lex_tokss (lexer));
158 else if (lex_match_id (lexer, "QUALIFIER"))
160 lex_match (lexer, T_EQUALS);
161 if (!lex_force_string (lexer))
163 /* XXX should support multibyte UTF-8 qualifiers */
164 if (ss_length (lex_tokss (lexer)) != 1)
166 lex_error (lexer, _("The %s string must contain exactly "
167 "one character."), "QUALIFIER");
170 qualifier = ss_first (lex_tokss (lexer));
173 else if (lex_match_id (lexer, "DECIMAL"))
175 lex_match (lexer, T_EQUALS);
176 if (lex_match_id (lexer, "DOT"))
178 else if (lex_match_id (lexer, "COMMA"))
182 lex_error_expecting (lexer, "DOT", "COMMA");
186 else if (lex_match_id (lexer, "FORMAT"))
188 lex_match (lexer, T_EQUALS);
189 if (lex_match_id (lexer, "PLAIN"))
190 use_print_formats = false;
191 else if (lex_match_id (lexer, "VARIABLE"))
192 use_print_formats = true;
195 lex_error_expecting (lexer, "PLAIN", "VARIABLE");
203 else if (lex_match_id (lexer, "UNSELECTED"))
205 lex_match (lexer, T_EQUALS);
206 if (lex_match_id (lexer, "RETAIN"))
207 retain_unselected = true;
208 else if (lex_match_id (lexer, "DELETE"))
209 retain_unselected = false;
212 lex_error_expecting (lexer, "RETAIN", "DELETE");
216 else if (!parse_dict_trim (lexer, dict))
222 lex_sbc_missing (lexer, "TYPE");
225 else if (handle == NULL)
227 lex_sbc_missing (lexer, "OUTFILE");
230 else if (!replace && fn_exists (handle))
232 lex_ofs_error (lexer, outfile_start, outfile_end,
233 _("Output file `%s' exists but %s was not specified."),
234 fh_get_file_name (handle), "REPLACE");
238 dict_delete_scratch_vars (dict);
240 struct csv_writer_options csv_opts = {
241 .recode_user_missing = recode_user_missing,
242 .include_var_names = include_var_names,
243 .use_value_labels = use_value_labels,
244 .use_print_formats = use_print_formats,
246 .delimiter = (delimiter ? delimiter
247 : type == TAB_FILE ? '\t'
248 : decimal == '.' ? ','
250 .qualifier = qualifier,
252 struct casewriter *writer = csv_writer_open (handle, dict, &csv_opts);
257 writer = case_map_create_output_translator (
258 case_map_stage_to_case_map (stage), writer);
261 casereader_transfer (proc_open_filtering (ds, !retain_unselected), writer);
262 bool ok = casewriter_destroy (writer);
263 ok = proc_commit (ds) && ok;
265 return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
268 case_map_stage_destroy (stage);