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