From: John Darrington Date: Wed, 18 Nov 2015 17:52:24 +0000 (+0100) Subject: Make fn_open and fn_close take a struct file_handle instead of char * X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d6cbbc8d634fa91f050661355139a4e4697e99ab;p=pspp Make fn_open and fn_close take a struct file_handle instead of char * 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. --- diff --git a/src/data/any-reader.c b/src/data/any-reader.c index aee034ce31..ff7f4ab6c9 100644 --- a/src/data/any-reader.c +++ b/src/data/any-reader.c @@ -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) diff --git a/src/data/any-reader.h b/src/data/any-reader.h index a12c256ae9..998e12441b 100644 --- a/src/data/any-reader.h +++ b/src/data/any-reader.h @@ -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 *); diff --git a/src/data/any-writer.c b/src/data/any-writer.c index 61d6ffc8a2..170702bab3 100644 --- a/src/data/any-writer.c +++ b/src/data/any-writer.c @@ -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")) diff --git a/src/data/encrypted-file.c b/src/data/encrypted-file.c index b90126ed26..f1074b4c1d 100644 --- a/src/data/encrypted-file.c +++ b/src/data/encrypted-file.c @@ -17,6 +17,7 @@ #include #include "data/encrypted-file.h" +#include "data/file-handle-def.h" #include #include @@ -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; diff --git a/src/data/encrypted-file.h b/src/data/encrypted-file.h index d089a046f0..9e3116b774 100644 --- a/src/data/encrypted-file.h +++ b/src/data/encrypted-file.h @@ -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 *); diff --git a/src/data/file-handle-def.c b/src/data/file-handle-def.c index 53e00be13a..f058a00752 100644 --- a/src/data/file-handle-def.c +++ b/src/data/file-handle-def.c @@ -24,7 +24,6 @@ #include #include "data/dataset.h" -#include "data/file-name.h" #include "data/variable.h" #include "libpspp/cast.h" #include "libpspp/compiler.h" diff --git a/src/data/file-name.c b/src/data/file-name.c index a81ea9341a..1c47b4751b 100644 --- a/src/data/file-name.c +++ b/src/data/file-name.c @@ -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" @@ -48,7 +49,32 @@ /* 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); +} + +/* 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); -} - -/* 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; diff --git a/src/data/file-name.h b/src/data/file-name.h index 0a0e2f26fe..b4eee83e76 100644 --- a/src/data/file-name.h +++ b/src/data/file-name.h @@ -21,15 +21,28 @@ #include #include +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 +#else +typedef char TCHAR; +#endif + +TCHAR * convert_to_filename_encoding (const char *s, size_t len, const char *current_encoding); + + #endif /* file-name.h */ diff --git a/src/data/make-file.c b/src/data/make-file.c index b67ed30701..f4456ca153 100644 --- a/src/data/make-file.c +++ b/src/data/make-file.c @@ -45,7 +45,6 @@ #if defined _WIN32 || defined __WIN32__ #define WIN32_LEAN_AND_MEAN /* avoid including junk */ -#define UNICODE 1 #include #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. diff --git a/src/data/pc+-file-reader.c b/src/data/pc+-file-reader.c index 08e6470697..4d08f27465 100644 --- a/src/data/pc+-file-reader.c +++ b/src/data/pc+-file-reader.c @@ -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)); diff --git a/src/data/por-file-reader.c b/src/data/por-file-reader.c index 058a0a81c5..15a3b7902e 100644 --- a/src/data/por-file-reader.c +++ b/src/data/por-file-reader.c @@ -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 " diff --git a/src/data/sys-file-reader.c b/src/data/sys-file-reader.c index ddc685431b..a1193de767 100644 --- a/src/data/sys-file-reader.c +++ b/src/data/sys-file-reader.c @@ -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)); diff --git a/src/language/data-io/data-reader.c b/src/language/data-io/data-reader.c index c28fa0700e..0a00619e84 100644 --- a/src/language/data-io/data-reader.c +++ b/src/language/data-io/data-reader.c @@ -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."), diff --git a/src/language/data-io/data-writer.c b/src/language/data-io/data-writer.c index 65de635302..bf9505e7dd 100644 --- a/src/language/data-io/data-writer.c +++ b/src/language/data-io/data-writer.c @@ -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); diff --git a/src/language/data-io/save-translate.c b/src/language/data-io/save-translate.c index 54b769ddee..c366f56c46 100644 --- a/src/language/data-io/save-translate.c +++ b/src/language/data-io/save-translate.c @@ -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"); diff --git a/src/output/ascii.c b/src/output/ascii.c index 0b6d659fa8..636d9ecc4f 100644 --- a/src/output/ascii.c +++ b/src/output/ascii.c @@ -28,6 +28,7 @@ #include #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; } diff --git a/src/output/cairo.c b/src/output/cairo.c index 7f22064106..122d1b786f 100644 --- a/src/output/cairo.c +++ b/src/output/cairo.c @@ -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 diff --git a/src/output/csv.c b/src/output/csv.c index cf17545871..455584914e 100644 --- a/src/output/csv.c +++ b/src/output/csv.c @@ -20,6 +20,7 @@ #include #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); } diff --git a/src/output/driver-provider.h b/src/output/driver-provider.h index 754b0d0b56..aa70bb454a 100644 --- a/src/output/driver-provider.h +++ b/src/output/driver-provider.h @@ -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); }; diff --git a/src/output/driver.c b/src/output/driver.c index 94bc2411c9..6f72ffe739 100644 --- a/src/output/driver.c +++ b/src/output/driver.c @@ -25,6 +25,7 @@ #include #include +#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; diff --git a/src/output/html.c b/src/output/html.c index 9e7f567a27..8b16ffa780 100644 --- a/src/output/html.c +++ b/src/output/html.c @@ -24,6 +24,7 @@ #include #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) "\n" "\n" "\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); } diff --git a/src/output/msglog.c b/src/output/msglog.c index a3f1954104..0d03295710 100644 --- a/src/output/msglog.c +++ b/src/output/msglog.c @@ -24,6 +24,7 @@ #include #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); } diff --git a/src/output/odt.c b/src/output/odt.c index a29c045d0b..8e94dd7ba6 100644 --- a/src/output/odt.c +++ b/src/output/odt.c @@ -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; diff --git a/src/ui/gui/psppire-window.c b/src/ui/gui/psppire-window.c index 6ef2dd4477..8e34c214be 100644 --- a/src/ui/gui/psppire-window.c +++ b/src/ui/gui/psppire-window.c @@ -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; diff --git a/src/ui/gui/psppire.c b/src/ui/gui/psppire.c index e55e616342..9ed7d15bec 100644 --- a/src/ui/gui/psppire.c +++ b/src/ui/gui/psppire.c @@ -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); } - -/* - 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; -} + static void handle_msg (const struct msg *m_, void *lexer_) diff --git a/utilities/pspp-convert.c b/utilities/pspp-convert.c index f71109524f..ce5fd875ea 100644 --- a/utilities/pspp-convert.c +++ b/utilities/pspp-convert.c @@ -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