Suppress GCC 4.7 warnings due to unimplemented features.
[pspp] / src / language / data-io / save.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
3
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.
8
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.
13
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/>. */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20
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"
38
39 #include "gl/xalloc.h"
40
41 #include "gettext.h"
42 #define _(msgid) gettext (msgid)
43
44 /* Writing system and portable files. */
45
46 /* Type of output file. */
47 enum writer_type
48   {
49     SYSFILE_WRITER,     /* System file. */
50     PORFILE_WRITER      /* Portable file. */
51   };
52
53 /* Type of a command. */
54 enum command_type
55   {
56     XFORM_CMD,          /* Transformation. */
57     PROC_CMD            /* Procedure. */
58   };
59
60 static int parse_output_proc (struct lexer *, struct dataset *,
61                               enum writer_type);
62 static int parse_output_trns (struct lexer *, struct dataset *,
63                               enum writer_type);
64
65 int
66 cmd_save (struct lexer *lexer, struct dataset *ds)
67 {
68   return parse_output_proc (lexer, ds, SYSFILE_WRITER);
69 }
70
71 int
72 cmd_export (struct lexer *lexer, struct dataset *ds)
73 {
74   return parse_output_proc (lexer, ds, PORFILE_WRITER);
75 }
76
77 int
78 cmd_xsave (struct lexer *lexer, struct dataset *ds)
79 {
80   return parse_output_trns (lexer, ds, SYSFILE_WRITER);
81 }
82
83 int
84 cmd_xexport (struct lexer *lexer, struct dataset *ds)
85 {
86   return parse_output_trns (lexer, ds, PORFILE_WRITER);
87 }
88 \f
89 struct output_trns
90   {
91     struct casewriter *writer;          /* Writer. */
92   };
93
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 *,
97                                                struct dataset *,
98                                                enum writer_type,
99                                                enum command_type,
100                                                bool *retain_unselected);
101
102 /* Parses and performs the SAVE or EXPORT procedure. */
103 static int
104 parse_output_proc (struct lexer *lexer, struct dataset *ds,
105                    enum writer_type writer_type)
106 {
107   bool retain_unselected;
108   struct casewriter *output;
109   bool ok;
110
111   output = parse_write_command (lexer, ds, writer_type, PROC_CMD,
112                                 &retain_unselected);
113   if (output == NULL)
114     return CMD_CASCADING_FAILURE;
115
116   casereader_transfer (proc_open_filtering (ds, !retain_unselected), output);
117   ok = casewriter_destroy (output);
118   ok = proc_commit (ds) && ok;
119
120   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
121 }
122
123 /* Parses the XSAVE or XEXPORT transformation command. */
124 static int
125 parse_output_trns (struct lexer *lexer, struct dataset *ds, enum writer_type writer_type)
126 {
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)
130     {
131       free (t);
132       return CMD_CASCADING_FAILURE;
133     }
134
135   add_transformation (ds, output_trns_proc, output_trns_free, t);
136   return CMD_SUCCESS;
137 }
138
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.
142
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
146    included.
147
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)
154 {
155   /* Common data. */
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. */
160
161   /* Common options. */
162   struct sfm_write_options sysfile_opts;
163   struct pfm_write_options porfile_opts;
164
165   assert (writer_type == SYSFILE_WRITER || writer_type == PORFILE_WRITER);
166   assert (command_type == XFORM_CMD || command_type == PROC_CMD);
167   assert ((retain_unselected != NULL) == (command_type == PROC_CMD));
168
169   if (command_type == PROC_CMD)
170     *retain_unselected = true;
171
172   handle = NULL;
173   dict = dict_clone (dataset_dict (ds));
174   writer = NULL;
175   map = NULL;
176   sysfile_opts = sfm_writer_default_options ();
177   porfile_opts = pfm_writer_default_options ();
178
179   case_map_prepare_dict (dict);
180   dict_delete_scratch_vars (dict);
181
182   lex_match (lexer, T_SLASH);
183   for (;;)
184     {
185       if (lex_match_id (lexer, "OUTFILE"))
186         {
187           if (handle != NULL)
188             {
189               lex_sbc_only_once ("OUTFILE");
190               goto error;
191             }
192
193           lex_match (lexer, T_EQUALS);
194
195           handle = fh_parse (lexer, FH_REF_FILE, NULL);
196           if (handle == NULL)
197             goto error;
198         }
199       else if (lex_match_id (lexer, "NAMES"))
200         {
201           /* Not yet implemented. */
202         }
203       else if (lex_match_id (lexer, "PERMISSIONS"))
204         {
205           bool cw;
206
207           lex_match (lexer, T_EQUALS);
208           if (lex_match_id (lexer, "READONLY"))
209             cw = false;
210           else if (lex_match_id (lexer, "WRITEABLE"))
211             cw = true;
212           else
213             {
214               lex_error_expecting (lexer, "READONLY", "WRITEABLE",
215                                    NULL_SENTINEL);
216               goto error;
217             }
218           sysfile_opts.create_writeable = porfile_opts.create_writeable = cw;
219         }
220       else if (command_type == PROC_CMD && lex_match_id (lexer, "UNSELECTED"))
221         {
222           lex_match (lexer, T_EQUALS);
223           if (lex_match_id (lexer, "RETAIN"))
224             *retain_unselected = true;
225           else if (lex_match_id (lexer, "DELETE"))
226             *retain_unselected = false;
227           else
228             {
229               lex_error_expecting (lexer, "RETAIN", "DELETE", NULL_SENTINEL);
230               goto error;
231             }
232         }
233       else if (writer_type == SYSFILE_WRITER
234                && lex_match_id (lexer, "COMPRESSED"))
235         sysfile_opts.compress = true;
236       else if (writer_type == SYSFILE_WRITER
237                && lex_match_id (lexer, "UNCOMPRESSED"))
238         sysfile_opts.compress = false;
239       else if (writer_type == SYSFILE_WRITER
240                && lex_match_id (lexer, "VERSION"))
241         {
242           lex_match (lexer, T_EQUALS);
243           if (!lex_force_int (lexer))
244             goto error;
245           sysfile_opts.version = lex_integer (lexer);
246           lex_get (lexer);
247         }
248       else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "TYPE"))
249         {
250           lex_match (lexer, T_EQUALS);
251           if (lex_match_id (lexer, "COMMUNICATIONS"))
252             porfile_opts.type = PFM_COMM;
253           else if (lex_match_id (lexer, "TAPE"))
254             porfile_opts.type = PFM_TAPE;
255           else
256             {
257               lex_error_expecting (lexer, "COMM", "TAPE", NULL_SENTINEL);
258               goto error;
259             }
260         }
261       else if (writer_type == PORFILE_WRITER && lex_match_id (lexer, "DIGITS"))
262         {
263           lex_match (lexer, T_EQUALS);
264           if (!lex_force_int (lexer))
265             goto error;
266           porfile_opts.digits = lex_integer (lexer);
267           lex_get (lexer);
268         }
269       else if (!parse_dict_trim (lexer, dict))
270         goto error;
271
272       if (!lex_match (lexer, T_SLASH))
273         break;
274     }
275   if (lex_end_of_command (lexer) != CMD_SUCCESS)
276     goto error;
277
278   if (handle == NULL)
279     {
280       lex_sbc_missing ("OUTFILE");
281       goto error;
282     }
283
284   dict_delete_scratch_vars (dict);
285   dict_compact_values (dict);
286
287   if (fh_get_referent (handle) == FH_REF_FILE)
288     {
289       switch (writer_type)
290         {
291         case SYSFILE_WRITER:
292           writer = sfm_open_writer (handle, dict, sysfile_opts);
293           break;
294         case PORFILE_WRITER:
295           writer = pfm_open_writer (handle, dict, porfile_opts);
296           break;
297         }
298     }
299   else
300     writer = any_writer_open (handle, dict);
301   if (writer == NULL)
302     goto error;
303
304   map = case_map_from_dict (dict);
305   if (map != NULL)
306     writer = case_map_create_output_translator (map, writer);
307   dict_destroy (dict);
308
309   fh_unref (handle);
310   return writer;
311
312  error:
313   fh_unref (handle);
314   casewriter_destroy (writer);
315   dict_destroy (dict);
316   case_map_destroy (map);
317   return NULL;
318 }
319
320 /* Writes case *C to the system file specified on XSAVE or XEXPORT. */
321 static int
322 output_trns_proc (void *trns_, struct ccase **c, casenumber case_num UNUSED)
323 {
324   struct output_trns *t = trns_;
325   casewriter_write (t->writer, case_ref (*c));
326   return TRNS_CONTINUE;
327 }
328
329 /* Frees an XSAVE or XEXPORT transformation.
330    Returns true if successful, false if an I/O error occurred. */
331 static bool
332 output_trns_free (void *trns_)
333 {
334   struct output_trns *t = trns_;
335   bool ok = casewriter_destroy (t->writer);
336   free (t);
337   return ok;
338 }