diff src/corefcn/dlmread.cc @ 15039:e753177cde93

maint: Move non-dynamically linked functions from DLD-FUNCTIONS/ to corefcn/ directory * __contourc__.cc, __dispatch__.cc, __lin_interpn__.cc, __pchip_deriv__.cc, __qp__.cc, balance.cc, besselj.cc, betainc.cc, bsxfun.cc, cellfun.cc, colloc.cc, conv2.cc, daspk.cc, dasrt.cc, dassl.cc, det.cc, dlmread.cc, dot.cc, eig.cc, fft.cc, fft2.cc, fftn.cc, filter.cc, find.cc, gammainc.cc, gcd.cc, getgrent.cc, getpwent.cc, getrusage.cc, givens.cc, hess.cc, hex2num.cc, inv.cc, kron.cc, lookup.cc, lsode.cc, lu.cc, luinc.cc, matrix_type.cc, max.cc, md5sum.cc, mgorth.cc, nproc.cc, pinv.cc, quad.cc, quadcc.cc, qz.cc, rand.cc, rcond.cc, regexp.cc, schur.cc, spparms.cc, sqrtm.cc, str2double.cc, strfind.cc, sub2ind.cc, svd.cc, syl.cc, time.cc, tril.cc, typecast.cc: Move functions from DLD-FUNCTIONS/ to corefcn/ directory. Include "defun.h", not "defun-dld.h". Change docstring to refer to these as "Built-in Functions". * build-aux/mk-opts.pl: Generate options code with '#include "defun.h"'. Change option docstrings to refer to these as "Built-in Functions". * corefcn/module.mk: List of functions to build in corefcn/ dir. * DLD-FUNCTIONS/config-module.awk: Update to new build system. * DLD-FUNCTIONS/module-files: Remove functions which are now in corefcn/ directory. * src/Makefile.am: Update to build "convenience library" in corefcn/. Octave program now links against all other libraries + corefcn libary. * src/find-defun-files.sh: Strip $srcdir from filename. * src/link-deps.mk: Add REGEX and FFTW link dependencies for liboctinterp. * type.m, which.m: Change failing tests to use 'amd', still a dynamic function, rather than 'dot', which isn't.
author Rik <rik@octave.org>
date Fri, 27 Jul 2012 15:35:00 -0700
parents src/DLD-FUNCTIONS/dlmread.cc@60e5cf354d80
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/corefcn/dlmread.cc	Fri Jul 27 15:35:00 2012 -0700
@@ -0,0 +1,520 @@
+/*
+
+Copyright (C) 2008-2012 Jonathan Stickel
+Copyright (C) 2010 Jaroslav Hajek
+
+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
+<http://www.gnu.org/licenses/>.
+
+*/
+
+// Adapted from previous version of dlmread.occ as authored by Kai
+// Habel, but core code has been completely re-written.
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <cctype>
+#include <fstream>
+#include <limits>
+
+#include "file-ops.h"
+#include "lo-ieee.h"
+
+#include "defun.h"
+#include "oct-stream.h"
+#include "error.h"
+#include "oct-obj.h"
+#include "utils.h"
+
+static const octave_idx_type idx_max =  std::numeric_limits<octave_idx_type>::max ();
+
+static bool
+read_cell_spec (std::istream& is, octave_idx_type& row, octave_idx_type& col)
+{
+  bool stat = false;
+
+  if (is.peek () == std::istream::traits_type::eof ())
+    stat = true;
+  else
+    {
+      if (::isalpha (is.peek ()))
+        {
+          col = 0;
+          while (is && ::isalpha (is.peek ()))
+            {
+              char ch = is.get ();
+              col *= 26;
+              if (ch >= 'a')
+                col += ch - 'a' + 1;
+              else
+                col += ch - 'A' + 1;
+            }
+          col --;
+
+          if (is)
+            {
+              is >> row;
+              row --;
+              if (is)
+                stat = true;
+            }
+        }
+    }
+
+  return stat;
+}
+
+static bool
+parse_range_spec (const octave_value& range_spec,
+                  octave_idx_type& rlo, octave_idx_type& clo,
+                  octave_idx_type& rup, octave_idx_type& cup)
+{
+  bool stat = true;
+
+  if (range_spec.is_string ())
+    {
+      std::istringstream is (range_spec.string_value ());
+      char ch = is.peek ();
+
+      if (ch == '.' || ch == ':')
+        {
+          rlo = 0;
+          clo = 0;
+          ch = is.get ();
+          if (ch == '.')
+            {
+              ch = is.get ();
+              if (ch != '.')
+                stat = false;
+            }
+        }
+      else
+        {
+          stat = read_cell_spec (is, rlo, clo);
+
+          if (stat)
+            {
+              ch = is.peek ();
+
+              if (ch == '.' || ch == ':')
+                {
+                  ch = is.get ();
+                  if (ch == '.')
+                    {
+                      ch = is.get ();
+                      if (!is || ch != '.')
+                        stat = false;
+                    }
+
+                  rup = idx_max - 1;
+                  cup = idx_max - 1;
+                }
+              else
+                {
+                  rup = rlo;
+                  cup = clo;
+                  if (!is || !is.eof ())
+                    stat = false;
+                }
+            }
+        }
+
+      if (stat && is && !is.eof ())
+        stat = read_cell_spec (is, rup, cup);
+
+      if (!is || !is.eof ())
+        stat = false;
+    }
+  else if (range_spec.is_real_matrix () && range_spec.numel () == 4)
+    {
+      ColumnVector range(range_spec.vector_value ());
+      // double --> unsigned int
+      rlo = static_cast<octave_idx_type> (range(0));
+      clo = static_cast<octave_idx_type> (range(1));
+      rup = static_cast<octave_idx_type> (range(2));
+      cup = static_cast<octave_idx_type> (range(3));
+    }
+  else
+    stat = false;
+
+  return stat;
+}
+
+DEFUN (dlmread, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Built-in Function} {@var{data} =} dlmread (@var{file})\n\
+@deftypefnx {Built-in Function} {@var{data} =} dlmread (@var{file}, @var{sep})\n\
+@deftypefnx {Built-in Function} {@var{data} =} dlmread (@var{file}, @var{sep}, @var{r0}, @var{c0})\n\
+@deftypefnx {Built-in Function} {@var{data} =} dlmread (@var{file}, @var{sep}, @var{range})\n\
+@deftypefnx {Built-in Function} {@var{data} =} dlmread (@dots{}, \"emptyvalue\", @var{EMPTYVAL})\n\
+Read the matrix @var{data} from a text file.  If not defined the separator\n\
+between fields is determined from the file itself.  Otherwise the\n\
+separation character is defined by @var{sep}.\n\
+\n\
+Given two scalar arguments @var{r0} and @var{c0}, these define the starting\n\
+row and column of the data to be read.  These values are indexed from zero,\n\
+such that the first row corresponds to an index of zero.\n\
+\n\
+The @var{range} parameter may be a 4-element vector containing the upper\n\
+left and lower right corner @code{[@var{R0},@var{C0},@var{R1},@var{C1}]}\n\
+where the lowest index value is zero.  Alternatively, a spreadsheet style\n\
+range such as \"A2..Q15\" or \"T1:AA5\" can be used.  The lowest alphabetical\n\
+index 'A' refers to the first column.  The lowest row index is 1.\n\
+\n\
+@var{file} should be a file name or file id given by @code{fopen}.  In the\n\
+latter case, the file is read until end of file is reached.\n\
+\n\
+The \"emptyvalue\" option may be used to specify the value used to fill empty\n\
+fields.  The default is zero.\n\
+@seealso{csvread, textscan, textread, dlmwrite}\n\
+@end deftypefn")
+{
+  octave_value_list retval;
+
+  int nargin = args.length ();
+
+  double empty_value = 0.0;
+
+  if (nargin > 2 && args(nargin-2).is_string ()
+      && args(nargin-2).string_value () == "emptyvalue")
+    {
+      empty_value = args(nargin-1).double_value ();
+      if (error_state)
+         return retval;
+      nargin -= 2;
+    }
+
+  if (nargin < 1 || nargin > 4)
+    {
+      print_usage ();
+      return retval;
+    }
+
+  std::istream *input = 0;
+  std::ifstream input_file;
+
+  if (args(0).is_string ())
+    {
+      // File name.
+      std::string fname (args(0).string_value ());
+      if (error_state)
+         return retval;
+
+      std::string tname = file_ops::tilde_expand (fname);
+
+      input_file.open (tname.c_str (), std::ios::in);
+
+      if (! input_file)
+        {
+          error ("dlmread: unable to open file `%s'", fname.c_str ());
+          return retval;
+        }
+      else
+        input = &input_file;
+    }
+  else if (args(0).is_scalar_type ())
+    {
+      octave_stream is = octave_stream_list::lookup (args(0), "dlmread");
+
+      if (error_state)
+         return retval;
+
+      input = is.input_stream ();
+
+      if (! input)
+        {
+          error ("dlmread: stream FILE not open for input");
+          return retval;
+        }
+    }
+  else
+    {
+      error ("dlmread: FILE argument must be a string or file id");
+      return retval;
+    }
+
+  // Set default separator.
+  std::string sep;
+  if (nargin > 1)
+    {
+      if (args(1).is_sq_string ())
+        sep = do_string_escapes (args(1).string_value ());
+      else
+        sep = args(1).string_value ();
+
+      if (error_state)
+        return retval;
+    }
+
+  // Take a subset if a range was given.
+  octave_idx_type r0 = 0, c0 = 0, r1 = idx_max-1, c1 = idx_max-1;
+  if (nargin > 2)
+    {
+      if (nargin == 3)
+        {
+          if (!parse_range_spec (args (2), r0, c0, r1, c1))
+            error ("dlmread: error parsing RANGE");
+        }
+      else if (nargin == 4)
+        {
+          r0 = args(2).idx_type_value ();
+          c0 = args(3).idx_type_value ();
+
+          if (error_state)
+            return retval;
+        }
+
+      if (r0 < 0 || c0 < 0)
+        error ("dlmread: left & top must be positive");
+    }
+
+  if (!error_state)
+    {
+      octave_idx_type i = 0, j = 0, r = 1, c = 1, rmax = 0, cmax = 0;
+
+      Matrix rdata;
+      ComplexMatrix cdata;
+
+      bool iscmplx = false;
+      bool sepflag = false;
+
+      std::string line;
+
+      // Skip the r0 leading lines as these might be a header.
+      for (octave_idx_type m = 0; m < r0; m++)
+        getline (*input, line);
+      r1 -= r0;
+
+      std::istringstream tmp_stream;
+
+      // Read in the data one field at a time, growing the data matrix
+      // as needed.
+      while (getline (*input, line))
+        {
+          // Skip blank lines for compatibility.
+          if (line.find_first_not_of (" \t") == std::string::npos)
+            continue;
+
+          // To be compatible with matlab, blank separator should
+          // correspond to whitespace as delimter.
+          if (!sep.length ())
+            {
+              size_t n = line.find_first_of (",:; \t",
+                                             line.find_first_of ("0123456789"));
+              if (n == std::string::npos)
+                {
+                  sep = " \t";
+                  sepflag = true;
+                }
+              else
+                {
+                  char ch = line.at (n);
+
+                  switch (line.at (n))
+                    {
+                    case ' ':
+                    case '\t':
+                      sepflag = true;
+                      sep = " \t";
+                      break;
+
+                    default:
+                      sep = ch;
+                      break;
+                    }
+                }
+            }
+
+          if (cmax == 0)
+            {
+              // Try to estimate the number of columns.  Skip leading
+              // whitespace.
+              size_t pos1 = line.find_first_not_of (" \t");
+              do
+                {
+                  size_t pos2 = line.find_first_of (sep, pos1);
+
+                  if (sepflag && pos2 != std::string::npos)
+                    // Treat consecutive separators as one.
+                    {
+                      pos2 = line.find_first_not_of (sep, pos2);
+                      if (pos2 != std::string::npos)
+                        pos2 -= 1;
+                      else
+                        pos2 = line.length () - 1;
+                    }
+
+                  cmax++;
+
+                  if (pos2 != std::string::npos)
+                    pos1 = pos2 + 1;
+                  else
+                    pos1 = std::string::npos;
+
+                }
+              while (pos1 != std::string::npos);
+
+              if (iscmplx)
+                cdata.resize (rmax, cmax);
+              else
+                rdata.resize (rmax, cmax);
+            }
+
+          r = (r > i + 1 ? r : i + 1);
+          j = 0;
+          // Skip leading whitespace.
+          size_t pos1 = line.find_first_not_of (" \t");
+          do
+            {
+              octave_quit ();
+
+              size_t pos2 = line.find_first_of (sep, pos1);
+              std::string str = line.substr (pos1, pos2 - pos1);
+
+              if (sepflag && pos2 != std::string::npos)
+                // Treat consecutive separators as one.
+                pos2 = line.find_first_not_of (sep, pos2) - 1;
+
+              c = (c > j + 1 ? c : j + 1);
+              if (r > rmax || c > cmax)
+                {
+                  // Use resize_and_fill for the case of not-equal
+                  // length rows.
+                  rmax = 2*r;
+                  cmax = c;
+                  if (iscmplx)
+                    cdata.resize (rmax, cmax);
+                  else
+                    rdata.resize (rmax, cmax);
+                }
+
+              tmp_stream.str (str);
+              tmp_stream.clear ();
+
+              double x = octave_read_double (tmp_stream);
+              if (tmp_stream)
+                {
+                  if (tmp_stream.eof ())
+                    {
+                      if (iscmplx)
+                        cdata(i,j++) = x;
+                      else
+                        rdata(i,j++) = x;
+                    }
+                  else if (std::toupper (tmp_stream.peek ()) == 'I')
+                    {
+                      // This is to allow pure imaginary numbers.
+                      if (iscmplx)
+                        cdata(i,j++) = x;
+                      else
+                        rdata(i,j++) = x;
+                    }
+                  else
+                    {
+                      double y = octave_read_double (tmp_stream);
+
+                      if (!iscmplx && y != 0.)
+                        {
+                          iscmplx = true;
+                          cdata = ComplexMatrix (rdata);
+                        }
+
+                      if (iscmplx)
+                        cdata(i,j++) = Complex (x, y);
+                      else
+                        rdata(i,j++) = x;
+                    }
+                }
+              else if (iscmplx)
+                cdata(i,j++) = empty_value;
+              else
+                rdata(i,j++) = empty_value;
+
+              if (pos2 != std::string::npos)
+                pos1 = pos2 + 1;
+              else
+                pos1 = std::string::npos;
+
+            }
+          while (pos1 != std::string::npos);
+
+          if (i == r1)
+            break;
+
+          i++;
+        }
+
+      if (r1 >= r)
+        r1 = r - 1;
+      if (c1 >= c)
+        c1 = c - 1;
+
+      // Now take the subset of the matrix.
+      if (iscmplx)
+        cdata = cdata.extract (0, c0, r1, c1);
+      else
+        rdata = rdata.extract (0, c0, r1, c1);
+
+      if (iscmplx)
+        retval(0) = cdata;
+      else
+        retval(0) = rdata;
+    }
+
+  return retval;
+}
+
+/*
+%!shared file
+%! file = tmpnam ();
+%! fid = fopen (file, "wt");
+%! fwrite (fid, "1, 2, 3\n4, 5, 6\n7, 8, 9\n10, 11, 12");
+%! fclose (fid);
+
+%!assert (dlmread (file), [1, 2, 3; 4, 5, 6; 7, 8, 9;10, 11, 12])
+%!assert (dlmread (file, ","), [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12])
+%!assert (dlmread (file, ",", [1, 0, 2, 1]), [4, 5; 7, 8])
+%!assert (dlmread (file, ",", "B1..C2"), [2, 3; 5, 6])
+%!assert (dlmread (file, ",", "B1:C2"), [2, 3; 5, 6])
+%!assert (dlmread (file, ",", "..C2"), [1, 2, 3; 4, 5, 6])
+%!assert (dlmread (file, ",", 0, 1), [2, 3; 5, 6; 8, 9; 11, 12])
+%!assert (dlmread (file, ",", "B1.."), [2, 3; 5, 6; 8, 9; 11, 12])
+%!error (dlmread (file, ",", [0 1]))
+
+%!test
+%! unlink (file);
+
+%!shared file
+%! file = tmpnam ();
+%! fid = fopen (file, "wt");
+%! fwrite (fid, "1, 2, 3\n4+4i, 5, 6\n7, 8, 9\n10, 11, 12");
+%! fclose (fid);
+
+%!assert (dlmread (file), [1, 2, 3; 4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12])
+%!assert (dlmread (file, ","), [1, 2, 3; 4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12])
+%!assert (dlmread (file, ",", [1, 0, 2, 1]), [4 + 4i, 5; 7, 8])
+%!assert (dlmread (file, ",", "A2..B3"), [4 + 4i, 5; 7, 8])
+%!assert (dlmread (file, ",", "A2:B3"), [4 + 4i, 5; 7, 8])
+%!assert (dlmread (file, ",", "..B3"), [1, 2; 4 + 4i, 5; 7, 8])
+%!assert (dlmread (file, ",", 1, 0), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12])
+%!assert (dlmread (file, ",", "A2.."), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12])
+%!error (dlmread (file, ",", [0 1]))
+
+%!test
+%! unlink (file);
+*/