1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2013 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/file-name.h"
30 #include "data/por-file-writer.h"
31 #include "data/settings.h"
32 #include "data/sys-file-encryption.h"
33 #include "data/sys-file-writer.h"
34 #include "data/file-handle-def.h"
35 #include "libpspp/assertion.h"
36 #include "libpspp/cast.h"
37 #include "libpspp/i18n.h"
40 #include "gl/getpass.h"
41 #include "gl/progname.h"
42 #include "gl/version-etc.h"
45 #define _(msgid) gettext (msgid)
47 static void usage (void);
49 static void decrypt_sav_file (struct encrypted_sys_file *enc,
50 const char *input_filename,
51 const char *output_filename,
52 const char *password);
55 main (int argc, char *argv[])
57 const char *input_filename;
58 const char *output_filename;
60 long long int max_cases = LLONG_MAX;
61 struct dictionary *dict;
62 struct casereader *reader;
63 struct file_handle *input_fh;
64 const char *encoding = NULL;
65 struct encrypted_sys_file *enc;
67 const char *output_format = NULL;
68 struct file_handle *output_fh;
69 struct casewriter *writer;
70 const char *password = NULL;
74 set_program_name (argv[0]);
81 static const struct option long_options[] =
83 { "cases", required_argument, NULL, 'c' },
84 { "encoding", required_argument, NULL, 'e' },
85 { "password", required_argument, NULL, 'p' },
87 { "output-format", required_argument, NULL, 'O' },
89 { "help", no_argument, NULL, 'h' },
90 { "version", no_argument, NULL, 'v' },
96 c = getopt_long (argc, argv, "c:e:p:O:hv", long_options, NULL);
103 max_cases = strtoull (optarg, NULL, 0);
115 output_format = optarg;
119 version_etc (stdout, "pspp-convert", PACKAGE_NAME, PACKAGE_VERSION,
120 "Ben Pfaff", "John Darrington", NULL_SENTINEL);
132 if (optind + 2 != argc)
133 error (1, 0, _("exactly two non-option arguments are required; "
134 "use --help for help"));
136 input_filename = argv[optind];
137 output_filename = argv[optind + 1];
138 if (output_format == NULL)
140 const char *dot = strrchr (output_filename, '.');
142 error (1, 0, _("%s: cannot guess output format (use -O option)"),
145 output_format = dot + 1;
148 if (encrypted_sys_file_open (&enc, input_filename) > 0)
150 if (strcmp (output_format, "sav") && strcmp (output_format, "sys"))
151 error (1, 0, _("can only convert encrypted data file to sav or sys "
154 decrypt_sav_file (enc, input_filename, output_filename, password);
158 input_fh = fh_create_file (NULL, input_filename, fh_default_properties ());
159 reader = any_reader_open (input_fh, encoding, &dict);
163 output_fh = fh_create_file (NULL, output_filename, fh_default_properties ());
164 if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt"))
166 struct csv_writer_options options;
168 csv_writer_options_init (&options);
169 options.include_var_names = true;
170 writer = csv_writer_open (output_fh, dict, &options);
172 else if (!strcmp (output_format, "sav") || !strcmp (output_format, "sys"))
174 struct sfm_write_options options;
176 options = sfm_writer_default_options ();
177 writer = sfm_open_writer (output_fh, dict, options);
179 else if (!strcmp (output_format, "por"))
181 struct pfm_write_options options;
183 options = pfm_writer_default_options ();
184 writer = pfm_open_writer (output_fh, dict, options);
188 error (1, 0, _("%s: unknown output format (use -O option)"),
193 for (i = 0; i < max_cases; i++)
197 c = casereader_read (reader);
201 casewriter_write (writer, c);
204 if (!casereader_destroy (reader))
205 error (1, 0, _("%s: error reading input file"), input_filename);
206 if (!casewriter_destroy (writer))
207 error (1, 0, _("%s: error writing output file"), output_filename);
217 decrypt_sav_file (struct encrypted_sys_file *enc,
218 const char *input_filename,
219 const char *output_filename,
220 const char *password)
225 if (password == NULL)
227 password = getpass ("password: ");
228 if (password == NULL)
232 if (!encrypted_sys_file_unlock (enc, password))
233 error (1, 0, _("sorry, wrong password"));
235 out = fn_open (output_filename, "wb");
237 error (1, errno, ("%s: error opening output file"), output_filename);
241 uint8_t buffer[1024];
244 n = encrypted_sys_file_read (enc, buffer, sizeof buffer);
248 if (fwrite (buffer, 1, n, out) != n)
249 error (1, errno, ("%s: write error"), output_filename);
252 err = encrypted_sys_file_close (enc);
254 error (1, err, ("%s: read error"), input_filename);
256 if (fflush (out) == EOF)
257 error (1, errno, ("%s: write error"), output_filename);
258 fn_close (output_filename, out);
265 %s, a utility for converting SPSS data files to other formats.\n\
266 Usage: %s [OPTION]... INPUT OUTPUT\n\
267 where INPUT is an SPSS system or portable file\n\
268 and OUTPUT is the name of the desired output file.\n\
270 The desired format of OUTPUT is by default inferred from its extension:\n\
271 csv txt comma-separated value\n\
272 sav sys SPSS system file\n\
273 por SPSS portable file\n\
276 -O, --output-format=FORMAT set specific output format, where FORMAT\n\
277 is one of the extensions listed above\n\
278 -e, --encoding=CHARSET override encoding of input data file\n\
279 -c MAXCASES limit number of cases to copy (default is all cases)\n\
280 -p PASSWORD password for encrypted .sav files\n\
281 --help display this help and exit\n\
282 --version output version information and exit\n",
283 program_name, program_name);