GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
dlmread.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2008-2023 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 // Adapted from previous version of dlmread.occ as authored by Kai
27 // Habel, but core code has been completely re-written.
28 
29 #if defined (HAVE_CONFIG_H)
30 # include "config.h"
31 #endif
32 
33 #include <clocale>
34 #include <cmath>
35 #include <cctype>
36 #include <fstream>
37 #include <limits>
38 
39 #include "file-ops.h"
40 #include "lo-ieee.h"
41 #include "lo-sysdep.h"
42 
43 #include "defun.h"
44 #include "interpreter.h"
45 #include "oct-stream.h"
46 #include "error.h"
47 #include "ovl.h"
48 #include "utils.h"
49 
52 
53 static const double idx_max_dbl = double (idx_max);
54 
55 static bool
56 read_cell_spec (std::istream& is, octave_idx_type& row, octave_idx_type& col)
57 {
58  bool stat = false;
59 
60  if (is.peek () == std::istream::traits_type::eof ())
61  stat = true;
62  else
63  {
64  if (::isalpha (is.peek ()))
65  {
66  col = 0;
67  while (is && ::isalpha (is.peek ()))
68  {
69  char ch = is.get ();
70  col *= 26;
71  if (ch >= 'a')
72  col += ch - 'a' + 1;
73  else
74  col += ch - 'A' + 1;
75  }
76  col--;
77 
78  if (is)
79  {
80  is >> row;
81  row--;
82  if (is)
83  stat = true;
84  }
85  }
86  }
87 
88  return stat;
89 }
90 
91 static bool
92 parse_range_spec (const octave_value& range_spec,
95 {
96  bool stat = true;
97 
98  if (range_spec.is_string ())
99  {
100  std::istringstream is (range_spec.string_value ());
101  char ch = is.peek ();
102 
103  if (ch == '.' || ch == ':')
104  {
105  rlo = 0;
106  clo = 0;
107  ch = is.get ();
108  if (ch == '.')
109  {
110  ch = is.get ();
111  if (ch != '.')
112  stat = false;
113  }
114  }
115  else
116  {
117  stat = read_cell_spec (is, rlo, clo);
118 
119  if (stat)
120  {
121  ch = is.peek ();
122 
123  if (ch == '.' || ch == ':')
124  {
125  ch = is.get ();
126  if (ch == '.')
127  {
128  ch = is.get ();
129  if (! is || ch != '.')
130  stat = false;
131  }
132 
133  rup = idx_max;
134  cup = idx_max;
135  }
136  else
137  {
138  rup = rlo;
139  cup = clo;
140  if (! is || ! is.eof ())
141  stat = false;
142  }
143  }
144  }
145 
146  if (stat && is && ! is.eof ())
147  stat = read_cell_spec (is, rup, cup);
148 
149  if (! is || ! is.eof ())
150  stat = false;
151  }
152  else if (range_spec.is_real_matrix () && range_spec.numel () == 4)
153  {
154  NDArray range (range_spec.array_value ());
155  if (range.any_element_is_nan ())
156  error ("dlmread: NaN is not a valid row or column specifier");
157 
158  // double --> unsigned int avoiding any overflow
159  rlo = static_cast<octave_idx_type> (std::min (range(0), idx_max_dbl));
160  clo = static_cast<octave_idx_type> (std::min (range(1), idx_max_dbl));
161  rup = static_cast<octave_idx_type> (std::min (range(2), idx_max_dbl));
162  cup = static_cast<octave_idx_type> (std::min (range(3), idx_max_dbl));
163  }
164  else
165  stat = false;
166 
167  return stat;
168 }
169 
171 
172 DEFMETHOD (dlmread, interp, args, ,
173  doc: /* -*- texinfo -*-
174 @deftypefn {} {@var{data} =} dlmread (@var{file})
175 @deftypefnx {} {@var{data} =} dlmread (@var{file}, @var{sep})
176 @deftypefnx {} {@var{data} =} dlmread (@var{file}, @var{sep}, @var{r0}, @var{c0})
177 @deftypefnx {} {@var{data} =} dlmread (@var{file}, @var{sep}, @var{range})
178 @deftypefnx {} {@var{data} =} dlmread (@dots{}, "emptyvalue", @var{EMPTYVAL})
179 Read numeric data from the text file @var{file} which uses the delimiter
180 @var{sep} between data values.
181 
182 If @var{sep} is not defined the separator between fields is determined from
183 the file itself.
184 
185 The optional scalar arguments @var{r0} and @var{c0} define the starting row
186 and column of the data to be read. These values are indexed from zero,
187 i.e., the first data row corresponds to an index of zero.
188 
189 The @var{range} parameter specifies exactly which data elements are read.
190 The first form of the parameter is a 4-element vector containing the upper
191 left and lower right corners @code{[@var{R0},@var{C0},@var{R1},@var{C1}]}
192 where the indices are zero-based. To specify the last column---the equivalent
193 of @code{end} when indexing---use the specifier @code{Inf}. Alternatively, a
194 spreadsheet style form such as @qcode{"A2..Q15"} or @qcode{"T1:AA5"} can be
195 used. The lowest alphabetical index @qcode{'A'} refers to the first column.
196 The lowest row index is 1.
197 
198 @var{file} should be a filename or a file id given by @code{fopen}. In the
199 latter case, the file is read until end of file is reached.
200 
201 The @qcode{"emptyvalue"} option may be used to specify the value used to
202 fill empty fields. The default is zero. Note that any non-numeric values,
203 such as text, are also replaced by the @qcode{"emptyvalue"}.
204 @seealso{csvread, textscan, dlmwrite}
205 @end deftypefn */)
206 {
207  int nargin = args.length ();
208 
209  double empty_value = 0.0;
210 
211  if (nargin > 2 && args(nargin-2).is_string ()
212  && args(nargin-2).string_value () == "emptyvalue")
213  {
214  empty_value = args(nargin-1).double_value ();
215 
216  nargin -= 2;
217  }
218 
219  if (nargin < 1 || nargin > 4)
220  print_usage ();
221 
222  std::istream *input = nullptr;
223  std::ifstream input_file;
224 
225  if (args(0).is_string ())
226  {
227  // Filename.
228  std::string fname (args(0).string_value ());
229 
230  std::string tname = sys::file_ops::tilde_expand (fname);
231 
232  tname = find_data_file_in_load_path ("dlmread", tname);
233 
234 #if defined (OCTAVE_USE_WINDOWS_API)
235  std::wstring wname = sys::u8_to_wstring (tname);
236  input_file.open (wname.c_str (), std::ios::in);
237 #else
238  input_file.open (tname.c_str (), std::ios::in);
239 #endif
240 
241  if (! input_file)
242  error ("dlmread: unable to open file '%s'", fname.c_str ());
243 
244  input = &input_file;
245  }
246  else if (args(0).is_scalar_type ())
247  {
248  stream_list& streams = interp.get_stream_list ();
249 
250  stream is = streams.lookup (args(0), "dlmread");
251 
252  input = is.input_stream ();
253 
254  if (! input)
255  error ("dlmread: stream FILE not open for input");
256  }
257  else
258  error ("dlmread: FILE argument must be a string or file id");
259 
260  // Set default separator.
261  std::string sep;
262  if (nargin > 1)
263  {
264  if (args(1).is_sq_string ())
265  sep = do_string_escapes (args(1).string_value ());
266  else
267  sep = args(1).string_value ();
268  }
269 
270  // Take a subset if a range was given.
271  octave_idx_type r0 = 0;
272  octave_idx_type c0 = 0;
275  if (nargin > 2)
276  {
277  if (nargin == 3)
278  {
279  if (! parse_range_spec (args(2), r0, c0, r1, c1))
280  error ("dlmread: error parsing RANGE");
281  }
282  else if (nargin == 4)
283  {
284  r0 = args(2).idx_type_value ();
285  c0 = args(3).idx_type_value ();
286  }
287 
288  if (r0 < 0 || c0 < 0)
289  error ("dlmread: left (R0) and top (C0) must be positive");
290 
291  // Short-circuit and return if range is empty
292  if (r1 < r0 || c1 < c0)
293  return ovl (Matrix (0, 0));
294  }
295 
296  octave_idx_type i = 0;
297  octave_idx_type j = 0;
298  octave_idx_type r = 1;
299  octave_idx_type c = 1;
300  // Start with a reasonable size to avoid constant resizing of matrix.
301  octave_idx_type rmax = 32;
302  octave_idx_type cmax = 0;
303 
304  Matrix rdata (rmax, cmax, empty_value);
305  ComplexMatrix cdata;
306 
307  bool iscmplx = false;
308  bool sep_is_wspace = (sep.find_first_of (" \t") != std::string::npos);
309  bool auto_sep_is_wspace = false;
310 
311  if (r0 == 0)
312  {
313  // Peek into stream and potentially strip Byte Order Mark (BOM)
314  const char BOM[3] = {'\xEF', '\xBB', '\xBF'};
315  char buf[3];
316  int i_bom;
317  bool found_bom = true;
318  for (i_bom = 0; i_bom < 3; i_bom++)
319  {
320  char ch_p = input->peek ();
321  if (ch_p == BOM[i_bom])
322  buf[i_bom] = input->get ();
323  else
324  {
325  found_bom = false;
326  break;
327  }
328  }
329  // Put back read characters if it wasn't a BOM
330  if (! found_bom)
331  {
332  for (int i_ret = i_bom-1; i_ret >= 0; i_ret--)
333  input->putback (buf[i_ret]);
334  }
335  }
336 
337  // Set "C" locale for the remainder of this function to avoid the performance
338  // panelty of frequently switching the locale when reading floating point
339  // values from the stream.
340  char *prev_locale = std::setlocale (LC_ALL, nullptr);
341  std::string old_locale (prev_locale ? prev_locale : "");
342  std::setlocale (LC_ALL, "C");
343  unwind_action act
344  ([old_locale] () { std::setlocale (LC_ALL, old_locale.c_str ()); });
345 
346  std::string line;
347 
348  // Skip the r0 leading lines
349  octave_idx_type rcnt = r0;
350  while (rcnt > 0 && getline (*input, line))
351  rcnt--;
352 
353  if (rcnt > 0)
354  return ovl (Matrix (0, 0)); // Not enough lines in file to satisfy RANGE
355  else
356  r1 -= r0;
357 
358  std::istringstream tmp_stream;
359 
360  // Read the data one field at a time, growing the data matrix as needed.
361  while (getline (*input, line))
362  {
363  // Skip blank lines for compatibility.
364  if ((! sep_is_wspace || auto_sep_is_wspace)
365  && line.find_first_not_of (" \t") == std::string::npos)
366  continue;
367 
368  // Infer separator from file if delimiter is blank.
369  if (sep.empty ())
370  {
371  // Skip leading whitespace.
372  std::size_t pos1 = line.find_first_not_of (" \t");
373 
374  // For Matlab compatibility, blank delimiter should
375  // correspond to whitespace (space and tab).
376  std::size_t n = line.find_first_of (",:; \t", pos1);
377  if (n == std::string::npos)
378  {
379  sep = " \t";
380  auto_sep_is_wspace = true;
381  }
382  else
383  {
384  char ch = line.at (n);
385 
386  switch (line.at (n))
387  {
388  case ' ':
389  case '\t':
390  sep = " \t";
391  auto_sep_is_wspace = true;
392  break;
393 
394  default:
395  sep = ch;
396  break;
397  }
398  }
399  }
400 
401  // Estimate the number of columns from first line of data.
402  if (cmax == 0)
403  {
404  std::size_t pos1, pos2;
405  if (auto_sep_is_wspace)
406  pos1 = line.find_first_not_of (" \t");
407  else
408  pos1 = 0;
409 
410  do
411  {
412  pos2 = line.find_first_of (sep, pos1);
413 
414  if (auto_sep_is_wspace && pos2 != std::string::npos)
415  {
416  // Treat consecutive separators as one.
417  pos2 = line.find_first_not_of (sep, pos2);
418  if (pos2 != std::string::npos)
419  pos2 -= 1;
420  }
421 
422  // Separator followed by EOL doesn't generate extra column
423  if (pos2 != std::string::npos)
424  cmax++;
425 
426  pos1 = pos2 + 1;
427  }
428  while (pos2 != std::string::npos);
429 
430  // FIXME: Should always be the case that iscmplx == false.
431  // Flag is initialized that way and no data has been read.
432  if (iscmplx)
433  cdata.resize (rmax, cmax, empty_value);
434  else
435  rdata.resize (rmax, cmax, empty_value);
436  }
437 
438  r = (r > i + 1 ? r : i + 1);
439  j = 0;
440 
441  std::size_t pos1, pos2;
442  if (auto_sep_is_wspace)
443  pos1 = line.find_first_not_of (" \t"); // Skip leading whitespace.
444  else
445  pos1 = 0;
446 
447  do
448  {
449  octave_quit ();
450 
451  pos2 = line.find_first_of (sep, pos1);
452  std::string str = line.substr (pos1, pos2 - pos1);
453 
454  if (auto_sep_is_wspace && pos2 != std::string::npos)
455  {
456  // Treat consecutive separators as one.
457  pos2 = line.find_first_not_of (sep, pos2);
458  if (pos2 != std::string::npos)
459  pos2 -= 1;
460  else
461  pos2 = line.length () - 1;
462  }
463 
464  // Separator followed by EOL doesn't generate extra column
465  if (pos2 == std::string::npos && str.empty ())
466  break;
467 
468  c = (c > j + 1 ? c : j + 1);
469  if (r > rmax || c > cmax)
470  {
471  // Use resize_and_fill for the case of unequal length rows.
472  // Keep rmax a power of 2.
473  rmax = std::max (2*(r-1), rmax);
474  cmax = std::max (c, cmax);
475  if (iscmplx)
476  cdata.resize (rmax, cmax, empty_value);
477  else
478  rdata.resize (rmax, cmax, empty_value);
479  }
480 
481  tmp_stream.str (str);
482  tmp_stream.clear ();
483 
484  double x = read_value<double> (tmp_stream);
485  if (tmp_stream)
486  {
487  if (tmp_stream.eof ())
488  {
489  if (iscmplx)
490  cdata(i, j++) = x;
491  else
492  rdata(i, j++) = x;
493  }
494  else
495  {
496  int next_char = tmp_stream.peek ();
497  if (next_char == 'i' || next_char == 'j'
498  || next_char == 'I' || next_char == 'J')
499  {
500  // Process pure imaginary numbers.
501  tmp_stream.get ();
502  next_char = tmp_stream.peek ();
503  if (next_char == std::istringstream::traits_type::eof ())
504  {
505  if (! iscmplx)
506  {
507  iscmplx = true;
508  cdata = ComplexMatrix (rdata);
509  }
510 
511  cdata(i, j++) = Complex (0, x);
512  }
513  else
514  {
515  // Parsing failed, <number>i|j<extra text>
516  j++; // Leave data initialized to empty_value
517  }
518  }
519  else if (std::isalpha (next_char) && ! std::isfinite (x))
520  {
521  // Parsing failed, <Inf|NA|NaN><extra text>
522  j++; // Leave data initialized to empty_value
523  }
524  else
525  {
526  double y = read_value<double> (tmp_stream);
527 
528  if (! iscmplx && y != 0.0)
529  {
530  iscmplx = true;
531  cdata = ComplexMatrix (rdata);
532  }
533 
534  if (iscmplx)
535  cdata(i, j++) = Complex (x, y);
536  else
537  rdata(i, j++) = x;
538  }
539  }
540  }
541  else
542  {
543  // read_value<double>() parsing failed
544  j++; // Leave data initialized to empty_value
545  }
546 
547  pos1 = pos2 + 1;
548  }
549  while (pos2 != std::string::npos);
550 
551  if (i == r1)
552  break; // Stop early if the desired range has been read.
553 
554  i++;
555  }
556 
557  // Clip selection indices to actual size of data
558  if (r1 >= r)
559  r1 = r - 1;
560  if (c1 >= c)
561  c1 = c - 1;
562 
563  if (iscmplx)
564  {
565  if ((i == 0 && j == 0) || (c0 > c1))
566  return ovl (ComplexMatrix (0, 0));
567 
568  cdata = cdata.extract (0, c0, r1, c1);
569  return ovl (cdata);
570  }
571  else
572  {
573  if ((i == 0 && j == 0) || (c0 > c1))
574  return ovl (Matrix (0, 0));
575 
576  rdata = rdata.extract (0, c0, r1, c1);
577  return ovl (rdata);
578  }
579 }
580 
581 /*
582 %!test
583 %! file = tempname ();
584 %! unwind_protect
585 %! fid = fopen (file, "wt");
586 %! fwrite (fid, "1, 2, 3\n4, 5, 6\n7, 8, 9\n10, 11, 12");
587 %! fclose (fid);
588 %!
589 %! assert (dlmread (file), [1, 2, 3; 4, 5, 6; 7, 8, 9;10, 11, 12]);
590 %! assert (dlmread (file, ","), [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12]);
591 %! assert (dlmread (file, ",", [1, 0, 2, 1]), [4, 5; 7, 8]);
592 %! assert (dlmread (file, ",", "B1..C2"), [2, 3; 5, 6]);
593 %! assert (dlmread (file, ",", "B1:C2"), [2, 3; 5, 6]);
594 %! assert (dlmread (file, ",", "..C2"), [1, 2, 3; 4, 5, 6]);
595 %! assert (dlmread (file, ",", 0, 1), [2, 3; 5, 6; 8, 9; 11, 12]);
596 %! assert (dlmread (file, ",", "B1.."), [2, 3; 5, 6; 8, 9; 11, 12]);
597 %! assert (dlmread (file, ",", 10, 0), []);
598 %! assert (dlmread (file, ",", 0, 10), []);
599 %! fail ('dlmread (file, ",", [0 1])', "error parsing RANGE");
600 %! unwind_protect_cleanup
601 %! unlink (file);
602 %! end_unwind_protect
603 
604 %!testif ; ! ismac ()
605 %! file = tempname ();
606 %! unwind_protect
607 %! fid = fopen (file, "wt");
608 %! fwrite (fid, "1, 2, 3\n4+4i, 5, 6\n7, 8, 9\n10, 11, 12");
609 %! fclose (fid);
610 %!
611 %! assert (dlmread (file), [1, 2, 3; 4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]);
612 %! assert (dlmread (file, ","), [1,2,3; 4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]);
613 %! assert (dlmread (file, ",", [1, 0, 2, 1]), [4 + 4i, 5; 7, 8]);
614 %! assert (dlmread (file, ",", "A2..B3"), [4 + 4i, 5; 7, 8]);
615 %! assert (dlmread (file, ",", "A2:B3"), [4 + 4i, 5; 7, 8]);
616 %! assert (dlmread (file, ",", "..B3"), [1, 2; 4 + 4i, 5; 7, 8]);
617 %! assert (dlmread (file, ",", 1, 0), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]);
618 %! assert (dlmread (file, ",", "A2.."), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]);
619 %! assert (dlmread (file, ",", 10, 0), []);
620 %! assert (dlmread (file, ",", 0, 10), []);
621 %! unwind_protect_cleanup
622 %! unlink (file);
623 %! end_unwind_protect
624 
625 %!test <47413>
626 %! ## Same test code as above, but intended only for test statistics on Mac.
627 %! if (! ismac ()), return; endif
628 %! file = tempname ();
629 %! unwind_protect
630 %! fid = fopen (file, "wt");
631 %! fwrite (fid, "1, 2, 3\n4+4i, 5, 6\n7, 8, 9\n10, 11, 12");
632 %! fclose (fid);
633 %!
634 %! assert (dlmread (file), [1, 2, 3; 4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]);
635 %! assert (dlmread (file, ","), [1,2,3; 4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]);
636 %! assert (dlmread (file, ",", [1, 0, 2, 1]), [4 + 4i, 5; 7, 8]);
637 %! assert (dlmread (file, ",", "A2..B3"), [4 + 4i, 5; 7, 8]);
638 %! assert (dlmread (file, ",", "A2:B3"), [4 + 4i, 5; 7, 8]);
639 %! assert (dlmread (file, ",", "..B3"), [1, 2; 4 + 4i, 5; 7, 8]);
640 %! assert (dlmread (file, ",", 1, 0), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]);
641 %! assert (dlmread (file, ",", "A2.."), [4 + 4i, 5, 6; 7, 8, 9; 10, 11, 12]);
642 %! assert (dlmread (file, ",", 10, 0), []);
643 %! assert (dlmread (file, ",", 0, 10), []);
644 %! unwind_protect_cleanup
645 %! unlink (file);
646 %! end_unwind_protect
647 
648 %!test <*42025>
649 %! file = tempname ();
650 %! unwind_protect
651 %! fid = fopen (file, "wt");
652 %! fwrite (fid, " \n 1 2\n11 22\n ");
653 %! fclose (fid);
654 %!
655 %! assert (dlmread (file), [1, 2; 11, 22]);
656 %! assert (dlmread (file, " "), [ 0, 0, 0, 0
657 %! 0, 1, 2, 0
658 %! 11, 22, 0, 0
659 %! 0, 0, 0, 0]);
660 %! unwind_protect_cleanup
661 %! unlink (file);
662 %! end_unwind_protect
663 
664 %!testif ; ! ismac () <*50589>
665 %! file = tempname ();
666 %! unwind_protect
667 %! fid = fopen (file, "wt");
668 %! fwrite (fid, "1;2;3\n");
669 %! fwrite (fid, "1i;2I;3j;4J\n");
670 %! fwrite (fid, "4;5;6\n");
671 %! fwrite (fid, "-4i;+5I;-6j;+7J\n");
672 %! fclose (fid);
673 %!
674 %! assert (dlmread (file), [1, 2, 3, 0; 1i, 2i, 3i, 4i;
675 %! 4, 5, 6, 0; -4i, 5i, -6i, 7i]);
676 %! assert (dlmread (file, "", [0 0 0 3]), [1, 2, 3]);
677 %! assert (dlmread (file, "", [1 0 1 3]), [1i, 2i, 3i, 4i]);
678 %! unwind_protect_cleanup
679 %! unlink (file);
680 %! end_unwind_protect
681 
682 %!test <47413>
683 %! ## Same test code as above, but intended only for test statistics on Mac.
684 %! if (! ismac ()), return; endif
685 %! file = tempname ();
686 %! unwind_protect
687 %! fid = fopen (file, "wt");
688 %! fwrite (fid, "1;2;3\n");
689 %! fwrite (fid, "1i;2I;3j;4J\n");
690 %! fwrite (fid, "4;5;6\n");
691 %! fwrite (fid, "-4i;+5I;-6j;+7J\n");
692 %! fclose (fid);
693 %!
694 %! assert (dlmread (file), [1, 2, 3, 0; 1i, 2i, 3i, 4i;
695 %! 4, 5, 6, 0; -4i, 5i, -6i, 7i]);
696 %! assert (dlmread (file, "", [0 0 0 3]), [1, 2, 3]);
697 %! assert (dlmread (file, "", [1 0 1 3]), [1i, 2i, 3i, 4i]);
698 %! unwind_protect_cleanup
699 %! unlink (file);
700 %! end_unwind_protect
701 
702 ## NA was not properly read from a file
703 %!test
704 %! file = tempname ();
705 %! unwind_protect
706 %! fid = fopen (file, "wt");
707 %! fwrite (fid, "1,NA,3");
708 %! fclose (fid);
709 %!
710 %! assert (dlmread (file), [1, NA, 3]);
711 %! unwind_protect_cleanup
712 %! unlink (file);
713 %! end_unwind_protect
714 
715 ## "Name" was read as NA rather than parse error
716 %!test <*54029>
717 %! file = tempname ();
718 %! unwind_protect
719 %! fid = fopen (file, "wt");
720 %! fwrite (fid, "NaNe,bNa,Name,c\n1,NaN,3,Inftest\n-Inf,6,NA,8");
721 %! fclose (fid);
722 %!
723 %! assert (dlmread (file), [0, 0, 0, 0; 1, NaN, 3, 0; -Inf, 6, NA, 8]);
724 %! unwind_protect_cleanup
725 %! unlink (file);
726 %! end_unwind_protect
727 
728 ## Infinity incorrectly changed matrix to complex, rather than parse error
729 %!test
730 %! file = tempname ();
731 %! unwind_protect
732 %! fid = fopen (file, "wt");
733 %! fwrite (fid, "1,Infinity,3");
734 %! fclose (fid);
735 %!
736 %! assert (dlmread (file), [1, 0, 3]);
737 %! unwind_protect_cleanup
738 %! unlink (file);
739 %! end_unwind_protect
740 
741 ## Purely complex numbers with trailing garbage produced complex matrix
742 %!test
743 %! file = tempname ();
744 %! unwind_protect
745 %! fid = fopen (file, "wt");
746 %! fwrite (fid, "1,2jack,3");
747 %! fclose (fid);
748 %!
749 %! assert (dlmread (file), [1, 0, 3]);
750 %! unwind_protect_cleanup
751 %! unlink (file);
752 %! end_unwind_protect
753 
754 ## Verify UTF-8 Byte Order Mark does not cause problems with reading
755 %!test <*58813>
756 %! file = tempname ();
757 %! unwind_protect
758 %! fid = fopen (file, "wt");
759 %! fwrite (fid, char ([0xEF, 0xBB, 0xBF])); # UTF-8 BOM
760 %! fwrite (fid, "1,2\n3,4");
761 %! fclose (fid);
762 %!
763 %! assert (dlmread (file), [1, 2; 3, 4]);
764 %! unwind_protect_cleanup
765 %! unlink (file);
766 %! end_unwind_protect
767 
768 */
769 
OCTAVE_END_NAMESPACE(octave)
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
OCTAVE_API ComplexMatrix extract(octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
Definition: CMatrix.cc:683
void resize(octave_idx_type nr, octave_idx_type nc, const Complex &rfv=Complex(0))
Definition: CMatrix.h:193
Definition: dMatrix.h:42
OCTAVE_API Matrix extract(octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) const
Definition: dMatrix.cc:397
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:158
octave_idx_type numel(void) const
Definition: ov.h:604
bool is_string(void) const
Definition: ov.h:682
std::string string_value(bool force=false) const
Definition: ov.h:1019
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:904
bool is_real_matrix(void) const
Definition: ov.h:658
OCTINTERP_API stream lookup(int fid, const std::string &who="") const
Definition: oct-stream.cc:7460
std::istream * input_stream(void)
Definition: oct-stream.h:452
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
OCTINTERP_API void print_usage(void)
Definition: defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:111
static bool read_cell_spec(std::istream &is, octave_idx_type &row, octave_idx_type &col)
Definition: dlmread.cc:56
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)
Definition: dlmread.cc:92
static const double idx_max_dbl
Definition: dlmread.cc:53
static const octave_idx_type idx_max
Definition: dlmread.cc:51
void error(const char *fmt,...)
Definition: error.cc:979
std::string tilde_expand(const std::string &name)
Definition: file-ops.cc:283
bool isfinite(double x)
Definition: lo-mappers.h:192
F77_RET_T const F77_DBLE * x
std::ifstream ifstream(const std::string &filename, const std::ios::openmode mode)
Definition: lo-sysdep.cc:424
std::wstring u8_to_wstring(const std::string &utf8_string)
Definition: lo-sysdep.cc:514
class OCTAVE_API ComplexMatrix
Definition: mx-fwd.h:32
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
std::complex< double > Complex
Definition: oct-cmplx.h:33
static int input(yyscan_t yyscanner)
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
class OCTAVE_API range
Definition: range-fwd.h:33
subroutine stat(x, n, av, var, xmin, xmax)
Definition: tstgmn.for:112
std::string do_string_escapes(const std::string &s)
Definition: utils.cc:804
std::string find_data_file_in_load_path(const std::string &fcn, const std::string &file, bool require_regular_file)
Definition: utils.cc:703