treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp] / src / data / csv-file-writer.c
index 70568c3e1d4dfe35fc10857d0aaf6ee1fe654c72..77224945bc9959aca8b18b2a64046bcd3f2031c6 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 2010 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011, 2012, 2013, 2014 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
@@ -33,7 +33,6 @@
 #include "data/data-out.h"
 #include "data/dictionary.h"
 #include "data/file-handle-def.h"
-#include "data/file-name.h"
 #include "data/format.h"
 #include "data/make-file.h"
 #include "data/missing-values.h"
@@ -45,6 +44,8 @@
 #include "libpspp/message.h"
 #include "libpspp/str.h"
 
+#include "gl/ftoastr.h"
+#include "gl/minmax.h"
 #include "gl/unlocked-io.h"
 #include "gl/xalloc.h"
 
@@ -86,19 +87,6 @@ static void write_var_names (struct csv_writer *, const struct dictionary *);
 static bool write_error (const struct csv_writer *);
 static bool close_writer (struct csv_writer *);
 
-/* Initializes OPTS with default options for writing a CSV file. */
-void
-csv_writer_options_init (struct csv_writer_options *opts)
-{
-  opts->recode_user_missing = false;
-  opts->include_var_names = false;
-  opts->use_value_labels = false;
-  opts->use_print_formats = false;
-  opts->decimal = settings_get_decimal_char (FMT_F);
-  opts->delimiter = 0;
-  opts->qualifier = '"';
-}
-
 /* Opens the CSV file designated by file handle FH for writing cases from
    dictionary DICT according to the given OPTS.
 
@@ -120,11 +108,9 @@ csv_writer_open (struct file_handle *fh, const struct dictionary *dict,
 
   w->opts = *opts;
 
-  w->encoding = (dict_get_encoding (dict)
-                 ? xstrdup (dict_get_encoding (dict))
-                 : NULL);
+  w->encoding = xstrdup (dict_get_encoding (dict));
 
-  w->n_csv_vars = dict_get_var_cnt (dict);
+  w->n_csv_vars = dict_get_n_vars (dict);
   w->csv_vars = xnmalloc (w->n_csv_vars, sizeof *w->csv_vars);
   for (i = 0; i < w->n_csv_vars; i++)
     {
@@ -154,11 +140,10 @@ csv_writer_open (struct file_handle *fh, const struct dictionary *dict,
     goto error;
 
   /* Create the file on disk. */
-  w->rf = replace_file_start (fh_get_file_name (fh), "w", 0666,
-                              &w->file, NULL);
+  w->rf = replace_file_start (fh, "w", 0666,  &w->file);
   if (w->rf == NULL)
     {
-      msg (ME, _("Error opening `%s' for writing as a system file: %s."),
+      msg (ME, _("Error opening `%s' for writing as a CSV file: %s."),
            fh_get_file_name (fh), strerror (errno));
       goto error;
     }
@@ -200,6 +185,12 @@ csv_output_buffer (struct csv_writer *w, const char *s, size_t len)
       putc (w->opts.qualifier, w->file);
       for (p = s; p < &s[len]; p++)
         {
+          /* We are writing the output file in text mode, so transform any
+             explicit CR-LF line breaks into LF only, to allow the C library to
+             use correct system-specific new-lines. */
+          if (*p == '\r' && p[1] == '\n')
+            continue;
+
           if (*p == w->opts.qualifier)
             putc (w->opts.qualifier, w->file);
           putc (*p, w->file);
@@ -234,7 +225,8 @@ static void
 csv_output_format (struct csv_writer *w, const struct csv_var *cv,
                    const union value *value)
 {
-  char *s = data_out (value, w->encoding, &cv->format);
+  char *s = data_out (value, w->encoding, &cv->format,
+                      settings_get_fmt_settings ());
   struct substring ss = ss_cstr (s);
   if (cv->format.type != FMT_A)
     ss_trim (&ss, ss_cstr (" "));
@@ -280,7 +272,8 @@ csv_write_var__ (struct csv_writer *w, const struct csv_var *cv,
     csv_output_format (w, cv, value);
   else
     {
-      char s[128];
+      char s[MAX (DBL_STRLEN_BOUND, 128)];
+      char *cp;
 
       switch (cv->format.type)
         {
@@ -306,13 +299,10 @@ csv_write_var__ (struct csv_writer *w, const struct csv_var *cv,
         case FMT_RBHEX:
         case FMT_WKDAY:
         case FMT_MONTH:
-          snprintf (s, sizeof s, "%.*g", DBL_DIG + 1, value->f);
-          if (w->opts.decimal != '.')
-            {
-              char *cp = strchr (s, '.');
-              if (cp != NULL)
-                *cp = w->opts.decimal;
-            }
+          dtoastr (s, sizeof s, 0, 0, value->f);
+          cp = strpbrk (s, ".,");
+          if (cp != NULL)
+            *cp = w->opts.decimal;
           break;
 
         case FMT_DATE:
@@ -335,6 +325,7 @@ csv_write_var__ (struct csv_writer *w, const struct csv_var *cv,
           break;
 
         case FMT_DATETIME:
+        case FMT_YMDHMS:
           if (value->f < 0)
             strcpy (s, " ");
           else
@@ -348,6 +339,7 @@ csv_write_var__ (struct csv_writer *w, const struct csv_var *cv,
             }
           break;
 
+        case FMT_MTIME:
         case FMT_TIME:
         case FMT_DTIME:
           {