GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
lo-utils.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2021 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 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <cstdlib>
31 #include <cstring>
32 
33 #include <complex>
34 #include <istream>
35 #include <limits>
36 #include <ostream>
37 #include <string>
38 
39 #include "quit.h"
40 
41 #include "lo-error.h"
42 #include "lo-ieee.h"
43 #include "lo-mappers.h"
44 #include "lo-utils.h"
45 
46 bool xis_int_or_inf_or_nan (double x)
47 { return octave::math::isnan (x) || octave::math::x_nint (x) == x; }
48 
49 bool xis_one_or_zero (double x)
50 { return x == 0 || x == 1; }
51 
52 bool xis_zero (double x)
53 { return x == 0; }
54 
55 bool xtoo_large_for_float (double x)
56 {
57  return (octave::math::isfinite (x)
58  && fabs (x) > std::numeric_limits<float>::max ());
59 }
60 
62 {
63  return (xtoo_large_for_float (x.real ())
64  || xtoo_large_for_float (x.imag ()));
65 }
66 
68 { return octave::math::isnan (x) || octave::math::x_nint (x) == x; }
69 
70 bool xis_one_or_zero (float x)
71 { return x == 0 || x == 1; }
72 
73 bool xis_zero (float x)
74 { return x == 0; }
75 
76 // Save a string.
77 
78 char *
79 strsave (const char *s)
80 {
81  if (! s)
82  return nullptr;
83 
84  int len = strlen (s);
85  char *tmp = new char [len+1];
86  tmp = strcpy (tmp, s);
87  return tmp;
88 }
89 
90 std::string
91 octave_fgets (FILE *f)
92 {
93  bool eof;
94  return octave_fgets (f, eof);
95 }
96 
97 std::string
98 octave_fgets (FILE *f, bool& eof)
99 {
100  eof = false;
101 
102  std::string retval;
103 
104  int grow_size = 1024;
105  int max_size = grow_size;
106 
107  char *buf = static_cast<char *> (std::malloc (max_size));
108  if (! buf)
109  (*current_liboctave_error_handler) ("octave_fgets: unable to malloc %d bytes", max_size);
110 
111  char *bufptr = buf;
112  int len = 0;
113 
114  do
115  {
116  if (std::fgets (bufptr, grow_size, f))
117  {
118  len = strlen (bufptr);
119 
120  if (len == grow_size - 1)
121  {
122  int tmp = bufptr - buf + grow_size - 1;
123  grow_size *= 2;
124  max_size += grow_size;
125  auto tmpbuf = static_cast<char *> (std::realloc (buf, max_size));
126  if (! tmpbuf)
127  {
128  free (buf);
129  (*current_liboctave_error_handler) ("octave_fgets: unable to realloc %d bytes", max_size);
130  }
131  buf = tmpbuf;
132  bufptr = buf + tmp;
133 
134  if (*(bufptr-1) == '\n')
135  {
136  *bufptr = '\0';
137  retval = buf;
138  }
139  }
140  else if (bufptr[len-1] != '\n')
141  {
142  bufptr[len++] = '\n';
143  bufptr[len] = '\0';
144  retval = buf;
145  }
146  else
147  retval = buf;
148  }
149  else
150  {
151  if (len == 0)
152  {
153  eof = true;
154 
155  free (buf);
156 
157  buf = nullptr;
158  }
159 
160  break;
161  }
162  }
163  while (retval.empty ());
164 
165  free (buf);
166 
167  octave_quit ();
168 
169  return retval;
170 }
171 
172 std::string
174 {
175  bool eof;
176  return octave_fgetl (f, eof);
177 }
178 
179 std::string
180 octave_fgetl (FILE *f, bool& eof)
181 {
182  std::string retval = octave_fgets (f, eof);
183 
184  if (! retval.empty () && retval.back () == '\n')
185  retval.pop_back ();
186 
187  return retval;
188 }
189 
190 // Note that the caller is responsible for repositioning the stream on failure.
191 
192 template <typename T>
193 T
194 read_inf_nan_na (std::istream& is, char c0)
195 {
196  T val = 0.0;
197 
198  switch (c0)
199  {
200  case 'i': case 'I':
201  {
202  char c1 = is.get ();
203  if (c1 == 'n' || c1 == 'N')
204  {
205  char c2 = is.get ();
206  if (c2 == 'f' || c2 == 'F')
207  val = std::numeric_limits<T>::infinity ();
208  else
209  is.setstate (std::ios::failbit);
210  }
211  else
212  is.setstate (std::ios::failbit);
213  }
214  break;
215 
216  case 'n': case 'N':
217  {
218  char c1 = is.get ();
219  if (c1 == 'a' || c1 == 'A')
220  {
221  char c2 = is.get ();
222  if (c2 == 'n' || c2 == 'N')
223  val = std::numeric_limits<T>::quiet_NaN ();
224  else
225  {
226  val = octave::numeric_limits<T>::NA ();
227  if (c2 != std::istream::traits_type::eof ())
228  is.putback (c2);
229  else
230  is.clear (is.rdstate () & ~std::ios::failbit);
231  }
232  }
233  else
234  is.setstate (std::ios::failbit);
235  }
236  break;
237 
238  default:
239  (*current_liboctave_error_handler)
240  ("read_inf_nan_na: invalid character '%c'", c0);
241  }
242 
243  return val;
244 }
245 
246 // Read a double value. Discard any sign on NaN and NA.
247 
248 template <typename T>
249 double
250 octave_read_fp_value (std::istream& is)
251 {
252  T val = 0.0;
253 
254  // FIXME: resetting stream position is likely to fail unless we are
255  // reading from a file.
256  std::streampos pos = is.tellg ();
257 
258  char c1 = ' ';
259 
260  while (isspace (c1))
261  c1 = is.get ();
262 
263  bool neg = false;
264 
265  switch (c1)
266  {
267  case '-':
268  neg = true;
269  OCTAVE_FALLTHROUGH;
270 
271  case '+':
272  {
273  char c2 = 0;
274  c2 = is.get ();
275  if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
276  val = read_inf_nan_na<T> (is, c2);
277  else
278  {
279  is.putback (c2);
280  is >> val;
281  }
282 
283  if (neg && ! is.fail ())
284  val = -val;
285  }
286  break;
287 
288  case 'i': case 'I':
289  case 'n': case 'N':
290  val = read_inf_nan_na<T> (is, c1);
291  break;
292 
293  default:
294  is.putback (c1);
295  is >> val;
296  break;
297  }
298 
299  std::ios::iostate status = is.rdstate ();
300  if (status & std::ios::failbit)
301  {
302  // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
303  if (val == std::numeric_limits<T>::max ())
304  {
305  if (neg)
306  val = -std::numeric_limits<T>::infinity ();
307  else
308  val = std::numeric_limits<T>::infinity ();
309  is.clear (status & ~std::ios::failbit);
310  }
311  else
312  {
313  // True error. Reset stream to original position and pass status on.
314  is.clear ();
315  is.seekg (pos);
316  is.setstate (status);
317  }
318  }
319 
320  return val;
321 }
322 
323 template <typename T>
324 std::complex<T>
325 octave_read_cx_fp_value (std::istream& is)
326 {
327  T re = 0.0;
328  T im = 0.0;
329 
330  std::complex<T> cx = 0.0;
331 
332  char ch = ' ';
333 
334  while (isspace (ch))
335  ch = is.get ();
336 
337  if (ch == '(')
338  {
339  re = octave_read_value<T> (is);
340  ch = is.get ();
341 
342  if (ch == ',')
343  {
344  im = octave_read_value<T> (is);
345  ch = is.get ();
346 
347  if (ch == ')')
348  cx = std::complex<T> (re, im);
349  else
350  is.setstate (std::ios::failbit);
351  }
352  else if (ch == ')')
353  cx = re;
354  else
355  is.setstate (std::ios::failbit);
356  }
357  else
358  {
359  is.putback (ch);
360  cx = octave_read_value<double> (is);
361  }
362 
363  return cx;
364 }
365 
366 template <> OCTAVE_API double octave_read_value (std::istream& is)
367 {
368  return octave_read_fp_value<double> (is);
369 }
370 
371 template <> OCTAVE_API Complex octave_read_value (std::istream& is)
372 {
373  return octave_read_cx_fp_value<double> (is);
374 }
375 
376 template <> OCTAVE_API float octave_read_value (std::istream& is)
377 {
378  return octave_read_fp_value<float> (is);
379 }
380 
381 template <> OCTAVE_API FloatComplex octave_read_value (std::istream& is)
382 {
383  return octave_read_cx_fp_value<float> (is);
384 }
385 
386 void
387 octave_write_double (std::ostream& os, double d)
388 {
389  if (lo_ieee_is_NA (d))
390  os << "NA";
391  else if (lo_ieee_isnan (d))
392  os << "NaN";
393  else if (lo_ieee_isinf (d))
394  os << (d < 0 ? "-Inf" : "Inf");
395  else
396  os << d;
397 }
398 
399 void
400 octave_write_complex (std::ostream& os, const Complex& c)
401 {
402  os << '(';
403  octave_write_double (os, real (c));
404  os << ',';
405  octave_write_double (os, imag (c));
406  os << ')';
407 }
408 
409 void
410 octave_write_float (std::ostream& os, float d)
411 {
412  if (lo_ieee_is_NA (d))
413  os << "NA";
414  else if (lo_ieee_isnan (d))
415  os << "NaN";
416  else if (lo_ieee_isinf (d))
417  os << (d < 0 ? "-Inf" : "Inf");
418  else
419  os << d;
420 }
421 
422 void
423 octave_write_float_complex (std::ostream& os, const FloatComplex& c)
424 {
425  os << '(';
426  octave_write_float (os, real (c));
427  os << ',';
428  octave_write_float (os, imag (c));
429  os << ')';
430 }
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
ColumnVector real(const ComplexColumnVector &a)
Definition: dColVector.cc:137
ColumnVector imag(const ComplexColumnVector &a)
Definition: dColVector.cc:143
#define lo_ieee_isnan(x)
Definition: lo-ieee.h:112
#define lo_ieee_isinf(x)
Definition: lo-ieee.h:120
#define lo_ieee_is_NA(x)
Definition: lo-ieee.h:124
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
F77_RET_T const F77_DBLE const F77_DBLE * f
std::complex< T > octave_read_cx_fp_value(std::istream &is)
Definition: lo-utils.cc:325
bool xis_zero(double x)
Definition: lo-utils.cc:52
bool xtoo_large_for_float(double x)
Definition: lo-utils.cc:55
void octave_write_double(std::ostream &os, double d)
Definition: lo-utils.cc:387
std::string octave_fgetl(FILE *f)
Definition: lo-utils.cc:173
void octave_write_complex(std::ostream &os, const Complex &c)
Definition: lo-utils.cc:400
bool xis_one_or_zero(double x)
Definition: lo-utils.cc:49
void octave_write_float_complex(std::ostream &os, const FloatComplex &c)
Definition: lo-utils.cc:423
double octave_read_fp_value(std::istream &is)
Definition: lo-utils.cc:250
void octave_write_float(std::ostream &os, float d)
Definition: lo-utils.cc:410
char * strsave(const char *s)
Definition: lo-utils.cc:79
bool xis_int_or_inf_or_nan(double x)
Definition: lo-utils.cc:46
std::string octave_fgets(FILE *f)
Definition: lo-utils.cc:91
T read_inf_nan_na(std::istream &is, char c0)
Definition: lo-utils.cc:194
OCTAVE_API double octave_read_value(std::istream &is)
Definition: lo-utils.cc:366
T x_nint(T x)
Definition: lo-mappers.h:262
bool isfinite(double x)
Definition: lo-mappers.h:192
bool isnan(bool)
Definition: lo-mappers.h:178
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:85
void * malloc(unsigned)
void free(void *)
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
F77_RET_T len
Definition: xerbla.cc:61