diff libinterp/corefcn/load-save.cc @ 31608:23664317f0d3

maint: merge stable to default
author Rik <rik@octave.org>
date Thu, 01 Dec 2022 20:05:44 -0800
parents dfa5d9c3ae72 aac27ad79be6
children 5f11de0e7440
line wrap: on
line diff
--- a/libinterp/corefcn/load-save.cc	Thu Dec 01 14:28:07 2022 -0800
+++ b/libinterp/corefcn/load-save.cc	Thu Dec 01 20:05:44 2022 -0800
@@ -92,1460 +92,1460 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-  OCTAVE_NORETURN static
-  void
-  err_file_open (const std::string& fcn, const std::string& file)
-  {
-    if (fcn == "load")
-      error ("%s: unable to open input file '%s'", fcn.c_str (), file.c_str ());
-    else if (fcn == "save")
-      error ("%s: unable to open output file '%s'", fcn.c_str (), file.c_str ());
-    else
-      error ("%s: unable to open file '%s'", fcn.c_str (), file.c_str ());
-  }
+OCTAVE_NORETURN static
+void
+err_file_open (const std::string& fcn, const std::string& file)
+{
+  if (fcn == "load")
+    error ("%s: unable to open input file '%s'", fcn.c_str (), file.c_str ());
+  else if (fcn == "save")
+    error ("%s: unable to open output file '%s'", fcn.c_str (), file.c_str ());
+  else
+    error ("%s: unable to open file '%s'", fcn.c_str (), file.c_str ());
+}
 
-  // Return TRUE if NAME matches one of the given globbing PATTERNS.
+// Return TRUE if NAME matches one of the given globbing PATTERNS.
 
-  static bool
-  matches_patterns (const string_vector& patterns, int pat_idx,
-                    int num_pat, const std::string& name)
-  {
-    for (int i = pat_idx; i < num_pat; i++)
-      {
-        glob_match pattern (patterns[i]);
+static bool
+matches_patterns (const string_vector& patterns, int pat_idx,
+                  int num_pat, const std::string& name)
+{
+  for (int i = pat_idx; i < num_pat; i++)
+    {
+      glob_match pattern (patterns[i]);
 
-        if (pattern.match (name))
-          return true;
-      }
+      if (pattern.match (name))
+        return true;
+    }
 
-    return false;
-  }
+  return false;
+}
 
-  static int
-  read_binary_file_header (std::istream& is, bool& swap,
-                           mach_info::float_format& flt_fmt,
-                           bool quiet = false)
-  {
-    const int magic_len = 10;
-    char magic[magic_len+1];
-    is.read (magic, magic_len);
-    magic[magic_len] = '\0';
+static int
+read_binary_file_header (std::istream& is, bool& swap,
+                         mach_info::float_format& flt_fmt,
+                         bool quiet = false)
+{
+  const int magic_len = 10;
+  char magic[magic_len+1];
+  is.read (magic, magic_len);
+  magic[magic_len] = '\0';
 
-    if (strncmp (magic, "Octave-1-L", magic_len) == 0)
-      swap = mach_info::words_big_endian ();
-    else if (strncmp (magic, "Octave-1-B", magic_len) == 0)
-      swap = ! mach_info::words_big_endian ();
-    else
-      {
-        if (! quiet)
-          error ("load: unable to read binary file");
+  if (strncmp (magic, "Octave-1-L", magic_len) == 0)
+    swap = mach_info::words_big_endian ();
+  else if (strncmp (magic, "Octave-1-B", magic_len) == 0)
+    swap = ! mach_info::words_big_endian ();
+  else
+    {
+      if (! quiet)
+        error ("load: unable to read binary file");
 
-        return -1;
-      }
+      return -1;
+    }
 
-    char tmp = 0;
-    is.read (&tmp, 1);
+  char tmp = 0;
+  is.read (&tmp, 1);
 
-    flt_fmt = mopt_digit_to_float_format (tmp);
+  flt_fmt = mopt_digit_to_float_format (tmp);
 
-    if (flt_fmt == mach_info::flt_fmt_unknown)
-      {
-        if (! quiet)
-          error ("load: unrecognized binary format!");
+  if (flt_fmt == mach_info::flt_fmt_unknown)
+    {
+      if (! quiet)
+        error ("load: unrecognized binary format!");
 
-        return -1;
-      }
+      return -1;
+    }
 
-    return 0;
-  }
+  return 0;
+}
 
 #if defined (HAVE_ZLIB)
-  static bool
-  check_gzip_magic (const std::string& fname)
-  {
-    bool retval = false;
+static bool
+check_gzip_magic (const std::string& fname)
+{
+  bool retval = false;
 
-    std::ifstream file = sys::ifstream (fname.c_str (),
-                                        std::ios::in | std::ios::binary);
+  std::ifstream file = sys::ifstream (fname.c_str (),
+                                      std::ios::in | std::ios::binary);
 
-    unsigned char magic[2];
-    if (file.read (reinterpret_cast<char *> (&magic[0]), 2)
-        && magic[0] == 0x1f && magic[1] == 0x8b)
-      retval = true;
+  unsigned char magic[2];
+  if (file.read (reinterpret_cast<char *> (&magic[0]), 2)
+      && magic[0] == 0x1f && magic[1] == 0x8b)
+    retval = true;
 
-    file.close ();
+  file.close ();
 
-    return retval;
-  }
+  return retval;
+}
 #endif
 
-  static std::string
-  find_file_to_load (const std::string& name, const std::string& orig_name)
-  {
-    std::string fname = find_data_file_in_load_path ("load", name, true);
+static std::string
+find_file_to_load (const std::string& name, const std::string& orig_name)
+{
+  std::string fname = find_data_file_in_load_path ("load", name, true);
 
-    std::size_t dot_pos = fname.rfind ('.');
-    std::size_t sep_pos = fname.find_last_of (sys::file_ops::dir_sep_chars ());
+  std::size_t dot_pos = fname.rfind ('.');
+  std::size_t sep_pos = fname.find_last_of (sys::file_ops::dir_sep_chars ());
 
-    if (dot_pos == std::string::npos
-        || (sep_pos != std::string::npos && dot_pos < sep_pos))
-      {
-        // Either no '.' in name or no '.' appears after last directory
-        // separator.
+  if (dot_pos == std::string::npos
+      || (sep_pos != std::string::npos && dot_pos < sep_pos))
+    {
+      // Either no '.' in name or no '.' appears after last directory
+      // separator.
 
-        sys::file_stat fs (fname);
+      sys::file_stat fs (fname);
 
-        if (! (fs.exists () && fs.is_reg ()))
-          fname = find_file_to_load (fname + ".mat", orig_name);
-      }
-    else
-      {
-        sys::file_stat fs (fname);
+      if (! (fs.exists () && fs.is_reg ()))
+        fname = find_file_to_load (fname + ".mat", orig_name);
+    }
+  else
+    {
+      sys::file_stat fs (fname);
 
-        if (! (fs.exists () && fs.is_reg ()))
-          {
-            fname = "";
+      if (! (fs.exists () && fs.is_reg ()))
+        {
+          fname = "";
 
-            error ("load: unable to find file %s", orig_name.c_str ());
-          }
-      }
+          error ("load: unable to find file %s", orig_name.c_str ());
+        }
+    }
 
-    return fname;
-  }
+  return fname;
+}
 
-  // Return TRUE if PATTERN has any special globbing chars in it.
+// Return TRUE if PATTERN has any special globbing chars in it.
 
-  static bool
-  glob_pattern_p (const std::string& pattern)
-  {
-    int open = 0;
+static bool
+glob_pattern_p (const std::string& pattern)
+{
+  int open = 0;
 
-    int len = pattern.length ();
+  int len = pattern.length ();
 
-    for (int i = 0; i < len; i++)
-      {
-        char c = pattern[i];
+  for (int i = 0; i < len; i++)
+    {
+      char c = pattern[i];
 
-        switch (c)
-          {
-          case '?':
-          case '*':
-            return true;
+      switch (c)
+        {
+        case '?':
+        case '*':
+          return true;
 
-          case '[':       // Only accept an open brace if there is a close
-            open++;       // brace to match it.  Bracket expressions must be
-            continue;     // complete, according to Posix.2
+        case '[':       // Only accept an open brace if there is a close
+          open++;       // brace to match it.  Bracket expressions must be
+          continue;     // complete, according to Posix.2
 
-          case ']':
-            if (open)
-              return true;
-            continue;
+        case ']':
+          if (open)
+            return true;
+          continue;
 
-          case '\\':
-            if (i == len - 1)
-              return false;
-            continue;
+        case '\\':
+          if (i == len - 1)
+            return false;
+          continue;
 
-          default:
-            continue;
-          }
-      }
+        default:
+          continue;
+        }
+    }
 
-    return false;
-  }
+  return false;
+}
 
-  load_save_system::load_save_system (interpreter& interp)
-    : m_interpreter (interp),
-      m_crash_dumps_octave_core (true),
-      m_octave_core_file_limit (-1.0),
-      m_octave_core_file_name ("octave-workspace"),
-      m_save_default_options ("-text"),
-      m_octave_core_file_options ("-binary"),
-      m_save_header_format_string (init_save_header_format ())
-  {
+load_save_system::load_save_system (interpreter& interp)
+  : m_interpreter (interp),
+    m_crash_dumps_octave_core (true),
+    m_octave_core_file_limit (-1.0),
+    m_octave_core_file_name ("octave-workspace"),
+    m_save_default_options ("-text"),
+    m_octave_core_file_options ("-binary"),
+    m_save_header_format_string (init_save_header_format ())
+{
 #if defined (HAVE_HDF5)
-    H5dont_atexit ();
+  H5dont_atexit ();
 #endif
-  }
+}
 
-  load_save_system::~load_save_system (void)
-  {
+load_save_system::~load_save_system (void)
+{
 #if defined (HAVE_HDF5)
-    H5close ();
+  H5close ();
 #endif
-  }
+}
 
