changeset 14806:980e2d5c83f7 stable

avoid calling putback more than once between reads * liboctave/lo-utils.cc (octave_read_value<double>, (octave_read_value<float>): Save stream position with tellg. On failure, restore stream position with seekg. Avoid calling putback multiple times between stream reads. (octave_read_inf_nan_na, octave_read_float_inf_nan_na): Don't call putback. Make it the caller's responsibility to reset stream positioning on failed reads.
author John W. Eaton <jwe@octave.org>
date Tue, 26 Jun 2012 16:18:35 -0400
parents f0552937a8eb
children 616981c9907c f06a16021024
files liboctave/lo-utils.cc
diffstat 1 files changed, 59 insertions(+), 73 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/lo-utils.cc	Tue Jun 26 16:14:58 2012 -0400
+++ b/liboctave/lo-utils.cc	Tue Jun 26 16:18:35 2012 -0400
@@ -195,8 +195,11 @@
   return retval;
 }
 
+// Note that the caller is responsible for repositioning the stream on
+// failure.
+
 static inline double
-read_inf_nan_na (std::istream& is, char c0, char sign = '+')
+read_inf_nan_na (std::istream& is, char c0)
 {
   double d = 0.0;
 
@@ -209,21 +212,12 @@
           {
             char c2 = is.get ();
             if (c2 == 'f' || c2 == 'F')
-              d = sign == '-' ? -octave_Inf : octave_Inf;
+              d = octave_Inf;
             else
-              {
-                is.putback (c2);
-                is.putback (c1);
-                is.putback (c0);
-                is.setstate (std::ios::failbit);
-              }
+              is.setstate (std::ios::failbit);
           }
         else
-          {
-            is.putback (c1);
-            is.putback (c0);
-            is.setstate (std::ios::failbit);
-          }
+          is.setstate (std::ios::failbit);
       }
       break;
 
@@ -236,17 +230,10 @@
             if (c2 == 'n' || c2 == 'N')
               d = octave_NaN;
             else
-              {
-                is.putback (c2);
-                d = octave_NA;
-              }
+              d = octave_NA;
           }
         else
-          {
-            is.putback (c1);
-            is.putback (c0);
-            is.setstate (std::ios::failbit);
-          }
+          is.setstate (std::ios::failbit);
       }
       break;
 
@@ -265,40 +252,37 @@
 {
   double d = 0.0;
 
+  // FIXME -- resetting stream position is likely to fail unless we are
+  // reading from a file.
+  std::ios::streampos pos = is.tellg ();
+
   char c1 = ' ';
 
   while (isspace (c1))
     c1 = is.get ();
 
+  bool neg = false;
+
   switch (c1)
     {
     case '-':
-      {
-        char c2 = 0;
-        c2 = is.get ();
-        if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          d = read_inf_nan_na (is, c2, c1);
-        else
-          {
-            is.putback (c2);
-            is.putback (c1);
-            is >> d;
-          }
-      }
-      break;
+      neg = true;
+      // fall through...
 
     case '+':
       {
         char c2 = 0;
         c2 = is.get ();
         if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          d = read_inf_nan_na (is, c2, c1);
+          d = read_inf_nan_na (is, c2);
         else
           {
             is.putback (c2);
-            is.putback (c1);
             is >> d;
           }
+
+        if (neg && ! is.fail ())
+          d = -d;
       }
       break;
 
@@ -310,6 +294,15 @@
     default:
       is.putback (c1);
       is >> d;
+      break;
+    }
+
+  std::ios::iostate status = is.rdstate ();
+  if (status & std::ios::failbit)
+    {
+      is.clear ();
+      is.seekg (pos);
+      is.setstate (status);
     }
 
   return d;
@@ -358,6 +351,9 @@
 
 }
 
+// Note that the caller is responsible for repositioning the stream on
+// failure.
+
 static inline float
 read_float_inf_nan_na (std::istream& is, char c0, char sign = '+')
 {
@@ -372,21 +368,12 @@
           {
             char c2 = is.get ();
             if (c2 == 'f' || c2 == 'F')
-              d = sign == '-' ? -octave_Float_Inf : octave_Float_Inf;
+              d = octave_Float_Inf;
             else
-              {
-                is.putback (c2);
-                is.putback (c1);
-                is.putback (c0);
-                is.setstate (std::ios::failbit);
-              }
+              is.setstate (std::ios::failbit);
           }
         else
-          {
-            is.putback (c1);
-            is.putback (c0);
-            is.setstate (std::ios::failbit);
-          }
+          is.setstate (std::ios::failbit);
       }
       break;
 
@@ -399,17 +386,10 @@
             if (c2 == 'n' || c2 == 'N')
               d = octave_Float_NaN;
             else
-              {
-                is.putback (c2);
-                d = octave_Float_NA;
-              }
+              d = octave_Float_NA;
           }
         else
-          {
-            is.putback (c1);
-            is.putback (c0);
-            is.setstate (std::ios::failbit);
-          }
+          is.setstate (std::ios::failbit);
       }
       break;
 
@@ -428,40 +408,37 @@
 {
   float d = 0.0;
 
+  // FIXME -- resetting stream position is likely to fail unless we are
+  // reading from a file.
+  std::ios::streampos pos = is.tellg ();
+
   char c1 = ' ';
 
   while (isspace (c1))
     c1 = is.get ();
 
+  bool neg = false;
+
   switch (c1)
     {
     case '-':
-      {
-        char c2 = 0;
-        c2 = is.get ();
-        if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          d = read_float_inf_nan_na (is, c2, c1);
-        else
-          {
-            is.putback (c2);
-            is.putback (c1);
-            is >> d;
-          }
-      }
-      break;
+      neg = true;
+      // fall through...
 
     case '+':
       {
         char c2 = 0;
         c2 = is.get ();
         if (c2 == 'i' || c2 == 'I' || c2 == 'n' || c2 == 'N')
-          d = read_float_inf_nan_na (is, c2, c1);
+          d = read_float_inf_nan_na (is, c2);
         else
           {
             is.putback (c2);
-            is.putback (c1);
             is >> d;
           }
+
+        if (neg && ! is.fail ())
+          d = -d;
       }
       break;
 
@@ -473,6 +450,15 @@
     default:
       is.putback (c1);
       is >> d;
+      break;
+    }
+
+  std::ios::iostate status = is.rdstate ();
+  if (status & std::ios::failbit)
+    {
+      is.clear ();
+      is.seekg (pos);
+      is.setstate (status);
     }
 
   return d;