lo-utils.cc

Go to the documentation of this file.
00001 // utils.cc
00002 /*
00003 
00004 Copyright (C) 1996-2012 John W. Eaton
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <cctype>
00029 #include <cstdlib>
00030 #include <cstdio>
00031 #include <cstring>
00032 #include <cfloat>
00033 
00034 #include <limits>
00035 #include <string>
00036 
00037 #include <sys/types.h>
00038 #include <unistd.h>
00039 
00040 #include "quit.h"
00041 
00042 #include "lo-error.h"
00043 #include "lo-ieee.h"
00044 #include "lo-mappers.h"
00045 #include "lo-utils.h"
00046 
00047 bool xis_int_or_inf_or_nan (double x)
00048 { return xisnan (x) || D_NINT (x) == x; }
00049 
00050 bool xis_one_or_zero (double x)
00051 { return x == 0 || x == 1; }
00052 
00053 bool xis_zero (double x)
00054 { return x == 0; }
00055 
00056 bool xtoo_large_for_float (double x)
00057 { return (! (xisnan (x) || xisinf (x)) && fabs (x) > FLT_MAX); }
00058 
00059 bool xis_int_or_inf_or_nan (float x)
00060 { return xisnan (x) || D_NINT (x) == x; }
00061 
00062 bool xis_one_or_zero (float x)
00063 { return x == 0 || x == 1; }
00064 
00065 bool xis_zero (float x)
00066 { return x == 0; }
00067 
00068 // Save a string.
00069 
00070 char *
00071 strsave (const char *s)
00072 {
00073   if (! s)
00074     return 0;
00075 
00076   int len = strlen (s);
00077   char *tmp = new char [len+1];
00078   tmp = strcpy (tmp, s);
00079   return tmp;
00080 }
00081 
00082 // This function was adapted from xputenv from Karl Berry's kpathsearch
00083 // library.
00084 
00085 // FIXME -- make this do the right thing if we don't have a
00086 // SMART_PUTENV.
00087 
00088 void
00089 octave_putenv (const std::string& name, const std::string& value)
00090 {
00091   int new_len = name.length () + value.length () + 2;
00092 
00093   char *new_item = static_cast<char*> (gnulib::malloc (new_len));
00094 
00095   sprintf (new_item, "%s=%s", name.c_str (), value.c_str ());
00096 
00097   // As far as I can see there's no way to distinguish between the
00098   // various errors; putenv doesn't have errno values.
00099 
00100   if (putenv (new_item) < 0)
00101     (*current_liboctave_error_handler) ("putenv (%s) failed", new_item);
00102 }
00103 
00104 std::string
00105 octave_fgets (FILE *f)
00106 {
00107   bool eof;
00108   return octave_fgets (f, eof);
00109 }
00110 
00111 std::string
00112 octave_fgets (FILE *f, bool& eof)
00113 {
00114   eof = false;
00115 
00116   std::string retval;
00117 
00118   int grow_size = 1024;
00119   int max_size = grow_size;
00120 
00121   char *buf = static_cast<char *> (gnulib::malloc (max_size));
00122   char *bufptr = buf;
00123   int len = 0;
00124 
00125   do
00126     {
00127       if (gnulib::fgets (bufptr, grow_size, f))
00128         {
00129           len = strlen (bufptr);
00130 
00131           if (len == grow_size - 1)
00132             {
00133               int tmp = bufptr - buf + grow_size - 1;
00134               grow_size *= 2;
00135               max_size += grow_size;
00136               buf = static_cast<char *> (gnulib::realloc (buf, max_size));
00137               bufptr = buf + tmp;
00138 
00139               if (*(bufptr-1) == '\n')
00140                 {
00141                   *bufptr = '\0';
00142                   retval = buf;
00143                 }
00144             }
00145           else if (bufptr[len-1] != '\n')
00146             {
00147               bufptr[len++] = '\n';
00148               bufptr[len] = '\0';
00149               retval = buf;
00150             }
00151           else
00152             retval = buf;
00153         }
00154       else
00155         {
00156           if (len == 0)
00157             {
00158               eof = true;
00159 
00160               free (buf);
00161 
00162               buf = 0;
00163             }
00164 
00165           break;
00166         }
00167     }
00168   while (retval.empty ());
00169 
00170   if (buf)
00171     free (buf);
00172 
00173   octave_quit ();
00174 
00175   return retval;
00176 }
00177 
00178 std::string
00179 octave_fgetl (FILE *f)
00180 {
00181   bool eof;
00182   return octave_fgetl (f, eof);
00183 }
00184 
00185 std::string
00186 octave_fgetl (FILE *f, bool& eof)
00187 {
00188   std::string retval = octave_fgets (f, eof);
00189 
00190   size_t len = retval.length ();
00191 
00192   if (retval[len-1] == '\n')
00193     retval.resize (len-1);
00194 
00195   return retval;
00196 }
00197 
00198 // Note that the caller is responsible for repositioning the stream on
00199 // failure.
00200 
00201 static inline double
00202 read_inf_nan_na (std::istream& is, char c0)
00203 {
00204   double d = 0.0;
00205 
00206   switch (c0)
00207     {
00208     case 'i': case 'I':
00209       {
00210         char c1 = is.get ();
00211         if (c1 == 'n' || c1 == 'N')
00212           {
00213             char c2 = is.get ();
00214             if (c2 == 'f' || c2 == 'F')
00215               d = octave_Inf;
00216             else
00217               is.setstate (std::ios::failbit);
00218           }
00219         else
00220           is.setstate (std::ios::failbit);
00221       }
00222       break;
00223 
00224     case 'n': case 'N':
00225       {
00226         char c1 = is.get ();
00227         if (c1 == 'a' || c1 == 'A')
00228           {
00229             char c2 = is.get ();
00230             if (c2 == 'n' || c2 == 'N')
00231               d = octave_NaN;
00232             else
00233               d = octave_NA;
00234           }
00235         else
00236           is.setstate (std::ios::failbit);
00237       }
00238       break;
00239 
00240     default:
00241       abort ();
00242     }
00243 
00244   return d;
00245 }
00246 
00247 // Read a double value.  Discard any sign on NaN and NA.
00248 
00249 template <>
00250 double
00251 octave_read_value (std::istream& is)
00252 {
00253   double d = 0.0;
00254 
00255   // FIXME -- resetting stream position is likely to fail unless we are
00256   // reading from a file.
00257   std::ios::streampos pos = is.tellg ();
00258 
00259   char c1 = ' ';
00260 
00261   while (isspace (c1))
00262     c1 = is.get ();
00263 
00264   bool neg = false;
00265 
00266   switch (c1)
00267     {
00268     case '-':
00269       neg = true;
00270       // fall through...
00271 
00272     case '+':
00273       {
00274         char c2 = 0;
00275         c2 = is.get ();
00276         if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
00277           d = read_inf_nan_na (is, c2);
00278         else
00279           {
00280             is.putback (c2);
00281             is >> d;
00282           }
00283 
00284         if (neg && ! is.fail ())
00285           d = -d;
00286       }
00287       break;
00288 
00289     case 'i': case 'I':
00290     case 'n': case 'N':
00291       d = read_inf_nan_na (is, c1);
00292       break;
00293 
00294     default:
00295       is.putback (c1);
00296       is >> d;
00297       break;
00298     }
00299 
00300   std::ios::iostate status = is.rdstate ();
00301   if (status & std::ios::failbit)
00302     {
00303       is.clear ();
00304       is.seekg (pos);
00305       is.setstate (status);
00306     }
00307 
00308   return d;
00309 }
00310 
00311 template <>
00312 Complex
00313 octave_read_value (std::istream& is)
00314 {
00315   double re = 0.0, im = 0.0;
00316 
00317   Complex cx = 0.0;
00318 
00319   char ch = ' ';
00320 
00321   while (isspace (ch))
00322     ch = is.get ();
00323 
00324   if (ch == '(')
00325     {
00326       re = octave_read_value<double> (is);
00327       ch = is.get ();
00328 
00329       if (ch == ',')
00330         {
00331           im = octave_read_value<double> (is);
00332           ch = is.get ();
00333 
00334           if (ch == ')')
00335             cx = Complex (re, im);
00336           else
00337             is.setstate (std::ios::failbit);
00338         }
00339       else if (ch == ')')
00340         cx = re;
00341       else
00342         is.setstate (std::ios::failbit);
00343     }
00344   else
00345     {
00346       is.putback (ch);
00347       cx = octave_read_value<double> (is);
00348     }
00349 
00350   return cx;
00351 
00352 }
00353 
00354 // Note that the caller is responsible for repositioning the stream on
00355 // failure.
00356 
00357 static inline float
00358 read_float_inf_nan_na (std::istream& is, char c0, char sign = '+')
00359 {
00360   float d = 0.0;
00361 
00362   switch (c0)
00363     {
00364     case 'i': case 'I':
00365       {
00366         char c1 = is.get ();
00367         if (c1 == 'n' || c1 == 'N')
00368           {
00369             char c2 = is.get ();
00370             if (c2 == 'f' || c2 == 'F')
00371               d = octave_Float_Inf;
00372             else
00373               is.setstate (std::ios::failbit);
00374           }
00375         else
00376           is.setstate (std::ios::failbit);
00377       }
00378       break;
00379 
00380     case 'n': case 'N':
00381       {
00382         char c1 = is.get ();
00383         if (c1 == 'a' || c1 == 'A')
00384           {
00385             char c2 = is.get ();
00386             if (c2 == 'n' || c2 == 'N')
00387               d = octave_Float_NaN;
00388             else
00389               d = octave_Float_NA;
00390           }
00391         else
00392           is.setstate (std::ios::failbit);
00393       }
00394       break;
00395 
00396     default:
00397       abort ();
00398     }
00399 
00400   return d;
00401 }
00402 
00403 // Read a float value.  Discard any sign on NaN and NA.
00404 
00405 template <>
00406 float
00407 octave_read_value (std::istream& is)
00408 {
00409   float d = 0.0;
00410 
00411   // FIXME -- resetting stream position is likely to fail unless we are
00412   // reading from a file.
00413   std::ios::streampos pos = is.tellg ();
00414 
00415   char c1 = ' ';
00416 
00417   while (isspace (c1))
00418     c1 = is.get ();
00419 
00420   bool neg = false;
00421 
00422   switch (c1)
00423     {
00424     case '-':
00425       neg = true;
00426       // fall through...
00427 
00428     case '+':
00429       {
00430         char c2 = 0;
00431         c2 = is.get ();
00432         if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
00433           d = read_float_inf_nan_na (is, c2);
00434         else
00435           {
00436             is.putback (c2);
00437             is >> d;
00438           }
00439 
00440         if (neg && ! is.fail ())
00441           d = -d;
00442       }
00443       break;
00444 
00445     case 'i': case 'I':
00446     case 'n': case 'N':
00447       d = read_float_inf_nan_na (is, c1);
00448       break;
00449 
00450     default:
00451       is.putback (c1);
00452       is >> d;
00453       break;
00454     }
00455 
00456   std::ios::iostate status = is.rdstate ();
00457   if (status & std::ios::failbit)
00458     {
00459       is.clear ();
00460       is.seekg (pos);
00461       is.setstate (status);
00462     }
00463 
00464   return d;
00465 }
00466 
00467 template <>
00468 FloatComplex
00469 octave_read_value (std::istream& is)
00470 {
00471   float re = 0.0, im = 0.0;
00472 
00473   FloatComplex cx = 0.0;
00474 
00475   char ch = ' ';
00476 
00477   while (isspace (ch))
00478     ch = is.get ();
00479 
00480   if (ch == '(')
00481     {
00482       re = octave_read_value<float> (is);
00483       ch = is.get ();
00484 
00485       if (ch == ',')
00486         {
00487           im = octave_read_value<float> (is);
00488           ch = is.get ();
00489 
00490           if (ch == ')')
00491             cx = FloatComplex (re, im);
00492           else
00493             is.setstate (std::ios::failbit);
00494         }
00495       else if (ch == ')')
00496         cx = re;
00497       else
00498         is.setstate (std::ios::failbit);
00499     }
00500   else
00501     {
00502       is.putback (ch);
00503       cx = octave_read_value<float> (is);
00504     }
00505 
00506   return cx;
00507 
00508 }
00509 
00510 void
00511 octave_write_double (std::ostream& os, double d)
00512 {
00513   if (lo_ieee_is_NA (d))
00514     os << "NA";
00515   else if (lo_ieee_isnan (d))
00516     os << "NaN";
00517   else if (lo_ieee_isinf (d))
00518     os << (d < 0 ? "-Inf" : "Inf");
00519   else
00520     os << d;
00521 }
00522 
00523 void
00524 octave_write_complex (std::ostream& os, const Complex& c)
00525 {
00526   os << "(";
00527   octave_write_double (os, real (c));
00528   os << ",";
00529   octave_write_double (os, imag (c));
00530   os << ")";
00531 }
00532 
00533 void
00534 octave_write_float (std::ostream& os, float d)
00535 {
00536   if (lo_ieee_is_NA (d))
00537     os << "NA";
00538   else if (lo_ieee_isnan (d))
00539     os << "NaN";
00540   else if (lo_ieee_isinf (d))
00541     os << (d < 0 ? "-Inf" : "Inf");
00542   else
00543     os << d;
00544 }
00545 
00546 void
00547 octave_write_float_complex (std::ostream& os, const FloatComplex& c)
00548 {
00549   os << "(";
00550   octave_write_float (os, real (c));
00551   os << ",";
00552   octave_write_float (os, imag (c));
00553   os << ")";
00554 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines