Make fn_open and fn_close take a struct file_handle instead of char *
authorJohn Darrington <john@darrington.wattle.id.au>
Wed, 18 Nov 2015 17:52:24 +0000 (18:52 +0100)
committerJohn Darrington <john@darrington.wattle.id.au>
Sat, 21 Nov 2015 15:17:18 +0000 (16:17 +0100)
This change alters the signature of the fn_open and fn_close functions,
and changes all callers appropriately.  The purpose of such a change is
so that the encoding of the filename is passed to fn_open from wherever
it was created.

It also changes the implementation of fn_open on windows systems to call
_wfopen instead of fopen.  This should fix the problem of windows builds
not being able to open files whose pathnames included non-ascii characters.

As a bonus, we no longer require the rather contrived function
local_to_filename_encoding.

Some related issues (what about the pspprc file?) remain.

26 files changed:
src/data/any-reader.c
src/data/any-reader.h
src/data/any-writer.c
src/data/encrypted-file.c
src/data/encrypted-file.h
src/data/file-handle-def.c
src/data/file-name.c
src/data/file-name.h
src/data/make-file.c
src/data/pc+-file-reader.c
src/data/por-file-reader.c
src/data/sys-file-reader.c
src/language/data-io/data-reader.c
src/language/data-io/data-writer.c
src/language/data-io/save-translate.c
src/output/ascii.c
src/output/cairo.c
src/output/csv.c
src/output/driver-provider.h
src/output/driver.c
src/output/html.c
src/output/msglog.c
src/output/odt.c
src/ui/gui/psppire-window.c
src/ui/gui/psppire.c
utilities/pspp-convert.c

index aee034ce319ae8131669305e3e3fa6aa4fc9ec3b..ff7f4ab6c923a4dd7bec8ea3e425e5523262b2bd 100644 (file)
@@ -51,7 +51,7 @@ static const struct any_reader_class *classes[] =
 enum { N_CLASSES = sizeof classes / sizeof *classes };
 
 int
