1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 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/any-writer.h"
22 #include "data/case-map.h"
23 #include "data/case.h"
24 #include "data/casereader.h"
25 #include "data/casewriter.h"
26 #include "data/dataset.h"
27 #include "data/dictionary.h"
28 #include "data/mdd-writer.h"
29 #include "data/por-file-writer.h"
30 #include "data/sys-file-writer.h"
31 #include "data/transformations.h"
32 #include "data/variable.h"
33 #include "language/command.h"
34 #include "language/data-io/file-handle.h"
35 #include "language/data-io/trim.h"
36 #include "language/lexer/lexer.h"
37 #include "libpspp/assertion.h"
38 #include "libpspp/compiler.h"
39 #include "libpspp/message.h"
41 #include "gl/xalloc.h"
44 #define _(msgid) gettext (msgid)
46 /* Writing system and portable files. */
48 /* Type of output file. */
51 SYSFILE_WRITER, /* System file. */
52 PORFILE_WRITER /* Portable file. */
55 /* Type of a command. */
58 XFORM_CMD, /* Transformation. */
59 PROC_CMD /* Procedure. */
62 static int parse_output_proc (struct lexer *, struct dataset *,
64 static int parse_output_trns (struct lexer *, struct dataset *,
68 cmd_save (struct lexer *lexer, struct dataset *ds)
70 return parse_output_proc (lexer, ds, SYSFILE_WRITER);
74 cmd_save_data_collection (struct lexer *lexer, struct dataset *ds)
76 return parse_output_proc (lexer, ds, SYSFILE_WRITER);
80 cmd_export (struct lexer *lexer, struct dataset *ds)
82 return parse_output_proc (lexer, ds, PORFILE_WRITER);
86 cmd_xsave (struct lexer *lexer, struct dataset *ds)
88 return parse_output_trns (lexer, ds, SYSFILE_WRITER);
92 cmd_xexport (struct lexer *lexer, struct dataset *ds)
94 return parse_output_trns (lexer, ds, PORFILE_WRITER);
99 struct casewriter *writer; /* Writer. */
102 static const struct trns_class output_trns_class;
103 static struct casewriter *parse_write_command (struct lexer *,
107 bool *retain_unselected);
109 /* Parses and performs the SAVE or EXPORT procedure. */
111 parse_output_proc (struct lexer *lexer, struct dataset *ds,
112 enum writer_type writer_type)
114 bool retain_unselected;
115 struct casewriter *output;
118 output = parse_write_command (lexer, ds, writer_type, PROC_CMD,
121 return CMD_CASCADING_FAILURE;
123 casereader_transfer (proc_open_filtering (ds, !retain_unselected), output);
124 ok = casewriter_destroy (output);
125 ok = proc_commit (ds) && ok;
127 return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
130 /* Parses the XSAVE or XEXPORT transformation command. */
132 parse_output_trns (struct lexer *lexer, struct dataset *ds, enum writer_type writer_type)
134 struct output_trns *t = xmalloc (sizeof *t);
135 t->writer = parse_write_command (lexer, ds, writer_type, XFORM_CMD, NULL);
136 if (t->writer == NULL)
139 return CMD_CASCADING_FAILURE;
142 add_transformation (ds, &output_trns_class, t);
146 /* Parses SAVE or XSAVE or EXPORT or XEXPORT command.
147 WRITER_TYPE identifies the type of file to write,
148 and COMMAND_TYPE identifies the type of command.
150 On success, returns a writer.
151 For procedures only, sets *RETAIN_UNSELECTED to true if cases
152 that would otherwise be excluded by FILTER or USE should be
155 On failure, returns a null pointer. */
156 static struct casewriter *
157 parse_write_command (struct lexer *lexer, struct dataset *ds,
158 enum writer_type writer_type,
159 enum command_type command_type,
160 bool *retain_unselected)
163 struct file_handle *handle; /* Output file. */
164 struct file_handle *metadata; /* MDD output file. */
165 struct dictionary *dict; /* Dictionary for output file. */
166 struct casewriter *writer; /* Writer. */
167 struct case_map_stage *stage; /* Preparation for 'map'. */
168 struct case_map *map; /* Map from input data to data for writer. */
169 const char *sav_name = "";
171 /* Common options. */
172 struct sfm_write_options sysfile_opts;
173 struct pfm_write_options porfile_opts;
175 assert (writer_type == SYSFILE_WRITER || writer_type == PORFILE_WRITER);
176 assert (command_type == XFORM_CMD || command_type == PROC_CMD);
177 assert ((retain_unselected != NULL) == (command_type == PROC_CMD));
179 if (command_type == PROC_CMD)
180 *retain_unselected = true;
184 dict = dict_clone (dataset_dict (ds));
188 sysfile_opts = sfm_writer_default_options ();
189 porfile_opts = pfm_writer_default_options ();
191 stage = case_map_stage_create (dict);
192 dict_delete_scratch_vars (dict);
194 lex_match (lexer, T_SLASH);
197 if (lex_match_id (lexer, "OUTFILE"))
201 lex_sbc_only_once ("OUTFILE");
205 lex_match (lexer, T_EQUALS);
207 handle = fh_parse (lexer, FH_REF_FILE, NULL);
211 else if (lex_match_id (lexer, "METADATA"))
213 if (metadata != NULL)
215 lex_sbc_only_once ("METADATA");
219 lex_match (lexer, T_EQUALS);
221 metadata = fh_parse (lexer, FH_REF_FILE, NULL);
222 if (metadata == NULL)
225 else if (lex_match_id (lexer, "NAMES"))
227 /* Not yet implemented. */
229 else if (lex_match_id (lexer, "PERMISSIONS"))
233 lex_match (lexer, T_EQUALS);
234 if (lex_match_id (lexer, "READONLY"))
236 else if (lex_match_id (lexer, "WRITEABLE"))
240 lex_error_expecting (lexer, "READONLY", "WRITEABLE");
243 sysfile_opts.create_writeable = porfile_opts.create_writeable = cw;
245 else if (command_type == PROC_CMD && lex_match_id (lexer, "UNSELECTED"))
247 lex_match (lexer, T_EQUALS);
248 if (lex_match_id (lexer, "RETAIN"))
249 *retain_unselected = true;
250 else if (lex_match_id (lexer, "DELETE"))
251 *retain_unselected = false;
254 lex_error_expecting (lexer, "RETAIN", "DELETE");
258 else if (writer_type == SYSFILE_WRITER
259 && lex_match_id (lexer, "COMPRESSED"))
260 sysfile_opts.compression = ANY_COMP_SIMPLE;
261 else if (writer_type == SYSFILE_WRITER
262 && lex_match_id (lexer, "UNCOMPRESSED"))
263 sysfile_opts.compression = ANY_COMP_NONE;
264 else if (writer_type == SYSFILE_WRITER
265 && lex_match_id (lexer, "ZCOMPRESSED"))
266 sysfile_opts.compression = ANY_COMP_ZLIB;
267 else if (writer_type == SYSFILE_WRITER
268 && lex_match_id (lexer, "VERSION"))
270 lex_match (lexer, T_EQUALS);
271 if (!lex_force_int_range (lexer, "VERSION", 2, 3))
273 sysfile_opts.version = lex_integer (lexer);
276 else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "TYPE"))
278 lex_match (lexer, T_EQUALS);
279 if (lex_match_id (lexer, "COMMUNICATIONS"))
280 porfile_opts.type = PFM_COMM;
281 else if (lex_match_id (lexer, "TAPE"))
282 porfile_opts.type = PFM_TAPE;
285 lex_error_expecting (lexer, "COMM", "TAPE");
289 else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "DIGITS"))
291 lex_match (lexer, T_EQUALS);
292 if (!lex_force_int_range (lexer, "DIGITS", 1, INT_MAX))
294 porfile_opts.digits = lex_integer (lexer);
297 else if (!parse_dict_trim (lexer, dict, false))
300 if (!lex_match (lexer, T_SLASH))
303 if (lex_end_of_command (lexer) != CMD_SUCCESS)
306 if (!handle && !metadata)
308 msg (SE, _("The OUTFILE or METADATA subcommand is required."));
312 dict_delete_scratch_vars (dict);
313 dict_compact_values (dict);
318 sav_name = (fh_get_referent (handle) == FH_REF_FILE
319 ? fh_get_file_name (handle)
320 : fh_get_name (handle));
321 if (fh_get_referent (handle) == FH_REF_FILE)
326 writer = sfm_open_writer (handle, dict, sysfile_opts);
329 writer = pfm_open_writer (handle, dict, porfile_opts);
334 writer = any_writer_open (handle, dict);
341 if (!mdd_write (metadata, dict, sav_name))
345 map = case_map_stage_get_case_map (stage);
346 case_map_stage_destroy (stage);
348 writer = case_map_create_output_translator (map, writer);
356 case_map_stage_destroy (stage);
359 casewriter_destroy (writer);
361 case_map_destroy (map);
365 /* Writes case *C to the system file specified on XSAVE or XEXPORT. */
366 static enum trns_result
367 output_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
369 struct output_trns *t = trns_;
370 casewriter_write (t->writer, case_ref (*c));
371 return TRNS_CONTINUE;
374 /* Frees an XSAVE or XEXPORT transformation.
375 Returns true if successful, false if an I/O error occurred. */
377 output_trns_free (void *trns_)
379 struct output_trns *t = trns_;
380 bool ok = casewriter_destroy (t->writer);
385 static const struct trns_class output_trns_class = {
386 .name = "XSAVE/XEXPORT",
387 .execute = output_trns_proc,
388 .destroy = output_trns_free,