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/data-io/file-handle.h"
32 #include "language/data-io/trim.h"
33 #include "language/lexer/lexer.h"
34 #include "libpspp/message.h"
39 #define _(msgid) gettext (msgid)
40 #define N_(msgid) (msgid)
43 cmd_save_translate (struct lexer
*lexer
, struct dataset
*ds
)
45 enum { CSV_FILE
= 1, TAB_FILE
} type
;
47 struct dictionary
*dict
;
48 struct case_map_stage
*stage
;
50 struct casewriter
*writer
;
51 struct file_handle
*handle
;
53 struct csv_writer_options csv_opts
;
57 bool retain_unselected
;
58 bool recode_user_missing
;
59 bool include_var_names
;
60 bool use_value_labels
;
61 bool use_print_formats
;
70 dict
= dict_clone (dataset_dict (ds
));
77 retain_unselected
= true;
78 recode_user_missing
= false;
79 include_var_names
= false;
80 use_value_labels
= false;
81 use_print_formats
= false;
82 decimal
= settings_get_decimal_char (FMT_F
);
86 stage
= case_map_stage_create (dict
);
87 dict_delete_scratch_vars (dict
);
89 while (lex_token (lexer
) != T_ENDCMD
)
91 if (!lex_force_match (lexer
, T_SLASH
))
94 if (lex_match_id (lexer
, "OUTFILE"))
98 lex_sbc_only_once ("OUTFILE");
102 lex_match (lexer
, T_EQUALS
);
104 handle
= fh_parse (lexer
, FH_REF_FILE
, NULL
);
108 else if (lex_match_id (lexer
, "TYPE"))
112 lex_sbc_only_once ("TYPE");
116 lex_match (lexer
, T_EQUALS
);
117 if (lex_match_id (lexer
, "CSV"))
119 else if (lex_match_id (lexer
, "TAB"))
123 lex_error_expecting (lexer
, "CSV", "TAB", NULL_SENTINEL
);
127 else if (lex_match_id (lexer
, "REPLACE"))
129 else if (lex_match_id (lexer
, "FIELDNAMES"))
130 include_var_names
= true;
131 else if (lex_match_id (lexer
, "MISSING"))
133 lex_match (lexer
, T_EQUALS
);
134 if (lex_match_id (lexer
, "IGNORE"))
135 recode_user_missing
= false;
136 else if (lex_match_id (lexer
, "RECODE"))
137 recode_user_missing
= true;
140 lex_error_expecting (lexer
, "IGNORE", "RECODE", NULL_SENTINEL
);
144 else if (lex_match_id (lexer
, "CELLS"))
146 lex_match (lexer
, T_EQUALS
);
147 if (lex_match_id (lexer
, "VALUES"))
148 use_value_labels
= false;
149 else if (lex_match_id (lexer
, "LABELS"))
150 use_value_labels
= true;
153 lex_error_expecting (lexer
, "VALUES", "LABELS", NULL_SENTINEL
);
157 else if (lex_match_id (lexer
, "TEXTOPTIONS"))
159 lex_match (lexer
, T_EQUALS
);
162 if (lex_match_id (lexer
, "DELIMITER"))
164 lex_match (lexer
, T_EQUALS
);
165 if (!lex_force_string (lexer
))
167 /* XXX should support multibyte UTF-8 delimiters */
168 if (ss_length (lex_tokss (lexer
)) != 1)
170 msg (SE
, _("The %s string must contain exactly one "
171 "character."), "DELIMITER");
174 delimiter
= ss_first (lex_tokss (lexer
));
177 else if (lex_match_id (lexer
, "QUALIFIER"))
179 lex_match (lexer
, T_EQUALS
);
180 if (!lex_force_string (lexer
))
182 /* XXX should support multibyte UTF-8 qualifiers */
183 if (ss_length (lex_tokss (lexer
)) != 1)
185 msg (SE
, _("The %s string must contain exactly one "
186 "character."), "QUALIFIER");
189 qualifier
= ss_first (lex_tokss (lexer
));
192 else if (lex_match_id (lexer
, "DECIMAL"))
194 lex_match (lexer
, T_EQUALS
);
195 if (lex_match_id (lexer
, "DOT"))
197 else if (lex_match_id (lexer
, "COMMA"))
201 lex_error_expecting (lexer
, "DOT", "COMMA",
206 else if (lex_match_id (lexer
, "FORMAT"))
208 lex_match (lexer
, T_EQUALS
);
209 if (lex_match_id (lexer
, "PLAIN"))
210 use_print_formats
= false;
211 else if (lex_match_id (lexer
, "VARIABLE"))
212 use_print_formats
= true;
215 lex_error_expecting (lexer
, "PLAIN", "VARIABLE",
224 else if (lex_match_id (lexer
, "UNSELECTED"))
226 lex_match (lexer
, T_EQUALS
);
227 if (lex_match_id (lexer
, "RETAIN"))
228 retain_unselected
= true;
229 else if (lex_match_id (lexer
, "DELETE"))
230 retain_unselected
= false;
233 lex_error_expecting (lexer
, "RETAIN", "DELETE", NULL_SENTINEL
);
237 else if (!parse_dict_trim (lexer
, dict
))
243 lex_sbc_missing ("TYPE");
246 else if (handle
== NULL
)
248 lex_sbc_missing ("OUTFILE");
251 else if (!replace
&& fn_exists (handle
))
253 msg (SE
, _("Output file `%s' exists but %s was not specified."),
254 fh_get_file_name (handle
), "REPLACE");
258 dict_delete_scratch_vars (dict
);
259 dict_compact_values (dict
);
261 csv_opts
.recode_user_missing
= recode_user_missing
;
262 csv_opts
.include_var_names
= include_var_names
;
263 csv_opts
.use_value_labels
= use_value_labels
;
264 csv_opts
.use_print_formats
= use_print_formats
;
265 csv_opts
.decimal
= decimal
;
266 csv_opts
.delimiter
= (delimiter
? delimiter
267 : type
== TAB_FILE
? '\t'
268 : decimal
== '.' ? ','
270 csv_opts
.qualifier
= qualifier
;
272 writer
= csv_writer_open (handle
, dict
, &csv_opts
);
277 map
= case_map_stage_get_case_map (stage
);
278 case_map_stage_destroy (stage
);
280 writer
= case_map_create_output_translator (map
, writer
);
283 casereader_transfer (proc_open_filtering (ds
, !retain_unselected
), writer
);
284 ok
= casewriter_destroy (writer
);
285 ok
= proc_commit (ds
) && ok
;
287 return ok
? CMD_SUCCESS
: CMD_CASCADING_FAILURE
;
290 case_map_stage_destroy (stage
);
293 case_map_destroy (map
);