From 4e30d33a680cceb0ac2ee3e78c94fdeb46ab2fcd Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Mon, 30 Jul 2007 17:07:50 +0000 Subject: [PATCH] Provisional fix for bug #18692 and bug #20161. Reviewed by John Darrington. --- doc/language.texi | 8 +++++++ src/data/ChangeLog | 16 +++++++++++++ src/data/file-name.c | 4 ++-- src/data/por-file-reader.c | 46 ++++++++++++++++++++++++++++++++------ 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/doc/language.texi b/doc/language.texi index d71ecc8a..398f7642 100644 --- a/doc/language.texi +++ b/doc/language.texi @@ -1331,6 +1331,14 @@ file, or scratch file. Most often, a file handle is specified as the name of a file as a string, that is, enclosed within @samp{'} or @samp{"}. +A file name string that begins or ends with @samp{|} is treated as the +name of a command to pipe data to or from. You can use this feature +to read data over the network using a program such as @samp{curl} +(e.g.@: @code{GET '|curl -s -S http://example.com/mydata.sav'}), to +read compressed data from a file using a program such as @samp{zcat} +(e.g.@: @code{GET '|zcat mydata.sav.gz'}), and for many other +purposes. + PSPP also supports declaring named file handles with the @cmd{FILE HANDLE} command. This command associates an identifier of your choice (the file handle's name) with a file. Later, the file handle name can diff --git a/src/data/ChangeLog b/src/data/ChangeLog index 553b753e..c404d820 100644 --- a/src/data/ChangeLog +++ b/src/data/ChangeLog @@ -1,3 +1,19 @@ +2007-07-29 Ben Pfaff + + Provisional fix for bug #18692 and bug #20161. Reviewed by John + Darrington. + + * file-name.c (fn_open): Only pass "r" or "w" to popen as mode + argument (never "rb" or "wb") because SUSv3 says that only those + modes are defined, and glibc in fact rejects other modes. + + Open portable files with fn_open so that they can be read from + pipes. Fix missing fh_close call to go along with fh_open. + Report an error if the file close reports an error. + * por-file-reader.c (close_reader): New function. + (por_file_casereader_destroy): Use close_reader. + (pfm_open_reader): Open file with fn_open. + 2007-07-28 Ben Pfaff Make PSPP able to read all the portable files I could find on the diff --git a/src/data/file-name.c b/src/data/file-name.c index 23d7ee08..cfe91932 100644 --- a/src/data/file-name.c +++ b/src/data/file-name.c @@ -267,7 +267,7 @@ fn_open (const char *fn, const char *mode) if (get_safer_mode ()) return safety_violation (fn); - return popen (&fn[1], mode); + return popen (&fn[1], mode[0] == 'r' ? "r" : "w"); } else if (*fn && fn[strlen (fn) - 1] == '|') { @@ -281,7 +281,7 @@ fn_open (const char *fn, const char *mode) memcpy (s, fn, strlen (fn) - 1); s[strlen (fn) - 1] = 0; - f = popen (s, mode); + f = popen (s, mode[0] == 'r' ? "r" : "w"); local_free (s); diff --git a/src/data/por-file-reader.c b/src/data/por-file-reader.c index e82e1361..8e6099f5 100644 --- a/src/data/por-file-reader.c +++ b/src/data/por-file-reader.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -136,12 +137,42 @@ warning (struct pfm_reader *r, const char *msg, ...) msg_emit (&m); } +/* Close and destroy R. + Returns false if an error was detected on R, true otherwise. */ +static bool +close_reader (struct pfm_reader *r) +{ + bool ok; + if (r == NULL) + return true; + + if (r->file) + { + if (fn_close (fh_get_file_name (r->fh), r->file) == EOF) + { + msg (ME, _("Error closing portable file \"%s\": %s."), + fh_get_file_name (r->fh), strerror (errno)); + r->ok = false; + } + r->file = NULL; + } + + if (r->fh != NULL) + fh_close (r->fh, "portable file", "rs"); + + ok = r->ok; + pool_destroy (r->pool); + + return ok; +} + /* Closes portable file reader R, after we're done with it. */ static void -por_file_casereader_destroy (struct casereader *reader UNUSED, void *r_) +por_file_casereader_destroy (struct casereader *reader, void *r_) { struct pfm_reader *r = r_; - pool_destroy (r->pool); + if (!close_reader (r)) + casereader_force_error (reader); } /* Read a single character into cur_char. */ @@ -217,10 +248,8 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, pool = pool_create (); r = pool_alloc (pool, sizeof *r); r->pool = pool; - if (setjmp (r->bail_out)) - goto error; r->fh = fh; - r->file = pool_fopen (r->pool, fh_get_file_name (r->fh), "rb"); + r->file = fn_open (fh_get_file_name (r->fh), "rb"); r->line_length = 0; r->weight_index = -1; r->trans = NULL; @@ -229,7 +258,10 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, r->value_cnt = 0; r->ok = true; - /* Check that file open succeeded, prime reading. */ + if (setjmp (r->bail_out)) + goto error; + + /* Check that file open succeeded. */ if (r->file == NULL) { msg (ME, _("An error occurred while opening \"%s\" for reading " @@ -260,7 +292,7 @@ pfm_open_reader (struct file_handle *fh, struct dictionary **dict, &por_file_casereader_class, r); error: - pool_destroy (r->pool); + close_reader (r); dict_destroy (*dict); *dict = NULL; return NULL; -- 2.30.2