GNU Octave  8.1.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-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 #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 "intprops-wrappers.h"
42 #include "lo-error.h"
43 #include "lo-ieee.h"
44 #include "lo-mappers.h"
45 #include "lo-utils.h"
46 #include "oct-inttypes.h"
47 
49 
50 bool is_int_or_inf_or_nan (double x)
51 {
52  return math::isnan (x) || math::x_nint (x) == x;
53 }
54 
55 bool too_large_for_float (double x)
56 {
57  return (math::isfinite (x)
58  && fabs (x) > std::numeric_limits<float>::max ());
59 }
60 
62 {
63  return (too_large_for_float (x.real ())
64  || too_large_for_float (x.imag ()));
65 }
66 
67 bool is_int_or_inf_or_nan (float x)
68 {
69  return math::isnan (x) || math::x_nint (x) == x;
70 }
71 
72 // Save a string.
73 
74 char * strsave (const char *s)
75 {
76  if (! s)
77  return nullptr;
78 
79  int len = strlen (s);
80  char *tmp = new char [len+1];
81  tmp = strcpy (tmp, s);
82  return tmp;
83 }
84 
85 std::string fgets (FILE *f)
86 {
87  bool eof;
88  return fgets (f, eof);
89 }
90 
91 std::string fgets (FILE *f, bool& eof)
92 {
93  eof = false;
94 
95  std::string retval;
96 
97  int grow_size = 1024;
98  int max_size = grow_size;
99 
100  char *buf = static_cast<char *> (std::malloc (max_size));
101  if (! buf)
102  (*current_liboctave_error_handler) ("octave_fgets: unable to malloc %d bytes", max_size);
103 
104  char *bufptr = buf;
105  int len = 0;
106 
107  do
108  {
109  if (std::fgets (bufptr, grow_size, f))
110  {
111  len = strlen (bufptr);
112 
113  if (len == grow_size - 1)
114  {
115  int tmp = bufptr - buf + grow_size - 1;
116  grow_size *= 2;
117  max_size += grow_size;
118  auto tmpbuf = static_cast<char *> (std::realloc (buf, max_size));
119  if (! tmpbuf)
120  {
121  free (buf);
122  (*current_liboctave_error_handler) ("octave_fgets: unable to realloc %d bytes", max_size);
123  }
124  buf = tmpbuf;
125  bufptr = buf + tmp;
126 
127  if (*(bufptr-1) == '\n')
128  {
129  *bufptr = '\0';
130  retval = buf;
131  }
132  }
133  else if (bufptr[len-1] != '\n')
134  {
135  bufptr[len++] = '\n';
136  bufptr[len] = '\0';
137  retval = buf;
138  }
139  else
140  retval = buf;
141  }
142  else
143  {
144  if (len == 0)
145  {
146  eof = true;
147 
148  free (buf);
149 
150  buf = nullptr;
151  }
152 
153  break;
154  }
155  }
156  while (retval.empty ());
157 
158  free (buf);
159 
160  octave_quit ();
161 
162  return retval;
163 }
164 
165 std::string fgetl (FILE *f)
166 {
167  bool eof;
168  return fgetl (f, eof);
169 }
170 
171 std::string fgetl (FILE *f, bool& eof)
172 {
173  std::string retval = fgets (f, eof);
174 
175  if (! retval.empty () && retval.back () == '\n')
176  retval.pop_back ();
177 
178  return retval;
179 }
180 
181 template <typename T>
182 T
183 read_value (std::istream& is)
184 {
185  T retval;
186  is >> retval;
187  return retval;
188 }
189 
190 template OCTAVE_API bool read_value<bool> (std::istream& is);
191 template OCTAVE_API octave_int8 read_value<octave_int8> (std::istream& is);
199 
200 // Note that the caller is responsible for repositioning the stream on
201 // failure.
202 
203 template <typename T>
204 T
205 read_inf_nan_na (std::istream& is, char c0)
206 {
207  T val = 0.0;
208 
209  switch (c0)
210  {
211  case 'i': case 'I':
212  {
213  char c1 = is.get ();
214  if (c1 == 'n' || c1 == 'N')
215  {
216  char c2 = is.get ();
217  if (c2 == 'f' || c2 == 'F')
218  val = std::numeric_limits<T>::infinity ();
219  else
220  is.setstate (std::ios::failbit);
221  }
222  else
223  is.setstate (std::ios::failbit);
224  }
225  break;
226 
227  case 'n': case 'N':
228  {
229  char c1 = is.get ();
230  if (c1 == 'a' || c1 == 'A')
231  {
232  char c2 = is.get ();
233  if (c2 == 'n' || c2 == 'N')
234  val = std::numeric_limits<T>::quiet_NaN ();
235  else
236  {
237  val = numeric_limits<T>::NA ();
238  if (c2 != std::istream::traits_type::eof ())
239  is.putback (c2);
240  else
241  is.clear (is.rdstate () & ~std::ios::failbit);
242  }
243  }
244  else
245  is.setstate (std::ios::failbit);
246  }
247  break;
248 
249  default:
250  (*current_liboctave_error_handler)
251  ("read_inf_nan_na: invalid character '%c'", c0);
252  }
253 
254  return val;
255 }
256 
257 // Read a double value. Discard any sign on NaN and NA.
258 
259 template <typename T>
260 double
261 read_fp_value (std::istream& is)
262 {
263  T val = 0.0;
264 
265  // FIXME: resetting stream position is likely to fail unless we are
266  // reading from a file.
267  std::streampos pos = is.tellg ();
268 
269  char c1 = ' ';
270 
271  while (isspace (c1))
272  c1 = is.get ();
273 
274  bool neg = false;
275 
276  switch (c1)
277  {
278  case '-':
279  neg = true;
280  OCTAVE_FALLTHROUGH;
281 
282  case '+':
283  {
284  char c2 = 0;
285  c2 = is.get ();
286  if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
287  val = read_inf_nan_na<T> (is, c2);
288  else
289  {
290  is.putback (c2);
291  is >> val;
292  }
293 
294  if (neg && ! is.fail ())
295  val = -val;
296  }
297  break;
298 
299  case 'i': case 'I':
300  case 'n': case 'N':
301  val = read_inf_nan_na<T> (is, c1);
302  break;
303 
304  default:
305  is.putback (c1);
306  is >> val;
307  break;
308  }
309 
310  std::ios::iostate status = is.rdstate ();
311  if (status & std::ios::failbit)
312  {
313  // Convert MAX_VAL returned by C++ streams for very large numbers to Inf
314  if (val == std::numeric_limits<T>::max ())
315  {
316  if (neg)
317  val = -std::numeric_limits<T>::infinity ();
318  else
319  val = std::numeric_limits<T>::infinity ();
320  is.clear (status & ~std::ios::failbit);
321  }
322  else
323  {
324  // True error. Reset stream to original position and pass status on.
325  is.clear ();
326  is.seekg (pos);
327  is.setstate (status);
328  }
329  }
330 
331  return val;
332 }
333 
334 template <typename T>
335 std::complex<T>
336 read_cx_fp_value (std::istream& is)
337 {
338  T re = 0.0;
339  T im = 0.0;
340 
341  std::complex<T> cx = 0.0;
342 
343  char ch = ' ';
344 
345  while (isspace (ch))
346  ch = is.get ();
347 
348  if (ch == '(')
349  {
350  re = read_value<T> (is);
351  ch = is.get ();
352 
353  if (ch == ',')
354  {
355  im = read_value<T> (is);
356  ch = is.get ();
357 
358  if (ch == ')')
359  cx = std::complex<T> (re, im);
360  else
361  is.setstate (std::ios::failbit);
362  }
363  else if (ch == ')')
364  cx = re;
365  else
366  is.setstate (std::ios::failbit);
367  }
368  else
369  {
370  is.putback (ch);
371  cx = read_value<T> (is);
372  }
373 
374  return cx;
375 }
376 
377 // FIXME: Could we use traits and enable_if to avoid duplication in the
378 // following specializations?
379 
380 template <> OCTAVE_API double read_value (std::istream& is)
381 {
382  return read_fp_value<double> (is);
383 }
384 
385 template <> OCTAVE_API Complex read_value (std::istream& is)
386 {
387  return read_cx_fp_value<double> (is);
388 }
389 
390 template <> OCTAVE_API float read_value (std::istream& is)
391 {
392  return read_fp_value<float> (is);
393 }
394 
395 template <> OCTAVE_API FloatComplex read_value (std::istream& is)
396 {
397  return read_cx_fp_value<float> (is);
398 }
399 
400 template <typename T>
401 void
402 write_value (std::ostream& os, const T& value)
403 {
404  os << value;
405 }
406 
407 template OCTAVE_API void
408 write_value<bool> (std::ostream& os, const bool& value);
409 template OCTAVE_API void
410 write_value<octave_int8> (std::ostream& os, const octave_int8& value);
411 template OCTAVE_API void
412 write_value<octave_int16> (std::ostream& os, const octave_int16& value);
413 template OCTAVE_API void
414 write_value<octave_int32> (std::ostream& os, const octave_int32& value);
415 template OCTAVE_API void
416 write_value<octave_int64> (std::ostream& os, const octave_int64& value);
417 template OCTAVE_API void
418 write_value<octave_uint8> (std::ostream& os, const octave_uint8& value);
419 template OCTAVE_API void
420 write_value<octave_uint16> (std::ostream& os, const octave_uint16& value);
421 template OCTAVE_API void
422 write_value<octave_uint32> (std::ostream& os, const octave_uint32& value);
423 template OCTAVE_API void
424 write_value<octave_uint64> (std::ostream& os, const octave_uint64& value);
425 
426 // Note: precision is supposed to be managed outside of this function by
427 // setting stream parameters.
428 
429 template <> OCTAVE_API void
430 write_value (std::ostream& os, const double& value)
431 {
432  if (lo_ieee_is_NA (value))
433  os << "NA";
434  else if (lo_ieee_isnan (value))
435  os << "NaN";
436  else if (lo_ieee_isinf (value))
437  os << (value < 0 ? "-Inf" : "Inf");
438  else
439  os << value;
440 }
441 
442 template <> OCTAVE_API void
443 write_value (std::ostream& os, const Complex& value)
444 {
445  os << '(';
446  write_value<double> (os, real (value));
447  os << ',';
448  write_value<double> (os, imag (value));
449  os << ')';
450 }
451 
452 // Note: precision is supposed to be managed outside of this function by
453 // setting stream parameters.
454 
455 template <> OCTAVE_API void
456 write_value (std::ostream& os, const float& value)
457 {
458  if (lo_ieee_is_NA (value))
459  os << "NA";
460  else if (lo_ieee_isnan (value))
461  os << "NaN";
462  else if (lo_ieee_isinf (value))
463  os << (value < 0 ? "-Inf" : "Inf");
464  else
465  os << value;
466 }
467 
468 template <> OCTAVE_API void
469 write_value (std::ostream& os, const FloatComplex& value)
470 {
471  os << '(';
472  write_value<float> (os, real (value));
473  os << ',';
474  write_value<float> (os, imag (value));
475  os << ')';
476 }
477 
479 
480 bool int_multiply_overflow (int a, int b, int *r)
481 {
482  return octave_i_multiply_overflow_wrapper (a, b, r);
483 }
484 
485 bool int_multiply_overflow (long int a, long int b, long int *r)
486 {
487  return octave_li_multiply_overflow_wrapper (a, b, r);
488 }
489 
490 #if defined (OCTAVE_HAVE_LONG_LONG_INT)
491 bool int_multiply_overflow (long long int a, long long int b,
492  long long int *r)
493 {
494  return octave_lli_multiply_overflow_wrapper (a, b, r);
495 }
496 #endif
497 
498 bool int_multiply_overflow (unsigned int a, unsigned int b,
499  unsigned int *r)
500 {
501  return octave_ui_multiply_overflow_wrapper (a, b, r);
502 }
503 
504 bool int_multiply_overflow (unsigned long int a, unsigned long int b,
505  unsigned long int *r)
506 {
508 }
509 
510 #if defined (OCTAVE_HAVE_UNSIGNED_LONG_LONG_INT)
511 bool int_multiply_overflow (unsigned long long int a,
512  unsigned long long int b,
513  unsigned long long int *r)
514 {
515  return octave_ulli_multiply_overflow_wrapper (a, b, r);
516 }
517 #endif
518 
OCTAVE_END_NAMESPACE(octave)
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
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
int octave_i_multiply_overflow_wrapper(int a, int b, int *r)
int octave_li_multiply_overflow_wrapper(long int a, long int b, long int *r)
int octave_uli_multiply_overflow_wrapper(unsigned long int a, unsigned long int b, unsigned long int *r)
int octave_ui_multiply_overflow_wrapper(unsigned int a, unsigned int b, unsigned int *r)
#define lo_ieee_isnan(x)
Definition: lo-ieee.h:100
#define lo_ieee_isinf(x)
Definition: lo-ieee.h:108
#define lo_ieee_is_NA(x)
Definition: lo-ieee.h:112
bool isfinite(double x)
Definition: lo-mappers.h:192
bool isnan(bool)
Definition: lo-mappers.h:178
T x_nint(T x)
Definition: lo-mappers.h:269
F77_RET_T const F77_DBLE * x
F77_RET_T const F77_DBLE const F77_DBLE * f
void write_value(std::ostream &os, const T &value)
Definition: lo-utils.cc:402
template OCTAVE_API octave_int64 read_value< octave_int64 >(std::istream &is)
bool is_int_or_inf_or_nan(double x)
Definition: lo-utils.cc:50
bool int_multiply_overflow(int a, int b, int *r)
Definition: lo-utils.cc:480
template OCTAVE_API void write_value< octave_uint8 >(std::ostream &os, const octave_uint8 &value)
template OCTAVE_API void write_value< octave_int8 >(std::ostream &os, const octave_int8 &value)
template OCTAVE_API octave_uint64 read_value< octave_uint64 >(std::istream &is)
template OCTAVE_API void write_value< octave_int16 >(std::ostream &os, const octave_int16 &value)
template OCTAVE_API void write_value< octave_int32 >(std::ostream &os, const octave_int32 &value)
template OCTAVE_API void write_value< octave_uint64 >(std::ostream &os, const octave_uint64 &value)
std::string fgetl(FILE *f)
Definition: lo-utils.cc:165
std::complex< T > read_cx_fp_value(std::istream &is)
Definition: lo-utils.cc:336
double read_fp_value(std::istream &is)
Definition: lo-utils.cc:261
template OCTAVE_API void write_value< octave_int64 >(std::ostream &os, const octave_int64 &value)
bool too_large_for_float(double x)
Definition: lo-utils.cc:55
template OCTAVE_API octave_uint8 read_value< octave_uint8 >(std::istream &is)
template OCTAVE_API octave_int32 read_value< octave_int32 >(std::istream &is)
template OCTAVE_API octave_int8 read_value< octave_int8 >(std::istream &is)
template OCTAVE_API void write_value< bool >(std::ostream &os, const bool &value)
std::string fgets(FILE *f)
Definition: lo-utils.cc:85
template OCTAVE_API bool read_value< bool >(std::istream &is)
template OCTAVE_API octave_int16 read_value< octave_int16 >(std::istream &is)
template OCTAVE_API octave_uint16 read_value< octave_uint16 >(std::istream &is)
template OCTAVE_API octave_uint32 read_value< octave_uint32 >(std::istream &is)
template OCTAVE_API void write_value< octave_uint16 >(std::ostream &os, const octave_uint16 &value)
char * strsave(const char *s)
Definition: lo-utils.cc:74
template OCTAVE_API void write_value< octave_uint32 >(std::ostream &os, const octave_uint32 &value)
T read_inf_nan_na(std::istream &is, char c0)
Definition: lo-utils.cc:205
T read_value(std::istream &is)
Definition: lo-utils.cc:183
#define OCTAVE_API
Definition: main.in.cc:55
T * r
Definition: mx-inlines.cc:773
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 *)
F77_RET_T len
Definition: xerbla.cc:61