-any_reader_detect (const char *file_name,
+any_reader_detect (const struct file_handle *file_handle,
                    const struct any_reader_class **classp)
 {
   struct detector
@@ -66,11 +66,11 @@ any_reader_detect (const char *file_name,
   if (classp)
     *classp = NULL;
 
-  file = fn_open (file_name, "rb");
+  file = fn_open (file_handle, "rb");
   if (file == NULL)
     {
       msg (ME, _("An error occurred while opening `%s': %s."),
-           file_name, strerror (errno));
+           fh_get_file_name (file_handle), strerror (errno));
       return -errno;
     }
 
@@ -90,9 +90,9 @@ any_reader_detect (const char *file_name,
     }
 
   if (retval < 0)
-    msg (ME, _("Error reading `%s': %s."), file_name, strerror (-retval));
+    msg (ME, _("Error reading `%s': %s."), fh_get_file_name (file_handle), strerror (-retval));
 
-  fn_close (file_name, file);
+  fn_close (file_handle, file);
 
   return retval;
 }
@@ -107,7 +107,7 @@ any_reader_open (struct file_handle *handle)
         const struct any_reader_class *class;
         int retval;
 
-        retval = any_reader_detect (fh_get_file_name (handle), &class);
+        retval = any_reader_detect (handle, &class);
         if (retval <= 0)
           {
             if (retval == 0)
index a12c256ae91023dd9bc90a76513f1a12e42c041b..998e12441b2894ccad6c1abdfd10e7754c66950f 100644 (file)
@@ -97,7 +97,7 @@ void any_read_info_destroy (struct any_read_info *);
 struct file_handle;
 struct dictionary;
 
-int any_reader_detect (const char *file_name,
+int any_reader_detect (const struct file_handle *file_name,
                        const struct any_reader_class **);
 
 struct any_reader *any_reader_open (struct file_handle *);
index 61d6ffc8a26ec5c53501f0dc38aa20078cad8280..170702bab36c333f4d9e4bb54aca596e70f70e25 100644 (file)
@@ -49,7 +49,7 @@ any_writer_open (struct file_handle *handle, struct dictionary *dict)
         struct casewriter *writer;
         char *extension;
 
-        extension = fn_extension (fh_get_file_name (handle));
+        extension = fn_extension (handle);
         str_lowercase (extension);
 
         if (!strcmp (extension, ".por"))
index b90126ed260be18b2163fe9c3a3ff63d17e15a0c..f1074b4c1d159d4ad805ea9b887f40400114e20f 100644 (file)
@@ -17,6 +17,7 @@
 #include <config.h>
 
 #include "data/encrypted-file.h"
+#include "data/file-handle-def.h"
 
 #include <errno.h>
 #include <stdlib.h>
@@ -60,7 +61,7 @@ static bool fill_buffer (struct encrypted_file *);
 
    If FILENAME cannot be open or read, returns a negative errno value. */
 int
-encrypted_file_open (struct encrypted_file **fp, const char *filename)
+encrypted_file_open (struct encrypted_file **fp, const struct file_handle *fh)
 {
   struct encrypted_file *f;
   char header[36 + 16];
@@ -69,11 +70,11 @@ encrypted_file_open (struct encrypted_file **fp, const char *filename)
 
   f = xmalloc (sizeof *f);
   f->error = 0;
-  f->file = fn_open (filename, "rb");
+  f->file = fn_open (fh, "rb");
   if (f->file == NULL)
     {
       msg (ME, _("An error occurred while opening `%s': %s."),
-           filename, strerror (errno));
+           fh_get_file_name (fh), strerror (errno));
       retval = -errno;
       goto error;
     }
@@ -84,7 +85,7 @@ encrypted_file_open (struct encrypted_file **fp, const char *filename)
       int error = feof (f->file) ? 0 : errno;
       if (error)
         msg (ME, _("An error occurred while reading `%s': %s."),
-             filename, strerror (error));
+             fh_get_file_name (fh), strerror (error));
       retval = -error;
       goto error;
     }
@@ -107,7 +108,7 @@ encrypted_file_open (struct encrypted_file **fp, const char *filename)
 
 error:
   if (f->file)
-    fn_close (filename, f->file);
+    fn_close (fh, f->file);
   free (f);
   *fp = NULL;
 
index d089a046f01a846362cbf2b2268489d486933de8..9e3116b774d4d4136a68d79cb13e853f738a687e 100644 (file)
@@ -23,8 +23,9 @@
 /* Reading encrypted SPSS files. */
 
 struct encrypted_file;
+struct file_handle;
 
-int encrypted_file_open (struct encrypted_file **, const char *filename);
+int encrypted_file_open (struct encrypted_file **, const struct file_handle *);
 bool encrypted_file_unlock (struct encrypted_file *, const char *password);
 size_t encrypted_file_read (struct encrypted_file *, void *, size_t);
 int encrypted_file_close (struct encrypted_file *);
index 53e00be13a71b2c2f1ea8f3ee7621d0780180bba..f058a0075222881231bbadd7ebefc5c00477948b 100644 (file)
@@ -24,7 +24,6 @@
 #include <string.h>
 
 #include "data/dataset.h"
-#include "data/file-name.h"
 #include "data/variable.h"
 #include "libpspp/cast.h"
 #include "libpspp/compiler.h"
index a81ea9341ae8fab5a5e0eb4e4f3d196edf4e9901..1c47b4751bd2cff865709fb000e02b20bc47838c 100644 (file)
@@ -31,6 +31,7 @@
 #include "data/settings.h"
 #include "libpspp/hash-functions.h"
 #include "libpspp/message.h"
+#include "libpspp/i18n.h"
 #include "libpspp/str.h"
 #include "libpspp/version.h"
 
 \f
 /* Functions for performing operations on file names. */
 
-/* Searches for a configuration file with name NAME in the directories given in
+
+/* Returns the extension part of FILE_NAME as a malloc()'d string.
+   If FILE_NAME does not have an extension, returns an empty
+   string. */
+char *
+fn_extension (const struct file_handle *fh)
+{
+  const char *file_name = fh_get_file_name (fh);
+
+  const char *extension = strrchr (file_name, '.');
+  if (extension == NULL)
+    extension = "";
+  return xstrdup (extension);
+}
+\f
+/* Find out information about files. */
+
+/* Returns true iff NAME specifies an absolute file name. */
+static bool
+fn_is_absolute (const char *name)
+{
+  return IS_ABSOLUTE_FILE_NAME (name);
+}
+
+
+/* Searches for a file with name NAME in the directories given in
    PATH, which is terminated by a null pointer.  Returns the full name of the
    first file found, which the caller is responsible for freeing with free(),
    or NULL if none is found. */
@@ -72,40 +98,23 @@ fn_search_path (const char *base_name, char **path)
       else
         file = xasprintf ("%s/%s", dir, base_name);
 
-      if (fn_exists (file))
-        return file;
+      struct stat temp;
+      if (( (stat (file, &temp) == 0 ) && ( ! S_ISDIR (temp.st_mode) )))
+       return file;
+      
       free (file);
     }
 
   return NULL;
 }
 
-/* Returns the extension part of FILE_NAME as a malloc()'d string.
-   If FILE_NAME does not have an extension, returns an empty
-   string. */
-char *
-fn_extension (const char *file_name)
-{
-  const char *extension = strrchr (file_name, '.');
-  if (extension == NULL)
-    extension = "";
-  return xstrdup (extension);
-}
-\f
-/* Find out information about files. */
-
-/* Returns true iff NAME specifies an absolute file name. */
-bool
-fn_is_absolute (const char *name)
-{
-  return IS_ABSOLUTE_FILE_NAME (name);
-}
 
 /* Returns true if file with name NAME exists, and that file is not a
    directory */
 bool
-fn_exists (const char *name)
+fn_exists (const struct file_handle *fh)
 {
+  const char *name = fh_get_file_name (fh);
   struct stat temp;
   if ( stat (name, &temp) != 0 )
     return false;
@@ -133,8 +142,10 @@ safety_violation (const char *fn)
    NULL on failure.  If NULL is returned then errno is set to a
    sensible value.  */
 FILE *
-fn_open (const char *fn, const char *mode)
+fn_open (const struct file_handle *fh, const char *mode)
 {
+  const char *fn = fh_get_file_name (fh);
+
   assert (mode[0] == 'r' || mode[0] == 'w' || mode[0] == 'a');
 
   if (mode[0] == 'r')
@@ -178,15 +189,28 @@ fn_open (const char *fn, const char *mode)
     }
   else
 #endif
+
+#if WIN32
+    {
+      wchar_t *ss = convert_to_filename_encoding (fn, strlen (fn), fh_get_file_name_encoding (fh));
+      wchar_t *m =  (wchar_t *) recode_string ("UTF-16LE", "ASCII", mode, strlen (mode));
+      FILE *fp = _wfopen (ss, m);
+      free (m);
+      free (ss);
+      return fp;
+    }
+#else    
     return fopen (fn, mode);
+#endif    
 }
 
 /* Counterpart to fn_open that closes file F with name FN; returns 0
    on success, EOF on failure.  If EOF is returned, errno is set to a
    sensible value. */
 int
