exporting patch:
# HG changeset patch
# User Daniel J Sebald <daniel.sebald@ieee.org>
# Date 1512170917 21600
#      Fri Dec 01 17:28:37 2017 -0600
# Node ID 5323f9e26850064d4317797520e633805a39dd06
# Parent  a17862b28f0d8b10e0fcde4410652bcfd400ecb4
Fix textscan missing fields and number reads for cell-specified delimiters (bug #52550).

* oct-stream.cc (textscan::read_double): Remove what looks like repetitive code
  hunk concerning reading INF and NAN.
  (textscan::read_until): Treat eol1 and eol2 as delimiters.  When no valid
  data is found between delimiters, put the delimiter symbol back into the
  stream since the ensuing skip_delimiter() call will be removing it.
  (textscan::scan_string): Add eol1 and eol2 characters to "ends" string array.
  (textscan::read_format_once): Distinguish between the cell-specified and
  string-specified delimiter scenario.  For cell-specified delimiters, use the
  tellg-seekg restoration of the stream position similar to what is present
  inside lookahead().

* file-io.cc (Ftextscan): Add BIST tests for bug #52550.

diff --git a/libinterp/corefcn/file-io.cc b/libinterp/corefcn/file-io.cc
--- a/libinterp/corefcn/file-io.cc
+++ b/libinterp/corefcn/file-io.cc
@@ -2214,12 +2214,44 @@ as the name of the function when reporti
 %!test <*52479>
 %! str = "\t\ta\tb\tc\n";
 %! ret = textscan (str, "%s", "delimiter", "\t");
-%! assert (ret, { {''; ''; 'a'; 'b'; 'c'} }) ;
+%! assert (ret, { {''; ''; 'a'; 'b'; 'c'} });
 
 %!test <52479>
 %! str = "\t\ta\tb\tc\n";
 %! ret = textscan (str, "%s", "delimiter", {"\t"});
-%! assert (ret, { {''; ''; 'a'; 'b'; 'c'} }) ;
+%! assert (ret, { {''; ''; 'a'; 'b'; 'c'} });
+
+%!test <52550>
+%! str = ",,1,2,3\n";
+%! obs = textscan (str, "%d", "delimiter", ",");
+%! assert (obs, { [0; 0; 1; 2; 3] });
+%! obs = textscan (str, "%d", "delimiter", {","});
+%! assert (obs, { [0; 0; 1; 2; 3] });
+
+%!test <52550>
+%! str = " , ,1,2,3\n";
+%! obs = textscan (str, "%d", "delimiter", ",");
+%! assert (obs, { [0; 0; 1; 2; 3] });
+%! textscan (str, "%d", "delimiter", {","});
+%! assert (obs, { [0; 0; 1; 2; 3] });
+
+%!test <52550>
+%! str = " 0 , 5+6j , -INF+INFj ,NaN,3\n";
+%! obs = textscan (str, "%f", "delimiter", ",");
+%! assert (obs, { [0; 5+6i; complex(-Inf,Inf); NaN; 3] });
+%! obs = textscan (str, "%f", "delimiter", {","});
+%! assert (obs, { [0; 5+6i; complex(-Inf,Inf); NaN; 3] });
+
+%!test <52550>
+%! str = " 0;,;,1;,2;,3\n";
+%! assert (textscan (str, "%f", "delimiter", {";,"}), { [0; NaN; 1; 2; 3] });
+
+%!test <52550>
+%! str = " 0 ;1 , $ 2 ;3\n";
+%! obs = textscan (str, "%f", "delimiter", ",;$");
+%! assert (obs, { [0; 1; NaN; 2; 3] });
+%! obs = textscan (str, "%f", "delimiter", {",",";","$"});
+%! assert (obs, { [0; 1; NaN; 2; 3] });
 
 */
 
diff --git a/libinterp/corefcn/oct-stream.cc b/libinterp/corefcn/oct-stream.cc
--- a/libinterp/corefcn/oct-stream.cc
+++ b/libinterp/corefcn/oct-stream.cc
@@ -2914,22 +2914,6 @@ namespace octave
           }
       }
 
-    // Check for +/- inf and NaN
-    if (! valid && width_left >= 3)
-      {
-        int i = lookahead (is, inf_nan, 3, false);   // false -> case insensitive
-        if (i == 0)
-          {
-            retval = numeric_limits<double>::Inf ();
-            valid = true;
-          }
-        else if (i == 1)
-          {
-            retval = numeric_limits<double>::NaN ();
-            valid = true;
-          }
-      }
-
     if (! valid)
       is.setstate (std::ios::failbit);
     else
@@ -3126,6 +3110,9 @@ namespace octave
 
         if (last != std::istream::traits_type::eof ())
           {
+            if (last == eol1 || last == eol2)
+                break;
+
             retval = retval + static_cast<char> (last);
             for (int i = 0; i < delimiters.numel (); i++)
               {
@@ -3138,6 +3125,8 @@ namespace octave
                   {
                     done = true;
                     retval = retval.substr (0, start);
+                    if (start == 0)
+                      is.putback (last);
                     break;
                   }
               }
@@ -3181,12 +3170,15 @@ namespace octave
       }
     else  // Cell array of multi-character delimiters
       {
-        std::string ends (delim_list.numel (), '\0');
-        for (int i = 0; i < delim_list.numel (); i++)
+        std::string ends (delim_list.numel () + 2, '\0');
+        int i;
+        for (i = 0; i < delim_list.numel (); i++)
           {
             std::string tmp = delim_list(i).string_value ();
             ends[i] = tmp.back ();
           }
+        ends[i++] = eol1;
+        ends[i++] = eol2;
         val = textscan::read_until (is, delim_list, ends);
       }
   }
@@ -3488,8 +3480,22 @@ namespace octave
           {
             is.clear (is.rdstate () & ~std::ios::failbit);
 
-            if (! is.eof () && ! is_delim (is.peek ()))
-              this_conversion_failed = true;
+            if (! is.eof ())
+              {
+                if (delim_list.isempty ())
+                  {
+                    if (! is_delim (is.peek ()))
+                      this_conversion_failed = true;
+                  }
+                else  // Cell array of multi-character delimiters
+                  {
+                    char *pos = is.tellg ();
+                    if (-1 == lookahead (is, delim_list, delim_len))
+                      this_conversion_failed = true;
+                    is.clear ();
+                    is.seekg (pos);     // reset to position before look-ahead
+                  }
+              }
           }
 
         if (! elem->discard)
@@ -3861,7 +3867,7 @@ namespace octave
     char *look = is.read (&tmp[0], tmp.size (), pos);
 
     is.clear ();
-    is.seekg (pos);              // reset to position before look-ahead
+    is.seekg (pos);              // reset to position before read
                                  // FIXME: pos may be corrupted by is.read
 
     int i;
