changeset 23965:6f0c2963674b

allow large ints to be read by C-style scanf (bug #51794) * oct-stream.cc (base_stream::do_oscanf): For 'd', 'i', 'o', 'u', and 'x' conversions, handle 'h' and 'l' modifiers in the same way as in do_scanf. * io.tst: New tests.
author John W. Eaton <jwe@octave.org>
date Tue, 29 Aug 2017 12:21:42 -0400
parents 1a0cbb573a67
children b833c7334308
files libinterp/corefcn/oct-stream.cc test/io.tst
diffstat 2 files changed, 92 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/oct-stream.cc	Tue Aug 29 18:01:48 2017 +0200
+++ b/libinterp/corefcn/oct-stream.cc	Tue Aug 29 12:21:42 2017 -0400
@@ -5057,29 +5057,93 @@
 
           case 'd': case 'i':
             {
-              int tmp;
-
-              if (octave_scan (is, *elt, &tmp))
+              switch (elt->modifier)
                 {
-                  if (! discard)
-                    retval = tmp;
+                case 'h':
+                  {
+                    int16_t tmp;
+                    if (octave_scan (is, *elt, &tmp))
+                      {
+                        if (! discard)
+                          retval = tmp;
+                      }
+                    else
+                      quit = true;
+                  }
+                  break;
+
+                case 'l':
+                  {
+                    int64_t tmp;
+                    if (octave_scan (is, *elt, &tmp))
+                      {
+                        if (! discard)
+                          retval = tmp;
+                      }
+                    else
+                      quit = true;
+                  }
+                  break;
+
+                default:
+                  {
+                    int32_t tmp;
+                    if (octave_scan (is, *elt, &tmp))
+                      {
+                        if (! discard)
+                          retval = tmp;
+                      }
+                    else
+                      quit = true;
+                  }
+                  break;
                 }
-              else
-                quit = true;
             }
             break;
 
           case 'o': case 'u': case 'x':
             {
-              long int tmp;
-
-              if (octave_scan (is, *elt, &tmp))
+              switch (elt->modifier)
                 {
-                  if (! discard)
-                    retval = tmp;
+                case 'h':
+                  {
+                    uint16_t tmp;
+                    if (octave_scan (is, *elt, &tmp))
+                      {
+                        if (! discard)
+                          retval = tmp;
+                      }
+                    else
+                      quit = true;
+                  }
+                  break;
+
+                case 'l':
+                  {
+                    uint64_t tmp;
+                    if (octave_scan (is, *elt, &tmp))
+                      {
+                        if (! discard)
+                          retval = tmp;
+                      }
+                    else
+                      quit = true;
+                  }
+                  break;
+
+                default:
+                  {
+                    uint32_t tmp;
+                    if (octave_scan (is, *elt, &tmp))
+                      {
+                        if (! discard)
+                          retval = tmp;
+                      }
+                    else
+                      quit = true;
+                  }
+                  break;
                 }
-              else
-                quit = true;
             }
             break;
 
--- a/test/io.tst	Tue Aug 29 18:01:48 2017 +0200
+++ b/test/io.tst	Tue Aug 29 12:21:42 2017 -0400
@@ -312,6 +312,20 @@
 %!assert (sscanf ('7777777777777777777777', '%lo'), double (intmax ("uint64")))
 %!assert (sscanf ('ffffffffffffffffffffff', '%lx'), double (intmax ("uint64")))
 
+## bug 51794
+%!assert (sscanf ('2147483647', '%d', 'C'), 2147483647)
+%!assert (sscanf ('2147483647', '%i', 'C'), 2147483647)
+%!assert (sscanf ('4294967295', '%u', 'C'), 4294967295)
+%!assert (sscanf ('37777777777', '%o', 'C'), 4294967295)
+%!assert (sscanf ('ffffffff', '%x', 'C'), 4294967295)
+## FIXME: scanf should return int64/uint64 if all conversions are %l[dioux].
+## Until then only test values that are within precision range of a double.
+%!assert (sscanf ('281474976710655', '%ld', 'C'), 281474976710655)
+%!assert (sscanf ('281474976710655', '%li', 'C'), 281474976710655)
+%!assert (sscanf ('281474976710655', '%lu', 'C'), 281474976710655)
+%!assert (sscanf ('7777777777777777', '%lo', 'C'), 281474976710655)
+%!assert (sscanf ('ffffffffffff', '%lx', 'C'), 281474976710655)
+
 %!test
 %! [val, count, msg, pos] = sscanf ("3I2", "%f");
 %! assert (val, 3);