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/>. */
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"
41 #include "gl/getpass.h"
42 #include "gl/progname.h"
43 #include "gl/version-etc.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);
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;
75 set_program_name (argv[0]);
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' },
97 c = getopt_long (argc, argv, "c:e:p:O:hv", long_options, NULL);
104 max_cases = strtoull (optarg, NULL, 0);
116 output_format = optarg;
120 version_etc (stdout, "pspp-convert", PACKAGE_NAME, PACKAGE_VERSION,
121 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
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, '.');
145 error (1, 0, _("%s: cannot guess output format (use -O option)"),
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 "
162 if (strcmp (output_format, "sps"))
163 error (1, 0, _("can only convert encrypted syntax file to sps "
167 if (! decrypt_file (enc, input_fh, output_fh, password))
174 reader = any_reader_open_and_decode (input_fh, encoding, &dict, NULL);
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);
202 error (1, 0, _("%s: unknown output format (use -O option)"),
207 error (1, 0, _("%s: error opening output file"), output_filename);
209 for (i = 0; i < max_cases; i++)
213 c = casereader_read (reader);
217 casewriter_write (writer, c);
220 if (!casereader_destroy (reader))
221 error (1, 0, _("%s: error reading input file"), input_filename);
222 if (!casewriter_destroy (writer))
223 error (1, 0, _("%s: error writing output file"), output_filename);
227 fh_unref (output_fh);
236 fh_unref (output_fh);
245 decrypt_file (struct encrypted_file *enc,
246 const struct file_handle *ifh,
247 const struct file_handle *ofh,
248 const char *password)
252 const char *input_filename = fh_get_file_name (ifh);
253 const char *output_filename = fh_get_file_name (ofh);
255 if (password == NULL)
257 password = getpass ("password: ");
258 if (password == NULL)
262 if (!encrypted_file_unlock (enc, password))
263 error (1, 0, _("sorry, wrong password"));
265 out = fn_open (ofh, "wb");
267 error (1, errno, ("%s: error opening output file"), output_filename);
271 uint8_t buffer[1024];
274 n = encrypted_file_read (enc, buffer, sizeof buffer);
278 if (fwrite (buffer, 1, n, out) != n)
279 error (1, errno, ("%s: write error"), output_filename);
282 err = encrypted_file_close (enc);
284 error (1, err, ("%s: read error"), input_filename);
286 if (fflush (out) == EOF)
287 error (1, errno, ("%s: write error"), output_filename);
297 %s, a utility for converting SPSS data files to other formats.\n\
298 Usage: %s [OPTION]... INPUT OUTPUT\n\
299 where INPUT is an SPSS data file or encrypted syntax file\n\
300 and OUTPUT is the name of the desired output file.\n\
302 The desired format of OUTPUT is by default inferred from its extension:\n\
303 csv txt comma-separated value\n\
304 sav sys SPSS system file\n\
305 por SPSS portable file\n\
306 sps SPSS syntax file (encrypted syntax input files only)\n\
309 -O, --output-format=FORMAT set specific output format, where FORMAT\n\
310 is one of the extensions listed above\n\
311 -e, --encoding=CHARSET override encoding of input data file\n\
312 -c MAXCASES limit number of cases to copy (default is all cases)\n\
313 -p PASSWORD password for encrypted files\n\
314 --help display this help and exit\n\
315 --version output version information and exit\n",
316 program_name, program_name);