pspp-convert: New utility to convert among data formats.
[pspp] / utilities / pspp-convert.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2013 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 <getopt.h>
20 #include <limits.h>
21 #include <stdlib.h>
22
23 #include "data/any-reader.h"
24 #include "data/casereader.h"
25 #include "data/casewriter.h"
26 #include "data/csv-file-writer.h"
27 #include "data/por-file-writer.h"
28 #include "data/settings.h"
29 #include "data/sys-file-writer.h"
30 #include "data/file-handle-def.h"
31 #include "libpspp/assertion.h"
32 #include "libpspp/cast.h"
33 #include "libpspp/i18n.h"
34
35 #include "gl/error.h"
36 #include "gl/progname.h"
37 #include "gl/version-etc.h"
38
39 #include "gettext.h"
40 #define _(msgid) gettext (msgid)
41
42 static void usage (void);
43
44 int
45 main (int argc, char *argv[])
46 {
47   const char *input_filename;
48   const char *output_filename;
49
50   struct fh_properties properties;
51   long long int max_cases = LLONG_MAX;
52   struct dictionary *dict;
53   struct casereader *reader;
54   struct file_handle *input_fh;
55
56   const char *output_format = NULL;
57   struct file_handle *output_fh;
58   struct casewriter *writer;
59
60   long long int i;
61
62   set_program_name (argv[0]);
63   i18n_init ();
64   fh_init ();
65   settings_init ();
66
67   properties = *fh_default_properties ();
68   for (;;)
69     {
70       static const struct option long_options[] =
71         {
72           { "cases",    required_argument, NULL, 'c' },
73           { "encoding", required_argument, NULL, 'e' },
74
75           { "output-format", required_argument, NULL, 'O' },
76
77           { "help",    no_argument,       NULL, 'h' },
78           { "version", no_argument,       NULL, 'v' },
79           { NULL,      0,                 NULL, 0 },
80         };
81
82       int c;
83
84       c = getopt_long (argc, argv, "c:e:O:hv", long_options, NULL);
85       if (c == -1)
86         break;
87
88       switch (c)
89         {
90         case 'c':
91           max_cases = strtoull (optarg, NULL, 0);
92           break;
93
94         case 'e':
95           properties.encoding = optarg;
96           break;
97
98         case 'O':
99           output_format = optarg;
100           break;
101
102         case 'v':
103           version_etc (stdout, "pspp-convert", PACKAGE_NAME, PACKAGE_VERSION,
104                        "Ben Pfaff", "John Darrington", NULL_SENTINEL);
105           exit (EXIT_SUCCESS);
106
107         case 'h':
108           usage ();
109           exit (EXIT_SUCCESS);
110
111         default:
112           exit (EXIT_FAILURE);
113         }
114     }
115
116   if (optind + 2 != argc)
117     error (1, 0, _("exactly two non-option arguments are required; "
118                    "use --help for help"));
119
120   input_filename = argv[optind];
121   output_filename = argv[optind + 1];
122   if (output_format == NULL)
123     {
124       const char *dot = strrchr (output_filename, '.');
125       if (dot == NULL)
126         error (1, 0, _("%s: cannot guess output format (use -O option)"),
127                output_filename);
128
129       output_format = dot + 1;
130     }
131
132   input_fh = fh_create_file (NULL, input_filename, &properties);
133   reader = any_reader_open (input_fh, properties.encoding, &dict);
134   if (reader == NULL)
135     exit (1);
136
137   output_fh = fh_create_file (NULL, output_filename, fh_default_properties ());
138   if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt"))
139     {
140       struct csv_writer_options options;
141
142       csv_writer_options_init (&options);
143       options.include_var_names = true;
144       writer = csv_writer_open (output_fh, dict, &options);
145     }
146   else if (!strcmp (output_format, "sav") || !strcmp (output_format, "sys"))
147     {
148       struct sfm_write_options options;
149
150       options = sfm_writer_default_options ();
151       writer = sfm_open_writer (output_fh, dict, options);
152     }
153   else if (!strcmp (output_format, "por"))
154     {
155       struct pfm_write_options options;
156
157       options = pfm_writer_default_options ();
158       writer = pfm_open_writer (output_fh, dict, options);
159     }
160   else
161     {
162       error (1, 0, _("%s: unknown output format (use -O option)"),
163              output_filename);
164       NOT_REACHED ();
165     }
166
167   for (i = 0; i < max_cases; i++)
168     {
169       struct ccase *c;
170
171       c = casereader_read (reader);
172       if (c == NULL)
173         break;
174
175       casewriter_write (writer, c);
176     }
177
178   if (!casereader_destroy (reader))
179     error (1, 0, _("%s: error reading input file"), input_filename);
180   if (!casewriter_destroy (writer))
181     error (1, 0, _("%s: error writing output file"), output_filename);
182
183   fh_done ();
184   i18n_done ();
185
186   return 0;
187 }
188
189 static void
190 usage (void)
191 {
192   printf ("\
193 %s, a utility for converting SPSS data files to other formats.\n\
194 Usage: %s [OPTION]... INPUT OUTPUT\n\
195 where INPUT is an SPSS system or portable file\n\
196   and OUTPUT is the name of the desired output file.\n\
197 \n\
198 The desired format of OUTPUT is by default inferred from its extension:\n\
199   csv txt             comma-separated value\n\
200   sav sys             SPSS system file\n\
201   por                 SPSS portable file\n\
202 \n\
203 Options:\n\
204   -O, --output-format=FORMAT  set specific output format, where FORMAT\n\
205                       is one of the extensions listed above\n\
206   -e, --encoding=CHARSET  override encoding of input data file\n\
207   -c MAXCASES         limit number of cases to copy (default is all cases)\n\
208   --help              display this help and exit\n\
209   --version           output version information and exit\n",
210           program_name, program_name);
211 }