-  octave_value
-  load_save_system::crash_dumps_octave_core (const octave_value_list& args,
-                                             int nargout)
-  {
-    return set_internal_variable (m_crash_dumps_octave_core, args, nargout,
-                                  "crash_dumps_octave_core");
-  }
+octave_value
+load_save_system::crash_dumps_octave_core (const octave_value_list& args,
+    int nargout)
+{
+  return set_internal_variable (m_crash_dumps_octave_core, args, nargout,
+                                "crash_dumps_octave_core");
+}
 
-  octave_value
-  load_save_system::octave_core_file_limit (const octave_value_list& args,
-                                            int nargout)
-  {
-    return set_internal_variable (m_octave_core_file_limit, args, nargout,
-                                  "octave_core_file_limit");
-  }
+octave_value
+load_save_system::octave_core_file_limit (const octave_value_list& args,
+    int nargout)
+{
+  return set_internal_variable (m_octave_core_file_limit, args, nargout,
+                                "octave_core_file_limit");
+}
 
-  octave_value
-  load_save_system::octave_core_file_name (const octave_value_list& args,
-                                           int nargout)
-  {
-    return set_internal_variable (m_octave_core_file_name, args, nargout,
-                                  "octave_core_file_name", false);
-  }
+octave_value
+load_save_system::octave_core_file_name (const octave_value_list& args,
+    int nargout)
+{
+  return set_internal_variable (m_octave_core_file_name, args, nargout,
+                                "octave_core_file_name", false);
+}
 
-  octave_value
-  load_save_system::save_default_options (const octave_value_list& args,
-                                          int nargout)
-  {
-    return set_internal_variable (m_save_default_options, args, nargout,
-                                  "save_default_options", false);
-  }
+octave_value
+load_save_system::save_default_options (const octave_value_list& args,
+                                        int nargout)
+{
+  return set_internal_variable (m_save_default_options, args, nargout,
+                                "save_default_options", false);
+}
 
-  octave_value
-  load_save_system::octave_core_file_options (const octave_value_list& args,
-                                              int nargout)
-  {
-    return set_internal_variable (m_octave_core_file_options, args, nargout,
-                                  "octave_core_file_options", false);
-  }
+octave_value
+load_save_system::octave_core_file_options (const octave_value_list& args,
+    int nargout)
+{
+  return set_internal_variable (m_octave_core_file_options, args, nargout,
+                                "octave_core_file_options", false);
+}
 
-  octave_value
-  load_save_system::save_header_format_string (const octave_value_list& args,
-                                               int nargout)
-  {
-    return set_internal_variable (m_save_header_format_string, args, nargout,
-                                  "save_header_format_string");
-  }
+octave_value
+load_save_system::save_header_format_string (const octave_value_list& args,
+    int nargout)
+{
+  return set_internal_variable (m_save_header_format_string, args, nargout,
+                                "save_header_format_string");
+}
 
-  load_save_format
-  load_save_system::get_file_format (const std::string& fname,
-                                     const std::string& orig_fname,
-                                     bool& use_zlib, bool quiet)
-  {
-    load_save_format retval = UNKNOWN;
+load_save_format
+load_save_system::get_file_format (const std::string& fname,
+                                   const std::string& orig_fname,
+                                   bool& use_zlib, bool quiet)
+{
+  load_save_format retval = UNKNOWN;
 
 #if defined (HAVE_HDF5_UTF8)
-    std::string ascii_fname = fname;
+  std::string ascii_fname = fname;
 #else
-    std::string ascii_fname = sys::get_ASCII_filename (fname);
+  std::string ascii_fname = sys::get_ASCII_filename (fname);
 #endif
 
 #if defined (HAVE_HDF5)
-    // check this before we open the file
-    if (H5Fis_hdf5 (ascii_fname.c_str ()) > 0)
-      return HDF5;
+  // check this before we open the file
+  if (H5Fis_hdf5 (ascii_fname.c_str ()) > 0)
+    return HDF5;
 #endif
 
 #if defined (HAVE_ZLIB)
-    use_zlib = check_gzip_magic (fname);
+  use_zlib = check_gzip_magic (fname);
 #else
-    use_zlib = false;
+  use_zlib = false;
 #endif
 
-    if (! use_zlib)
-      {
-        std::ifstream file = sys::ifstream (fname.c_str (),
-                                            std::ios::in | std::ios::binary);
-        if (file)
-          {
-            retval = get_file_format (file, orig_fname);
-            file.close ();
-          }
-        else if (! quiet)
-          err_file_open ("load", orig_fname);
-      }
+  if (! use_zlib)
+    {
+      std::ifstream file = sys::ifstream (fname.c_str (),
+                                          std::ios::in | std::ios::binary);
+      if (file)
+        {
+          retval = get_file_format (file, orig_fname);
+          file.close ();
+        }
+      else if (! quiet)
+        err_file_open ("load", orig_fname);
+    }
 #if defined (HAVE_ZLIB)
-    else
-      {
-        gzifstream gzfile (fname.c_str (), std::ios::in | std::ios::binary);
-        if (gzfile)
-          {
-            retval = get_file_format (gzfile, orig_fname);
-            gzfile.close ();
-          }
-        else if (! quiet)
-          err_file_open ("load", orig_fname);
-      }
+  else
+    {
+      gzifstream gzfile (fname.c_str (), std::ios::in | std::ios::binary);
+      if (gzfile)
+        {
+          retval = get_file_format (gzfile, orig_fname);
+          gzfile.close ();
+        }
+      else if (! quiet)
+        err_file_open ("load", orig_fname);
+    }
 #endif
 
-    return retval;
-  }
+  return retval;
+}
 
