pspp-convert: New utility to convert among data formats.
[pspp] / utilities / pspp-convert.c
diff --git a/utilities/pspp-convert.c b/utilities/pspp-convert.c
new file mode 100644 (file)
index 0000000..233bfbf
--- /dev/null
@@ -0,0 +1,211 @@
+/* PSPP - a program for statistical analysis.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <getopt.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "data/any-reader.h"
+#include "data/casereader.h"
+#include "data/casewriter.h"
+#include "data/csv-file-writer.h"
+#include "data/por-file-writer.h"
+#include "data/settings.h"
+#include "data/sys-file-writer.h"
+#include "data/file-handle-def.h"
+#include "libpspp/assertion.h"
+#include "libpspp/cast.h"
+#include "libpspp/i18n.h"
+
+#include "gl/error.h"
+#include "gl/progname.h"
+#include "gl/version-etc.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+static void usage (void);
+
+int
+main (int argc, char *argv[])
+{
+  const char *input_filename;
+  const char *output_filename;
+
+  struct fh_properties properties;
+  long long int max_cases = LLONG_MAX;
+  struct dictionary *dict;
+  struct casereader *reader;
+  struct file_handle *input_fh;
+
+  const char *output_format = NULL;
+  struct file_handle *output_fh;
+  struct casewriter *writer;
+
+  long long int i;
+
+  set_program_name (argv[0]);
+  i18n_init ();
+  fh_init ();
+  settings_init ();
+
+  properties = *fh_default_properties ();
+  for (;;)
+    {
+      static const struct option long_options[] =
+        {
+          { "cases",    required_argument, NULL, 'c' },
+          { "encoding", required_argument, NULL, 'e' },
+
+          { "output-format", required_argument, NULL, 'O' },
+
+          { "help",    no_argument,       NULL, 'h' },
+          { "version", no_argument,       NULL, 'v' },
+          { NULL,      0,                 NULL, 0 },
+        };
+
+      int c;
+
+      c = getopt_long (argc, argv, "c:e:O:hv", long_options, NULL);
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case 'c':
+          max_cases = strtoull (optarg, NULL, 0);
+          break;
+
+        case 'e':
+          properties.encoding = optarg;
+          break;
+
+        case 'O':
+          output_format = optarg;
+          break;
+
+        case 'v':
+          version_etc (stdout, "pspp-convert", PACKAGE_NAME, PACKAGE_VERSION,
+                       "Ben Pfaff", "John Darrington", NULL_SENTINEL);
+          exit (EXIT_SUCCESS);
+
+        case 'h':
+          usage ();
+          exit (EXIT_SUCCESS);
+
+        default:
+          exit (EXIT_FAILURE);
+        }
+    }
+
+  if (optind + 2 != argc)
+    error (1, 0, _("exactly two non-option arguments are required; "
+                   "use --help for help"));
+
+  input_filename = argv[optind];
+  output_filename = argv[optind + 1];
+  if (output_format == NULL)
+    {
+      const char *dot = strrchr (output_filename, '.');
+      if (dot == NULL)
+        error (1, 0, _("%s: cannot guess output format (use -O option)"),
+               output_filename);
+
+      output_format = dot + 1;
+    }
+
+  input_fh = fh_create_file (NULL, input_filename, &properties);
+  reader = any_reader_open (input_fh, properties.encoding, &dict);
+  if (reader == NULL)
+    exit (1);
+
+  output_fh = fh_create_file (NULL, output_filename, fh_default_properties ());
+  if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt"))
+    {
+      struct csv_writer_options options;
+
+      csv_writer_options_init (&options);
+      options.include_var_names = true;
+      writer = csv_writer_open (output_fh, dict, &options);
+    }
+  else if (!strcmp (output_format, "sav") || !strcmp (output_format, "sys"))
+    {
+      struct sfm_write_options options;
+
+      options = sfm_writer_default_options ();
+      writer = sfm_open_writer (output_fh, dict, options);
+    }
+  else if (!strcmp (output_format, "por"))
+    {
+      struct pfm_write_options options;
+
+      options = pfm_writer_default_options ();
+      writer = pfm_open_writer (output_fh, dict, options);
+    }
+  else
+    {
+      error (1, 0, _("%s: unknown output format (use -O option)"),
+             output_filename);
+      NOT_REACHED ();
+    }
+
+  for (i = 0; i < max_cases; i++)
+    {
+      struct ccase *c;
+
+      c = casereader_read (reader);
+      if (c == NULL)
+        break;
+
+      casewriter_write (writer, c);
+    }
+
+  if (!casereader_destroy (reader))
+    error (1, 0, _("%s: error reading input file"), input_filename);
+  if (!casewriter_destroy (writer))
+    error (1, 0, _("%s: error writing output file"), output_filename);
+
+  fh_done ();
+  i18n_done ();
+
+  return 0;
+}
+
+static void
+usage (void)
+{
+  printf ("\
+%s, a utility for converting SPSS data files to other formats.\n\
+Usage: %s [OPTION]... INPUT OUTPUT\n\
+where INPUT is an SPSS system or portable file\n\
+  and OUTPUT is the name of the desired output file.\n\
+\n\
+The desired format of OUTPUT is by default inferred from its extension:\n\
+  csv txt             comma-separated value\n\
+  sav sys             SPSS system file\n\
+  por                 SPSS portable file\n\
+\n\
+Options:\n\
+  -O, --output-format=FORMAT  set specific output format, where FORMAT\n\
+                      is one of the extensions listed above\n\
+  -e, --encoding=CHARSET  override encoding of input data file\n\
+  -c MAXCASES         limit number of cases to copy (default is all cases)\n\
+  --help              display this help and exit\n\
+  --version           output version information and exit\n",
+          program_name, program_name);
+}