Mercurial > hg > octave-shane
changeset 16590:2d968b7830d6
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.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Mon, 29 Apr 2013 13:46:55 -0400 |
parents | fe6beca15813 |
children | 2931e9282190 |
files | libinterp/interpfcn/file-io.cc test/io.tst |
diffstat | 2 files changed, 87 insertions(+), 66 deletions(-) [+] |
line wrap: on
line diff
--- a/libinterp/interpfcn/file-io.cc +++ b/libinterp/interpfcn/file-io.cc @@ -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);
--- a/test/io.tst +++ b/test/io.tst @@ -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);