-fn_close (const char *fn, FILE *f)
+fn_close (const struct file_handle *fh, FILE *f)
 {
+  const char *fn = fh_get_file_name (fh);
   if (fileno (f) == STDIN_FILENO
       || fileno (f) == STDOUT_FILENO
       || fileno (f) == STDERR_FILENO)
@@ -216,7 +240,6 @@ default_output_path (void)
     {
       /* Windows NT defines HOMEDRIVE and HOMEPATH.  But give preference
         to HOME, because the user can change HOME.  */
-
       const char *home_dir = getenv ("HOME");
       int i;
 
index 0a0e2f26fe9775c10a999bf44e32d579268d441c..b4eee83e76aa1d596620f92f2f69d643ae115404 100644 (file)
 #include <stdbool.h>
 #include <sys/types.h>
 
+struct file_handle ;
+
 char *fn_search_path (const char *base_name, char **path);
-char *fn_extension (const char *fn);
+char *fn_extension (const struct file_handle *);
+
+bool fn_exists (const struct file_handle *);
 
-bool fn_is_absolute (const char *fn);
-bool fn_exists (const char *fn);
 
-FILE *fn_open (const char *fn, const char *mode);
-int fn_close (const char *fn, FILE *file);
+FILE *fn_open (const struct file_handle *fn, const char *mode);
+int fn_close (const struct file_handle *fn, FILE *file);
 
 const char * default_output_path (void);
 
+#if defined _WIN32 || defined __WIN32__
+#define WIN32_LEAN_AND_MEAN  /* avoid including junk */
+#define UNICODE 1
+#include <windows.h>
+#else
+typedef char TCHAR;
+#endif
+
+TCHAR * convert_to_filename_encoding (const char *s, size_t len, const char *current_encoding);
+
+
 #endif /* file-name.h */
index b67ed307019b87133ec343ab1f7893f782f3f360..f4456ca153aac03218e94120ecf71f212e6ff689 100644 (file)
@@ -45,7 +45,6 @@
 
 #if defined _WIN32 || defined __WIN32__
 #define WIN32_LEAN_AND_MEAN  /* avoid including junk */
-#define UNICODE 1
 #include <windows.h>
 #define TS_stat _stat
 #define Tunlink _wunlink
@@ -149,7 +148,7 @@ Trename (TCHAR const *src, TCHAR const *dst)
   return -1;
 }
 
-static TCHAR * 
+TCHAR * 
 convert_to_filename_encoding (const char *s, size_t len, const char *current_encoding)
 {
   const char *enc = current_encoding;
@@ -168,7 +167,7 @@ typedef char TCHAR;
 #define Topen open
 #define Tstat stat
 
-static TCHAR * 
+TCHAR * 
 convert_to_filename_encoding (const char *s, size_t len UNUSED, const char *current_encoding UNUSED)
 {
   /* Non-windows systems don't care about the encoding.  
index 08e6470697361b871acecdd6d9174da670268e62..4d08f27465407bff935163af10525bea0237e653 100644 (file)
@@ -209,7 +209,7 @@ pcp_open (struct file_handle *fh)
     goto error;
 
   /* Open file. */
-  r->file = fn_open (fh_get_file_name (fh), "rb");
+  r->file = fn_open (fh, "rb");
   if (r->file == NULL)
     {
       msg (ME, _("Error opening `%s' for reading as an SPSS/PC+ "
@@ -478,7 +478,7 @@ pcp_close (struct any_reader *r_)
 
   if (r->file)
     {
-      if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
+      if (fn_close (r->fh, r->file) == EOF)
         {
           msg (ME, _("Error closing system file `%s': %s."),
                fh_get_file_name (r->fh), strerror (errno));
index 058a0a81c5e12355b2d55f761a5d989819eb7ce0..15a3b7902e45b59f1548299e412482044897fa9c 100644 (file)
@@ -170,7 +170,7 @@ pfm_close (struct any_reader *r_)
   any_read_info_destroy (&r->info);
   if (r->file)
     {
-      if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
+      if (fn_close (r->fh, r->file) == EOF)
         {
           msg (ME, _("Error closing portable file `%s': %s."),
                fh_get_file_name (r->fh), strerror (errno));
@@ -288,7 +288,7 @@ pfm_open (struct file_handle *fh)
     goto error;
 
   /* Open file. */
-  r->file = fn_open (fh_get_file_name (r->fh), "rb");
+  r->file = fn_open (r->fh, "rb");
   if (r->file == NULL)
     {
       msg (ME, _("An error occurred while opening `%s' for reading "
index ddc685431b470c335694f98378d97754817ed056..a1193de767dc4618d4a8a1bdf1b0e6f6d5e33341 100644 (file)
@@ -408,7 +408,7 @@ sfm_open (struct file_handle *fh)
   if (r->lock == NULL)
     goto error;
 
-  r->file = fn_open (fh_get_file_name (fh), "rb");
+  r->file = fn_open (fh, "rb");
   if (r->file == NULL)
     {
       msg (ME, _("Error opening `%s' for reading as a system file: %s."),
@@ -894,7 +894,7 @@ sfm_close (struct any_reader *r_)
 
   if (r->file)
     {
-      if (fn_close (fh_get_file_name (r->fh), r->file) == EOF)
+      if (fn_close (r->fh, r->file) == EOF)
         {
           msg (ME, _("Error closing system file `%s': %s."),
                fh_get_file_name (r->fh), strerror (errno));
index c28fa0700efbfd239a58cf64bc570938a45395ee..0a00619e84b3cbac356c9b5094101ab7a06d3001 100644 (file)
@@ -95,7 +95,7 @@ dfm_close_reader (struct dfm_reader *r)
 
   /* This was the last client, so close the underlying file. */
   if (fh_get_referent (r->fh) != FH_REF_INLINE)
-    fn_close (fh_get_file_name (r->fh), r->file);
+    fn_close (r->fh, r->file);
   else
     {
       /* Skip any remaining data on the inline file. */
@@ -157,7 +157,7 @@ dfm_open_reader (struct file_handle *fh, struct lexer *lexer,
     {
       struct stat s;
       r->line_number = 0;
-      r->file = fn_open (fh_get_file_name (fh), "rb");
+      r->file = fn_open (fh, "rb");
       if (r->file == NULL)
         {
           msg (ME, _("Could not open `%s' for reading as a data file: %s."),
index 65de635302e3fe2613bb04b72e49243ba06310e5..bf9505e7dd82878270a59ab13372c2a0137720c4 100644 (file)
@@ -218,7 +218,7 @@ dfm_close_writer (struct dfm_writer *w)
   if (w->file != NULL)
     {
       const char *file_name = fh_get_file_name (w->fh);
-      ok = !dfm_write_error (w) && !fn_close (file_name, w->file);
+      ok = !dfm_write_error (w) && !fn_close (w->fh, w->file);
 
       if (!ok)
         msg (ME, _("I/O error occurred writing data file `%s'."), file_name);
index 54b769ddee26cff951111d130bc507498ed51adf..c366f56c46e8529b771efea734244afb6bf51d81 100644 (file)
@@ -247,7 +247,7 @@ cmd_save_translate (struct lexer *lexer, struct dataset *ds)
       lex_sbc_missing ("OUTFILE");
       goto error;
     }
-  else if (!replace && fn_exists (fh_get_file_name (handle)))
+  else if (!replace && fn_exists (handle))
     {
       msg (SE, _("Output file `%s' exists but %s was not specified."),
            fh_get_file_name (handle), "REPLACE");
index 0b6d659fa8c7317f31329ced1b60bd25abdb98a6..636d9ecc4fc822ed949f35ddbcce291a2a686e65 100644 (file)
@@ -28,6 +28,7 @@
 #include <uniwidth.h>
 
 #include "data/file-name.h"
+#include "data/file-handle-def.h"
 #include "data/settings.h"
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
@@ -172,7 +173,7 @@ struct ascii_driver
     char *command_name;
     char *title;
     char *subtitle;
-    char *file_name;            /* Output file name. */
+    struct file_handle *handle;
     FILE *file;                 /* Output file. */
     bool error;                 /* Output error? */
     int page_number;           /* Current page number. */
@@ -233,7 +234,7 @@ opt (struct output_driver *d, struct string_map *options, const char *key,
 }
 
 static struct output_driver *
-ascii_create (const char *file_name, enum settings_output_devices device_type,
+ascii_create (struct  file_handle *fh, enum settings_output_devices device_type,
               struct string_map *o)
 {
   enum { BOX_ASCII, BOX_UNICODE } box;
@@ -244,7 +245,7 @@ ascii_create (const char *file_name, enum settings_output_devices device_type,
 
   a = xzalloc (sizeof *a);
   d = &a->driver;
-  output_driver_init (&a->driver, &ascii_driver_class, file_name, device_type);
+  output_driver_init (&a->driver, &ascii_driver_class, fh_get_file_name (fh), device_type);
   a->append = parse_boolean (opt (d, o, "append", "false"));
   a->headers = parse_boolean (opt (d, o, "headers", "false"));
   a->paginate = parse_boolean (opt (d, o, "paginate", "false"));
@@ -255,7 +256,8 @@ ascii_create (const char *file_name, enum settings_output_devices device_type,
                             "none", EMPH_NONE,
                             NULL_SENTINEL);
 
-  a->chart_file_name = parse_chart_file_name (opt (d, o, "charts", file_name));
+  a->chart_file_name = parse_chart_file_name (opt (d, o, "charts", fh_get_file_name (fh)));
+  a->handle = fh;
 
   a->top_margin = parse_int (opt (d, o, "top-margin", "0"), 0, INT_MAX);
   a->bottom_margin = parse_int (opt (d, o, "bottom-margin", "0"), 0, INT_MAX);
@@ -283,7 +285,6 @@ ascii_create (const char *file_name, enum settings_output_devices device_type,
   a->command_name = NULL;
   a->title = xstrdup ("");
   a->subtitle = xstrdup ("");
-  a->file_name = xstrdup (file_name);
   a->file = NULL;
   a->error = false;
   a->page_number = 0;
@@ -380,11 +381,11 @@ ascii_destroy (struct output_driver *driver)
     ascii_close_page (a);
 
   if (a->file != NULL)
-    fn_close (a->file_name, a->file);
+    fn_close (a->handle, a->file);
+  fh_unref (a->handle);
   free (a->command_name);
   free (a->title);
   free (a->subtitle);
-  free (a->file_name);
   free (a->chart_file_name);
   for (i = 0; i < a->allocated_lines; i++)
     u8_line_destroy (&a->lines[i]);
@@ -400,8 +401,8 @@ ascii_flush (struct output_driver *driver)
     {
       ascii_close_page (a);
 
-      if (fn_close (a->file_name, a->file) != 0)
-        msg_error (errno, _("ascii: closing output file `%s'"), a->file_name);
+      if (fn_close (a->handle, a->file) != 0)
+        msg_error (errno, _("ascii: closing output file `%s'"), fh_get_file_name (a->handle));
       a->file = NULL;
     }
 }
@@ -1091,7 +1092,7 @@ ascii_open_page (struct ascii_driver *a)
 
   if (a->file == NULL)
     {
-      a->file = fn_open (a->file_name, a->append ? "a" : "w");
+      a->file = fn_open (a->handle, a->append ? "a" : "w");
       if (a->file != NULL)
         {
          if ( isatty (fileno (a->file)))
@@ -1111,7 +1112,7 @@ ascii_open_page (struct ascii_driver *a)
       else
         {
           msg_error (errno, _("ascii: opening output file `%s'"),
-                 a->file_name);
+                    fh_get_file_name (a->handle));
           a->error = true;
           return false;
         }
index 7f220641061907ae771c5caf5cd5a28af3635cd5..122d1b786f2a28430380e7220b399d0fd5822540 100644 (file)
@@ -25,6 +25,7 @@
 #include "libpspp/str.h"
 #include "libpspp/string-map.h"
 #include "libpspp/version.h"
+#include "data/file-handle-def.h"
 #include "output/cairo-chart.h"
 #include "output/chart-item-provider.h"
 #include "output/charts/boxplot.h"
@@ -475,24 +476,30 @@ xr_create (const char *file_name, enum settings_output_devices device_type,
 }
 
 static struct output_driver *
-xr_pdf_create (const char *file_name, enum settings_output_devices device_type,
+xr_pdf_create (struct  file_handle *fh, enum settings_output_devices device_type,
                struct string_map *o)
 {
-  return xr_create (file_name, device_type, o, XR_PDF);
+  struct output_driver *od = xr_create (fh_get_file_name (fh), device_type, o, XR_PDF);
+  fh_unref (fh);
+  return od ;
 }
 
 static struct output_driver *
-xr_ps_create (const char *file_name, enum settings_output_devices device_type,
+xr_ps_create (struct  file_handle *fh, enum settings_output_devices device_type,
                struct string_map *o)
 {
-  return xr_create (file_name, device_type, o, XR_PS);
+  struct output_driver *od =  xr_create (fh_get_file_name (fh), device_type, o, XR_PS);
+  fh_unref (fh);
+  return od ;
 }
 
 static struct output_driver *
-xr_svg_create (const char *file_name, enum settings_output_devices device_type,
+xr_svg_create (struct file_handle *fh, enum settings_output_devices device_type,
                struct string_map *o)
 {
-  return xr_create (file_name, device_type, o, XR_SVG);
+  struct output_driver *od = xr_create (fh_get_file_name (fh), device_type, o, XR_SVG);
+  fh_unref (fh);
+  return od ;
 }
 
 static void
index cf175458716b29b952f4de58c2546bce0a176870..455584914e7c4a470e8c506640880d6b94bad1f7 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 
 #include "data/file-name.h"
+#include "data/file-handle-def.h"
 #include "libpspp/assertion.h"
 #include "libpspp/compiler.h"
 #include "libpspp/message.h"
@@ -49,7 +50,7 @@ struct csv_driver
     bool titles;                /* Print table titles? */
     bool captions;              /* Print table captions? */
 
-    char *file_name;            /* Output file name. */
+    struct file_handle *handle;
     char *command_name;         /* Current command. */
     FILE *file;                 /* Output file. */
     int n_items;                /* Number of items output so far. */
@@ -72,7 +73,7 @@ opt (struct output_driver *d, struct string_map *options, const char *key,
 }
 
 static struct output_driver *
-csv_create (const char *file_name, enum settings_output_devices device_type,
+csv_create (struct file_handle *fh, enum settings_output_devices device_type,
             struct string_map *o)
 {
   struct output_driver *d;
@@ -81,7 +82,7 @@ csv_create (const char *file_name, enum settings_output_devices device_type,
 
   csv = xzalloc (sizeof *csv);
   d = &csv->driver;
-  output_driver_init (&csv->driver, &csv_driver_class, file_name, device_type);
+  output_driver_init (&csv->driver, &csv_driver_class, fh_get_file_name (fh), device_type);
 
   csv->separator = parse_string (opt (d, o, "separator", ","));
   quote = parse_string (opt (d, o, "quote", "\""));
@@ -90,13 +91,13 @@ csv_create (const char *file_name, enum settings_output_devices device_type,
   csv->quote_set = xasprintf ("\n\r\t%s%c", csv->separator, csv->quote);
   csv->titles = parse_boolean (opt (d, o, "titles", "true"));
   csv->captions = parse_boolean (opt (d, o, "captions", "true"));
-  csv->file_name = xstrdup (file_name);
-  csv->file = fn_open (csv->file_name, "w");
+  csv->handle = fh;
+  csv->file = fn_open (fh, "w");
   csv->n_items = 0;
 
   if (csv->file == NULL)
     {
-      msg_error (errno, _("error opening output file `%s'"), csv->file_name);
+      msg_error (errno, _("error opening output file `%s'"), fh_get_file_name (fh));
       output_driver_destroy (d);
       return NULL;
     }
@@ -110,11 +111,11 @@ csv_destroy (struct output_driver *driver)
   struct csv_driver *csv = csv_driver_cast (driver);
 
   if (csv->file != NULL)
-    fn_close (csv->file_name, csv->file);
+    fn_close (csv->handle, csv->file);
 
   free (csv->separator);
   free (csv->quote_set);
-  free (csv->file_name);
+  fh_unref (csv->handle);
   free (csv);
 }
 
index 754b0d0b5677adaa54b7f37c550dfe643fe22a20..aa70bb454adc691a830d0164b5d77dbe15158977 100644 (file)
@@ -25,6 +25,7 @@
 
 struct output_item;
 struct string_map;
+struct file_handle;
 
 /* A configured output driver. */
 struct output_driver
@@ -36,7 +37,8 @@ struct output_driver
 
 void output_driver_init (struct output_driver *,
                          const struct output_driver_class *,
-                         const char *name, enum settings_output_devices);
+                         const char *, enum settings_output_devices);
+
 void output_driver_destroy (struct output_driver *);
 
 const char *output_driver_get_name (const struct output_driver *);
@@ -98,7 +100,7 @@ struct output_driver_factory
        The returned driver should not have been registered (with
        output_driver_register).  The caller will register the driver (if this
        is desirable). */
-    struct output_driver *(*create) (const char *name,
+    struct output_driver *(*create) (struct file_handle *,
                                      enum settings_output_devices type,
                                      struct string_map *options);
   };
index 94bc2411c97878781980a455818e326357e7bb6e..6f72ffe739aca687e07bfbd1bb4a92be5c1fd92d 100644 (file)
@@ -25,6 +25,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "data/file-handle-def.h"
 #include "data/settings.h"
 #include "libpspp/array.h"
 #include "libpspp/assertion.h"
@@ -374,8 +375,10 @@ output_driver_create (struct string_map *options)
                      device_string, "terminal", "listing");
       device_type = default_device_type (file_name);
     }
+  
+  struct file_handle *fh = fh_create_file (NULL, file_name, NULL, fh_default_properties ());
 
-  driver = f->create (file_name, device_type, options);
+  driver = f->create (fh, device_type, options);
   if (driver != NULL)
     {
       const struct string_map_node *node;
index 9e7f567a27274866efda6d67fddef2ca74082d3c..8b16ffa780d29d07fc6cf8e9a2fdbab233ccd0ae 100644 (file)
@@ -24,6 +24,7 @@
 #include <unistd.h>
 
 #include "data/file-name.h"
+#include "data/file-handle-def.h"
 #include "libpspp/assertion.h"
 #include "libpspp/cast.h"
 #include "libpspp/compiler.h"
@@ -51,7 +52,7 @@ struct html_driver
     struct xr_color fg;
     struct xr_color bg;
 #endif    
-    char *file_name;
+    struct file_handle *handle;
     char *chart_file_name;
 
     char *command_name;
@@ -86,7 +87,7 @@ opt (struct output_driver *d, struct string_map *options, const char *key,
 }
 
 static struct output_driver *
-html_create (const char *file_name, enum settings_output_devices device_type,
+html_create (struct file_handle *fh, enum settings_output_devices device_type,
              struct string_map *o)
 {
   struct output_driver *d;
@@ -94,24 +95,24 @@ html_create (const char *file_name, enum settings_output_devices device_type,
 
   html = xzalloc (sizeof *html);
   d = &html->driver;
-  output_driver_init (&html->driver, &html_driver_class, file_name,
+  output_driver_init (&html->driver, &html_driver_class, fh_get_file_name (fh),
                       device_type);
   html->css = parse_boolean (opt (d, o, "css", "true"));
   html->borders = parse_boolean (opt (d, o, "borders", "true"));
 
-  html->file_name = xstrdup (file_name);
+  html->handle = fh;
   html->chart_file_name = parse_chart_file_name (opt (d, o, "charts",
-                                                      file_name));
+                                                      fh_get_file_name (fh)));
   html->file = NULL;
   html->chart_cnt = 1;
 #ifdef HAVE_CAIRO
   parse_color (d, o, "background-color", "#FFFFFFFFFFFF", &html->bg);
   parse_color (d, o, "foreground-color", "#000000000000", &html->fg);
 #endif
-  html->file = fn_open (html->file_name, "w");
+  html->file = fn_open (html->handle, "w");
   if (html->file == NULL)
     {
-      msg_error (errno, _("error opening output file `%s'"), html->file_name);
+      msg_error (errno, _("error opening output file `%s'"), fh_get_file_name (html->handle));
       goto error;
     }
 
@@ -216,10 +217,10 @@ html_destroy (struct output_driver *driver)
                "</BODY>\n"
                "</HTML>\n"
                "<!-- end of file -->\n");
-      fn_close (html->file_name, html->file);
+      fn_close (html->handle, html->file);
     }
   free (html->chart_file_name);
-  free (html->file_name);
+  fh_unref (html->handle);
   free (html->command_name);
   free (html);
 }
index a3f195410406b70c6f18c00d57578d9cf6cf8fd6..0d0329571045daa79b48190e3a22b1600250f9c7 100644 (file)
@@ -24,6 +24,7 @@
 #include <unistd.h>
 
 #include "data/file-name.h"
+#include "data/file-handle-def.h"
 #include "data/settings.h"
 #include "libpspp/cast.h"
 #include "libpspp/message.h"
@@ -40,7 +41,7 @@ struct msglog_driver
   {
     struct output_driver driver;
     FILE *file;
-    char *file_name;
+    struct file_handle *handle;
     char *command_name;
   };
 
@@ -60,7 +61,9 @@ msglog_create (const char *file_name)
   struct msglog_driver *ml;
   FILE *file;
 
-  file = fn_open (file_name, "w");
+  struct file_handle *handle = fh_create_file  (NULL, file_name, NULL, fh_default_properties ());
+
+  file = fn_open (handle, "w");
   if (file == NULL)
     {
       msg_error (errno, _("error opening output file `%s'"), file_name);
@@ -72,9 +75,9 @@ msglog_create (const char *file_name)
           : SETTINGS_DEVICE_UNFILTERED);
 
   ml = xzalloc (sizeof *ml);
+  ml->handle = handle;
   output_driver_init (&ml->driver, &msglog_class, file_name, type);
   ml->file = file;
-  ml->file_name = xstrdup (file_name);
   ml->command_name = NULL;
 
   output_driver_register (&ml->driver);
@@ -87,9 +90,9 @@ msglog_destroy (struct output_driver *driver)
 {
   struct msglog_driver *ml = msglog_driver_cast (driver);
 
-  fn_close (ml->file_name, ml->file);
-  free (ml->file_name);
+  fn_close (ml->handle, ml->file);
   free (ml->command_name);
+  fh_unref (ml->handle);
   free (ml);
 }
 
index a29c045d0b67e8920344a0e3e0b6f6a5f99f4db8..8e94dd7ba6694769275da5769d67c59591a7866c 100644 (file)
@@ -36,6 +36,7 @@
 #include "libpspp/temp-file.h"
 #include "libpspp/version.h"
 #include "libpspp/zip-writer.h"
+#include "data/file-handle-def.h"
 #include "output/driver-provider.h"
 #include "output/message-item.h"
 #include "output/options.h"
@@ -290,12 +291,13 @@ write_meta_data (struct odt_driver *odt)
 }
 
 static struct output_driver *
-odt_create (const char *file_name, enum settings_output_devices device_type,
+odt_create (struct file_handle *fh, enum settings_output_devices device_type,
             struct string_map *o UNUSED)
 {
   struct output_driver *d;
   struct odt_driver *odt;
   struct zip_writer *zip;
+  const char *file_name = fh_get_file_name (fh);
 
   zip = zip_writer_create (file_name);
   if (zip == NULL)
@@ -303,6 +305,7 @@ odt_create (const char *file_name, enum settings_output_devices device_type,
 
   odt = xzalloc (sizeof *odt);
   d = &odt->driver;
+
   output_driver_init (d, &odt_driver_class, file_name, device_type);
 
   odt->zip = zip;
index 6ef2dd4477a8bd073337e10f05c01a614a68b005..8e34c214be3db729a4b5f7fb9d99eb35214e7b2c 100644 (file)
@@ -30,6 +30,7 @@
 #define N_(msgid) msgid
 
 #include "data/any-reader.h"
+#include "data/file-handle-def.h"
 #include "data/dataset.h"
 #include "libpspp/version.h"
 
@@ -778,19 +779,22 @@ psppire_window_open (PsppireWindow *de)
        gchar *name =
          gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
 
-       gchar *sysname = convert_glib_filename_to_system_filename (name, NULL);
+       const gchar **cs = NULL;
+       g_get_filename_charsets (&cs);
 
         gchar *encoding = psppire_encoding_selector_get_encoding (
           gtk_file_chooser_get_extra_widget (GTK_FILE_CHOOSER (dialog)));
 
-        int retval = any_reader_detect (sysname, NULL);
+       struct file_handle *fh = fh_create_file (NULL, name, cs[0], fh_default_properties ());
+
+        int retval = any_reader_detect (fh, NULL);
        if (retval == 1)
           open_data_window (de, name, encoding, NULL);
        else if (retval == 0)
          open_syntax_window (name, encoding);
 
         g_free (encoding);
-       g_free (sysname);
+       fh_unref (fh);
        g_free (name);
       }
       break;
index e55e616342f7185c0e2d2f1b91109b6898e7109f..9ed7d15becb3e4757006d6bbfcc95238eb2c605e 100644 (file)
@@ -64,8 +64,6 @@
 #include "gl/relocatable.h"
 
 static void create_icon_factory (void);
-static gchar *local_to_filename_encoding (const char *fn);
-
 
 #define _(msgid) gettext (msgid)
 #define N_(msgid) msgid
@@ -130,9 +128,13 @@ initialize (const struct init_source *is)
       {
       if (is->file)
        {
-         gchar *filename = local_to_filename_encoding (is->file);
+         const gchar *local_encoding = NULL;
+         g_get_charset (&local_encoding);
+
+         struct file_handle *fh = fh_create_file (NULL, is->file, local_encoding, fh_default_properties ());
+         const char *filename = fh_get_file_name (fh);
 
-         int retval = any_reader_detect (filename, NULL);
+         int retval = any_reader_detect (fh, NULL);
 
          /* Check to see if the file is a .sav or a .por file.  If not
             assume that it is a syntax file */
@@ -143,7 +145,8 @@ initialize (const struct init_source *is)
              create_data_window ();
              open_syntax_window (filename, NULL);
            }
-         g_free (filename);
+
+         fh_unref (fh);
        }
       else
        {
@@ -328,67 +331,8 @@ create_icon_factory (void)
 
   gtk_icon_factory_add_default (factory);
 }
-\f
-/* 
-   Convert a filename from the local encoding into "filename" encoding.
-   The return value will be allocated on the heap.  It is the responsibility
-   of the caller to free it.
- */
-static gchar *
-local_to_filename_encoding (const char *fn)
-{
-  gchar *filename = NULL;
-  gchar *utf8 = NULL;
-  const gchar *local_encoding = NULL;
-  gsize written = -1;
-  const gboolean local_is_utf8 = g_get_charset (&local_encoding);
-
-  /* There seems to be no Glib function to convert from local encoding
-     to filename encoding.  Therefore it has to be done in two steps:
-     the intermediate encoding is UTF8.
-
-     Either step could fail.  However, in many cases the file can still
-     be loaded even if the conversion fails. So in those cases, after showing
-     a warning, we simply copy the locally encoded filename to the destination
-     and hope for the best.
-  */
-
-  if ( local_is_utf8)
-    {
-      utf8 = xstrdup (fn);
-    }
-  else
-    {
-      GError *err = NULL;
-      utf8 = g_locale_to_utf8 (fn, -1, NULL, &written, &err);
-      if ( NULL == utf8)
-        {
-          g_warning ("Cannot convert filename from local encoding `%s' to UTF-8: %s",
-                     local_encoding,
-                     err->message);
-          g_clear_error (&err);
-        }
-    }
-
-  if ( NULL != utf8)
-    {
-      GError *err = NULL;
-      filename = g_filename_from_utf8 (utf8, written, NULL, NULL, &err);
-      if ( NULL == filename)
-        {
-          g_warning ("Cannot convert filename from UTF8 to filename encoding: %s",
-                     err->message);
-          g_clear_error (&err);
-        }
-    }
 
-  g_free (utf8);
-
-  if ( filename == NULL)
-    filename = xstrdup (fn);
-
-  return filename;
-}
+\f
 
 static void
 handle_msg (const struct msg *m_, void *lexer_)
index f71109524f5f9ba851966734d9332557efe86800..ce5fd875eace83ad57692bef1f8e11ee9fb25bb9 100644 (file)
@@ -47,8 +47,8 @@
 static void usage (void);
 
 static void decrypt_file (struct encrypted_file *enc,
-                          const char *input_filename,
-                          const char *output_filename,
+                          const struct file_handle *input_filename,
+                          const struct file_handle *output_filename,
                           const char *password);
 
 int
@@ -135,6 +135,8 @@ main (int argc, char *argv[])
 
   input_filename = argv[optind];
   output_filename = argv[optind + 1];
+  input_fh = fh_create_file (NULL, input_filename, NULL, fh_default_properties ());
+
   if (output_format == NULL)
     {
       const char *dot = strrchr (output_filename, '.');
@@ -145,7 +147,8 @@ main (int argc, char *argv[])
       output_format = dot + 1;
     }
 
-  if (encrypted_file_open (&enc, input_filename) > 0)
+  output_fh = fh_create_file (NULL, output_filename, NULL, fh_default_properties ());
+  if (encrypted_file_open (&enc, input_fh) > 0)
     {
       if (encrypted_file_is_sav (enc))
         {
@@ -160,16 +163,16 @@ main (int argc, char *argv[])
                            "format"));
         }
 
-      decrypt_file (enc, input_filename, output_filename, password);
+      decrypt_file (enc, input_fh, output_fh, password);
       goto exit;
     }
 
-  input_fh = fh_create_file (NULL, input_filename, NULL, fh_default_properties ());
+
   reader = any_reader_open_and_decode (input_fh, encoding, &dict, NULL);
   if (reader == NULL)
     exit (1);
 
-  output_fh = fh_create_file (NULL, output_filename, NULL, fh_default_properties ());
+
   if (!strcmp (output_format, "csv") || !strcmp (output_format, "txt"))
     {
       struct csv_writer_options options;
@@ -224,12 +227,14 @@ exit:
 
 static void
 decrypt_file (struct encrypted_file *enc,
-              const char *input_filename,
-              const char *output_filename,
+             const struct file_handle *ifh,
+             const struct file_handle *ofh,
               const char *password)
 {
   FILE *out;
   int err;
+  const char *input_filename = fh_get_file_name (ifh);
+  const char *output_filename = fh_get_file_name (ofh);
 
   if (password == NULL)
     {
@@ -241,7 +246,7 @@ decrypt_file (struct encrypted_file *enc,
   if (!encrypted_file_unlock (enc, password))
     error (1, 0, _("sorry, wrong password"));
 
-  out = fn_open (output_filename, "wb");
+  out = fn_open (ofh, "wb");
   if (out == NULL)
     error (1, errno, ("%s: error opening output file"), output_filename);
 
@@ -264,7 +269,7 @@ decrypt_file (struct encrypted_file *enc,
 
   if (fflush (out) == EOF)
     error (1, errno, ("%s: write error"), output_filename);
-  fn_close (output_filename, out);
+  fn_close (ofh, out);
 }
 
 static void