changeset 30123:d809b99f1280

maint: rename "zfstream.[h|cc]" to "gzfstream.[h|cc]" to match class name. * gzfstream.cc: Renamed from zfstream.cc * gzfstream.h: Renamed from zfstream.h * libinterp/corefcn/module.mk: Rename files in build system. * load-save.cc: Update #include to renamed file.
author Rik <rik@octave.org>
date Sun, 05 Sep 2021 19:40:02 -0700
parents a7813409b8c6
children 3161a1ee0045
files libinterp/corefcn/gzfstream.cc libinterp/corefcn/gzfstream.h libinterp/corefcn/load-save.cc libinterp/corefcn/module.mk libinterp/corefcn/zfstream.cc libinterp/corefcn/zfstream.h
diffstat 6 files changed, 1133 insertions(+), 1133 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/gzfstream.cc	Sun Sep 05 19:40:02 2021 -0700
@@ -0,0 +1,621 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2005-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave 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.
+//
+// Octave 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 Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+/*
+
+ This file is adapted from the zlib 1.2.2 contrib/iostream3 code,
+ written by
+
+   Ludwig Schwardt <schwardt@sun.ac.za>
+   original version by Kevin Ruland <kevin@rodin.wustl.edu>
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <iomanip>
+#include <istream>
+#include <ostream>
+
+#include "gzfstream.h"
+
+#if defined (HAVE_ZLIB)
+
+// For strcpy, strcat, strlen (mode strings).
+#include <cstring>
+// For BUFSIZ.
+#include <cstdio>
+
+// Internal buffer sizes (default and "unbuffered" versions)
+#define STASHED_CHARACTERS 16
+#define BIGBUFSIZE (256 * 1024 + STASHED_CHARACTERS)
+#define SMALLBUFSIZE 1
+
+// Default constructor
+gzfilebuf::gzfilebuf ()
+  : m_file(nullptr), m_io_mode(std::ios_base::openmode(0)), m_own_fd(false),
+    m_buffer(nullptr), m_buffer_size(BIGBUFSIZE), m_own_buffer(true)
+{
+  // No buffers to start with
+  this->disable_buffer ();
+}
+
+// Destructor
+gzfilebuf::~gzfilebuf ()
+{
+  // Sync output buffer and close only if responsible for file
+  // (i.e., attached streams should be left open at this stage)
+  this->sync ();
+  if (m_own_fd)
+    this->close ();
+  // Make sure internal buffer is deallocated
+  this->disable_buffer ();
+}
+
+// Set compression level and strategy
+int
+gzfilebuf::setcompression (int comp_level, int comp_strategy)
+{
+  return gzsetparams (m_file, comp_level, comp_strategy);
+}
+
+// Open gzipped file
+gzfilebuf*
+gzfilebuf::open (const char *name, std::ios_base::openmode mode)
+{
+  // Fail if file already open
+  if (this->is_open ())
+    return nullptr;
+  // Don't support simultaneous read/write access (yet)
+  if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
+    return nullptr;
+
+  // Build mode string for gzopen and check it [27.8.1.3.2]
+  char char_mode[6] = "\0\0\0\0\0";
+  if (! this->open_mode (mode, char_mode))
+    return nullptr;
+
+  // Attempt to open file
+  if ((m_file = gzopen (name, char_mode)) == nullptr)
+    return nullptr;
+
+  // On success, allocate internal buffer and set flags
+  this->enable_buffer ();
+  m_io_mode = mode;
+  m_own_fd = true;
+  return this;
+}
+
+// Attach to gzipped file
+gzfilebuf*
+gzfilebuf::attach (int fd, std::ios_base::openmode mode)
+{
+  // Fail if file already open
+  if (this->is_open ())
+    return nullptr;
+  // Don't support simultaneous read/write access (yet)
+  if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
+    return nullptr;
+
+  // Build mode string for gzdopen and check it [27.8.1.3.2]
+  char char_mode[6] = "\0\0\0\0\0";
+  if (! this->open_mode (mode, char_mode))
+    return nullptr;
+
+  // Attempt to attach to file
+  if ((m_file = gzdopen (fd, char_mode)) == nullptr)
+    return nullptr;
+
+  // On success, allocate internal buffer and set flags
+  this->enable_buffer ();
+  m_io_mode = mode;
+  m_own_fd = false;
+  return this;
+}
+
+// Close gzipped file
+gzfilebuf*
+gzfilebuf::close ()
+{
+  // Fail immediately if no file is open
+  if (! this->is_open ())
+    return nullptr;
+  // Assume success
+  gzfilebuf *retval = this;
+  // Attempt to sync and close gzipped file
+  if (this->sync () == -1)
+    retval = nullptr;
+  if (gzclose (m_file) < 0)
+    retval = nullptr;
+  // File is now gone anyway (postcondition [27.8.1.3.8])
+  m_file = nullptr;
+  m_own_fd = false;
+  // Destroy internal buffer if it exists
+  this->disable_buffer ();
+  return retval;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Convert int open mode to mode string
+bool
+gzfilebuf::open_mode (std::ios_base::openmode mode, char *c_mode) const
+{
+  // FIXME: do we need testb?
+  // bool testb = mode & std::ios_base::binary;
+  bool testi = mode & std::ios_base::in;
+  bool testo = mode & std::ios_base::out;
+  bool testt = mode & std::ios_base::trunc;
+  bool testa = mode & std::ios_base::app;
+
+  // Check for valid flag combinations - see [27.8.1.3.2] (Table 92)
+  // Original zfstream hardcoded the compression level to maximum here...
+  // Double the time for less than 1% size improvement seems
+  // excessive though - keeping it at the default level
+  // To change back, just append "9" to the next three mode strings
+  if (! testi && testo && ! testt && ! testa)
+    strcpy (c_mode, "w");
+  if (! testi && testo && ! testt && testa)
+    strcpy (c_mode, "a");
+  if (! testi && testo && testt && ! testa)
+    strcpy (c_mode, "w");
+  if (testi && ! testo && ! testt && ! testa)
+    strcpy (c_mode, "r");
+  // No read/write mode yet
+  //  if (testi && testo && ! testt && ! testa)
+  //    strcpy(c_mode, "r+");
+  //  if (testi && testo && testt && ! testa)
+  //    strcpy(c_mode, "w+");
+
+  // Mode string should be empty for invalid combination of flags
+  if (strlen (c_mode) == 0)
+    return false;
+
+  strcat (c_mode, "b");
+
+  return true;
+}
+
+// Determine number of characters in internal get buffer
+std::streamsize
+gzfilebuf::showmanyc ()
+{
+  // Calls to underflow will fail if file not opened for reading
+  if (! this->is_open () || ! (m_io_mode & std::ios_base::in))
+    return -1;
+  // Make sure get area is in use
+  if (this->gptr () && (this->gptr () < this->egptr ()))
+    return std::streamsize (this->egptr () - this->gptr ());
+  else
+    return 0;
+}
+
+// Puts back a character to the stream in two cases.  Firstly, when there
+// is no putback position available, and secondly when the character putback
+// differs from the one in the file.  We can only support the first case
+// with gzipped files.
+gzfilebuf::int_type
+gzfilebuf::pbackfail (gzfilebuf::int_type c)
+{
+  if (this->is_open ())
+    {
+      if (gzseek (m_file, this->gptr () - this->egptr () - 1, SEEK_CUR) < 0)
+        return traits_type::eof ();
+
+      // Invalidates contents of the buffer
+      enable_buffer ();
+
+      // Attempt to fill internal buffer from gzipped file
+      // (buffer must be guaranteed to exist...)
+      int bytes_read = gzread (m_file, m_buffer, m_buffer_size);
+      // Indicates error or EOF
+      if (bytes_read <= 0)
+        {
+          // Reset get area
+          this->setg (m_buffer, m_buffer, m_buffer);
+          return traits_type::eof ();
+        }
+
+      // Make all bytes read from file available as get area
+      this->setg (m_buffer, m_buffer, m_buffer + bytes_read);
+
+      // If next character in get area differs from putback character
+      // flag a failure
+      gzfilebuf::int_type ret = traits_type::to_int_type (*(this->gptr ()));
+      if (ret != c)
+        return traits_type::eof ();
+      else
+        return ret;
+    }
+  else
+    return traits_type::eof ();
+}
+
+// Fill get area from gzipped file
+gzfilebuf::int_type
+gzfilebuf::underflow ()
+{
+  // If something is left in the get area by chance, return it
+  // (this shouldn't normally happen, as underflow is only supposed
+  // to be called when gptr >= egptr, but it serves as error check)
+  if (this->gptr () && (this->gptr () < this->egptr ()))
+    return traits_type::to_int_type (*(this->gptr ()));
+
+  // If the file hasn't been opened for reading, produce error
+  if (! this->is_open () || ! (m_io_mode & std::ios_base::in))
+    return traits_type::eof ();
+
+  // Copy the final characters to the front of the buffer
+  int stash = 0;
+  if (this->eback () && m_buffer && m_buffer_size > STASHED_CHARACTERS)
+    {
+      char_type *ptr1 = m_buffer;
+      char_type *ptr2 = this->egptr () - STASHED_CHARACTERS + 1;
+      if (ptr2 > this->eback ())
+        while (stash++ <= STASHED_CHARACTERS)
+          *ptr1++ = *ptr2++;
+    }
+
+  // Attempt to fill internal buffer from gzipped file
+  // (buffer must be guaranteed to exist...)
+  int bytes_read = gzread (m_file, m_buffer + stash, m_buffer_size - stash);
+
+  // Indicates error or EOF
+  if (bytes_read <= 0)
+    {
+      // Reset get area
+      this->setg (m_buffer, m_buffer, m_buffer);
+      return traits_type::eof ();
+    }
+  // Make all bytes read from file plus the stash available as get area
+  this->setg (m_buffer, m_buffer + stash, m_buffer + bytes_read + stash);
+
+  // Return next character in get area
+  return traits_type::to_int_type (*(this->gptr ()));
+}
+
+// Write put area to gzipped file
+gzfilebuf::int_type
+gzfilebuf::overflow (int_type c)
+{
+  // Determine whether put area is in use
+  if (this->pbase ())
+    {
+      // Double-check pointer range
+      if (this->pptr () > this->epptr () || this->pptr () < this->pbase ())
+        return traits_type::eof ();
+      // Add extra character to buffer if not EOF
+      if (! traits_type::eq_int_type (c, traits_type::eof ()))
+        {
+          *(this->pptr ()) = traits_type::to_char_type (c);
+          this->pbump (1);
+        }
+      // Number of characters to write to file
+      int bytes_to_write = this->pptr () - this->pbase ();
+      // Overflow doesn't fail if nothing is to be written
+      if (bytes_to_write > 0)
+        {
+          // If the file hasn't been opened for writing, produce error
+          if (! this->is_open () || ! (m_io_mode & std::ios_base::out))
+            return traits_type::eof ();
+          // If gzipped file won't accept all bytes written to it, fail
+          if (gzwrite (m_file, this->pbase (), bytes_to_write)
+              != bytes_to_write)
+            return traits_type::eof ();
+          // Reset next pointer to point to pbase on success
+          this->pbump (-bytes_to_write);
+        }
+    }
+  // Write extra character to file if not EOF
+  else if (! traits_type::eq_int_type (c, traits_type::eof ()))
+    {
+      // If the file hasn't been opened for writing, produce error
+      if (! this->is_open () || ! (m_io_mode & std::ios_base::out))
+        return traits_type::eof ();
+      // Impromptu char buffer (allows "unbuffered" output)
+      char_type last_char = traits_type::to_char_type (c);
+      // If gzipped file won't accept this character, fail
+      if (gzwrite (m_file, &last_char, 1) != 1)
+        return traits_type::eof ();
+    }
+
+  // If you got here, you have succeeded (even if c was EOF)
+  // The return value should therefore be non-EOF
+  if (traits_type::eq_int_type (c, traits_type::eof ()))
+    return traits_type::not_eof (c);
+  else
+    return c;
+}
+
+// Assign new buffer
+std::streambuf*
+gzfilebuf::setbuf (char_type *p, std::streamsize n)
+{
+  // First make sure stuff is sync'ed, for safety
+  if (this->sync () == -1)
+    return nullptr;
+  // If buffering is turned off on purpose via setbuf(0,0), still allocate one.
+  // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at
+  // least a buffer of size 1 (very inefficient though, therefore make it
+  // bigger?).  This follows from [27.5.2.4.3]/12 (gptr needs to point at
+  // something, it seems).
+  if (! p || ! n)
+    {
+      // Replace existing buffer (if any) with small internal buffer
+      this->disable_buffer ();
+      m_buffer = nullptr;
+      m_buffer_size = 0;
+      m_own_buffer = true;
+      this->enable_buffer ();
+    }
+  else
+    {
+      // Replace existing buffer (if any) with external buffer
+      this->disable_buffer ();
+      m_buffer = p;
+      m_buffer_size = n;
+      m_own_buffer = false;
+      this->enable_buffer ();
+    }
+  return this;
+}
+
+// Write put area to gzipped file (i.e., ensures that put area is empty)
+int
+gzfilebuf::sync ()
+{
+  return traits_type::eq_int_type (this->overflow (),
+                                   traits_type::eof ()) ? -1 : 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Allocate internal buffer
+void
+gzfilebuf::enable_buffer ()
+{
+  // If internal buffer required, allocate one
+  if (m_own_buffer && ! m_buffer)
+    {
+      // Check for buffered vs. "unbuffered"
+      if (m_buffer_size > 0)
+        {
+          // Allocate internal buffer
+          m_buffer = new char_type [m_buffer_size];
+          // Get area starts empty and will be expanded by underflow as needed
+          this->setg (m_buffer, m_buffer, m_buffer);
+          // Setup entire internal buffer as put area.
+          // The one-past-end pointer actually points to the last element of
+          // the buffer, so that overflow(c) can safely add the extra character
+          // c to the sequence.  These pointers remain in place for the
+          // duration of the buffer
+          this->setp (m_buffer, m_buffer + m_buffer_size - 1);
+        }
+      else
+        {
+          // Even in "unbuffered" case, (small?) get buffer is still required
+          m_buffer_size = SMALLBUFSIZE;
+          m_buffer = new char_type [m_buffer_size];
+          this->setg (m_buffer, m_buffer, m_buffer);
+          // "Unbuffered" means no put buffer
+          this->setp (nullptr, nullptr);
+        }
+    }
+  else
+    {
+      // If buffer already allocated, reset buffer pointers just to make sure no
+      // stale chars are lying around
+      this->setg (m_buffer, m_buffer, m_buffer);
+      this->setp (m_buffer, m_buffer + m_buffer_size - 1);
+    }
+}
+
+// Destroy internal buffer
+void
+gzfilebuf::disable_buffer ()
+{
+  // If internal buffer exists, deallocate it
+  if (m_own_buffer && m_buffer)
+    {
+      // Preserve unbuffered status by zeroing size
+      if (! this->pbase ())
+        m_buffer_size = 0;
+      delete [] m_buffer;
+      m_buffer = nullptr;
+      this->setg (nullptr, nullptr, nullptr);
+      this->setp (nullptr, nullptr);
+    }
+  else
+    {
+      // Reset buffer pointers to initial state if external buffer exists
+      this->setg (m_buffer, m_buffer, m_buffer);
+      if (m_buffer)
+        this->setp (m_buffer, m_buffer + m_buffer_size - 1);
+      else
+        this->setp (nullptr, nullptr);
+    }
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Seek functions
+gzfilebuf::pos_type
+gzfilebuf::seekoff (off_type off, std::ios_base::seekdir way,
+                    std::ios_base::openmode)
+{
+  pos_type ret = pos_type (off_type (-1));
+
+  if (this->is_open ())
+    {
+      off_type computed_off = off;
+
+      if ((m_io_mode & std::ios_base::in) && way == std::ios_base::cur)
+        computed_off += this->gptr () - this->egptr ();
+
+      // Handle tellg/tellp as a special case up front, no need to seek
+      // or invalidate get/put buffers
+      if (off == 0 && way == std::ios_base::cur)
+        return pos_type (gztell (m_file) + computed_off);
+
+      if (way == std::ios_base::beg)
+        ret = pos_type (gzseek (m_file, computed_off, SEEK_SET));
+      else if (way == std::ios_base::cur)
+        ret = pos_type (gzseek (m_file, computed_off, SEEK_CUR));
+      else
+        // Can't seek from end of a gzipped file, so this will give -1
+        ret = pos_type (gzseek (m_file, computed_off, SEEK_END));
+
+      if (m_io_mode & std::ios_base::in)
+        // Invalidates contents of the buffer
+        enable_buffer ();
+      else
+        // flush contents of buffer to file
+        overflow ();
+    }
+
+  return ret;
+}
+
+gzfilebuf::pos_type
+gzfilebuf::seekpos (pos_type sp, std::ios_base::openmode)
+{
+  pos_type ret = pos_type (off_type (-1));
+
+  if (this->is_open ())
+    {
+      ret = pos_type (gzseek (m_file, sp, SEEK_SET));
+
+      if (m_io_mode & std::ios_base::in)
+        // Invalidates contents of the buffer
+        enable_buffer ();
+      else
+        // flush contents of buffer to file
+        overflow ();
+    }
+
+  return ret;
+}
+
+// Default constructor initializes stream buffer
+gzifstream::gzifstream ()
+  : std::istream (nullptr), sb ()
+{ this->init (&sb); }
+
+// Initialize stream buffer and open file
+gzifstream::gzifstream (const char *name, std::ios_base::openmode mode)
+  : std::istream (nullptr), sb ()
+{
+  this->init (&sb);
+  this->open (name, mode);
+}
+
+// Initialize stream buffer and attach to file
+gzifstream::gzifstream (int fd, std::ios_base::openmode mode)
+  : std::istream (nullptr), sb ()
+{
+  this->init (&sb);
+  this->attach (fd, mode);
+}
+
+// Open file and go into fail() state if unsuccessful
+void
+gzifstream::open (const char *name, std::ios_base::openmode mode)
+{
+  if (! sb.open (name, mode | std::ios_base::in))
+    this->setstate (std::ios_base::failbit);
+  else
+    this->clear ();
+}
+
+// Attach to file and go into fail() state if unsuccessful
+void
+gzifstream::attach (int fd, std::ios_base::openmode mode)
+{
+  if (! sb.attach (fd, mode | std::ios_base::in))
+    this->setstate (std::ios_base::failbit);
+  else
+    this->clear ();
+}
+
+// Close file
+void
+gzifstream::close ()
+{
+  if (! sb.close ())
+    this->setstate (std::ios_base::failbit);
+}
+
+// Default constructor initializes stream buffer
+gzofstream::gzofstream ()
+  : std::ostream (nullptr), sb ()
+{ this->init (&sb); }
+
+// Initialize stream buffer and open file
+gzofstream::gzofstream (const char *name, std::ios_base::openmode mode)
+  : std::ostream (nullptr), sb ()
+{
+  this->init (&sb);
+  this->open (name, mode);
+}
+
+// Initialize stream buffer and attach to file
+gzofstream::gzofstream (int fd, std::ios_base::openmode mode)
+  : std::ostream (nullptr), sb ()
+{
+  this->init (&sb);
+  this->attach (fd, mode);
+}
+
+// Open file and go into fail() state if unsuccessful
+void
+gzofstream::open (const char *name, std::ios_base::openmode mode)
+{
+  if (! sb.open (name, mode | std::ios_base::out))
+    this->setstate (std::ios_base::failbit);
+  else
+    this->clear ();
+}
+
+// Attach to file and go into fail() state if unsuccessful
+void
+gzofstream::attach (int fd, std::ios_base::openmode mode)
+{
+  if (! sb.attach (fd, mode | std::ios_base::out))
+    this->setstate (std::ios_base::failbit);
+  else
+    this->clear ();
+}
+
+// Close file
+void
+gzofstream::close ()
+{
+  if (! sb.close ())
+    this->setstate (std::ios_base::failbit);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libinterp/corefcn/gzfstream.h	Sun Sep 05 19:40:02 2021 -0700
@@ -0,0 +1,509 @@
+////////////////////////////////////////////////////////////////////////
+//
+// Copyright (C) 2005-2021 The Octave Project Developers
+//
+// See the file COPYRIGHT.md in the top-level directory of this
+// distribution or <https://octave.org/copyright/>.
+//
+// This file is part of Octave.
+//
+// Octave 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.
+//
+// Octave 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 Octave; see the file COPYING.  If not, see
+// <https://www.gnu.org/licenses/>.
+//
+////////////////////////////////////////////////////////////////////////
+
+/*
+
+ This file is adapted from the zlib 1.2.2 contrib/iostream3 code,
+ written by
+
+   Ludwig Schwardt <schwardt@sun.ac.za>
+   original version by Kevin Ruland <kevin@rodin.wustl.edu>
+
+*/
+
+#if ! defined (octave_zfsstream_h)
+#define octave_zfsstream_h 1
+
+#include "octave-config.h"
+
+#if defined (HAVE_ZLIB)
+
+#include <iosfwd>
+
+#include "zlib.h"
+
+/**
+ *  @brief  Gzipped file stream buffer class.
+ *
+ *  This class implements basic_filebuf for gzipped files.  It doesn't yet
+ *  support seeking (allowed by zlib but slow/limited), putback and read/write
+ *  access *  (tricky).  Otherwise, it attempts to be a drop-in replacement for
+ *  the standard file streambuf.
+*/
+class gzfilebuf : public std::streambuf
+{
+public:
+  //  Default constructor.
+  gzfilebuf ();
+
+  // No copying!
+
+  gzfilebuf (const gzfilebuf&) = delete;
+
+  gzfilebuf& operator = (const gzfilebuf&) = delete;
+
+  //  Destructor.
+  virtual ~gzfilebuf ();
+
+  /**
+   *  @brief  Set compression level and strategy on the fly.
+   *  @param  comp_level  Compression level (see zlib.h for allowed values)
+   *  @param  comp_strategy  Compression strategy (see zlib.h for allowed values)
+   *  @return  Z_OK on success, Z_STREAM_ERROR otherwise.
+   *
+   *  Unfortunately, these parameters cannot be modified separately, as the
+   *  previous zfstream version assumed.  Since the strategy is seldom changed,
+   *  it can default and setcompression(level) then becomes like the old
+   *  setcompressionlevel(level).
+  */
+  int
+  setcompression (int comp_level,
+                  int comp_strategy = Z_DEFAULT_STRATEGY);
+
+  /**
+   *  @brief  Check if file is open.
+   *  @return  True if file is open.
+  */
+  bool
+  is_open () const { return (m_file != nullptr); }
+
+  /**
+   *  @brief  Open gzipped file.
+   *  @param  name  Filename.
+   *  @param  mode  Open mode flags.
+   *  @return  @c this on success, NULL on failure.
+  */
+  gzfilebuf*
+  open (const char *name,
+        std::ios_base::openmode mode);
+
+  /**
+   *  @brief  Attach to already open gzipped file.
+   *  @param  fd  File descriptor.
+   *  @param  mode  Open mode flags.
+   *  @return  @c this on success, NULL on failure.
+  */
+  gzfilebuf*
+  attach (int fd,
+          std::ios_base::openmode mode);
+
+  /**
+   *  @brief  Close gzipped file.
+   *  @return  @c this on success, NULL on failure.
+  */
+  gzfilebuf*
+  close ();
+
+protected:
+  /**
+   *  @brief  Convert ios open mode int to mode string used by zlib.
+   *  @return  True if valid mode flag combination.
+  */
+  bool
+  open_mode (std::ios_base::openmode mode,
+             char *c_mode) const;
+
+  /**
+   *  @brief  Number of characters available in stream buffer.
+   *  @return  Number of characters.
+   *
+   *  This indicates number of characters in get area of stream buffer.
+   *  These characters can be read without accessing the gzipped file.
+  */
+  virtual std::streamsize
+  showmanyc ();
+
+  /**
+   *  @brief  Fill get area from gzipped file.
+   *  @return  First character in get area on success, EOF on error.
+   *
+   *  This actually reads characters from gzipped file to stream
+   *  buffer.  Always buffered.
+  */
+  virtual int_type
+  underflow ();
+
+  /**
+   *  @brief  Write put area to gzipped file.
+   *  @param  c  Extra character to add to buffer contents.
+   *  @return  Non-EOF on success, EOF on error.
+   *
+   *  This actually writes characters in stream buffer to
+   *  gzipped file.  With unbuffered output this is done one
+   *  character at a time.
+  */
+  virtual int_type
+  overflow (int_type c = traits_type::eof ());
+
+  /**
+   *  @brief  Installs external stream buffer.
+   *  @param  p  Pointer to char buffer.
+   *  @param  n  Size of external buffer.
+   *  @return  @c this on success, NULL on failure.
+   *
+   *  Call setbuf(0,0) to enable unbuffered output.
+  */
+  virtual std::streambuf*
+  setbuf (char_type *p,
+          std::streamsize n);
+
+  /**
+   *  @brief  Flush stream buffer to file.
+   *  @return  0 on success, -1 on error.
+   *
+   *  This calls underflow(EOF) to do the job.
+  */
+  virtual int
+  sync ();
+
+  /**
+   *  @brief  Alters the stream positions.
+   *
+   *  Each derived class provides its own appropriate behavior.
+   */
+  virtual pos_type
+  seekoff (off_type off, std::ios_base::seekdir way,
+           std::ios_base::openmode mode =
+             std::ios_base::in | std::ios_base::out);
+
+  /**
+   *  @brief  Alters the stream positions.
+   *
+   *  Each derived class provides its own appropriate behavior.
+   */
+  virtual pos_type
+  seekpos (pos_type sp, std::ios_base::openmode mode =
+             std::ios_base::in | std::ios_base::out);
+
+  virtual int_type
+  pbackfail (int_type c = traits_type::eof ());
+
+//
+// Some future enhancements
+//
+//  virtual int_type uflow();
+//  virtual int_type pbackfail(int_type c = traits_type::eof());
+
+private:
+
+  /**
+   *  @brief  Allocate internal buffer.
+   *
+   *  This function is safe to call multiple times.  It will ensure
+   *  that a proper internal buffer exists if it is required.  If the
+   *  buffer already exists or is external, the buffer pointers will be
+   *  reset to their original state.
+  */
+  void
+  enable_buffer ();
+
+  /**
+   *  @brief  Destroy internal buffer.
+   *
+   *  This function is safe to call multiple times.  It will ensure
+   *  that the internal buffer is deallocated if it exists.  In any
+   *  case, it will also reset the buffer pointers.
+  */
+  void
+  disable_buffer ();
+
+  /**
+   *  Underlying file pointer.
+  */
+  gzFile m_file;
+
+  /**
+   *  Mode in which file was opened.
+  */
+  std::ios_base::openmode m_io_mode;
+
+  /**
+   *  @brief  True if this object owns file descriptor.
+   *
+   *  This makes the class responsible for closing the file
+   *  upon destruction.
+  */
+  bool m_own_fd;
+
+  /**
+   *  @brief  Stream buffer.
+   *
+   *  For simplicity this remains allocated on the free store for the
+   *  entire life span of the gzfilebuf object, unless replaced by setbuf.
+  */
+  char_type *m_buffer;
+
+  /**
+   *  @brief  Stream buffer size.
+   *
+   *  Defaults to system default buffer size (typically 8192 bytes).
+   *  Modified by setbuf.
+  */
+  std::streamsize m_buffer_size;
+
+  /**
+   *  @brief  True if this object owns stream buffer.
+   *
+   *  This makes the class responsible for deleting the buffer
+   *  upon destruction.
+  */
+  bool m_own_buffer;
+};
+
+/**
+ *  @brief  Gzipped file input stream class.
+ *
+ *  This class implements ifstream for gzipped files.  Seeking and putback
+ *  is not supported yet.
+*/
+class gzifstream : public std::istream
+{
+public:
+  //  Default constructor
+  gzifstream ();
+
+  /**
+   *  @brief  Construct stream on gzipped file to be opened.
+   *  @param  name  Filename.
+   *  @param  mode  Open mode flags (forced to contain ios::in).
+  */
+  explicit
+  gzifstream (const char *name,
+              std::ios_base::openmode mode = std::ios_base::in);
+
+  /**
+   *  @brief  Construct stream on already open gzipped file.
+   *  @param  fd    File descriptor.
+   *  @param  mode  Open mode flags (forced to contain ios::in).
+  */
+  explicit
+  gzifstream (int fd,
+              std::ios_base::openmode mode = std::ios_base::in);
+
+  /**
+   *  Obtain underlying stream buffer.
+  */
+  gzfilebuf*
+  rdbuf () const
+  { return const_cast<gzfilebuf *>(&sb); }
+
+  /**
+   *  @brief  Check if file is open.
+   *  @return  True if file is open.
+  */
+  bool
+  is_open () { return sb.is_open (); }
+
+  /**
+   *  @brief  Open gzipped file.
+   *  @param  name  Filename.
+   *  @param  mode  Open mode flags (forced to contain ios::in).
+   *
+   *  Stream will be in state good() if file opens successfully;
+   *  otherwise in state fail().  This differs from the behavior of
+   *  ifstream, which never sets the state to good() and therefore
+   *  won't allow you to reuse the stream for a second file unless
+   *  you manually clear() the state.  The choice is a matter of
+   *  convenience.
+  */
+  void
+  open (const char *name,
+        std::ios_base::openmode mode = std::ios_base::in);
+
+  /**
+   *  @brief  Attach to already open gzipped file.
+   *  @param  fd  File descriptor.
+   *  @param  mode  Open mode flags (forced to contain ios::in).
+   *
+   *  Stream will be in state good() if attach succeeded; otherwise
+   *  in state fail().
+  */
+  void
+  attach (int fd,
+          std::ios_base::openmode mode = std::ios_base::in);
+
+  /**
+   *  @brief  Close gzipped file.
+   *
+   *  Stream will be in state fail() if close failed.
+  */
+  void
+  close ();
+
+private:
+  /**
+   *  Underlying stream buffer.
+  */
+  gzfilebuf sb;
+};
+
+/**
+ *  @brief  Gzipped file output stream class.
+ *
+ *  This class implements ofstream for gzipped files.  Seeking and putback
+ *  is not supported yet.
+*/
+class gzofstream : public std::ostream
+{
+public:
+  //  Default constructor
+  gzofstream ();
+
+  /**
+   *  @brief  Construct stream on gzipped file to be opened.
+   *  @param  name  Filename.
+   *  @param  mode  Open mode flags (forced to contain ios::out).
+  */
+  explicit
+  gzofstream (const char *name,
+              std::ios_base::openmode mode = std::ios_base::out);
+
+  /**
+   *  @brief  Construct stream on already open gzipped file.
+   *  @param  fd    File descriptor.
+   *  @param  mode  Open mode flags (forced to contain ios::out).
+  */
+  explicit
+  gzofstream (int fd,
+              std::ios_base::openmode mode = std::ios_base::out);
+
+  /**
+   *  Obtain underlying stream buffer.
+  */
+  gzfilebuf*
+  rdbuf () const
+  { return const_cast<gzfilebuf *>(&sb); }
+
+  /**
+   *  @brief  Check if file is open.
+   *  @return  True if file is open.
+  */
+  bool
+  is_open () { return sb.is_open (); }
+
+  /**
+   *  @brief  Open gzipped file.
+   *  @param  name  Filename.
+   *  @param  mode  Open mode flags (forced to contain ios::out).
+   *
+   *  Stream will be in state good() if file opens successfully;
+   *  otherwise in state fail().  This differs from the behavior of
+   *  ofstream, which never sets the state to good() and therefore
+   *  won't allow you to reuse the stream for a second file unless
+   *  you manually clear() the state.  The choice is a matter of
+   *  convenience.
+  */
+  void
+  open (const char *name,
+        std::ios_base::openmode mode = std::ios_base::out);
+
+  /**
+   *  @brief  Attach to already open gzipped file.
+   *  @param  fd  File descriptor.
+   *  @param  mode  Open mode flags (forced to contain ios::out).
+   *
+   *  Stream will be in state good() if attach succeeded; otherwise
+   *  in state fail().
+  */
+  void
+  attach (int fd,
+          std::ios_base::openmode mode = std::ios_base::out);
+
+  /**
+   *  @brief  Close gzipped file.
+   *
+   *  Stream will be in state fail() if close failed.
+  */
+  void
+  close ();
+
+private:
+  /**
+   *  Underlying stream buffer.
+  */
+  gzfilebuf sb;
+};
+
+/**
+ *  @brief  Gzipped file output stream manipulator class.
+ *
+ *  This class defines a two-argument manipulator for gzofstream.  It is used
+ *  as base for the setcompression(int,int) manipulator.
+*/
+template <typename T1, typename T2>
+class gzomanip2
+{
+public:
+  // Allows insertor to peek at internals
+  template <typename Ta, typename Tb>
+  friend gzofstream&
+  operator<<(gzofstream&,
+             const gzomanip2<Ta,Tb>&);
+
+  // Constructor
+  gzomanip2 (gzofstream& (*f)(gzofstream&, T1, T2),
+             T1 v1,
+             T2 v2);
+private:
+  // Underlying manipulator function
+  gzofstream&
+  (*func)(gzofstream&, T1, T2);
+
+  // Arguments for manipulator function
+  T1 val1;
+  T2 val2;
+};
+
+// Manipulator function thunks through to stream buffer
+inline gzofstream&
+setcompression (gzofstream& gzs, int l, int s = Z_DEFAULT_STRATEGY)
+{
+  (gzs.rdbuf ())->setcompression (l, s);
+  return gzs;
+}
+
+// Manipulator constructor stores arguments
+template <typename T1, typename T2>
+inline
+gzomanip2<T1,T2>::gzomanip2 (gzofstream &(*f)(gzofstream &, T1, T2),
+                             T1 v1,
+                             T2 v2)
+  : func(f), val1(v1), val2(v2)
+{ }
+
+// Insertor applies underlying manipulator function to stream
+template <typename T1, typename T2>
+inline gzofstream&
+operator<<(gzofstream& s, const gzomanip2<T1,T2>& m)
+{ return (*m.func)(s, m.val1, m.val2); }
+
+// Insert this onto stream to simplify setting of compression level
+inline gzomanip2<int,int>
+setcompression (int l, int s = Z_DEFAULT_STRATEGY)
+{ return gzomanip2<int,int>(&setcompression, l, s); }
+
+#endif
+
+#endif
--- a/libinterp/corefcn/load-save.cc	Sun Sep 05 19:34:37 2021 -0700
+++ b/libinterp/corefcn/load-save.cc	Sun Sep 05 19:40:02 2021 -0700
@@ -87,7 +87,7 @@
 #endif
 
 #if defined (HAVE_ZLIB)
-#  include "zfstream.h"
+#  include "gzfstream.h"
 #endif
 
 OCTAVE_NAMESPACE_BEGIN
--- a/libinterp/corefcn/module.mk	Sun Sep 05 19:34:37 2021 -0700
+++ b/libinterp/corefcn/module.mk	Sun Sep 05 19:40:02 2021 -0700
@@ -98,7 +98,7 @@
   %reldir%/xdiv.h \
   %reldir%/xnorm.h \
   %reldir%/xpow.h \
-  %reldir%/zfstream.h
+  %reldir%/gzfstream.h
 
 NOINSTALL_COREFCN_INC = \
   %reldir%/interpreter-private.h \
@@ -276,7 +276,7 @@
   %reldir%/xdiv.cc \
   %reldir%/xnorm.cc \
   %reldir%/xpow.cc \
-  %reldir%/zfstream.cc \
+  %reldir%/gzfstream.cc \
   $(NOINSTALL_COREFCN_INC)
 
 ## Special rules for sources which must be built before rest of compilation.
--- a/libinterp/corefcn/zfstream.cc	Sun Sep 05 19:34:37 2021 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,621 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2005-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-/*
-
- This file is adapted from the zlib 1.2.2 contrib/iostream3 code,
- written by
-
-   Ludwig Schwardt <schwardt@sun.ac.za>
-   original version by Kevin Ruland <kevin@rodin.wustl.edu>
-
-*/
-
-#if defined (HAVE_CONFIG_H)
-#  include "config.h"
-#endif
-
-#include <iomanip>
-#include <istream>
-#include <ostream>
-
-#include "zfstream.h"
-
-#if defined (HAVE_ZLIB)
-
-// For strcpy, strcat, strlen (mode strings).
-#include <cstring>
-// For BUFSIZ.
-#include <cstdio>
-
-// Internal buffer sizes (default and "unbuffered" versions)
-#define STASHED_CHARACTERS 16
-#define BIGBUFSIZE (256 * 1024 + STASHED_CHARACTERS)
-#define SMALLBUFSIZE 1
-
-// Default constructor
-gzfilebuf::gzfilebuf ()
-  : m_file(nullptr), m_io_mode(std::ios_base::openmode(0)), m_own_fd(false),
-    m_buffer(nullptr), m_buffer_size(BIGBUFSIZE), m_own_buffer(true)
-{
-  // No buffers to start with
-  this->disable_buffer ();
-}
-
-// Destructor
-gzfilebuf::~gzfilebuf ()
-{
-  // Sync output buffer and close only if responsible for file
-  // (i.e., attached streams should be left open at this stage)
-  this->sync ();
-  if (m_own_fd)
-    this->close ();
-  // Make sure internal buffer is deallocated
-  this->disable_buffer ();
-}
-
-// Set compression level and strategy
-int
-gzfilebuf::setcompression (int comp_level, int comp_strategy)
-{
-  return gzsetparams (m_file, comp_level, comp_strategy);
-}
-
-// Open gzipped file
-gzfilebuf*
-gzfilebuf::open (const char *name, std::ios_base::openmode mode)
-{
-  // Fail if file already open
-  if (this->is_open ())
-    return nullptr;
-  // Don't support simultaneous read/write access (yet)
-  if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
-    return nullptr;
-
-  // Build mode string for gzopen and check it [27.8.1.3.2]
-  char char_mode[6] = "\0\0\0\0\0";
-  if (! this->open_mode (mode, char_mode))
-    return nullptr;
-
-  // Attempt to open file
-  if ((m_file = gzopen (name, char_mode)) == nullptr)
-    return nullptr;
-
-  // On success, allocate internal buffer and set flags
-  this->enable_buffer ();
-  m_io_mode = mode;
-  m_own_fd = true;
-  return this;
-}
-
-// Attach to gzipped file
-gzfilebuf*
-gzfilebuf::attach (int fd, std::ios_base::openmode mode)
-{
-  // Fail if file already open
-  if (this->is_open ())
-    return nullptr;
-  // Don't support simultaneous read/write access (yet)
-  if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
-    return nullptr;
-
-  // Build mode string for gzdopen and check it [27.8.1.3.2]
-  char char_mode[6] = "\0\0\0\0\0";
-  if (! this->open_mode (mode, char_mode))
-    return nullptr;
-
-  // Attempt to attach to file
-  if ((m_file = gzdopen (fd, char_mode)) == nullptr)
-    return nullptr;
-
-  // On success, allocate internal buffer and set flags
-  this->enable_buffer ();
-  m_io_mode = mode;
-  m_own_fd = false;
-  return this;
-}
-
-// Close gzipped file
-gzfilebuf*
-gzfilebuf::close ()
-{
-  // Fail immediately if no file is open
-  if (! this->is_open ())
-    return nullptr;
-  // Assume success
-  gzfilebuf *retval = this;
-  // Attempt to sync and close gzipped file
-  if (this->sync () == -1)
-    retval = nullptr;
-  if (gzclose (m_file) < 0)
-    retval = nullptr;
-  // File is now gone anyway (postcondition [27.8.1.3.8])
-  m_file = nullptr;
-  m_own_fd = false;
-  // Destroy internal buffer if it exists
-  this->disable_buffer ();
-  return retval;
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-// Convert int open mode to mode string
-bool
-gzfilebuf::open_mode (std::ios_base::openmode mode, char *c_mode) const
-{
-  // FIXME: do we need testb?
-  // bool testb = mode & std::ios_base::binary;
-  bool testi = mode & std::ios_base::in;
-  bool testo = mode & std::ios_base::out;
-  bool testt = mode & std::ios_base::trunc;
-  bool testa = mode & std::ios_base::app;
-
-  // Check for valid flag combinations - see [27.8.1.3.2] (Table 92)
-  // Original zfstream hardcoded the compression level to maximum here...
-  // Double the time for less than 1% size improvement seems
-  // excessive though - keeping it at the default level
-  // To change back, just append "9" to the next three mode strings
-  if (! testi && testo && ! testt && ! testa)
-    strcpy (c_mode, "w");
-  if (! testi && testo && ! testt && testa)
-    strcpy (c_mode, "a");
-  if (! testi && testo && testt && ! testa)
-    strcpy (c_mode, "w");
-  if (testi && ! testo && ! testt && ! testa)
-    strcpy (c_mode, "r");
-  // No read/write mode yet
-  //  if (testi && testo && ! testt && ! testa)
-  //    strcpy(c_mode, "r+");
-  //  if (testi && testo && testt && ! testa)
-  //    strcpy(c_mode, "w+");
-
-  // Mode string should be empty for invalid combination of flags
-  if (strlen (c_mode) == 0)
-    return false;
-
-  strcat (c_mode, "b");
-
-  return true;
-}
-
-// Determine number of characters in internal get buffer
-std::streamsize
-gzfilebuf::showmanyc ()
-{
-  // Calls to underflow will fail if file not opened for reading
-  if (! this->is_open () || ! (m_io_mode & std::ios_base::in))
-    return -1;
-  // Make sure get area is in use
-  if (this->gptr () && (this->gptr () < this->egptr ()))
-    return std::streamsize (this->egptr () - this->gptr ());
-  else
-    return 0;
-}
-
-// Puts back a character to the stream in two cases.  Firstly, when there
-// is no putback position available, and secondly when the character putback
-// differs from the one in the file.  We can only support the first case
-// with gzipped files.
-gzfilebuf::int_type
-gzfilebuf::pbackfail (gzfilebuf::int_type c)
-{
-  if (this->is_open ())
-    {
-      if (gzseek (m_file, this->gptr () - this->egptr () - 1, SEEK_CUR) < 0)
-        return traits_type::eof ();
-
-      // Invalidates contents of the buffer
-      enable_buffer ();
-
-      // Attempt to fill internal buffer from gzipped file
-      // (buffer must be guaranteed to exist...)
-      int bytes_read = gzread (m_file, m_buffer, m_buffer_size);
-      // Indicates error or EOF
-      if (bytes_read <= 0)
-        {
-          // Reset get area
-          this->setg (m_buffer, m_buffer, m_buffer);
-          return traits_type::eof ();
-        }
-
-      // Make all bytes read from file available as get area
-      this->setg (m_buffer, m_buffer, m_buffer + bytes_read);
-
-      // If next character in get area differs from putback character
-      // flag a failure
-      gzfilebuf::int_type ret = traits_type::to_int_type (*(this->gptr ()));
-      if (ret != c)
-        return traits_type::eof ();
-      else
-        return ret;
-    }
-  else
-    return traits_type::eof ();
-}
-
-// Fill get area from gzipped file
-gzfilebuf::int_type
-gzfilebuf::underflow ()
-{
-  // If something is left in the get area by chance, return it
-  // (this shouldn't normally happen, as underflow is only supposed
-  // to be called when gptr >= egptr, but it serves as error check)
-  if (this->gptr () && (this->gptr () < this->egptr ()))
-    return traits_type::to_int_type (*(this->gptr ()));
-
-  // If the file hasn't been opened for reading, produce error
-  if (! this->is_open () || ! (m_io_mode & std::ios_base::in))
-    return traits_type::eof ();
-
-  // Copy the final characters to the front of the buffer
-  int stash = 0;
-  if (this->eback () && m_buffer && m_buffer_size > STASHED_CHARACTERS)
-    {
-      char_type *ptr1 = m_buffer;
-      char_type *ptr2 = this->egptr () - STASHED_CHARACTERS + 1;
-      if (ptr2 > this->eback ())
-        while (stash++ <= STASHED_CHARACTERS)
-          *ptr1++ = *ptr2++;
-    }
-
-  // Attempt to fill internal buffer from gzipped file
-  // (buffer must be guaranteed to exist...)
-  int bytes_read = gzread (m_file, m_buffer + stash, m_buffer_size - stash);
-
-  // Indicates error or EOF
-  if (bytes_read <= 0)
-    {
-      // Reset get area
-      this->setg (m_buffer, m_buffer, m_buffer);
-      return traits_type::eof ();
-    }
-  // Make all bytes read from file plus the stash available as get area
-  this->setg (m_buffer, m_buffer + stash, m_buffer + bytes_read + stash);
-
-  // Return next character in get area
-  return traits_type::to_int_type (*(this->gptr ()));
-}
-
-// Write put area to gzipped file
-gzfilebuf::int_type
-gzfilebuf::overflow (int_type c)
-{
-  // Determine whether put area is in use
-  if (this->pbase ())
-    {
-      // Double-check pointer range
-      if (this->pptr () > this->epptr () || this->pptr () < this->pbase ())
-        return traits_type::eof ();
-      // Add extra character to buffer if not EOF
-      if (! traits_type::eq_int_type (c, traits_type::eof ()))
-        {
-          *(this->pptr ()) = traits_type::to_char_type (c);
-          this->pbump (1);
-        }
-      // Number of characters to write to file
-      int bytes_to_write = this->pptr () - this->pbase ();
-      // Overflow doesn't fail if nothing is to be written
-      if (bytes_to_write > 0)
-        {
-          // If the file hasn't been opened for writing, produce error
-          if (! this->is_open () || ! (m_io_mode & std::ios_base::out))
-            return traits_type::eof ();
-          // If gzipped file won't accept all bytes written to it, fail
-          if (gzwrite (m_file, this->pbase (), bytes_to_write)
-              != bytes_to_write)
-            return traits_type::eof ();
-          // Reset next pointer to point to pbase on success
-          this->pbump (-bytes_to_write);
-        }
-    }
-  // Write extra character to file if not EOF
-  else if (! traits_type::eq_int_type (c, traits_type::eof ()))
-    {
-      // If the file hasn't been opened for writing, produce error
-      if (! this->is_open () || ! (m_io_mode & std::ios_base::out))
-        return traits_type::eof ();
-      // Impromptu char buffer (allows "unbuffered" output)
-      char_type last_char = traits_type::to_char_type (c);
-      // If gzipped file won't accept this character, fail
-      if (gzwrite (m_file, &last_char, 1) != 1)
-        return traits_type::eof ();
-    }
-
-  // If you got here, you have succeeded (even if c was EOF)
-  // The return value should therefore be non-EOF
-  if (traits_type::eq_int_type (c, traits_type::eof ()))
-    return traits_type::not_eof (c);
-  else
-    return c;
-}
-
-// Assign new buffer
-std::streambuf*
-gzfilebuf::setbuf (char_type *p, std::streamsize n)
-{
-  // First make sure stuff is sync'ed, for safety
-  if (this->sync () == -1)
-    return nullptr;
-  // If buffering is turned off on purpose via setbuf(0,0), still allocate one.
-  // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at
-  // least a buffer of size 1 (very inefficient though, therefore make it
-  // bigger?).  This follows from [27.5.2.4.3]/12 (gptr needs to point at
-  // something, it seems).
-  if (! p || ! n)
-    {
-      // Replace existing buffer (if any) with small internal buffer
-      this->disable_buffer ();
-      m_buffer = nullptr;
-      m_buffer_size = 0;
-      m_own_buffer = true;
-      this->enable_buffer ();
-    }
-  else
-    {
-      // Replace existing buffer (if any) with external buffer
-      this->disable_buffer ();
-      m_buffer = p;
-      m_buffer_size = n;
-      m_own_buffer = false;
-      this->enable_buffer ();
-    }
-  return this;
-}
-
-// Write put area to gzipped file (i.e., ensures that put area is empty)
-int
-gzfilebuf::sync ()
-{
-  return traits_type::eq_int_type (this->overflow (),
-                                   traits_type::eof ()) ? -1 : 0;
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-// Allocate internal buffer
-void
-gzfilebuf::enable_buffer ()
-{
-  // If internal buffer required, allocate one
-  if (m_own_buffer && ! m_buffer)
-    {
-      // Check for buffered vs. "unbuffered"
-      if (m_buffer_size > 0)
-        {
-          // Allocate internal buffer
-          m_buffer = new char_type [m_buffer_size];
-          // Get area starts empty and will be expanded by underflow as needed
-          this->setg (m_buffer, m_buffer, m_buffer);
-          // Setup entire internal buffer as put area.
-          // The one-past-end pointer actually points to the last element of
-          // the buffer, so that overflow(c) can safely add the extra character
-          // c to the sequence.  These pointers remain in place for the
-          // duration of the buffer
-          this->setp (m_buffer, m_buffer + m_buffer_size - 1);
-        }
-      else
-        {
-          // Even in "unbuffered" case, (small?) get buffer is still required
-          m_buffer_size = SMALLBUFSIZE;
-          m_buffer = new char_type [m_buffer_size];
-          this->setg (m_buffer, m_buffer, m_buffer);
-          // "Unbuffered" means no put buffer
-          this->setp (nullptr, nullptr);
-        }
-    }
-  else
-    {
-      // If buffer already allocated, reset buffer pointers just to make sure no
-      // stale chars are lying around
-      this->setg (m_buffer, m_buffer, m_buffer);
-      this->setp (m_buffer, m_buffer + m_buffer_size - 1);
-    }
-}
-
-// Destroy internal buffer
-void
-gzfilebuf::disable_buffer ()
-{
-  // If internal buffer exists, deallocate it
-  if (m_own_buffer && m_buffer)
-    {
-      // Preserve unbuffered status by zeroing size
-      if (! this->pbase ())
-        m_buffer_size = 0;
-      delete [] m_buffer;
-      m_buffer = nullptr;
-      this->setg (nullptr, nullptr, nullptr);
-      this->setp (nullptr, nullptr);
-    }
-  else
-    {
-      // Reset buffer pointers to initial state if external buffer exists
-      this->setg (m_buffer, m_buffer, m_buffer);
-      if (m_buffer)
-        this->setp (m_buffer, m_buffer + m_buffer_size - 1);
-      else
-        this->setp (nullptr, nullptr);
-    }
-}
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-// Seek functions
-gzfilebuf::pos_type
-gzfilebuf::seekoff (off_type off, std::ios_base::seekdir way,
-                    std::ios_base::openmode)
-{
-  pos_type ret = pos_type (off_type (-1));
-
-  if (this->is_open ())
-    {
-      off_type computed_off = off;
-
-      if ((m_io_mode & std::ios_base::in) && way == std::ios_base::cur)
-        computed_off += this->gptr () - this->egptr ();
-
-      // Handle tellg/tellp as a special case up front, no need to seek
-      // or invalidate get/put buffers
-      if (off == 0 && way == std::ios_base::cur)
-        return pos_type (gztell (m_file) + computed_off);
-
-      if (way == std::ios_base::beg)
-        ret = pos_type (gzseek (m_file, computed_off, SEEK_SET));
-      else if (way == std::ios_base::cur)
-        ret = pos_type (gzseek (m_file, computed_off, SEEK_CUR));
-      else
-        // Can't seek from end of a gzipped file, so this will give -1
-        ret = pos_type (gzseek (m_file, computed_off, SEEK_END));
-
-      if (m_io_mode & std::ios_base::in)
-        // Invalidates contents of the buffer
-        enable_buffer ();
-      else
-        // flush contents of buffer to file
-        overflow ();
-    }
-
-  return ret;
-}
-
-gzfilebuf::pos_type
-gzfilebuf::seekpos (pos_type sp, std::ios_base::openmode)
-{
-  pos_type ret = pos_type (off_type (-1));
-
-  if (this->is_open ())
-    {
-      ret = pos_type (gzseek (m_file, sp, SEEK_SET));
-
-      if (m_io_mode & std::ios_base::in)
-        // Invalidates contents of the buffer
-        enable_buffer ();
-      else
-        // flush contents of buffer to file
-        overflow ();
-    }
-
-  return ret;
-}
-
-// Default constructor initializes stream buffer
-gzifstream::gzifstream ()
-  : std::istream (nullptr), sb ()
-{ this->init (&sb); }
-
-// Initialize stream buffer and open file
-gzifstream::gzifstream (const char *name, std::ios_base::openmode mode)
-  : std::istream (nullptr), sb ()
-{
-  this->init (&sb);
-  this->open (name, mode);
-}
-
-// Initialize stream buffer and attach to file
-gzifstream::gzifstream (int fd, std::ios_base::openmode mode)
-  : std::istream (nullptr), sb ()
-{
-  this->init (&sb);
-  this->attach (fd, mode);
-}
-
-// Open file and go into fail() state if unsuccessful
-void
-gzifstream::open (const char *name, std::ios_base::openmode mode)
-{
-  if (! sb.open (name, mode | std::ios_base::in))
-    this->setstate (std::ios_base::failbit);
-  else
-    this->clear ();
-}
-
-// Attach to file and go into fail() state if unsuccessful
-void
-gzifstream::attach (int fd, std::ios_base::openmode mode)
-{
-  if (! sb.attach (fd, mode | std::ios_base::in))
-    this->setstate (std::ios_base::failbit);
-  else
-    this->clear ();
-}
-
-// Close file
-void
-gzifstream::close ()
-{
-  if (! sb.close ())
-    this->setstate (std::ios_base::failbit);
-}
-
-// Default constructor initializes stream buffer
-gzofstream::gzofstream ()
-  : std::ostream (nullptr), sb ()
-{ this->init (&sb); }
-
-// Initialize stream buffer and open file
-gzofstream::gzofstream (const char *name, std::ios_base::openmode mode)
-  : std::ostream (nullptr), sb ()
-{
-  this->init (&sb);
-  this->open (name, mode);
-}
-
-// Initialize stream buffer and attach to file
-gzofstream::gzofstream (int fd, std::ios_base::openmode mode)
-  : std::ostream (nullptr), sb ()
-{
-  this->init (&sb);
-  this->attach (fd, mode);
-}
-
-// Open file and go into fail() state if unsuccessful
-void
-gzofstream::open (const char *name, std::ios_base::openmode mode)
-{
-  if (! sb.open (name, mode | std::ios_base::out))
-    this->setstate (std::ios_base::failbit);
-  else
-    this->clear ();
-}
-
-// Attach to file and go into fail() state if unsuccessful
-void
-gzofstream::attach (int fd, std::ios_base::openmode mode)
-{
-  if (! sb.attach (fd, mode | std::ios_base::out))
-    this->setstate (std::ios_base::failbit);
-  else
-    this->clear ();
-}
-
-// Close file
-void
-gzofstream::close ()
-{
-  if (! sb.close ())
-    this->setstate (std::ios_base::failbit);
-}
-
-#endif
--- a/libinterp/corefcn/zfstream.h	Sun Sep 05 19:34:37 2021 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,509 +0,0 @@
-////////////////////////////////////////////////////////////////////////
-//
-// Copyright (C) 2005-2021 The Octave Project Developers
-//
-// See the file COPYRIGHT.md in the top-level directory of this
-// distribution or <https://octave.org/copyright/>.
-//
-// This file is part of Octave.
-//
-// Octave 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.
-//
-// Octave 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 Octave; see the file COPYING.  If not, see
-// <https://www.gnu.org/licenses/>.
-//
-////////////////////////////////////////////////////////////////////////
-
-/*
-
- This file is adapted from the zlib 1.2.2 contrib/iostream3 code,
- written by
-
-   Ludwig Schwardt <schwardt@sun.ac.za>
-   original version by Kevin Ruland <kevin@rodin.wustl.edu>
-
-*/
-
-#if ! defined (octave_zfsstream_h)
-#define octave_zfsstream_h 1
-
-#include "octave-config.h"
-
-#if defined (HAVE_ZLIB)
-
-#include <iosfwd>
-
-#include "zlib.h"
-
-/**
- *  @brief  Gzipped file stream buffer class.
- *
- *  This class implements basic_filebuf for gzipped files.  It doesn't yet
- *  support seeking (allowed by zlib but slow/limited), putback and read/write
- *  access *  (tricky).  Otherwise, it attempts to be a drop-in replacement for
- *  the standard file streambuf.
-*/
-class gzfilebuf : public std::streambuf
-{
-public:
-  //  Default constructor.
-  gzfilebuf ();
-
-  // No copying!
-
-  gzfilebuf (const gzfilebuf&) = delete;
-
-  gzfilebuf& operator = (const gzfilebuf&) = delete;
-
-  //  Destructor.
-  virtual ~gzfilebuf ();
-
-  /**
-   *  @brief  Set compression level and strategy on the fly.
-   *  @param  comp_level  Compression level (see zlib.h for allowed values)
-   *  @param  comp_strategy  Compression strategy (see zlib.h for allowed values)
-   *  @return  Z_OK on success, Z_STREAM_ERROR otherwise.
-   *
-   *  Unfortunately, these parameters cannot be modified separately, as the
-   *  previous zfstream version assumed.  Since the strategy is seldom changed,
-   *  it can default and setcompression(level) then becomes like the old
-   *  setcompressionlevel(level).
-  */
-  int
-  setcompression (int comp_level,
-                  int comp_strategy = Z_DEFAULT_STRATEGY);
-
-  /**
-   *  @brief  Check if file is open.
-   *  @return  True if file is open.
-  */
-  bool
-  is_open () const { return (m_file != nullptr); }
-
-  /**
-   *  @brief  Open gzipped file.
-   *  @param  name  Filename.
-   *  @param  mode  Open mode flags.
-   *  @return  @c this on success, NULL on failure.
-  */
-  gzfilebuf*
-  open (const char *name,
-        std::ios_base::openmode mode);
-
-  /**
-   *  @brief  Attach to already open gzipped file.
-   *  @param  fd  File descriptor.
-   *  @param  mode  Open mode flags.
-   *  @return  @c this on success, NULL on failure.
-  */
-  gzfilebuf*
-  attach (int fd,
-          std::ios_base::openmode mode);
-
-  /**
-   *  @brief  Close gzipped file.
-   *  @return  @c this on success, NULL on failure.
-  */
-  gzfilebuf*
-  close ();
-
-protected:
-  /**
-   *  @brief  Convert ios open mode int to mode string used by zlib.
-   *  @return  True if valid mode flag combination.
-  */
-  bool
-  open_mode (std::ios_base::openmode mode,
-             char *c_mode) const;
-
-  /**
-   *  @brief  Number of characters available in stream buffer.
-   *  @return  Number of characters.
-   *
-   *  This indicates number of characters in get area of stream buffer.
-   *  These characters can be read without accessing the gzipped file.
-  */
-  virtual std::streamsize
-  showmanyc ();
-
-  /**
-   *  @brief  Fill get area from gzipped file.
-   *  @return  First character in get area on success, EOF on error.
-   *
-   *  This actually reads characters from gzipped file to stream
-   *  buffer.  Always buffered.
-  */
-  virtual int_type
-  underflow ();
-
-  /**
-   *  @brief  Write put area to gzipped file.
-   *  @param  c  Extra character to add to buffer contents.
-   *  @return  Non-EOF on success, EOF on error.
-   *
-   *  This actually writes characters in stream buffer to
-   *  gzipped file.  With unbuffered output this is done one
-   *  character at a time.
-  */
-  virtual int_type
-  overflow (int_type c = traits_type::eof ());
-
-  /**
-   *  @brief  Installs external stream buffer.
-   *  @param  p  Pointer to char buffer.
-   *  @param  n  Size of external buffer.
-   *  @return  @c this on success, NULL on failure.
-   *
-   *  Call setbuf(0,0) to enable unbuffered output.
-  */
-  virtual std::streambuf*
-  setbuf (char_type *p,
-          std::streamsize n);
-
-  /**
-   *  @brief  Flush stream buffer to file.
-   *  @return  0 on success, -1 on error.
-   *
-   *  This calls underflow(EOF) to do the job.
-  */
-  virtual int
-  sync ();
-
-  /**
-   *  @brief  Alters the stream positions.
-   *
-   *  Each derived class provides its own appropriate behavior.
-   */
-  virtual pos_type
-  seekoff (off_type off, std::ios_base::seekdir way,
-           std::ios_base::openmode mode =
-             std::ios_base::in | std::ios_base::out);
-
-  /**
-   *  @brief  Alters the stream positions.
-   *
-   *  Each derived class provides its own appropriate behavior.
-   */
-  virtual pos_type
-  seekpos (pos_type sp, std::ios_base::openmode mode =
-             std::ios_base::in | std::ios_base::out);
-
-  virtual int_type
-  pbackfail (int_type c = traits_type::eof ());
-
-//
-// Some future enhancements
-//
-//  virtual int_type uflow();
-//  virtual int_type pbackfail(int_type c = traits_type::eof());
-
-private:
-
-  /**
-   *  @brief  Allocate internal buffer.
-   *
-   *  This function is safe to call multiple times.  It will ensure
-   *  that a proper internal buffer exists if it is required.  If the
-   *  buffer already exists or is external, the buffer pointers will be
-   *  reset to their original state.
-  */
-  void
-  enable_buffer ();
-
-  /**
-   *  @brief  Destroy internal buffer.
-   *
-   *  This function is safe to call multiple times.  It will ensure
-   *  that the internal buffer is deallocated if it exists.  In any
-   *  case, it will also reset the buffer pointers.
-  */
-  void
-  disable_buffer ();
-
-  /**
-   *  Underlying file pointer.
-  */
-  gzFile m_file;
-
-  /**
-   *  Mode in which file was opened.
-  */
-  std::ios_base::openmode m_io_mode;
-
-  /**
-   *  @brief  True if this object owns file descriptor.
-   *
-   *  This makes the class responsible for closing the file
-   *  upon destruction.
-  */
-  bool m_own_fd;
-
-  /**
-   *  @brief  Stream buffer.
-   *
-   *  For simplicity this remains allocated on the free store for the
-   *  entire life span of the gzfilebuf object, unless replaced by setbuf.
-  */
-  char_type *m_buffer;
-
-  /**
-   *  @brief  Stream buffer size.
-   *
-   *  Defaults to system default buffer size (typically 8192 bytes).
-   *  Modified by setbuf.
-  */
-  std::streamsize m_buffer_size;
-
-  /**
-   *  @brief  True if this object owns stream buffer.
-   *
-   *  This makes the class responsible for deleting the buffer
-   *  upon destruction.
-  */
-  bool m_own_buffer;
-};
-
-/**
- *  @brief  Gzipped file input stream class.
- *
- *  This class implements ifstream for gzipped files.  Seeking and putback
- *  is not supported yet.
-*/
-class gzifstream : public std::istream
-{
-public:
-  //  Default constructor
-  gzifstream ();
-
-  /**
-   *  @brief  Construct stream on gzipped file to be opened.
-   *  @param  name  Filename.
-   *  @param  mode  Open mode flags (forced to contain ios::in).
-  */
-  explicit
-  gzifstream (const char *name,
-              std::ios_base::openmode mode = std::ios_base::in);
-
-  /**
-   *  @brief  Construct stream on already open gzipped file.
-   *  @param  fd    File descriptor.
-   *  @param  mode  Open mode flags (forced to contain ios::in).
-  */
-  explicit
-  gzifstream (int fd,
-              std::ios_base::openmode mode = std::ios_base::in);
-
-  /**
-   *  Obtain underlying stream buffer.
-  */
-  gzfilebuf*
-  rdbuf () const
-  { return const_cast<gzfilebuf *>(&sb); }
-
-  /**
-   *  @brief  Check if file is open.
-   *  @return  True if file is open.
-  */
-  bool
-  is_open () { return sb.is_open (); }
-
-  /**
-   *  @brief  Open gzipped file.
-   *  @param  name  Filename.
-   *  @param  mode  Open mode flags (forced to contain ios::in).
-   *
-   *  Stream will be in state good() if file opens successfully;
-   *  otherwise in state fail().  This differs from the behavior of
-   *  ifstream, which never sets the state to good() and therefore
-   *  won't allow you to reuse the stream for a second file unless
-   *  you manually clear() the state.  The choice is a matter of
-   *  convenience.
-  */
-  void
-  open (const char *name,
-        std::ios_base::openmode mode = std::ios_base::in);
-
-  /**
-   *  @brief  Attach to already open gzipped file.
-   *  @param  fd  File descriptor.
-   *  @param  mode  Open mode flags (forced to contain ios::in).
-   *
-   *  Stream will be in state good() if attach succeeded; otherwise
-   *  in state fail().
-  */
-  void
-  attach (int fd,
-          std::ios_base::openmode mode = std::ios_base::in);
-
-  /**
-   *  @brief  Close gzipped file.
-   *
-   *  Stream will be in state fail() if close failed.
-  */
-  void
-  close ();
-
-private:
-  /**
-   *  Underlying stream buffer.
-  */
-  gzfilebuf sb;
-};
-
-/**
- *  @brief  Gzipped file output stream class.
- *
- *  This class implements ofstream for gzipped files.  Seeking and putback
- *  is not supported yet.
-*/
-class gzofstream : public std::ostream
-{
-public:
-  //  Default constructor
-  gzofstream ();
-
-  /**
-   *  @brief  Construct stream on gzipped file to be opened.
-   *  @param  name  Filename.
-   *  @param  mode  Open mode flags (forced to contain ios::out).
-  */
-  explicit
-  gzofstream (const char *name,
-              std::ios_base::openmode mode = std::ios_base::out);
-
-  /**
-   *  @brief  Construct stream on already open gzipped file.
-   *  @param  fd    File descriptor.
-   *  @param  mode  Open mode flags (forced to contain ios::out).
-  */
-  explicit
-  gzofstream (int fd,
-              std::ios_base::openmode mode = std::ios_base::out);
-
-  /**
-   *  Obtain underlying stream buffer.
-  */
-  gzfilebuf*
-  rdbuf () const
-  { return const_cast<gzfilebuf *>(&sb); }
-
-  /**
-   *  @brief  Check if file is open.
-   *  @return  True if file is open.
-  */
-  bool
-  is_open () { return sb.is_open (); }
-
-  /**
-   *  @brief  Open gzipped file.
-   *  @param  name  Filename.
-   *  @param  mode  Open mode flags (forced to contain ios::out).
-   *
-   *  Stream will be in state good() if file opens successfully;
-   *  otherwise in state fail().  This differs from the behavior of
-   *  ofstream, which never sets the state to good() and therefore
-   *  won't allow you to reuse the stream for a second file unless
-   *  you manually clear() the state.  The choice is a matter of
-   *  convenience.
-  */
-  void
-  open (const char *name,
-        std::ios_base::openmode mode = std::ios_base::out);
-
-  /**
-   *  @brief  Attach to already open gzipped file.
-   *  @param  fd  File descriptor.
-   *  @param  mode  Open mode flags (forced to contain ios::out).
-   *
-   *  Stream will be in state good() if attach succeeded; otherwise
-   *  in state fail().
-  */
-  void
-  attach (int fd,
-          std::ios_base::openmode mode = std::ios_base::out);
-
-  /**
-   *  @brief  Close gzipped file.
-   *
-   *  Stream will be in state fail() if close failed.
-  */
-  void
-  close ();
-
-private:
-  /**
-   *  Underlying stream buffer.
-  */
-  gzfilebuf sb;
-};
-
-/**
- *  @brief  Gzipped file output stream manipulator class.
- *
- *  This class defines a two-argument manipulator for gzofstream.  It is used
- *  as base for the setcompression(int,int) manipulator.
-*/
-template <typename T1, typename T2>
-class gzomanip2
-{
-public:
-  // Allows insertor to peek at internals
-  template <typename Ta, typename Tb>
-  friend gzofstream&
-  operator<<(gzofstream&,
-             const gzomanip2<Ta,Tb>&);
-
-  // Constructor
-  gzomanip2 (gzofstream& (*f)(gzofstream&, T1, T2),
-             T1 v1,
-             T2 v2);
-private:
-  // Underlying manipulator function
-  gzofstream&
-  (*func)(gzofstream&, T1, T2);
-
-  // Arguments for manipulator function
-  T1 val1;
-  T2 val2;
-};
-
-// Manipulator function thunks through to stream buffer
-inline gzofstream&
-setcompression (gzofstream& gzs, int l, int s = Z_DEFAULT_STRATEGY)
-{
-  (gzs.rdbuf ())->setcompression (l, s);
-  return gzs;
-}
-
-// Manipulator constructor stores arguments
-template <typename T1, typename T2>
-inline
-gzomanip2<T1,T2>::gzomanip2 (gzofstream &(*f)(gzofstream &, T1, T2),
-                             T1 v1,
-                             T2 v2)
-  : func(f), val1(v1), val2(v2)
-{ }
-
-// Insertor applies underlying manipulator function to stream
-template <typename T1, typename T2>
-inline gzofstream&
-operator<<(gzofstream& s, const gzomanip2<T1,T2>& m)
-{ return (*m.func)(s, m.val1, m.val2); }
-
-// Insert this onto stream to simplify setting of compression level
-inline gzomanip2<int,int>
-setcompression (int l, int s = Z_DEFAULT_STRATEGY)
-{ return gzomanip2<int,int>(&setcompression, l, s); }
-
-#endif
-
-#endif