# HG changeset patch # User John W. Eaton # Date 1367257615 14400 # Node ID 2d968b7830d61dd0504e51ac2b43e6669e66390c # Parent fe6beca1581391354d9ce8e75aff16696a32a816 handle A, R, and W fopen modes correctly (bug #38851) * file-io.cc (normalize_fopen_mode): New function. Handle 'A'. Also handle 'b' and 't' suffixes here. Use Octave:fopen-mode warning id. (fopen_mode_to_ios_mode): Only convert from mode string to ios mode. (do_stream_open): Call normalize_fopen_mode before calling fopen_mode_to_ios_mode. Don't process mode string directly. * io.tst: Update test for fopen modes. diff -r fe6beca15813 -r 2d968b7830d6 libinterp/interpfcn/file-io.cc --- a/libinterp/interpfcn/file-io.cc Mon Apr 29 00:47:36 2013 -0400 +++ b/libinterp/interpfcn/file-io.cc Mon Apr 29 13:46:55 2013 -0400 @@ -130,26 +130,25 @@ } } -static std::ios::openmode -fopen_mode_to_ios_mode (const std::string& mode_arg) +static void +normalize_fopen_mode (std::string& mode, bool& use_zlib) { - std::ios::openmode retval = std::ios::in; + use_zlib = false; - if (! mode_arg.empty ()) + if (! mode.empty ()) { // Could probably be faster, but does it really matter? - std::string mode = mode_arg; - - // 'W' and 'R' are accepted as 'w' and 'r', but we warn about - // them because Matlab says they perform "automatic flushing" - // but we don't know precisely what action that implies. + // Accept 'W', 'R', and 'A' as 'w', 'r', and 'a' but we warn about + // them because Matlab says they don't perform "automatic + // flushing" but we don't know precisely what action that implies. size_t pos = mode.find ('W'); if (pos != std::string::npos) { - warning ("fopen: treating mode \"W\" as equivalent to \"w\""); + warning_with_id ("Octave:fopen-mode", + "fopen: treating mode \"W\" as equivalent to \"w\""); mode[pos] = 'w'; } @@ -157,15 +156,26 @@ if (pos != std::string::npos) { - warning ("fopen: treating mode \"R\" as equivalent to \"r\""); + warning_with_id ("Octave:fopen-mode", + "fopen: treating mode \"R\" as equivalent to \"r\""); mode[pos] = 'r'; } + pos = mode.find ('A'); + + if (pos != std::string::npos) + { + warning_with_id ("Octave:fopen-mode", + "fopen: treating mode \"A\" as equivalent to \"a\""); + mode[pos] = 'a'; + } + pos = mode.find ('z'); if (pos != std::string::npos) { #if defined (HAVE_ZLIB) + use_zlib = true; mode.erase (pos, 1); #else error ("this version of Octave does not support gzipped files"); @@ -174,36 +184,54 @@ if (! error_state) { - if (mode == "rt") - retval = std::ios::in; - else if (mode == "wt") - retval = std::ios::out | std::ios::trunc; - else if (mode == "at") - retval = std::ios::out | std::ios::app; - else if (mode == "r+t" || mode == "rt+") - retval = std::ios::in | std::ios::out; - else if (mode == "w+t" || mode == "wt+") - retval = std::ios::in | std::ios::out | std::ios::trunc; - else if (mode == "a+t" || mode == "at+") - retval = std::ios::in | std::ios::out | std::ios::app; - else if (mode == "rb" || mode == "r") - retval = std::ios::in | std::ios::binary; - else if (mode == "wb" || mode == "w") - retval = std::ios::out | std::ios::trunc | std::ios::binary; - else if (mode == "ab" || mode == "a") - retval = std::ios::out | std::ios::app | std::ios::binary; - else if (mode == "r+b" || mode == "rb+" || mode == "r+") - retval = std::ios::in | std::ios::out | std::ios::binary; - else if (mode == "w+b" || mode == "wb+" || mode == "w+") - retval = (std::ios::in | std::ios::out | std::ios::trunc - | std::ios::binary); - else if (mode == "a+b" || mode == "ab+" || mode == "a+") - retval = (std::ios::in | std::ios::out | std::ios::app - | std::ios::binary); - else - ::error ("invalid mode specified"); + // Use binary mode if 't' is not specified, but don't add + // 'b' if it is already present. + + size_t bpos = mode.find ('b'); + size_t tpos = mode.find ('t'); + + if (bpos == std::string::npos && tpos == std::string::npos) + mode += 'b'; } } +} + +static std::ios::openmode +fopen_mode_to_ios_mode (const std::string& mode) +{ + std::ios::openmode retval = std::ios::in; + + if (! error_state) + { + if (mode == "rt") + retval = std::ios::in; + else if (mode == "wt") + retval = std::ios::out | std::ios::trunc; + else if (mode == "at") + retval = std::ios::out | std::ios::app; + else if (mode == "r+t" || mode == "rt+") + retval = std::ios::in | std::ios::out; + else if (mode == "w+t" || mode == "wt+") + retval = std::ios::in | std::ios::out | std::ios::trunc; + else if (mode == "a+t" || mode == "at+") + retval = std::ios::in | std::ios::out | std::ios::app; + else if (mode == "rb" || mode == "r") + retval = std::ios::in | std::ios::binary; + else if (mode == "wb" || mode == "w") + retval = std::ios::out | std::ios::trunc | std::ios::binary; + else if (mode == "ab" || mode == "a") + retval = std::ios::out | std::ios::app | std::ios::binary; + else if (mode == "r+b" || mode == "rb+" || mode == "r+") + retval = std::ios::in | std::ios::out | std::ios::binary; + else if (mode == "w+b" || mode == "wb+" || mode == "w+") + retval = (std::ios::in | std::ios::out | std::ios::trunc + | std::ios::binary); + else if (mode == "a+b" || mode == "ab+" || mode == "a+") + retval = (std::ios::in | std::ios::out | std::ios::app + | std::ios::binary); + else + ::error ("invalid mode specified"); + } return retval; } @@ -448,13 +476,17 @@ static octave_stream -do_stream_open (const std::string& name, const std::string& mode, +do_stream_open (const std::string& name, const std::string& mode_arg, const std::string& arch, int& fid) { octave_stream retval; fid = -1; + std::string mode = mode_arg; + bool use_zlib = false; + normalize_fopen_mode (mode, use_zlib); + std::ios::openmode md = fopen_mode_to_ios_mode (mode); if (! error_state) @@ -488,29 +520,14 @@ if (! fs.is_dir ()) { - std::string tmode = mode; - - // Use binary mode if 't' is not specified, but don't add - // 'b' if it is already present. - - size_t bpos = tmode.find ('b'); - size_t tpos = tmode.find ('t'); - - if (bpos == std::string::npos && tpos == std::string::npos) - tmode += 'b'; - #if defined (HAVE_ZLIB) - size_t pos = tmode.find ('z'); - - if (pos != std::string::npos) + if (use_zlib) { - tmode.erase (pos, 1); - - FILE *fptr = gnulib::fopen (fname.c_str (), tmode.c_str ()); + FILE *fptr = gnulib::fopen (fname.c_str (), mode.c_str ()); int fd = fileno (fptr); - gzFile gzf = ::gzdopen (fd, tmode.c_str ()); + gzFile gzf = ::gzdopen (fd, mode.c_str ()); if (fptr) retval = octave_zstdiostream::create (fname, gzf, fd, @@ -521,7 +538,7 @@ else #endif { - FILE *fptr = gnulib::fopen (fname.c_str (), tmode.c_str ()); + FILE *fptr = gnulib::fopen (fname.c_str (), mode.c_str ()); retval = octave_stdiostream::create (fname, fptr, md, flt_fmt); diff -r fe6beca15813 -r 2d968b7830d6 test/io.tst --- a/test/io.tst Mon Apr 29 00:47:36 2013 -0400 +++ b/test/io.tst Mon Apr 29 13:46:55 2013 -0400 @@ -335,21 +335,25 @@ %% test/octave.test/io/fopen-1.m %!test -%! arch_list = ["native"; "ieee-le"; "ieee-be"; "vaxd"; "vaxg"; "cray"]; -%! +%! arch_list = {"native"; "ieee-le"; "ieee-be"; "vaxd"; "vaxg"; "cray"}; +%! warning ("off", "Octave:fopen-mode") %! status = 1; %! %! for i = 1:6 -%! arch = deblank (arch_list (i,:)); -%! for j = 1:6 +%! arch = arch_list{i}; +%! for j = 1:4 %! if (j == 1) -%! mode_list = ["w"; "r"; "a"]; +%! mode_list = {"w"; "r"; "a"}; %! elseif (j == 2) -%! mode_list = ["w+"; "r+"; "a+"]; +%! mode_list = {"w+"; "r+"; "a+"}; +%! elseif (j == 3) +%! mode_list = {"W"; "R"; "A"}; +%! elseif (j == 4) +%! mode_list = {"W+"; "R+"; "A+"}; %! endif %! nm = tmpnam (); %! for k = 1:3 -%! mode = deblank (mode_list (k,:)); +%! mode = mode_list{k}; %! [id, err] = fopen (nm, mode, arch); %! if (id < 0) %! __printf_assert__ ("open failed: %s (%s, %s): %s\n", nm, mode, arch, err);