GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ls-mat-ascii.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 1996-2018 John W. Eaton
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include <cctype>
28 
29 #include <iomanip>
30 #include <iostream>
31 #include <sstream>
32 #include <string>
33 
34 #include "byte-swap.h"
35 #include "dMatrix.h"
36 #include "data-conv.h"
37 #include "file-ops.h"
38 #include "glob-match.h"
39 #include "lo-mappers.h"
40 #include "mach-info.h"
41 #include "oct-env.h"
42 #include "oct-time.h"
43 #include "quit.h"
44 
45 #include "Cell.h"
46 #include "defun.h"
47 #include "error.h"
48 #include "interpreter.h"
49 #include "lex.h"
50 #include "load-save.h"
51 #include "ls-ascii-helper.h"
52 #include "ls-mat-ascii.h"
53 #include "oct-map.h"
54 #include "ov-cell.h"
55 #include "ov.h"
56 #include "pager.h"
57 #include "pt-exp.h"
58 #include "sysdep.h"
59 #include "utils.h"
60 #include "variables.h"
61 #include "version.h"
62 
63 static std::string
64 get_mat_data_input_line (std::istream& is)
65 {
67 
68  bool have_data = false;
69 
70  do
71  {
72  retval = "";
73 
74  char c;
75  while (is.get (c))
76  {
77  if (c == '\n' || c == '\r')
78  {
79  is.putback (c);
81  break;
82  }
83 
84  if (c == '%' || c == '#')
85  {
86  skip_until_newline (is, false);
87  break;
88  }
89 
90  if (! is.eof ())
91  {
92  if (! have_data && c != ' ' && c != '\t')
93  have_data = true;
94 
95  retval += c;
96  }
97  }
98  }
99  while (! (have_data || is.eof ()));
100 
101  return retval;
102 }
103 
104 static void
105 get_lines_and_columns (std::istream& is,
107  const std::string& filename = "",
108  bool quiet = false, bool check_numeric = false)
109 {
110  std::streampos pos = is.tellg ();
111 
112  int file_line_number = 0;
113 
114  nr = 0;
115  nc = 0;
116 
117  while (is)
118  {
119  octave_quit ();
120 
122 
123  file_line_number++;
124 
125  size_t beg = buf.find_first_not_of (", \t");
126 
127  // If we see a CR as the last character in the buffer, we had a
128  // CRLF pair as the line separator. Any other CR in the text
129  // will not be considered as whitespace.
130 
131  if (beg != std::string::npos && buf[beg] == '\r'
132  && beg == buf.length () - 1)
133  {
134  // We had a blank line ending with a CRLF. Handle it the
135  // same as an empty line.
136  beg = std::string::npos;
137  }
138 
139  octave_idx_type tmp_nc = 0;
140 
141  while (beg != std::string::npos)
142  {
143  tmp_nc++;
144 
145  size_t end = buf.find_first_of (", \t", beg);
146 
147  if (end != std::string::npos)
148  {
149  if (check_numeric)
150  {
151  std::istringstream tmp_stream (buf.substr (beg, end-beg));
152 
153  octave_read_double (tmp_stream);
154 
155  if (tmp_stream.fail ())
156  {
157  if (! quiet)
158  error ("load: %s: non-numeric data found near line %d",
159  filename.c_str (), file_line_number);
160 
161  nr = 0;
162  nc = 0;
163 
164  goto done;
165  }
166  }
167 
168  beg = buf.find_first_not_of (", \t", end);
169 
170  if (beg == std::string::npos
171  || (buf[beg] == '\r' && beg == buf.length () - 1))
172  {
173  // We had a line with trailing spaces and ending with a CRLF,
174  // so this should look like EOL, not a new column.
175  break;
176  }
177  }
178  else
179  break;
180  }
181 
182  if (tmp_nc > 0)
183  {
184  if (nc == 0)
185  {
186  nc = tmp_nc;
187  nr++;
188  }
189  else if (nc == tmp_nc)
190  nr++;
191  else
192  {
193  if (! quiet)
194  error ("load: %s: inconsistent number of columns near line %d",
195  filename.c_str (), file_line_number);
196 
197  nr = 0;
198  nc = 0;
199 
200  goto done;
201  }
202  }
203  }
204 
205  if (! quiet && (nr == 0 || nc == 0))
206  error ("load: file '%s' seems to be empty!", filename.c_str ());
207 
208 done:
209 
210  is.clear ();
211  is.seekg (pos);
212 }
213 
214 // Extract a matrix from a file of numbers only.
215 //
216 // Comments are not allowed. The file should only have numeric values.
217 //
218 // Reads the file twice. Once to find the number of rows and columns,
219 // and once to extract the matrix.
220 //
221 // FILENAME is used for error messages.
222 //
223 // This format provides no way to tag the data as global.
224 
227  octave_value& tc)
228 {
229  std::string varname;
230 
231  size_t pos = filename.rfind ('/');
232 
233  if (pos != std::string::npos)
234  varname = filename.substr (pos+1);
235  else
236  varname = filename;
237 
238  pos = varname.rfind ('.');
239 
240  if (pos != std::string::npos)
241  varname = varname.substr (0, pos);
242 
243  size_t len = varname.length ();
244  for (size_t i = 0; i < len; i++)
245  {
246  char c = varname[i];
247  if (! (isalnum (c) || c == '_'))
248  varname[i] = '_';
249  }
250 
251  if (octave::is_keyword (varname) || ! isalpha (varname[0]))
252  varname.insert (0, "X");
253 
254  if (! valid_identifier (varname))
255  error ("load: unable to convert filename '%s' to valid identifier",
256  filename.c_str ());
257 
258  octave_idx_type nr = 0;
259  octave_idx_type nc = 0;
260 
261  int total_count = 0;
262 
263  get_lines_and_columns (is, nr, nc, filename);
264 
265  octave_quit ();
266 
267  if (nr <= 0 || nc <= 0)
268  error ("load: unable to extract matrix size from file '%s'",
269  filename.c_str ());
270 
271  Matrix tmp (nr, nc);
272 
273  if (nr < 1 || nc < 1)
274  is.clear (std::ios::badbit);
275  else
276  {
277  double d;
278  for (octave_idx_type i = 0; i < nr; i++)
279  {
281 
282  std::istringstream tmp_stream (buf);
283 
284  for (octave_idx_type j = 0; j < nc; j++)
285  {
286  octave_quit ();
287 
288  d = octave_read_value<double> (tmp_stream);
289 
290  if (! tmp_stream && ! tmp_stream.eof ())
291  error ("load: failed to read matrix from file '%s'",
292  filename.c_str ());
293 
294  tmp.elem (i, j) = d;
295  total_count++;
296 
297  // Skip whitespace and commas.
298  char c;
299  while (1)
300  {
301  tmp_stream >> c;
302 
303  if (! tmp_stream)
304  break;
305 
306  if (! (c == ' ' || c == '\t' || c == ','))
307  {
308  tmp_stream.putback (c);
309  break;
310  }
311  }
312 
313  if (tmp_stream.eof ())
314  break;
315  }
316  }
317  }
318 
319  if (! is && ! is.eof ())
320  error ("load: failed to read matrix from file '%s'",
321  filename.c_str ());
322 
323  // FIXME: not sure this is best, but it works.
324 
325  if (is.eof ())
326  is.clear ();
327 
328  octave_idx_type expected = nr * nc;
329 
330  if (expected != total_count)
331  error ("load: expected %d elements, found %d",
332  expected, total_count);
333 
334  tc = tmp;
335 
336  return varname;
337 }
338 
339 bool
340 save_mat_ascii_data (std::ostream& os, const octave_value& val,
341  int precision, bool tabs)
342 {
343  bool success = true;
344 
345  if (val.iscomplex ())
346  warning ("save: omitting imaginary part for ASCII file");
347 
348  if (val.ndims () > 2)
349  {
350  warning ("save: skipping variable which is not a 2-D matrix");
351  return true;
352  }
353 
354  Matrix m;
355 
356  try
357  {
358  m = val.matrix_value (true);
359  }
360  catch (const octave::execution_exception& e)
361  {
363 
364  success = false;
365  }
366 
367  if (success)
368  {
369  long old_precision = os.precision ();
370 
371  os.precision (precision);
372 
373  std::ios::fmtflags oflags
374  = os.flags (static_cast<std::ios::fmtflags> (std::ios::scientific));
375 
376  if (tabs)
377  {
378  for (octave_idx_type i = 0; i < m.rows (); i++)
379  {
380  for (octave_idx_type j = 0; j < m.cols (); j++)
381  {
382  // Omit leading tabs.
383  if (j != 0) os << '\t';
384  octave_write_double (os, m(i, j));
385  }
386  os << "\n";
387  }
388  }
389  else
390  os << m;
391 
392  // Restore format
393  os.flags (oflags);
394  os.precision (old_precision);
395  }
396 
397  return (os && success);
398 }
399 
400 bool
402 {
403  bool retval = false;
404  octave_idx_type nr = 0;
405  octave_idx_type nc = 0;
406 
407  get_lines_and_columns (is, nr, nc, filename, true, true);
408  retval = (nr != 0 && nc != 0);
409 
410  return retval;
411 }
void octave_write_double(std::ostream &os, double d)
Definition: lo-utils.cc:395
octave_idx_type rows(void) const
Definition: Array.h:404
double octave_read_double(std::istream &is)
Definition: lo-utils.h:104
std::string read_mat_ascii_data(std::istream &is, const std::string &filename, octave_value &tc)
static void recover_from_exception(void)
static void get_lines_and_columns(std::istream &is, octave_idx_type &nr, octave_idx_type &nc, const std::string &filename="", bool quiet=false, bool check_numeric=false)
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
void skip_until_newline(std::istream &is, bool keep_newline)
bool looks_like_mat_ascii_file(std::istream &is, const std::string &filename)
void error(const char *fmt,...)
Definition: error.cc:578
std::string filename
Definition: urlwrite.cc:121
void skip_preceeding_newline(std::istream &is)
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
i e
Definition: data.cc:2591
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
octave_idx_type cols(void) const
Definition: Array.h:412
bool save_mat_ascii_data(std::ostream &os, const octave_value &val, int precision, bool tabs)
done
Definition: syscalls.cc:251
bool valid_identifier(const char *s)
Definition: utils.cc:74
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
Definition: dMatrix.h:36
bool is_keyword(const std::string &s)
static std::string get_mat_data_input_line(std::istream &is)
Definition: ls-mat-ascii.cc:64
void warning(const char *fmt,...)
Definition: error.cc:801
for i
Definition: data.cc:5264
write the output to stdout if nargout is
Definition: load-save.cc:1612
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
octave::stream os
Definition: file-io.cc:627