VECTOR: Support creating string variables also.
[pspp.git] / utilities / pspp-convert.c
blobb7dd30b6c9c9e7325fec3b9f2a2458d787c24877
1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2013, 2014, 2015, 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/>. */
17 #include <config.h>
19 #include <errno.h>
20 #include <getopt.h>
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <unistd.h>
25 #include "data/any-reader.h"
26 #include "data/casereader.h"
27 #include "data/casewriter.h"
28 #include "data/csv-file-writer.h"
29 #include "data/dictionary.h"
30 #include "data/encrypted-file.h"
31 #include "data/file-name.h"
32 #include "data/por-file-writer.h"
33 #include "data/settings.h"
34 #include "data/sys-file-writer.h"
35 #include "data/file-handle-def.h"
36 #include "libpspp/assertion.h"
37 #include "libpspp/cast.h"
38 #include "libpspp/i18n.h"
40 #include "gl/error.h"
41 #include "gl/getpass.h"
42 #include "gl/progname.h"
43 #include "gl/version-etc.h"
45 #include "gettext.h"
46 #define _(msgid) gettext (msgid)
48 static void usage (void);
50 static bool decrypt_file (struct encrypted_file *enc,
51 const struct file_handle *input_filename,
52 const struct file_handle *output_filename,
53 const char *password);
55 int
56 main (int argc, char *argv[])
58 const char *input_filename;
59 const char *output_filename;
61 long long int max_cases = LLONG_MAX;
62 struct dictionary *dict = NULL;
63 struct casereader *reader;
64 struct file_handle *input_fh = NULL;
65 const char *encoding = NULL;
66 struct encrypted_file *enc;
68 const char *output_format = NULL;
69 struct file_handle *output_fh = NULL;
70 struct casewriter *writer;
71 const char *password = NULL;
73 long long int i;
75 set_program_name (argv[0]);
76 i18n_init ();
77 fh_init ();
78 settings_init ();
80 for (;;)
82 static const struct option long_options[] =
84 { "cases", required_argument, NULL, 'c' },
85 { "encoding", required_argument, NULL, 'e' },
86 { "password", required_argument, NULL, 'p' },
88 { "output-format", required_argument, NULL, 'O' },
90 { "help", no_argument, NULL, 'h' },
91 { "version", no_argument, NULL, 'v' },
92 { NULL, 0, NULL, 0 },
95 int c;
97 c = getopt_long (argc, argv, "c:e:p:O:hv", long_options, NULL);
98 if (c == -1)
99 break;
101 switch (c)
103 case 'c':
104 max_cases = strtoull (optarg, NULL, 0);
105 break;
107 case 'e':
108 encoding = optarg;
109 break;
111 case 'p':
112 password = optarg;
113 break;
115 case 'O':
116 output_format = optarg;
117 break;
119 case 'v':
120 version_etc (stdout, "pspp-convert", PACKAGE_NAME, PACKAGE_VERSION,
121 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
122 exit (EXIT_SUCCESS);
124 case 'h':
125 usage ();
126 exit (EXIT_SUCCESS);
128 default:
129 goto error;
133 if (optind + 2 != argc)
134 error (1, 0, _("exactly two non-option arguments are required; "
135 "use --help for help"));
137 input_filename = argv[optind];
138 output_filename = argv[optind + 1];
139 input_fh = fh_create_file (NULL, input_filename, NULL, fh_default_properties ());
141 if (output_format == NULL)
143 const char *dot = strrchr (output_filename, '.');
144 if (dot == NULL)
145 error (1, 0, _("%s: cannot guess output format (use -O option)"),
146 output_filename);
148 output_format = dot + 1;
151 output_fh = fh_create_file (NULL, output_filename, NULL, fh_default_properties ());
152 if (encrypted_file_open (&enc, input_fh) > 0)
154 if (encrypted_file_is_sav (enc))
156 if (strcmp (output_format, "sav") && strcmp (output_format, "sys"))
157 error (1, 0, _("can only convert encrypted data file to sav or "
158 "sys format"));
160 else
162 if (strcmp (output_format, "sps"))
163 error (1, 0, _("can only convert encrypted syntax file to sps "
164 "format"));
167 if (! decrypt_file (enc, input_fh, output_fh, password))
168 goto error;
170 goto exit;
174 reader = any_reader_open_and_decode (input_fh, encoding, &dict, NULL);
175 if (reader == NULL)
176 goto error;
178 if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt"))
180 struct csv_writer_options options;
182 csv_writer_options_init (&options);
183 options.include_var_names = true;
184 writer = csv_writer_open (output_fh, dict, &options);
186 else if (!strcmp (output_format, "sav") || !strcmp (output_format, "sys"))
188 struct sfm_write_options options;
190 options = sfm_writer_default_options ();
191 writer = sfm_open_writer (output_fh, dict, options);
193 else if (!strcmp (output_format, "por"))
195 struct pfm_write_options options;
197 options = pfm_writer_default_options ();
198 writer = pfm_open_writer (output_fh, dict, options);
200 else
202 error (1, 0, _("%s: unknown output format (use -O option)"),
203 output_filename);
204 NOT_REACHED ();
207 for (i = 0; i < max_cases; i++)
209 struct ccase *c;
211 c = casereader_read (reader);
212 if (c == NULL)
213 break;
215 casewriter_write (writer, c);
218 if (!casereader_destroy (reader))
219 error (1, 0, _("%s: error reading input file"), input_filename);
220 if (!casewriter_destroy (writer))
221 error (1, 0, _("%s: error writing output file"), output_filename);
223 exit:
224 dict_destroy (dict);
225 fh_unref (output_fh);
226 fh_unref (input_fh);
227 fh_done ();
228 i18n_done ();
230 return 0;
232 error:
233 dict_destroy (dict);
234 fh_unref (output_fh);
235 fh_unref (input_fh);
236 fh_done ();
237 i18n_done ();
239 return 1;
242 static bool
243 decrypt_file (struct encrypted_file *enc,
244 const struct file_handle *ifh,
245 const struct file_handle *ofh,
246 const char *password)
248 FILE *out;
249 int err;
250 const char *input_filename = fh_get_file_name (ifh);
251 const char *output_filename = fh_get_file_name (ofh);
253 if (password == NULL)
255 password = getpass ("password: ");
256 if (password == NULL)
257 return false;
260 if (!encrypted_file_unlock (enc, password))
261 error (1, 0, _("sorry, wrong password"));
263 out = fn_open (ofh, "wb");
264 if (out == NULL)
265 error (1, errno, ("%s: error opening output file"), output_filename);
267 for (;;)
269 uint8_t buffer[1024];
270 size_t n;
272 n = encrypted_file_read (enc, buffer, sizeof buffer);
273 if (n == 0)
274 break;
276 if (fwrite (buffer, 1, n, out) != n)
277 error (1, errno, ("%s: write error"), output_filename);
280 err = encrypted_file_close (enc);
281 if (err)
282 error (1, err, ("%s: read error"), input_filename);
284 if (fflush (out) == EOF)
285 error (1, errno, ("%s: write error"), output_filename);
286 fn_close (ofh, out);
288 return true;
291 static void
292 usage (void)
294 printf ("\
295 %s, a utility for converting SPSS data files to other formats.\n\
296 Usage: %s [OPTION]... INPUT OUTPUT\n\
297 where INPUT is an SPSS data file or encrypted syntax file\n\
298 and OUTPUT is the name of the desired output file.\n\
300 The desired format of OUTPUT is by default inferred from its extension:\n\
301 csv txt comma-separated value\n\
302 sav sys SPSS system file\n\
303 por SPSS portable file\n\
304 sps SPSS syntax file (encrypted syntax input files only)\n\
306 Options:\n\
307 -O, --output-format=FORMAT set specific output format, where FORMAT\n\
308 is one of the extensions listed above\n\
309 -e, --encoding=CHARSET override encoding of input data file\n\
310 -c MAXCASES limit number of cases to copy (default is all cases)\n\
311 -p PASSWORD password for encrypted files\n\
312 --help display this help and exit\n\
313 --version output version information and exit\n",
314 program_name, program_name);