-  octave_value
-  load_save_system::load_vars (std::istream& stream,
-                               const std::string& orig_fname,
-                               const load_save_format& fmt,
-                               mach_info::float_format flt_fmt,
-                               bool list_only, bool swap, bool verbose,
-                               const string_vector& argv, int argv_idx,
-                               int argc, int nargout)
-  {
-    octave_value retval;
+octave_value
+load_save_system::load_vars (std::istream& stream,
+                             const std::string& orig_fname,
+                             const load_save_format& fmt,
+                             mach_info::float_format flt_fmt,
+                             bool list_only, bool swap, bool verbose,
+                             const string_vector& argv, int argv_idx,
+                             int argc, int nargout)
+{
+  octave_value retval;
 
-    octave_scalar_map retstruct;
+  octave_scalar_map retstruct;
 
-    std::ostringstream output_buf;
-    std::list<std::string> symbol_names;
+  std::ostringstream output_buf;
+  std::list<std::string> symbol_names;
 
-    octave_idx_type count = 0;
+  octave_idx_type count = 0;
 
-    for (;;)
-      {
-        bool global = false;
-        octave_value tc;
+  for (;;)
+    {
+      bool global = false;
+      octave_value tc;
 
-        std::string name;
-        std::string doc;
+      std::string name;
+      std::string doc;
 
-        switch (fmt.type ())
-          {
-          case TEXT:
-            name = read_text_data (stream, orig_fname, global, tc, count);
-            break;
+      switch (fmt.type ())
+        {
+        case TEXT:
+          name = read_text_data (stream, orig_fname, global, tc, count);
+          break;
 
-          case BINARY:
-            name = read_binary_data (stream, swap, flt_fmt, orig_fname,
-                                     global, tc, doc);
-            break;
+        case BINARY:
+          name = read_binary_data (stream, swap, flt_fmt, orig_fname,
+                                   global, tc, doc);
+          break;
 
-          case MAT_ASCII:
-            name = read_mat_ascii_data (stream, orig_fname, tc);
-            break;
+        case MAT_ASCII:
+          name = read_mat_ascii_data (stream, orig_fname, tc);
+          break;
 
-          case MAT_BINARY:
-            name = read_mat_binary_data (stream, orig_fname, tc);
-            break;
+        case MAT_BINARY:
+          name = read_mat_binary_data (stream, orig_fname, tc);
+          break;
 
 #if defined (HAVE_HDF5)
-          case HDF5:
-            name = read_hdf5_data (stream, orig_fname, global, tc, doc,
-                                   argv, argv_idx, argc);
-            break;
+        case HDF5:
+          name = read_hdf5_data (stream, orig_fname, global, tc, doc,
+                                 argv, argv_idx, argc);
+          break;
 #endif
 
-          case MAT5_BINARY:
-          case MAT7_BINARY:
-            name = read_mat5_binary_element (stream, orig_fname, swap,
-                                             global, tc);
-            break;
+        case MAT5_BINARY:
+        case MAT7_BINARY:
+          name = read_mat5_binary_element (stream, orig_fname, swap,
+                                           global, tc);
+          break;
 
-          default:
-            err_unrecognized_data_fmt ("load");
-            break;
-          }
-
-        if (stream.eof () || name.empty ())
+        default:
+          err_unrecognized_data_fmt ("load");
           break;
-        else
-          {
-            if (! tc.is_defined ())
-              error ("load: unable to load variable '%s'", name.c_str ());
+        }
 
-            if (fmt.type () == MAT_ASCII && argv_idx < argc)
-              warning ("load: loaded ASCII file '%s' -- ignoring extra args",
-                       orig_fname.c_str ());
+      if (stream.eof () || name.empty ())
+        break;
+      else
+        {
+          if (! tc.is_defined ())
+            error ("load: unable to load variable '%s'", name.c_str ());
 
-            if (fmt.type () == MAT_ASCII
-                || argv_idx == argc
-                || matches_patterns (argv, argv_idx, argc, name))
-              {
-                count++;
-                if (list_only)
-                  {
-                    if (verbose)
-                      {
-                        if (count == 1)
-                          output_buf
+          if (fmt.type () == MAT_ASCII && argv_idx < argc)
+            warning ("load: loaded ASCII file '%s' -- ignoring extra args",
+                     orig_fname.c_str ());
+
+          if (fmt.type () == MAT_ASCII
+              || argv_idx == argc
+              || matches_patterns (argv, argv_idx, argc, name))
+            {
+              count++;
+              if (list_only)
+                {
+                  if (verbose)
+                    {
+                      if (count == 1)
+                        output_buf
                             << "type               rows   cols   name\n"
                             << "====               ====   ====   ====\n";
 
-                        output_buf
+                      output_buf
                           << std::setiosflags (std::ios::left)
                           << std::setw (16) << tc.type_name ().c_str ()
                           << std::setiosflags (std::ios::right)
                           << std::setw (7) << tc.rows ()
                           << std::setw (7) << tc.columns ()
                           << "   " << name << "\n";
-                      }
-                    else
-                      symbol_names.push_back (name);
-                  }
-                else
-                  {
-                    if (nargout == 1)
-                      {
-                        if (fmt.type () == MAT_ASCII)
-                          retval = tc;
-                        else
-                          retstruct.assign (name, tc);
-                      }
-                    else
-                      install_loaded_variable (name, tc, global, doc);
-                  }
-              }
-
-            // Only attempt to read one item from a headless text file.
-
-            if (fmt.type () == MAT_ASCII)
-              break;
-          }
-      }
-
-    if (list_only && count)
-      {
-        if (verbose)
-          {
-            std::string msg = output_buf.str ();
-
-            if (nargout > 0)
-              retval = msg;
-            else
-              octave_stdout << msg;
-          }
-        else
-          {
-            if (nargout  > 0)
-              retval = Cell (string_vector (symbol_names));
-            else
-              {
-                string_vector names (symbol_names);
-
-                names.list_in_columns (octave_stdout);
-
-                octave_stdout << "\n";
-              }
-          }
-      }
-    else if (retstruct.nfields () != 0)
-      retval = retstruct;
-
-    return retval;
-  }
-
-  string_vector
-  load_save_system::parse_save_options (const string_vector& argv,
-                                        load_save_format& fmt, bool& append,
-                                        bool& save_as_floats, bool& use_zlib)
-  {
-#if ! defined (HAVE_ZLIB)
-    octave_unused_parameter (use_zlib);
-#endif
-
-    string_vector retval;
-    int argc = argv.numel ();
-
-    bool do_double = false;
-    bool do_tabs = false;
-
-    for (int i = 0; i < argc; i++)
-      {
-        if (argv[i] == "-append")
-          {
-            append = true;
-          }
-        else if (argv[i] == "-ascii" || argv[i] == "-a")
-          {
-            fmt.set_type (MAT_ASCII);
-          }
-        else if (argv[i] == "-double")
-          {
-            do_double = true;
-          }
-        else if (argv[i] == "-tabs")
-          {
-            do_tabs = true;
-          }
-        else if (argv[i] == "-text" || argv[i] == "-t")
-          {
-            fmt.set_type (TEXT);
-          }
-        else if (argv[i] == "-binary" || argv[i] == "-b")
-          {
-            fmt.set_type (BINARY);
-          }
-        else if (argv[i] == "-hdf5" || argv[i] == "-h")
-          {
-#if defined (HAVE_HDF5)
-            fmt.set_type (HDF5);
-#else
-            err_disabled_feature ("save", "HDF5");
-#endif
-          }
-        else if (argv[i] == "-v7.3" || argv[i] == "-V7.3" || argv[i] == "-7.3")
-          {
-            error ("save: Matlab file format -v7.3 is not yet implemented");
-          }
-#if defined (HAVE_ZLIB)
-        else if (argv[i] == "-v7" || argv[i] == "-V7" || argv[i] == "-7"
-                 || argv[i] == "-mat7-binary")
-          {
-            fmt.set_type (MAT7_BINARY);
-          }
-#endif
-        else if (argv[i] == "-mat" || argv[i] == "-m"
-                 || argv[i] == "-v6" || argv[i] == "-V6" || argv[i] == "-6"
-                 || argv[i] == "-mat-binary")
-          {
-            fmt.set_type (MAT5_BINARY);
-          }
-        else if (argv[i] == "-v4" || argv[i] == "-V4" || argv[i] == "-4"
-                 || argv[i] == "-mat4-binary")
-          {
-            fmt.set_type (MAT_BINARY);
-          }
-        else if (argv[i] == "-float-binary" || argv[i] == "-f")
-          {
-            fmt.set_type (BINARY);
-            save_as_floats = true;
-          }
-        else if (argv[i] == "-float-hdf5")
-          {
-#if defined (HAVE_HDF5)
-            fmt.set_type (HDF5);
-            save_as_floats = true;
-#else
-            err_disabled_feature ("save", "HDF5");
-#endif
-          }
-#if defined (HAVE_ZLIB)
-        else if (argv[i] == "-zip" || argv[i] == "-z")
-          {
-            use_zlib = true;
-          }
-#endif
-        else if (argv[i] == "-struct")
-          {
-            retval.append (argv[i]);
-          }
-        else if (argv[i][0] == '-' && argv[i] != "-")
-          {
-            error ("save: Unrecognized option '%s'", argv[i].c_str ());
-          }
-        else
-          retval.append (argv[i]);
-      }
-
-    if (do_double)
-      {
-        if (fmt.type () == MAT_ASCII)
-          fmt.set_option (MAT_ASCII_LONG);
-        else
-          warning (R"(save: "-double" option only has an effect with "-ascii")");
-      }
-
-    if (do_tabs)
-      {
-        if (fmt.type () == MAT_ASCII)
-          fmt.set_option (MAT_ASCII_TABS);
-        else
-          warning (R"(save: "-tabs" option only has an effect with "-ascii")");
-      }
-
-    if (append && use_zlib
-        && (fmt.type () != TEXT && fmt.type () != MAT_ASCII))
-      error ("save: -append and -zip options can only be used together with a text format (-text or -ascii)");
-
-    return retval;
-  }
-
-  string_vector
-  load_save_system::parse_save_options (const std::string& arg,
-                                        load_save_format& fmt,
-                                        bool& append, bool& save_as_floats,
-                                        bool& use_zlib)
-  {
-    std::istringstream is (arg);
-    std::string str;
-    string_vector argv;
-
-    while (! is.eof ())
-      {
-        is >> str;
-        argv.append (str);
-      }
-
-    return parse_save_options (argv, fmt, append, save_as_floats, use_zlib);
-  }
-
-  void load_save_system::save_vars (const string_vector& argv, int argv_idx,
-                                    int argc, std::ostream& os,
-                                    const load_save_format& fmt,
-                                    bool save_as_floats,
-                                    bool write_header_info)
-  {
-    if (write_header_info)
-      write_header (os, fmt);
-
-    if (argv_idx == argc)
-      {
-        save_vars (os, "*", fmt, save_as_floats);
-      }
-    else if (argv[argv_idx] == "-struct")
-      {
-        if (++argv_idx >= argc)
-          error ("save: missing struct name");
-
-        std::string struct_name = argv[argv_idx];
-
-        if (! m_interpreter.is_variable (struct_name))
-          error ("save: no such variable: '%s'", struct_name.c_str ());
-
-        octave_value struct_var = m_interpreter.varval (struct_name);
-
-        if (! struct_var.isstruct () || struct_var.numel () != 1)
-          error ("save: '%s' is not a scalar structure", struct_name.c_str ());
-
-        octave_scalar_map struct_var_map = struct_var.scalar_map_value ();
-
-        ++argv_idx;
-
-        if (argv_idx < argc)
-          {
-            for (int i = argv_idx; i < argc; i++)
-              {
-                if (! save_fields (os, struct_var_map, argv[i], fmt,
-                                   save_as_floats))
-                  {
-                    warning ("save: no such field '%s.%s'",
-                             struct_name.c_str (), argv[i].c_str ());
-                  }
-              }
-          }
-        else
-          save_fields (os, struct_var_map, "*", fmt, save_as_floats);
-      }
-    else
-      {
-        for (int i = argv_idx; i < argc; i++)
-          {
-            if (argv[i] == "")
-              continue;  // Skip empty vars for Matlab compatibility
-            if (! save_vars (os, argv[i], fmt, save_as_floats))
-              warning ("save: no such variable '%s'", argv[i].c_str ());
-          }
-      }
-  }
-
-  void load_save_system::dump_octave_core (void)
-  {
-    if (m_crash_dumps_octave_core)
-      {
-        // FIXME: should choose better filename?
-
-        const char *fname = m_octave_core_file_name.c_str ();
-
-        message (nullptr, "attempting to save variables to '%s'...", fname);
-
-        load_save_format fmt (BINARY);
-
-        bool save_as_floats = false;
-
-        bool append = false;
-
-        bool use_zlib = false;
-
-        load_save_system::parse_save_options (m_octave_core_file_options,
-                                              fmt, append, save_as_floats,
-                                              use_zlib);
-
-        std::ios::openmode mode = std::ios::out;
-
-        // Matlab v7 files are always compressed
-        if (fmt.type () == MAT7_BINARY)
-          use_zlib = false;
-
-        if (fmt.type () == BINARY
-#if defined (HAVE_HDF5)
-            || fmt.type () == HDF5
-#endif
-            || fmt.type () == MAT_BINARY
-            || fmt.type () == MAT5_BINARY
-            || fmt.type () == MAT7_BINARY)
-          mode |= std::ios::binary;
-
-        mode |= append ? std::ios::ate : std::ios::trunc;
-
-#if defined (HAVE_HDF5)
-        if (fmt.type () == HDF5)
-          {
-            hdf5_ofstream file (fname, mode);
-
-            if (file.file_id >= 0)
-              {
-                dump_octave_core (file, fname, fmt, save_as_floats);
-
-                file.close ();
-              }
-            else
-              warning ("dump_octave_core: unable to open '%s' for writing...",
-                       fname);
-          }
-        else
-#endif
-          // don't insert any commands here!  The open brace below must
-          // go with the else above!
-          {
-#if defined (HAVE_ZLIB)
-            if (use_zlib)
-              {
-                gzofstream file (fname, mode);
-
-                if (file)
-                  {
-                    dump_octave_core (file, fname, fmt, save_as_floats);
-
-                    file.close ();
-                  }
-                else
-                  warning ("dump_octave_core: unable to open '%s' for writing...",
-                           fname);
-              }
-            else
-#endif
-              {
-                std::ofstream file = sys::ofstream (fname, mode);
-
-                if (file)
-                  {
-                    dump_octave_core (file, fname, fmt, save_as_floats);
-
-                    file.close ();
-                  }
-                else
-                  warning ("dump_octave_core: unable to open '%s' for writing...",
-                           fname);
-              }
-          }
-      }
-  }
-
-  void load_save_system::write_header (std::ostream& os,
-                                       const load_save_format& fmt)
-  {
-    switch (fmt.type ())
-      {
-      case BINARY:
-        {
-          os << (mach_info::words_big_endian ()
-                 ? "Octave-1-B" : "Octave-1-L");
-
-          mach_info::float_format flt_fmt = mach_info::native_float_format ();
-
-          char tmp = static_cast<char> (float_format_to_mopt_digit (flt_fmt));
-
-          os.write (&tmp, 1);
-        }
-        break;
-
-      case MAT5_BINARY:
-      case MAT7_BINARY:
-        {
-          char const *versionmagic;
-          char headertext[128];
-          sys::gmtime now;
-
-          // ISO 8601 format date
-          const char *matlab_format = "MATLAB 5.0 MAT-file, written by Octave "
-                                      OCTAVE_VERSION ", %Y-%m-%d %T UTC";
-          std::string comment_string = now.strftime (matlab_format);
-
-          std::size_t len = std::min (comment_string.length (),
-                                      static_cast<std::size_t> (124));
-          memset (headertext, ' ', 124);
-          memcpy (headertext, comment_string.data (), len);
-
-          // The first pair of bytes give the version of the MAT file
-          // format.  The second pair of bytes form a magic number which
-          // signals a MAT file.  MAT file data are always written in
-          // native byte order.  The order of the bytes in the second
-          // pair indicates whether the file was written by a big- or
-          // little-endian machine.  However, the version number is
-          // written in the *opposite* byte order from everything else!
-          if (mach_info::words_big_endian ())
-            versionmagic = "\x01\x00\x4d\x49"; // this machine is big endian
-          else
-            versionmagic = "\x00\x01\x49\x4d"; // this machine is little endian
-
-          memcpy (headertext+124, versionmagic, 4);
-          os.write (headertext, 128);
-        }
-
-        break;
-
-#if defined (HAVE_HDF5)
-      case HDF5:
-#endif
-      case TEXT:
-        {
-          sys::localtime now;
-
-          std::string comment_string = now.strftime (m_save_header_format_string);
-
-          if (! comment_string.empty ())
-            {
-#if defined (HAVE_HDF5)
-              if (fmt.type () == HDF5)
-                {
-                  hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
-                  H5Gset_comment (hs.file_id, "/", comment_string.c_str ());
+                    }
+                  else
+                    symbol_names.push_back (name);
                 }
               else
-#endif
-                os << comment_string << "\n";
+                {
+                  if (nargout == 1)
+                    {
+                      if (fmt.type () == MAT_ASCII)
+                        retval = tc;
+                      else
+                        retstruct.assign (name, tc);
+                    }
+                  else
+                    install_loaded_variable (name, tc, global, doc);
+                }
+            }
+
+          // Only attempt to read one item from a headless text file.
+
+          if (fmt.type () == MAT_ASCII)
+            break;
+        }
+    }
+
+  if (list_only && count)
+    {
+      if (verbose)
+        {
+          std::string msg = output_buf.str ();
+
+          if (nargout > 0)
+            retval = msg;
+          else
+            octave_stdout << msg;
+        }
+      else
+        {
+          if (nargout  > 0)
+            retval = Cell (string_vector (symbol_names));
+          else
+            {
+              string_vector names (symbol_names);
+
+              names.list_in_columns (octave_stdout);
+
+              octave_stdout << "\n";
             }
         }
-        break;
-
-      default:
-        break;
-      }
-  }
-
-  // Save variables with names matching PATTERN on stream OS in the
-  // format specified by FMT.
+    }
+  else if (retstruct.nfields () != 0)
+    retval = retstruct;
 
-  std::size_t load_save_system::save_vars (std::ostream& os,
-                                           const std::string& pattern,
-                                           const load_save_format& fmt,
-                                           bool save_as_floats)
-  {
-    tree_evaluator& tw = m_interpreter.get_evaluator ();
-
-    symbol_info_list syminfo_list = tw.glob_symbol_info (pattern);
-
-    std::size_t saved = 0;
-
-    for (const auto& syminfo : syminfo_list)
-      {
-        do_save (os, syminfo, fmt, save_as_floats);
-
-        saved++;
-      }
-
-    return saved;
-  }
+  return retval;
+}
 
-  void load_save_system::do_save (std::ostream& os, const octave_value& tc,
-                                  const std::string& name,
-                                  const std::string& help,
-                                  bool global, const load_save_format& fmt,
-                                  bool save_as_floats)
-  {
-    switch (fmt.type ())
-      {
-      case TEXT:
-        save_text_data (os, tc, name, global, 0);
-        break;
-
-      case BINARY:
-        save_binary_data (os, tc, name, help, global, save_as_floats);
-        break;
-
-      case MAT_ASCII:
-        if (! save_mat_ascii_data (os, tc,
-                                   fmt.options () & MAT_ASCII_LONG ? 16 : 8,
-                                   fmt.options () & MAT_ASCII_TABS))
-          warning ("save: unable to save %s in ASCII format", name.c_str ());
-        break;
-
-      case MAT_BINARY:
-        save_mat_binary_data (os, tc, name);
-        break;
-
-#if defined (HAVE_HDF5)
-      case HDF5:
-        save_hdf5_data (os, tc, name, help, global, save_as_floats);
-        break;
+string_vector
+load_save_system::parse_save_options (const string_vector& argv,
+                                      load_save_format& fmt, bool& append,
+                                      bool& save_as_floats, bool& use_zlib)
+{
+#if ! defined (HAVE_ZLIB)
+  octave_unused_parameter (use_zlib);
 #endif
 
-      case MAT5_BINARY:
-        save_mat5_binary_element (os, tc, name, global, false, save_as_floats);
-        break;
-
-      case MAT7_BINARY:
-        save_mat5_binary_element (os, tc, name, global, true, save_as_floats);
-        break;
-
-      default:
-        err_unrecognized_data_fmt ("save");
-        break;
-      }
-  }
-
-  // Save the info from SR on stream OS in the format specified by FMT.
+  string_vector retval;
+  int argc = argv.numel ();
 
-  void load_save_system::do_save (std::ostream& os,
-                                  const symbol_info& syminfo,
-                                  const load_save_format& fmt,
-                                  bool save_as_floats)
-  {
-    octave_value val = syminfo.value ();
-
-    if (val.is_defined ())
-      {
-        std::string name = syminfo.name ();
-        std::string help;
-        bool global = syminfo.is_global ();
-
-        do_save (os, val, name, help, global, fmt, save_as_floats);
-      }
-  }
+  bool do_double = false;
+  bool do_tabs = false;
 
-  // save fields of a scalar structure STR matching PATTERN on stream OS
-  // in the format specified by FMT.
-
-  std::size_t load_save_system::save_fields (std::ostream& os,
-                                             const octave_scalar_map& m,
-                                             const std::string& pattern,
-                                             const load_save_format& fmt,
-                                             bool save_as_floats)
-  {
-    glob_match pat (pattern);
-
-    std::size_t saved = 0;
-
-    for (auto it = m.begin (); it != m.end (); it++)
-      {
-        std::string empty_str;
+  for (int i = 0; i < argc; i++)
+    {
+      if (argv[i] == "-append")
+        {
+          append = true;
+        }
+      else if (argv[i] == "-ascii" || argv[i] == "-a")
+        {
+          fmt.set_type (MAT_ASCII);
+        }
+      else if (argv[i] == "-double")
+        {
+          do_double = true;
+        }
+      else if (argv[i] == "-tabs")
+        {
+          do_tabs = true;
+        }
+      else if (argv[i] == "-text" || argv[i] == "-t")
+        {
+          fmt.set_type (TEXT);
+        }
+      else if (argv[i] == "-binary" || argv[i] == "-b")
+        {
+          fmt.set_type (BINARY);
+        }
+      else if (argv[i] == "-hdf5" || argv[i] == "-h")
+        {
+#if defined (HAVE_HDF5)
+          fmt.set_type (HDF5);
+#else
+          err_disabled_feature ("save", "HDF5");
+#endif
+        }
+      else if (argv[i] == "-v7.3" || argv[i] == "-V7.3" || argv[i] == "-7.3")
+        {
+          error ("save: Matlab file format -v7.3 is not yet implemented");
+        }
+#if defined (HAVE_ZLIB)
+      else if (argv[i] == "-v7" || argv[i] == "-V7" || argv[i] == "-7"
+               || argv[i] == "-mat7-binary")
+        {
+          fmt.set_type (MAT7_BINARY);
+        }
+#endif
+      else if (argv[i] == "-mat" || argv[i] == "-m"
+               || argv[i] == "-v6" || argv[i] == "-V6" || argv[i] == "-6"
+               || argv[i] == "-mat-binary")
+        {
+          fmt.set_type (MAT5_BINARY);
+        }
+      else if (argv[i] == "-v4" || argv[i] == "-V4" || argv[i] == "-4"
+               || argv[i] == "-mat4-binary")
+        {
+          fmt.set_type (MAT_BINARY);
+        }
+      else if (argv[i] == "-float-binary" || argv[i] == "-f")
+        {
+          fmt.set_type (BINARY);
+          save_as_floats = true;
+        }
+      else if (argv[i] == "-float-hdf5")
+        {
+#if defined (HAVE_HDF5)
+          fmt.set_type (HDF5);
+          save_as_floats = true;
+#else
+          err_disabled_feature ("save", "HDF5");
+#endif
+        }
+#if defined (HAVE_ZLIB)
+      else if (argv[i] == "-zip" || argv[i] == "-z")
+        {
+          use_zlib = true;
+        }
+#endif
+      else if (argv[i] == "-struct")
+        {
+          retval.append (argv[i]);
+        }
+      else if (argv[i][0] == '-' && argv[i] != "-")
+        {
+          error ("save: Unrecognized option '%s'", argv[i].c_str ());
+        }
+      else
+        retval.append (argv[i]);
+    }
 
-        if (pat.match (m.key (it)))
-          {
-            do_save (os, m.contents (it), m.key (it), empty_str,
-                     0, fmt, save_as_floats);
+  if (do_double)
+    {
+      if (fmt.type () == MAT_ASCII)
+        fmt.set_option (MAT_ASCII_LONG);
+      else
+        warning (R"(save: "-double" option only has an effect with "-ascii")");
+    }
 
-            saved++;
-          }
-      }
+  if (do_tabs)
+    {
+      if (fmt.type () == MAT_ASCII)
+        fmt.set_option (MAT_ASCII_TABS);
+      else
+        warning (R"(save: "-tabs" option only has an effect with "-ascii")");
+    }
+
+  if (append && use_zlib
+      && (fmt.type () != TEXT && fmt.type () != MAT_ASCII))
+    error ("save: -append and -zip options can only be used together with a text format (-text or -ascii)");
+
+  return retval;
+}
 
-    return saved;
-  }
+string_vector
+load_save_system::parse_save_options (const std::string& arg,
+                                      load_save_format& fmt,
+                                      bool& append, bool& save_as_floats,
+                                      bool& use_zlib)
+{
+  std::istringstream is (arg);
+  std::string str;
+  string_vector argv;
 
-  void load_save_system::dump_octave_core (std::ostream& os,
-                                           const char *fname,
-                                           const load_save_format& fmt,
-                                           bool save_as_floats)
-  {
+  while (! is.eof ())
+    {
+      is >> str;
+      argv.append (str);
+    }
+
+  return parse_save_options (argv, fmt, append, save_as_floats, use_zlib);
+}
+
+void load_save_system::save_vars (const string_vector& argv, int argv_idx,
+                                  int argc, std::ostream& os,
+                                  const load_save_format& fmt,
+                                  bool save_as_floats,
+                                  bool write_header_info)
+{
+  if (write_header_info)
     write_header (os, fmt);
 
-    tree_evaluator& tw = m_interpreter.get_evaluator ();
-
-    symbol_info_list syminfo_list = tw.top_scope_symbol_info ();
-
-    double save_mem_size = 0;
-
-    for (const auto& syminfo : syminfo_list)
-      {
-        octave_value val = syminfo.value ();
-
-        std::string name = syminfo.name ();
-        std::string help;
-        bool global = syminfo.is_global ();
-
-        double val_size = val.byte_size () / 1024;
-
-        // FIXME: maybe we should try to throw out the largest first...
-
-        if (m_octave_core_file_limit < 0
-            || save_mem_size + val_size < m_octave_core_file_limit)
-          {
-            save_mem_size += val_size;
+  if (argv_idx == argc)
+    {
+      save_vars (os, "*", fmt, save_as_floats);
+    }
+  else if (argv[argv_idx] == "-struct")
+    {
+      if (++argv_idx >= argc)
+        error ("save: missing struct name");
 
-            do_save (os, val, name, help, global, fmt, save_as_floats);
-          }
-      }
-
-    message (nullptr, "save to '%s' complete", fname);
-  }
-
-  // Install a variable with name NAME and the value VAL in the
-  // symbol table.  If GLOBAL is TRUE, make the variable global.
-
-  void load_save_system::install_loaded_variable (const std::string& name,
-                                                  const octave_value& val,
-                                                  bool global,
-                                                  const std::string& /*doc*/)
-  {
-    m_interpreter.install_variable (name, val, global);
-  }
-
-  std::string load_save_system::init_save_header_format (void)
-  {
-    return
-      (std::string ("# Created by Octave " OCTAVE_VERSION
-                    ", %a %b %d %H:%M:%S %Y %Z <")
-       + sys::env::get_user_name ()
-       + '@'
-       + sys::env::get_host_name ()
-       + '>');
-  }
+      std::string struct_name = argv[argv_idx];
 
-  load_save_format
-  load_save_system::get_file_format (std::istream& file,
-                                     const std::string& filename)
-  {
-    load_save_format retval = load_save_system::UNKNOWN;
-
-    mach_info::float_format flt_fmt
-      = mach_info::flt_fmt_unknown;
-
-    bool swap = false;
+      if (! m_interpreter.is_variable (struct_name))
+        error ("save: no such variable: '%s'", struct_name.c_str ());
 
-    if (read_binary_file_header (file, swap, flt_fmt, true) == 0)
-      retval = BINARY;
-    else
-      {
-        file.clear ();
-        file.seekg (0, std::ios::beg);
-
-        int32_t mopt, nr, nc, imag, len;
-
-        int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len,
-                                        true);
-
-        if (! err)
-          retval = MAT_BINARY;
-        else
-          {
-            file.clear ();
-            file.seekg (0, std::ios::beg);
+      octave_value struct_var = m_interpreter.varval (struct_name);
 
-            err = read_mat5_binary_file_header (file, swap, true, filename);
-
-            if (! err)
-              {
-                file.clear ();
-                file.seekg (0, std::ios::beg);
-                retval = MAT5_BINARY;
-              }
-            else
-              {
-                file.clear ();
-                file.seekg (0, std::ios::beg);
+      if (! struct_var.isstruct () || struct_var.numel () != 1)
+        error ("save: '%s' is not a scalar structure", struct_name.c_str ());
 
-                std::string name_val = extract_keyword (file, "name");
-                std::string type_val = extract_keyword (file, "type");
+      octave_scalar_map struct_var_map = struct_var.scalar_map_value ();
 
-                if (name_val.empty () != true && type_val.empty () != true)
-                  retval = TEXT;
-                else
-                  {
-                    file.clear ();
-                    file.seekg (0, std::ios::beg);
-
-                    // FIXME: looks_like_mat_ascii_file does not check
-                    // to see whether the file contains numbers.  It
-                    // just skips comments and checks for the same
-                    // number of words on each line.  We may need a
-                    // better check here.  The best way to do that might
-                    // be just to try to read the file and see if it
-                    // works.
+      ++argv_idx;
 
-                    if (looks_like_mat_ascii_file (file, filename))
-                      retval = MAT_ASCII;
-                  }
-              }
-          }
-      }
-
-    return retval;
-  }
-
-  octave_value_list
-  load_save_system::load (const octave_value_list& args, int nargout)
-  {
-    octave_value_list retval;
-
-    int argc = args.length () + 1;
-
-    string_vector argv = args.make_argv ("load");
-
-    int i = 1;
-    std::string orig_fname = "";
+      if (argv_idx < argc)
+        {
+          for (int i = argv_idx; i < argc; i++)
+            {
+              if (! save_fields (os, struct_var_map, argv[i], fmt,
+                                 save_as_floats))
+                {
+                  warning ("save: no such field '%s.%s'",
+                           struct_name.c_str (), argv[i].c_str ());
+                }
+            }
+        }
+      else
+        save_fields (os, struct_var_map, "*", fmt, save_as_floats);
+    }
+  else
+    {
+      for (int i = argv_idx; i < argc; i++)
+        {
+          if (argv[i] == "")
+            continue;  // Skip empty vars for Matlab compatibility
+          if (! save_vars (os, argv[i], fmt, save_as_floats))
+            warning ("save: no such variable '%s'", argv[i].c_str ());
+        }
+    }
+}
 
-    // Function called with Matlab-style ["filename", options] syntax
-    if (argc > 1 && ! argv[1].empty () && argv[1].at (0) != '-')
-      {
-        orig_fname = argv[1];
-        i++;
-      }
+void load_save_system::dump_octave_core (void)
+{
+  if (m_crash_dumps_octave_core)
+    {
+      // FIXME: should choose better filename?
+
+      const char *fname = m_octave_core_file_name.c_str ();
 
-    // It isn't necessary to have the default load format stored in a
-    // user preference variable since we can determine the type of file
-    // as we are reading.
+      message (nullptr, "attempting to save variables to '%s'...", fname);
+
+      load_save_format fmt (BINARY);
 
-    load_save_format format = UNKNOWN;
+      bool save_as_floats = false;
 
-    bool list_only = false;
-    bool verbose = false;
+      bool append = false;
 
-    for (; i < argc; i++)
-      {
-        if (argv[i] == "-text" || argv[i] == "-t")
-          {
-            format = TEXT;
-          }
-        else if (argv[i] == "-binary" || argv[i] == "-b")
-          {
-            format = BINARY;
-          }
-        else if (argv[i] == "-hdf5" || argv[i] == "-h")
-          {
+      bool use_zlib = false;
+
+      load_save_system::parse_save_options (m_octave_core_file_options,
+                                            fmt, append, save_as_floats,
+                                            use_zlib);
+
+      std::ios::openmode mode = std::ios::out;
+
+      // Matlab v7 files are always compressed
+      if (fmt.type () == MAT7_BINARY)
+        use_zlib = false;
+
+      if (fmt.type () == BINARY
 #if defined (HAVE_HDF5)
-            format = HDF5;
-#else
-            err_disabled_feature ("load", "HDF5");
+          || fmt.type () == HDF5
 #endif
-          }
-        else if (argv[i] == "-ascii" || argv[i] == "-a")
-          {
-            format = MAT_ASCII;
-          }
-        else if (argv[i] == "-v7.3" || argv[i] == "-V7.3" || argv[i] == "-7.3")
-          {
-            error ("load: Matlab file format -v7.3 is not yet implemented");
-          }
-        else if (argv[i] == "-v7" || argv[i] == "-V7" || argv[i] == "-7"
-                 || argv[i] == "-mat7-binary")
-          {
-            format = MAT7_BINARY;
-          }
-        else if (argv[i] == "-mat" || argv[i] == "-m"
-                 || argv[i] == "-v6" || argv[i] == "-V6" || argv[i] == "-6"
-                 || argv[i] == "-mat-binary")
-          {
-            format = MAT5_BINARY;
-          }
-        else if (argv[i] == "-v4" || argv[i] == "-V4" || argv[i] == "-4"
-                 || argv[i] == "-mat4-binary")
-          {
-            format = MAT_BINARY;
-          }
-        else if (argv[i] == "-force" || argv[i] == "-f")
-          {
-            // Silently ignore this
-            // warning ("load: -force ignored");
-          }
-        else if (argv[i] == "-import" || argv[i] == "-i")
-          {
-            warning ("load: -import ignored");
-          }
-        else if (argv[i] == "-list" || argv[i] == "-l")
-          {
-            list_only = true;
-          }
-        else if (argv[i] == "-verbose" || argv[i] == "-v")
-          {
-            verbose = true;
-          }
-        else
-          break;
-      }
+          || fmt.type () == MAT_BINARY
+          || fmt.type () == MAT5_BINARY
+          || fmt.type () == MAT7_BINARY)
+        mode |= std::ios::binary;
 
-    if (orig_fname == "")
-      {
-        if (i == argc)
-          print_usage ();
-
-        orig_fname = argv[i];
-      }
-    else
-      i--;
-
-    mach_info::float_format flt_fmt = mach_info::flt_fmt_unknown;
-
-    bool swap = false;
-
-    if (orig_fname == "-")
-      {
-        i++;
+      mode |= append ? std::ios::ate : std::ios::trunc;
 
 #if defined (HAVE_HDF5)
-        if (format.type () == HDF5)
-          error ("load: cannot read HDF5 format from stdin");
-        else
-#endif
-          if (format.type () != UNKNOWN)
+      if (fmt.type () == HDF5)
+        {
+          hdf5_ofstream file (fname, mode);
+
+          if (file.file_id >= 0)
             {
-              // FIXME: if we have already seen EOF on a previous call,
-              // how do we fix up the state of std::cin so that we can get
-              // additional input?  I'm afraid that we can't fix this
-              // using std::cin only.
+              dump_octave_core (file, fname, fmt, save_as_floats);
 
-              retval = load_vars (std::cin, orig_fname, format, flt_fmt,
-                                  list_only, swap, verbose, argv, i,
-                                  argc, nargout);
+              file.close ();
             }
           else
-            error ("load: must specify file format if reading from stdin");
-      }
-    else
-      {
-        std::string fname = sys::file_ops::tilde_expand (orig_fname);
-
-        fname = find_file_to_load (fname, orig_fname);
-
-        bool use_zlib = false;
-
-        if (format.type () == UNKNOWN)
-          format = get_file_format (fname, orig_fname, use_zlib);
-
-#if defined (HAVE_HDF5)
-        if (format.type () == HDF5)
-          {
-            i++;
-
-            hdf5_ifstream hdf5_file (fname.c_str ());
-
-            if (hdf5_file.file_id < 0)
-              err_file_open ("load", orig_fname);
-
-            retval = load_vars (hdf5_file, orig_fname, format, flt_fmt,
-                                list_only, swap, verbose, argv, i,
-                                argc, nargout);
-
-            hdf5_file.close ();
-          }
-        else
+            warning ("dump_octave_core: unable to open '%s' for writing...",
+                     fname);
+        }
+      else
 #endif
-          // don't insert any statements here; the "else" above has to
-          // go with the "if" below!!!!!
-          if (format.type () != UNKNOWN)
+        // don't insert any commands here!  The open brace below must
+        // go with the else above!
+        {
+#if defined (HAVE_ZLIB)
+          if (use_zlib)
             {
-              i++;
-
-              // Always open in binary mode and handle various
-              // line-endings explicitly.
-              std::ios::openmode mode = std::ios::in | std::ios::binary;
+              gzofstream file (fname, mode);
 
-#if defined (HAVE_ZLIB)
-              if (use_zlib)
+              if (file)
                 {
-                  gzifstream file (fname.c_str (), mode);
-
-                  if (! file)
-                    err_file_open ("load", orig_fname);
+                  dump_octave_core (file, fname, fmt, save_as_floats);
 
-                  if (format.type () == BINARY)
-                    {
-                      if (read_binary_file_header (file, swap, flt_fmt) < 0)
-                        {
-                          if (file) file.close ();
-                          return retval;
-                        }
-                    }
-                  else if (format.type () == MAT5_BINARY
-                           || format.type () == MAT7_BINARY)
-                    {
-                      if (read_mat5_binary_file_header (file, swap, false,
-                                                        orig_fname) < 0)
-                        {
-                          if (file) file.close ();
-                          return retval;
-                        }
-                    }
+                  file.close ();
+                }
+              else
+                warning ("dump_octave_core: unable to open '%s' for writing...",
+                         fname);
+            }
+          else
+#endif
+            {
+              std::ofstream file = sys::ofstream (fname, mode);
 
-                  retval = load_vars (file, orig_fname, format, flt_fmt,
-                                      list_only, swap, verbose, argv, i,
-                                      argc, nargout);
+              if (file)
+                {
+                  dump_octave_core (file, fname, fmt, save_as_floats);
 
                   file.close ();
                 }
               else
-#endif
-                {
-                  std::ifstream file = sys::ifstream (fname.c_str (), mode);
+                warning ("dump_octave_core: unable to open '%s' for writing...",
+                         fname);
+            }
+        }
+    }
+}
 
-                  if (! file)
-                    error ("load: unable to open input file '%s'",
-                           orig_fname.c_str ());
+void load_save_system::write_header (std::ostream& os,
+                                     const load_save_format& fmt)
+{
+  switch (fmt.type ())
+    {
+    case BINARY:
+      {
+        os << (mach_info::words_big_endian ()
+               ? "Octave-1-B" : "Octave-1-L");
+
+        mach_info::float_format flt_fmt = mach_info::native_float_format ();
+
+        char tmp = static_cast<char> (float_format_to_mopt_digit (flt_fmt));
+
+        os.write (&tmp, 1);
+      }
+      break;
 
-                  if (format.type () == BINARY)
-                    {
-                      if (read_binary_file_header (file, swap, flt_fmt) < 0)
-                        {
-                          if (file) file.close ();
-                          return retval;
-                        }
-                    }
-                  else if (format.type () == MAT5_BINARY
-                           || format.type () == MAT7_BINARY)
-                    {
-                      if (read_mat5_binary_file_header (file, swap, false,
-                                                        orig_fname) < 0)
-                        {
-                          if (file) file.close ();
-                          return retval;
-                        }
-                    }
+    case MAT5_BINARY:
+    case MAT7_BINARY:
+      {
+        char const *versionmagic;
+        char headertext[128];
+        sys::gmtime now;
+
+        // ISO 8601 format date
+        const char *matlab_format = "MATLAB 5.0 MAT-file, written by Octave "
+                                    OCTAVE_VERSION ", %Y-%m-%d %T UTC";
+        std::string comment_string = now.strftime (matlab_format);
 
-                  retval = load_vars (file, orig_fname, format, flt_fmt,
-                                      list_only, swap, verbose, argv, i,
-                                      argc, nargout);
+        std::size_t len = std::min (comment_string.length (),
+                                    static_cast<std::size_t> (124));
+        memset (headertext, ' ', 124);
+        memcpy (headertext, comment_string.data (), len);
 
-                  file.close ();
-                }
-            }
-          else
-            error ("load: unable to determine file format of '%s'",
-                   orig_fname.c_str ());
+        // The first pair of bytes give the version of the MAT file
+        // format.  The second pair of bytes form a magic number which
+        // signals a MAT file.  MAT file data are always written in
+        // native byte order.  The order of the bytes in the second
+        // pair indicates whether the file was written by a big- or
+        // little-endian machine.  However, the version number is
+        // written in the *opposite* byte order from everything else!
+        if (mach_info::words_big_endian ())
+          versionmagic = "\x01\x00\x4d\x49"; // this machine is big endian
+        else
+          versionmagic = "\x00\x01\x49\x4d"; // this machine is little endian
 
+        memcpy (headertext+124, versionmagic, 4);
+        os.write (headertext, 128);
       }
 
-    return retval;
-  }
+      break;
+
+#if defined (HAVE_HDF5)
+    case HDF5:
+#endif
+    case TEXT:
+      {
+        sys::localtime now;
+
+        std::string comment_string = now.strftime (m_save_header_format_string);
 
-  octave_value_list
-  load_save_system::save (const octave_value_list& args, int nargout)
-  {
-    // Here is where we would get the default save format if it were
-    // stored in a user preference variable.
-    load_save_format format = TEXT;
-    bool save_as_floats = false;
-    bool append = false;
-    bool use_zlib = false;
+        if (! comment_string.empty ())
+          {
+#if defined (HAVE_HDF5)
+            if (fmt.type () == HDF5)
+              {
+                hdf5_ofstream& hs = dynamic_cast<hdf5_ofstream&> (os);
+                H5Gset_comment (hs.file_id, "/", comment_string.c_str ());
+              }
+            else
+#endif
+              os << comment_string << "\n";
+          }
+      }
+      break;
 
+    default:
+      break;
+    }
+}
 
-    // get default options
-    parse_save_options (save_default_options (), format, append,
-                        save_as_floats, use_zlib);
+// Save variables with names matching PATTERN on stream OS in the
+// format specified by FMT.
+
+std::size_t load_save_system::save_vars (std::ostream& os,
+    const std::string& pattern,
+    const load_save_format& fmt,
+    bool save_as_floats)
+{
+  tree_evaluator& tw = m_interpreter.get_evaluator ();
 
-    // override from command line
-    string_vector argv = args.make_argv ();
+  symbol_info_list syminfo_list = tw.glob_symbol_info (pattern);
+
+  std::size_t saved = 0;
 
-    argv = parse_save_options (argv, format, append, save_as_floats, use_zlib);
+  for (const auto& syminfo : syminfo_list)
+    {
+      do_save (os, syminfo, fmt, save_as_floats);
 
-    int argc = argv.numel ();
-    int i = 0;
+      saved++;
+    }
+
+  return saved;
+}
 
-    if (i == argc)
-      print_usage ();
-
-    if (save_as_floats && format.type () == TEXT)
-      error ("save: cannot specify both -text and -float-binary");
+void load_save_system::do_save (std::ostream& os, const octave_value& tc,
+                                const std::string& name,
+                                const std::string& help,
+                                bool global, const load_save_format& fmt,
+                                bool save_as_floats)
+{
+  switch (fmt.type ())
+    {
+    case TEXT:
+      save_text_data (os, tc, name, global, 0);
+      break;
 
-    octave_value_list retval;
+    case BINARY:
+      save_binary_data (os, tc, name, help, global, save_as_floats);
+      break;
 
-    if (argv[i] == "-")
-      {
-        i++;
+    case MAT_ASCII:
+      if (! save_mat_ascii_data (os, tc,
+                                 fmt.options () & MAT_ASCII_LONG ? 16 : 8,
+                                 fmt.options () & MAT_ASCII_TABS))
+        warning ("save: unable to save %s in ASCII format", name.c_str ());
+      break;
+
+    case MAT_BINARY:
+      save_mat_binary_data (os, tc, name);
+      break;
 
 #if defined (HAVE_HDF5)
-        if (format.type () == HDF5)
-          error ("save: cannot write HDF5 format to stdout");
-        else
+    case HDF5:
+      save_hdf5_data (os, tc, name, help, global, save_as_floats);
+      break;
 #endif
-          // don't insert any commands here!  the brace below must go
-          // with the "else" above!
-          {
-            if (append)
-              warning ("save: ignoring -append option for output to stdout");
+
+    case MAT5_BINARY:
+      save_mat5_binary_element (os, tc, name, global, false, save_as_floats);
+      break;
+
+    case MAT7_BINARY:
+      save_mat5_binary_element (os, tc, name, global, true, save_as_floats);
+      break;
+
+    default:
+      err_unrecognized_data_fmt ("save");
+      break;
+    }
+}
+
+// Save the info from SR on stream OS in the format specified by FMT.
+
+void load_save_system::do_save (std::ostream& os,
+                                const symbol_info& syminfo,
+                                const load_save_format& fmt,
+                                bool save_as_floats)
+{
+  octave_value val = syminfo.value ();
+
+  if (val.is_defined ())
+    {
+      std::string name = syminfo.name ();
+      std::string help;
+      bool global = syminfo.is_global ();
+
+      do_save (os, val, name, help, global, fmt, save_as_floats);
+    }
+}
+
+// save fields of a scalar structure STR matching PATTERN on stream OS
+// in the format specified by FMT.
+
+std::size_t load_save_system::save_fields (std::ostream& os,
+    const octave_scalar_map& m,
+    const std::string& pattern,
+    const load_save_format& fmt,
+    bool save_as_floats)
+{
+  glob_match pat (pattern);
+
+  std::size_t saved = 0;
+
+  for (auto it = m.begin (); it != m.end (); it++)
+    {
+      std::string empty_str;
+
+      if (pat.match (m.key (it)))
+        {
+          do_save (os, m.contents (it), m.key (it), empty_str,
+                   0, fmt, save_as_floats);
+
+          saved++;
+        }
+    }
+
+  return saved;
+}
+
+void load_save_system::dump_octave_core (std::ostream& os,
+    const char *fname,
+    const load_save_format& fmt,
+    bool save_as_floats)
+{
+  write_header (os, fmt);
+
+  tree_evaluator& tw = m_interpreter.get_evaluator ();
+
+  symbol_info_list syminfo_list = tw.top_scope_symbol_info ();
+
+  double save_mem_size = 0;
+
+  for (const auto& syminfo : syminfo_list)
+    {
+      octave_value val = syminfo.value ();
+
+      std::string name = syminfo.name ();
+      std::string help;
+      bool global = syminfo.is_global ();
+
+      double val_size = val.byte_size () / 1024;
+
+      // FIXME: maybe we should try to throw out the largest first...
+
+      if (m_octave_core_file_limit < 0
+          || save_mem_size + val_size < m_octave_core_file_limit)
+        {
+          save_mem_size += val_size;
+
+          do_save (os, val, name, help, global, fmt, save_as_floats);
+        }
+    }
+
+  message (nullptr, "save to '%s' complete", fname);
+}
+
+// Install a variable with name NAME and the value VAL in the
+// symbol table.  If GLOBAL is TRUE, make the variable global.
+
+void load_save_system::install_loaded_variable (const std::string& name,
+    const octave_value& val,
+    bool global,
+    const std::string& /*doc*/)
+{
+  m_interpreter.install_variable (name, val, global);
+}
+
+std::string load_save_system::init_save_header_format (void)
+{
+  return
+    (std::string ("# Created by Octave " OCTAVE_VERSION
+                  ", %a %b %d %H:%M:%S %Y %Z <")
+     + sys::env::get_user_name ()
+     + '@'
+     + sys::env::get_host_name ()
+     + '>');
+}
+
+load_save_format
+load_save_system::get_file_format (std::istream& file,
+                                   const std::string& filename)
+{
+  load_save_format retval = load_save_system::UNKNOWN;
+
+  mach_info::float_format flt_fmt
+    = mach_info::flt_fmt_unknown;
+
+  bool swap = false;
+
+  if (read_binary_file_header (file, swap, flt_fmt, true) == 0)
+    retval = BINARY;
+  else
+    {
+      file.clear ();
+      file.seekg (0, std::ios::beg);
+
+      int32_t mopt, nr, nc, imag, len;
+
+      int err = read_mat_file_header (file, swap, mopt, nr, nc, imag, len,
+                                      true);
 
-            if (nargout == 0)
-              save_vars (argv, i, argc, octave_stdout, format,
-                         save_as_floats, true);
-            else
-              {
-                std::ostringstream output_buf;
-                save_vars (argv, i, argc, output_buf, format,
-                           save_as_floats, true);
-                retval = octave_value (output_buf.str());
-              }
-          }
-      }
+      if (! err)
+        retval = MAT_BINARY;
+      else
+        {
+          file.clear ();
+          file.seekg (0, std::ios::beg);
+
+          err = read_mat5_binary_file_header (file, swap, true, filename);
+
+          if (! err)
+            {
+              file.clear ();
+              file.seekg (0, std::ios::beg);
+              retval = MAT5_BINARY;
+            }
+          else
+            {
+              file.clear ();
+              file.seekg (0, std::ios::beg);
+
+              std::string name_val = extract_keyword (file, "name");
+              std::string type_val = extract_keyword (file, "type");
+
+              if (name_val.empty () != true && type_val.empty () != true)
+                retval = TEXT;
+              else
+                {
+                  file.clear ();
+                  file.seekg (0, std::ios::beg);
+
+                  // FIXME: looks_like_mat_ascii_file does not check
+                  // to see whether the file contains numbers.  It
+                  // just skips comments and checks for the same
+                  // number of words on each line.  We may need a
+                  // better check here.  The best way to do that might
+                  // be just to try to read the file and see if it
+                  // works.
 
-    // Guard against things like 'save a*', which are probably mistakes...
+                  if (looks_like_mat_ascii_file (file, filename))
+                    retval = MAT_ASCII;
+                }
+            }
+        }
+    }
+
+  return retval;
+}
+
+octave_value_list
+load_save_system::load (const octave_value_list& args, int nargout)
+{
+  octave_value_list retval;
+
+  int argc = args.length () + 1;
+
+  string_vector argv = args.make_argv ("load");
+
+  int i = 1;
+  std::string orig_fname = "";
+
+  // Function called with Matlab-style ["filename", options] syntax
+  if (argc > 1 && ! argv[1].empty () && argv[1].at (0) != '-')
+    {
+      orig_fname = argv[1];
+      i++;
+    }
+
+  // It isn't necessary to have the default load format stored in a
+  // user preference variable since we can determine the type of file
+  // as we are reading.
+
+  load_save_format format = UNKNOWN;
+
+  bool list_only = false;
+  bool verbose = false;
 
-    else if (i == argc - 1 && glob_pattern_p (argv[i]))
-      print_usage ();
-    else
-      {
-        std::string fname = sys::file_ops::tilde_expand (argv[i]);
-
-        i++;
+  for (; i < argc; i++)
+    {
+      if (argv[i] == "-text" || argv[i] == "-t")
+        {
+          format = TEXT;
+        }
+      else if (argv[i] == "-binary" || argv[i] == "-b")
+        {
+          format = BINARY;
+        }
+      else if (argv[i] == "-hdf5" || argv[i] == "-h")
+        {
+#if defined (HAVE_HDF5)
+          format = HDF5;
+#else
+          err_disabled_feature ("load", "HDF5");
+#endif
+        }
+      else if (argv[i] == "-ascii" || argv[i] == "-a")
+        {
+          format = MAT_ASCII;
+        }
+      else if (argv[i] == "-v7.3" || argv[i] == "-V7.3" || argv[i] == "-7.3")
+        {
+          error ("load: Matlab file format -v7.3 is not yet implemented");
+        }
+      else if (argv[i] == "-v7" || argv[i] == "-V7" || argv[i] == "-7"
+               || argv[i] == "-mat7-binary")
+        {
+          format = MAT7_BINARY;
+        }
+      else if (argv[i] == "-mat" || argv[i] == "-m"
+               || argv[i] == "-v6" || argv[i] == "-V6" || argv[i] == "-6"
+               || argv[i] == "-mat-binary")
+        {
+          format = MAT5_BINARY;
+        }
+      else if (argv[i] == "-v4" || argv[i] == "-V4" || argv[i] == "-4"
+               || argv[i] == "-mat4-binary")
+        {
+          format = MAT_BINARY;
+        }
+      else if (argv[i] == "-force" || argv[i] == "-f")
+        {
+          // Silently ignore this
+          // warning ("load: -force ignored");
+        }
+      else if (argv[i] == "-import" || argv[i] == "-i")
+        {
+          warning ("load: -import ignored");
+        }
+      else if (argv[i] == "-list" || argv[i] == "-l")
+        {
+          list_only = true;
+        }
+      else if (argv[i] == "-verbose" || argv[i] == "-v")
+        {
+          verbose = true;
+        }
+      else
+        break;
+    }
 
-        // Matlab v7 files are always compressed
-        if (format.type () == MAT7_BINARY)
-          use_zlib = false;
+  if (orig_fname == "")
+    {
+      if (i == argc)
+        print_usage ();
 
-        std::ios::openmode mode
-          = (append ? (std::ios::app | std::ios::ate) : std::ios::out);
+      orig_fname = argv[i];
+    }
+  else
+    i--;
 
-        // Always open in binary mode to save line endings as is.
-        mode |= std::ios::binary;
+  mach_info::float_format flt_fmt = mach_info::flt_fmt_unknown;
+
+  bool swap = false;
+
+  if (orig_fname == "-")
+    {
+      i++;
 
 #if defined (HAVE_HDF5)
-        if (format.type () == HDF5)
+      if (format.type () == HDF5)
+        error ("load: cannot read HDF5 format from stdin");
+      else
+#endif
+        if (format.type () != UNKNOWN)
           {
-            // FIXME: It should be possible to append to HDF5 files.
-            if (append)
-              error ("save: appending to HDF5 files is not implemented");
-
-#  if defined (HAVE_HDF5_UTF8)
-            bool write_header_info
-              = ! (append && H5Fis_hdf5 (fname.c_str ()) > 0);
-#  else
-            std::string ascii_fname = sys::get_ASCII_filename (fname);
+            // FIXME: if we have already seen EOF on a previous call,
+            // how do we fix up the state of std::cin so that we can get
+            // additional input?  I'm afraid that we can't fix this
+            // using std::cin only.
 
-            bool write_header_info
-              = ! (append && H5Fis_hdf5 (ascii_fname.c_str ()) > 0);
-#  endif
-
-            hdf5_ofstream hdf5_file (fname.c_str (), mode);
-
-            if (hdf5_file.file_id == -1)
-              err_file_open ("save", fname);
-
-            save_vars (argv, i, argc, hdf5_file, format, save_as_floats,
-                       write_header_info);
-
-            hdf5_file.close ();
+            retval = load_vars (std::cin, orig_fname, format, flt_fmt,
+                                list_only, swap, verbose, argv, i,
+                                argc, nargout);
           }
         else
+          error ("load: must specify file format if reading from stdin");
+    }
+  else
+    {
+      std::string fname = sys::file_ops::tilde_expand (orig_fname);
+
+      fname = find_file_to_load (fname, orig_fname);
+
+      bool use_zlib = false;
+
+      if (format.type () == UNKNOWN)
+        format = get_file_format (fname, orig_fname, use_zlib);
+
+#if defined (HAVE_HDF5)
+      if (format.type () == HDF5)
+        {
+          i++;
+
+          hdf5_ifstream hdf5_file (fname.c_str ());
+
+          if (hdf5_file.file_id < 0)
+            err_file_open ("load", orig_fname);
+
+          retval = load_vars (hdf5_file, orig_fname, format, flt_fmt,
+                              list_only, swap, verbose, argv, i,
+                              argc, nargout);
+
+          hdf5_file.close ();
+        }
+      else
 #endif
-          // don't insert any statements here!  The brace below must go
-          // with the "else" above!
+        // don't insert any statements here; the "else" above has to
+        // go with the "if" below!!!!!
+        if (format.type () != UNKNOWN)
           {
+            i++;
+
+            // Always open in binary mode and handle various
+            // line-endings explicitly.
+            std::ios::openmode mode = std::ios::in | std::ios::binary;
+
 #if defined (HAVE_ZLIB)
             if (use_zlib)
               {
-                gzofstream file (fname.c_str (), mode);
+                gzifstream file (fname.c_str (), mode);
 
                 if (! file)
-                  err_file_open ("save", fname);
+                  err_file_open ("load", orig_fname);
 
-                bool write_header_info = ! file.tellp ();
+                if (format.type () == BINARY)
+                  {
+                    if (read_binary_file_header (file, swap, flt_fmt) < 0)
+                      {
+                        if (file) file.close ();
+                        return retval;
+                      }
+                  }
+                else if (format.type () == MAT5_BINARY
+                         || format.type () == MAT7_BINARY)
+                  {
+                    if (read_mat5_binary_file_header (file, swap, false,
+                                                      orig_fname) < 0)
+                      {
+                        if (file) file.close ();
+                        return retval;
+                      }
+                  }
 
-                save_vars (argv, i, argc, file, format, save_as_floats,
-                           write_header_info);
+                retval = load_vars (file, orig_fname, format, flt_fmt,
+                                    list_only, swap, verbose, argv, i,
+                                    argc, nargout);
 
                 file.close ();
               }
             else
 #endif
               {
-                std::ofstream file = sys::ofstream (fname.c_str (), mode);
+                std::ifstream file = sys::ifstream (fname.c_str (), mode);
 
                 if (! file)
-                  err_file_open ("save", fname);
+                  error ("load: unable to open input file '%s'",
+                         orig_fname.c_str ());
 
-                bool write_header_info = ! file.tellp ();
+                if (format.type () == BINARY)
+                  {
+                    if (read_binary_file_header (file, swap, flt_fmt) < 0)
+                      {
+                        if (file) file.close ();
+                        return retval;
+                      }
+                  }
+                else if (format.type () == MAT5_BINARY
+                         || format.type () == MAT7_BINARY)
+                  {
+                    if (read_mat5_binary_file_header (file, swap, false,
+                                                      orig_fname) < 0)
+                      {
+                        if (file) file.close ();
+                        return retval;
+                      }
+                  }
 
-                save_vars (argv, i, argc, file, format, save_as_floats,
-                           write_header_info);
+                retval = load_vars (file, orig_fname, format, flt_fmt,
+                                    list_only, swap, verbose, argv, i,
+                                    argc, nargout);
 
                 file.close ();
               }
           }
-      }
+        else
+          error ("load: unable to determine file format of '%s'",
+                 orig_fname.c_str ());
+
+    }
+
+  return retval;
+}
+
+octave_value_list
+load_save_system::save (const octave_value_list& args, int nargout)
+{
+  // Here is where we would get the default save format if it were
+  // stored in a user preference variable.
+  load_save_format format = TEXT;
+  bool save_as_floats = false;
+  bool append = false;
+  bool use_zlib = false;
+
+
+  // get default options
+  parse_save_options (save_default_options (), format, append,
+                      save_as_floats, use_zlib);
+
+  // override from command line
+  string_vector argv = args.make_argv ();
+
+  argv = parse_save_options (argv, format, append, save_as_floats, use_zlib);
+
+  int argc = argv.numel ();
+  int i = 0;
+
+  if (i == argc)
+    print_usage ();
+
+  if (save_as_floats && format.type () == TEXT)
+    error ("save: cannot specify both -text and -float-binary");
+
+  octave_value_list retval;
+
+  if (argv[i] == "-")
+    {
+      i++;
+
+#if defined (HAVE_HDF5)
+      if (format.type () == HDF5)
+        error ("save: cannot write HDF5 format to stdout");
+      else
+#endif
+        // don't insert any commands here!  the brace below must go
+        // with the "else" above!
+        {
+          if (append)
+            warning ("save: ignoring -append option for output to stdout");
+
+          if (nargout == 0)
+            save_vars (argv, i, argc, octave_stdout, format,
+                       save_as_floats, true);
+          else
+            {
+              std::ostringstream output_buf;
+              save_vars (argv, i, argc, output_buf, format,
+                         save_as_floats, true);
+              retval = octave_value (output_buf.str());
+            }
+        }
+    }
+
+  // Guard against things like 'save a*', which are probably mistakes...
+
+  else if (i == argc - 1 && glob_pattern_p (argv[i]))
+    print_usage ();
+  else
+    {
+      std::string fname = sys::file_ops::tilde_expand (argv[i]);
+
+      i++;
 
-    return retval;
-  }
+      // Matlab v7 files are always compressed
+      if (format.type () == MAT7_BINARY)
+        use_zlib = false;
+
+      std::ios::openmode mode
+        = (append ? (std::ios::app | std::ios::ate) : std::ios::out);
+
+      // Always open in binary mode to save line endings as is.
+      mode |= std::ios::binary;
+
+#if defined (HAVE_HDF5)
+      if (format.type () == HDF5)
+        {
+          // FIXME: It should be possible to append to HDF5 files.
+          if (append)
+            error ("save: appending to HDF5 files is not implemented");
+
+#  if defined (HAVE_HDF5_UTF8)
+          bool write_header_info
+            = ! (append && H5Fis_hdf5 (fname.c_str ()) > 0);
+#  else
+          std::string ascii_fname = sys::get_ASCII_filename (fname);
+
+          bool write_header_info
+            = ! (append && H5Fis_hdf5 (ascii_fname.c_str ()) > 0);
+#  endif
+
+          hdf5_ofstream hdf5_file (fname.c_str (), mode);
+
+          if (hdf5_file.file_id == -1)
+            err_file_open ("save", fname);
+
+          save_vars (argv, i, argc, hdf5_file, format, save_as_floats,
+                     write_header_info);
+
+          hdf5_file.close ();
+        }
+      else
+#endif
+        // don't insert any statements here!  The brace below must go
+        // with the "else" above!
+        {
+#if defined (HAVE_ZLIB)
+          if (use_zlib)
+            {
+              gzofstream file (fname.c_str (), mode);
+
+              if (! file)
+                err_file_open ("save", fname);
+
+              bool write_header_info = ! file.tellp ();
+
+              save_vars (argv, i, argc, file, format, save_as_floats,
+                         write_header_info);
+
+              file.close ();
+            }
+          else
+#endif
+            {
+              std::ofstream file = sys::ofstream (fname.c_str (), mode);
+
+              if (! file)
+                err_file_open ("save", fname);
+
+              bool write_header_info = ! file.tellp ();
+
+              save_vars (argv, i, argc, file, format, save_as_floats,
+                         write_header_info);
+
+              file.close ();
+            }
+        }
+    }
+
+  return retval;
+}
 
 DEFMETHOD (load, interp, args, nargout,
            doc: /* -*- texinfo -*-