Mercurial > octave-libgccjit
comparison libinterp/interpfcn/file-io.cc @ 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 | 122c1a7a3004 |
children | 7268845c0a1e |
comparison
equal
deleted
inserted
replaced
16589:fe6beca15813 | 16590:2d968b7830d6 |
---|---|
128 tmp_files.pop (); | 128 tmp_files.pop (); |
129 gnulib::unlink (filename.c_str ()); | 129 gnulib::unlink (filename.c_str ()); |
130 } | 130 } |
131 } | 131 } |
132 | 132 |
133 static std::ios::openmode | 133 static void |
134 fopen_mode_to_ios_mode (const std::string& mode_arg) | 134 normalize_fopen_mode (std::string& mode, bool& use_zlib) |
135 { | 135 { |
136 std::ios::openmode retval = std::ios::in; | 136 use_zlib = false; |
137 | 137 |
138 if (! mode_arg.empty ()) | 138 if (! mode.empty ()) |
139 { | 139 { |
140 // Could probably be faster, but does it really matter? | 140 // Could probably be faster, but does it really matter? |
141 | 141 |
142 std::string mode = mode_arg; | 142 // Accept 'W', 'R', and 'A' as 'w', 'r', and 'a' but we warn about |
143 | 143 // them because Matlab says they don't perform "automatic |
144 // 'W' and 'R' are accepted as 'w' and 'r', but we warn about | 144 // flushing" but we don't know precisely what action that implies. |
145 // them because Matlab says they perform "automatic flushing" | |
146 // but we don't know precisely what action that implies. | |
147 | 145 |
148 size_t pos = mode.find ('W'); | 146 size_t pos = mode.find ('W'); |
149 | 147 |
150 if (pos != std::string::npos) | 148 if (pos != std::string::npos) |
151 { | 149 { |
152 warning ("fopen: treating mode \"W\" as equivalent to \"w\""); | 150 warning_with_id ("Octave:fopen-mode", |
151 "fopen: treating mode \"W\" as equivalent to \"w\""); | |
153 mode[pos] = 'w'; | 152 mode[pos] = 'w'; |
154 } | 153 } |
155 | 154 |
156 pos = mode.find ('R'); | 155 pos = mode.find ('R'); |
157 | 156 |
158 if (pos != std::string::npos) | 157 if (pos != std::string::npos) |
159 { | 158 { |
160 warning ("fopen: treating mode \"R\" as equivalent to \"r\""); | 159 warning_with_id ("Octave:fopen-mode", |
160 "fopen: treating mode \"R\" as equivalent to \"r\""); | |
161 mode[pos] = 'r'; | 161 mode[pos] = 'r'; |
162 } | 162 } |
163 | 163 |
164 pos = mode.find ('A'); | |
165 | |
166 if (pos != std::string::npos) | |
167 { | |
168 warning_with_id ("Octave:fopen-mode", | |
169 "fopen: treating mode \"A\" as equivalent to \"a\""); | |
170 mode[pos] = 'a'; | |
171 } | |
172 | |
164 pos = mode.find ('z'); | 173 pos = mode.find ('z'); |
165 | 174 |
166 if (pos != std::string::npos) | 175 if (pos != std::string::npos) |
167 { | 176 { |
168 #if defined (HAVE_ZLIB) | 177 #if defined (HAVE_ZLIB) |
178 use_zlib = true; | |
169 mode.erase (pos, 1); | 179 mode.erase (pos, 1); |
170 #else | 180 #else |
171 error ("this version of Octave does not support gzipped files"); | 181 error ("this version of Octave does not support gzipped files"); |
172 #endif | 182 #endif |
173 } | 183 } |
174 | 184 |
175 if (! error_state) | 185 if (! error_state) |
176 { | 186 { |
177 if (mode == "rt") | 187 // Use binary mode if 't' is not specified, but don't add |
178 retval = std::ios::in; | 188 // 'b' if it is already present. |
179 else if (mode == "wt") | 189 |
180 retval = std::ios::out | std::ios::trunc; | 190 size_t bpos = mode.find ('b'); |
181 else if (mode == "at") | 191 size_t tpos = mode.find ('t'); |
182 retval = std::ios::out | std::ios::app; | 192 |
183 else if (mode == "r+t" || mode == "rt+") | 193 if (bpos == std::string::npos && tpos == std::string::npos) |
184 retval = std::ios::in | std::ios::out; | 194 mode += 'b'; |
185 else if (mode == "w+t" || mode == "wt+") | 195 } |
186 retval = std::ios::in | std::ios::out | std::ios::trunc; | 196 } |
187 else if (mode == "a+t" || mode == "at+") | 197 } |
188 retval = std::ios::in | std::ios::out | std::ios::app; | 198 |
189 else if (mode == "rb" || mode == "r") | 199 static std::ios::openmode |
190 retval = std::ios::in | std::ios::binary; | 200 fopen_mode_to_ios_mode (const std::string& mode) |
191 else if (mode == "wb" || mode == "w") | 201 { |
192 retval = std::ios::out | std::ios::trunc | std::ios::binary; | 202 std::ios::openmode retval = std::ios::in; |
193 else if (mode == "ab" || mode == "a") | 203 |
194 retval = std::ios::out | std::ios::app | std::ios::binary; | 204 if (! error_state) |
195 else if (mode == "r+b" || mode == "rb+" || mode == "r+") | 205 { |
196 retval = std::ios::in | std::ios::out | std::ios::binary; | 206 if (mode == "rt") |
197 else if (mode == "w+b" || mode == "wb+" || mode == "w+") | 207 retval = std::ios::in; |
198 retval = (std::ios::in | std::ios::out | std::ios::trunc | 208 else if (mode == "wt") |
199 | std::ios::binary); | 209 retval = std::ios::out | std::ios::trunc; |
200 else if (mode == "a+b" || mode == "ab+" || mode == "a+") | 210 else if (mode == "at") |
201 retval = (std::ios::in | std::ios::out | std::ios::app | 211 retval = std::ios::out | std::ios::app; |
202 | std::ios::binary); | 212 else if (mode == "r+t" || mode == "rt+") |
203 else | 213 retval = std::ios::in | std::ios::out; |
204 ::error ("invalid mode specified"); | 214 else if (mode == "w+t" || mode == "wt+") |
205 } | 215 retval = std::ios::in | std::ios::out | std::ios::trunc; |
216 else if (mode == "a+t" || mode == "at+") | |
217 retval = std::ios::in | std::ios::out | std::ios::app; | |
218 else if (mode == "rb" || mode == "r") | |
219 retval = std::ios::in | std::ios::binary; | |
220 else if (mode == "wb" || mode == "w") | |
221 retval = std::ios::out | std::ios::trunc | std::ios::binary; | |
222 else if (mode == "ab" || mode == "a") | |
223 retval = std::ios::out | std::ios::app | std::ios::binary; | |
224 else if (mode == "r+b" || mode == "rb+" || mode == "r+") | |
225 retval = std::ios::in | std::ios::out | std::ios::binary; | |
226 else if (mode == "w+b" || mode == "wb+" || mode == "w+") | |
227 retval = (std::ios::in | std::ios::out | std::ios::trunc | |
228 | std::ios::binary); | |
229 else if (mode == "a+b" || mode == "ab+" || mode == "a+") | |
230 retval = (std::ios::in | std::ios::out | std::ios::app | |
231 | std::ios::binary); | |
232 else | |
233 ::error ("invalid mode specified"); | |
206 } | 234 } |
207 | 235 |
208 return retval; | 236 return retval; |
209 } | 237 } |
210 | 238 |
446 return retval; | 474 return retval; |
447 } | 475 } |
448 | 476 |
449 | 477 |
450 static octave_stream | 478 static octave_stream |
451 do_stream_open (const std::string& name, const std::string& mode, | 479 do_stream_open (const std::string& name, const std::string& mode_arg, |
452 const std::string& arch, int& fid) | 480 const std::string& arch, int& fid) |
453 { | 481 { |
454 octave_stream retval; | 482 octave_stream retval; |
455 | 483 |
456 fid = -1; | 484 fid = -1; |
485 | |
486 std::string mode = mode_arg; | |
487 bool use_zlib = false; | |
488 normalize_fopen_mode (mode, use_zlib); | |
457 | 489 |
458 std::ios::openmode md = fopen_mode_to_ios_mode (mode); | 490 std::ios::openmode md = fopen_mode_to_ios_mode (mode); |
459 | 491 |
460 if (! error_state) | 492 if (! error_state) |
461 { | 493 { |
486 } | 518 } |
487 } | 519 } |
488 | 520 |
489 if (! fs.is_dir ()) | 521 if (! fs.is_dir ()) |
490 { | 522 { |
491 std::string tmode = mode; | |
492 | |
493 // Use binary mode if 't' is not specified, but don't add | |
494 // 'b' if it is already present. | |
495 | |
496 size_t bpos = tmode.find ('b'); | |
497 size_t tpos = tmode.find ('t'); | |
498 | |
499 if (bpos == std::string::npos && tpos == std::string::npos) | |
500 tmode += 'b'; | |
501 | |
502 #if defined (HAVE_ZLIB) | 523 #if defined (HAVE_ZLIB) |
503 size_t pos = tmode.find ('z'); | 524 if (use_zlib) |
504 | |
505 if (pos != std::string::npos) | |
506 { | 525 { |
507 tmode.erase (pos, 1); | 526 FILE *fptr = gnulib::fopen (fname.c_str (), mode.c_str ()); |
508 | |
509 FILE *fptr = gnulib::fopen (fname.c_str (), tmode.c_str ()); | |
510 | 527 |
511 int fd = fileno (fptr); | 528 int fd = fileno (fptr); |
512 | 529 |
513 gzFile gzf = ::gzdopen (fd, tmode.c_str ()); | 530 gzFile gzf = ::gzdopen (fd, mode.c_str ()); |
514 | 531 |
515 if (fptr) | 532 if (fptr) |
516 retval = octave_zstdiostream::create (fname, gzf, fd, | 533 retval = octave_zstdiostream::create (fname, gzf, fd, |
517 md, flt_fmt); | 534 md, flt_fmt); |
518 else | 535 else |
519 retval.error (gnulib::strerror (errno)); | 536 retval.error (gnulib::strerror (errno)); |
520 } | 537 } |
521 else | 538 else |
522 #endif | 539 #endif |
523 { | 540 { |
524 FILE *fptr = gnulib::fopen (fname.c_str (), tmode.c_str ()); | 541 FILE *fptr = gnulib::fopen (fname.c_str (), mode.c_str ()); |
525 | 542 |
526 retval = octave_stdiostream::create (fname, fptr, md, flt_fmt); | 543 retval = octave_stdiostream::create (fname, fptr, md, flt_fmt); |
527 | 544 |
528 if (! fptr) | 545 if (! fptr) |
529 retval.error (gnulib::strerror (errno)); | 546 retval.error (gnulib::strerror (errno)); |