1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010, 2011 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/por-file-writer.h"
29 #include "data/sys-file-writer.h"
30 #include "data/transformations.h"
31 #include "data/variable.h"
32 #include "language/command.h"
33 #include "language/data-io/file-handle.h"
34 #include "language/data-io/trim.h"
35 #include "language/lexer/lexer.h"
36 #include "libpspp/assertion.h"
37 #include "libpspp/compiler.h"
39 #include "gl/xalloc.h"
42 #define _(msgid) gettext (msgid)
44 /* Writing system and portable files. */
46 /* Type of output file. */
49 SYSFILE_WRITER, /* System file. */
50 PORFILE_WRITER /* Portable file. */
53 /* Type of a command. */
56 XFORM_CMD, /* Transformation. */
57 PROC_CMD /* Procedure. */
60 static int parse_output_proc (struct lexer *, struct dataset *,
62 static int parse_output_trns (struct lexer *, struct dataset *,
66 cmd_save (struct lexer *lexer, struct dataset *ds)
68 return parse_output_proc (lexer, ds, SYSFILE_WRITER);
72 cmd_export (struct lexer *lexer, struct dataset *ds)
74 return parse_output_proc (lexer, ds, PORFILE_WRITER);
78 cmd_xsave (struct lexer *lexer, struct dataset *ds)
80 return parse_output_trns (lexer, ds, SYSFILE_WRITER);
84 cmd_xexport (struct lexer *lexer, struct dataset *ds)
86 return parse_output_trns (lexer, ds, PORFILE_WRITER);
91 struct casewriter *writer; /* Writer. */
94 static trns_proc_func output_trns_proc;
95 static trns_free_func output_trns_free;
96 static struct casewriter *parse_write_command (struct lexer *,
100 bool *retain_unselected);
102 /* Parses and performs the SAVE or EXPORT procedure. */
104 parse_output_proc (struct lexer *lexer, struct dataset *ds,
105 enum writer_type writer_type)
107 bool retain_unselected;
108 struct casewriter *output;
111 output = parse_write_command (lexer, ds, writer_type, PROC_CMD,
114 return CMD_CASCADING_FAILURE;
116 casereader_transfer (proc_open_filtering (ds, !retain_unselected), output);
117 ok = casewriter_destroy (output);
118 ok = proc_commit (ds) && ok;
120 return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
123 /* Parses the XSAVE or XEXPORT transformation command. */
125 parse_output_trns (struct lexer *lexer, struct dataset *ds, enum writer_type writer_type)
127 struct output_trns *t = xmalloc (sizeof *t);
128 t->writer = parse_write_command (lexer, ds, writer_type, XFORM_CMD, NULL);
129 if (t->writer == NULL)
132 return CMD_CASCADING_FAILURE;
135 add_transformation (ds, output_trns_proc, output_trns_free, t);
139 /* Parses SAVE or XSAVE or EXPORT or XEXPORT command.
140 WRITER_TYPE identifies the type of file to write,
141 and COMMAND_TYPE identifies the type of command.
143 On success, returns a writer.
144 For procedures only, sets *RETAIN_UNSELECTED to true if cases
145 that would otherwise be excluded by FILTER or USE should be
148 On failure, returns a null pointer. */
149 static struct casewriter *
150 parse_write_command (struct lexer *lexer, struct dataset *ds,
151 enum writer_type writer_type,
152 enum command_type command_type,
153 bool *retain_unselected)
156 struct file_handle *handle; /* Output file. */
157 struct dictionary *dict; /* Dictionary for output file. */
158 struct casewriter *writer; /* Writer. */
159 struct case_map *map; /* Map from input data to data for writer. */
161 /* Common options. */
162 bool print_map; /* Print map? TODO. */
163 bool print_short_names; /* Print long-to-short name map. TODO. */
164 struct sfm_write_options sysfile_opts;
165 struct pfm_write_options porfile_opts;
167 assert (writer_type == SYSFILE_WRITER || writer_type == PORFILE_WRITER);
168 assert (command_type == XFORM_CMD || command_type == PROC_CMD);
169 assert ((retain_unselected != NULL) == (command_type == PROC_CMD));
171 if (command_type == PROC_CMD)
172 *retain_unselected = true;
175 dict = dict_clone (dataset_dict (ds));
179 print_short_names = false;
180 sysfile_opts = sfm_writer_default_options ();
181 porfile_opts = pfm_writer_default_options ();
183 case_map_prepare_dict (dict);
184 dict_delete_scratch_vars (dict);
186 lex_match (lexer, T_SLASH);
189 if (lex_match_id (lexer, "OUTFILE"))
193 lex_sbc_only_once ("OUTFILE");
197 lex_match (lexer, T_EQUALS);
199 handle = fh_parse (lexer, FH_REF_FILE | FH_REF_SCRATCH);
203 else if (lex_match_id (lexer, "NAMES"))
204 print_short_names = true;
205 else if (lex_match_id (lexer, "PERMISSIONS"))
209 lex_match (lexer, T_EQUALS);
210 if (lex_match_id (lexer, "READONLY"))
212 else if (lex_match_id (lexer, "WRITEABLE"))
216 lex_error (lexer, _("expecting %s or %s"),
217 "READONLY", "WRITEABLE");
220 sysfile_opts.create_writeable = porfile_opts.create_writeable = cw;
222 else if (command_type == PROC_CMD && lex_match_id (lexer, "UNSELECTED"))
224 lex_match (lexer, T_EQUALS);
225 if (lex_match_id (lexer, "RETAIN"))
226 *retain_unselected = true;
227 else if (lex_match_id (lexer, "DELETE"))
228 *retain_unselected = false;
231 lex_error (lexer, _("expecting %s or %s"), "RETAIN", "DELETE");
235 else if (writer_type == SYSFILE_WRITER
236 && lex_match_id (lexer, "COMPRESSED"))
237 sysfile_opts.compress = true;
238 else if (writer_type == SYSFILE_WRITER
239 && lex_match_id (lexer, "UNCOMPRESSED"))
240 sysfile_opts.compress = false;
241 else if (writer_type == SYSFILE_WRITER
242 && lex_match_id (lexer, "VERSION"))
244 lex_match (lexer, T_EQUALS);
245 if (!lex_force_int (lexer))
247 sysfile_opts.version = lex_integer (lexer);
250 else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "TYPE"))
252 lex_match (lexer, T_EQUALS);
253 if (lex_match_id (lexer, "COMMUNICATIONS"))
254 porfile_opts.type = PFM_COMM;
255 else if (lex_match_id (lexer, "TAPE"))
256 porfile_opts.type = PFM_TAPE;
259 lex_error (lexer, _("expecting %s or %s"), "COMM", "TAPE");
263 else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "DIGITS"))
265 lex_match (lexer, T_EQUALS);
266 if (!lex_force_int (lexer))
268 porfile_opts.digits = lex_integer (lexer);
271 else if (!parse_dict_trim (lexer, dict))
274 if (!lex_match (lexer, T_SLASH))
277 if (lex_end_of_command (lexer) != CMD_SUCCESS)
282 lex_sbc_missing (lexer, "OUTFILE");
286 dict_delete_scratch_vars (dict);
287 dict_compact_values (dict);
289 if (fh_get_referent (handle) == FH_REF_FILE)
294 writer = sfm_open_writer (handle, dict, sysfile_opts);
297 writer = pfm_open_writer (handle, dict, porfile_opts);
302 writer = any_writer_open (handle, dict);
306 map = case_map_from_dict (dict);
308 writer = case_map_create_output_translator (map, writer);
316 casewriter_destroy (writer);
318 case_map_destroy (map);
322 /* Writes case *C to the system file specified on XSAVE or XEXPORT. */
324 output_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
326 struct output_trns *t = trns_;
327 casewriter_write (t->writer, case_ref (*c));
328 return TRNS_CONTINUE;
331 /* Frees an XSAVE or XEXPORT transformation.
332 Returns true if successful, false if an I/O error occurred. */
334 output_trns_free (void *trns_)
336 struct output_trns *t = trns_;
337 bool ok = casewriter_destroy (t->writer);