Project

General

Profile

Backport #6179 ยป pos_backport.patch

h.shirosaki (Hiroshi Shirosaki), 04/03/2012 05:11 PM

View differences:

branches/ruby_1_9_3/io.c (revision 35220) โ†’ branches/ruby_1_9_3/io.c (working copy)
222 222
#define rb_sys_fail_path(path) rb_sys_fail_str(path)
223 223

  
224 224
static int io_fflush(rb_io_t *);
225
static rb_io_t *flush_before_seek(rb_io_t *fptr);
225 226

  
226 227
#define NEED_NEWLINE_DECORATOR_ON_READ(fptr) ((fptr)->mode & FMODE_TEXTMODE)
227 228
#define NEED_NEWLINE_DECORATOR_ON_WRITE(fptr) ((fptr)->mode & FMODE_TEXTMODE)
......
257 258
	(ecflags) |= ECONV_UNIVERSAL_NEWLINE_DECORATOR;\
258 259
    }\
259 260
} while(0)
261

  
260 262
/*
261
 * We use io_seek to back cursor position when changing mode from text to binary,
262
 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
263
 * conversion for working properly with mode change.
263
 * IO unread with taking care of removed '\r' in text mode.
264 264
 */
265
/*
266
 * Return previous translation mode.
267
 */
268
inline static int set_binary_mode_with_seek_cur(rb_io_t *fptr) {
265
static void
266
io_unread(rb_io_t *fptr)
267
{
269 268
    off_t r, pos;
270 269
    ssize_t read_size;
271 270
    long i;
272 271
    long newlines = 0;
273 272
    long extra_max;
274 273
    char *p;
274
    char *buf;
275 275

  
276
    if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
277

  
276
    rb_io_check_closed(fptr);
278 277
    if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
279
	return setmode(fptr->fd, O_BINARY);
278
	return;
280 279
    }
281 280

  
282
    if (io_fflush(fptr) < 0) {
283
	rb_sys_fail(0);
281
    errno = 0;
282
    if (!rb_w32_fd_is_text(fptr->fd)) {
283
	r = lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
284
	if (r < 0 && errno) {
285
	    if (errno == ESPIPE)
286
		fptr->mode |= FMODE_DUPLEX;
287
	    return;
288
	}
289

  
290
	fptr->rbuf.off = 0;
291
	fptr->rbuf.len = 0;
292
	return;
284 293
    }
285
    errno = 0;
294

  
286 295
    pos = lseek(fptr->fd, 0, SEEK_CUR);
287 296
    if (pos < 0 && errno) {
288 297
	if (errno == ESPIPE)
289 298
	    fptr->mode |= FMODE_DUPLEX;
290
	return setmode(fptr->fd, O_BINARY);
299
	return;
291 300
    }
301

  
292 302
    /* add extra offset for removed '\r' in rbuf */
293 303
    extra_max = pos - fptr->rbuf.len;
294 304
    p = fptr->rbuf.ptr + fptr->rbuf.off;
......
297 307
	if (extra_max == newlines) break;
298 308
	p++;
299 309
    }
310

  
311
    buf = ALLOC_N(char, fptr->rbuf.len + newlines);
300 312
    while (newlines >= 0) {
301 313
	r = lseek(fptr->fd, pos - fptr->rbuf.len - newlines, SEEK_SET);
302 314
	if (newlines == 0) break;
......
304 316
	    newlines--;
305 317
	    continue;
306 318
	}
307
	read_size = _read(fptr->fd, fptr->rbuf.ptr, fptr->rbuf.len + newlines);
319
	read_size = _read(fptr->fd, buf, fptr->rbuf.len + newlines);
308 320
	if (read_size < 0) {
321
	    free(buf);
309 322
	    rb_sys_fail_path(fptr->pathv);
310 323
	}
311 324
	if (read_size == fptr->rbuf.len) {
......
316 329
	    newlines--;
317 330
	}
318 331
    }
332
    free(buf);
319 333
    fptr->rbuf.off = 0;
320 334
    fptr->rbuf.len = 0;
335
    return;
336
}
337

  
338
/*
339
 * We use io_seek to back cursor position when changing mode from text to binary,
340
 * but stdin and pipe cannot seek back. Stdin and pipe read should use encoding
341
 * conversion for working properly with mode change.
342
 *
343
 * Return previous translation mode.
344
 */
345
static inline int
346
set_binary_mode_with_seek_cur(rb_io_t *fptr)
347
{
348
    if (!rb_w32_fd_is_text(fptr->fd)) return O_BINARY;
349

  
350
    if (fptr->rbuf.len == 0 || fptr->mode & FMODE_DUPLEX) {
351
	return setmode(fptr->fd, O_BINARY);
352
    }
353
    flush_before_seek(fptr);
321 354
    return setmode(fptr->fd, O_BINARY);
322 355
}
323 356
#define SET_BINARY_MODE_WITH_SEEK_CUR(fptr) set_binary_mode_with_seek_cur(fptr)
......
448 481
    return rb_io_check_io(io);
449 482
}
450 483

  
484
#if !(defined(RUBY_TEST_CRLF_ENVIRONMENT) || defined(_WIN32))
451 485
static void
452 486
io_unread(rb_io_t *fptr)
453 487
{
......
467 501
    fptr->rbuf.len = 0;
468 502
    return;
469 503
}
504
#endif
470 505

  
471 506
static rb_encoding *io_input_encoding(rb_io_t *fptr);
472 507

  
branches/ruby_1_9_3/test/ruby/test_io.rb (revision 35220) โ†’ branches/ruby_1_9_3/test/ruby/test_io.rb (working copy)
1307 1307
    end
1308 1308
  end
1309 1309

  
1310
  def test_pos_with_getc
1311
    bug6179 = '[ruby-core:43497]'
1312
    t = make_tempfile
1313
    ["", "t", "b"].each do |mode|
1314
      open(t.path, "w#{mode}") do |f|
1315
        f.write "0123456789\n"
1316
      end
1317

  
1318
      open(t.path, "r#{mode}") do |f|
1319
        assert_equal 0, f.pos, "mode=r#{mode}"
1320
        assert_equal '0', f.getc, "mode=r#{mode}"
1321
        assert_equal 1, f.pos, "mode=r#{mode}"
1322
        assert_equal '1', f.getc, "mode=r#{mode}"
1323
        assert_equal 2, f.pos, "mode=r#{mode}"
1324
        assert_equal '2', f.getc, "mode=r#{mode}"
1325
        assert_equal 3, f.pos, "mode=r#{mode}"
1326
        assert_equal '3', f.getc, "mode=r#{mode}"
1327
        assert_equal 4, f.pos, "mode=r#{mode}"
1328
        assert_equal '4', f.getc, "mode=r#{mode}"
1329
      end
1330
    end
1331
  end
1332

  
1333

  
1310 1334
  def test_sysseek
1311 1335
    t = make_tempfile
1312 1336

  
branches/ruby_1_9_3/test/ruby/test_io_m17n.rb (revision 35220) โ†’ branches/ruby_1_9_3/test/ruby/test_io_m17n.rb (working copy)
2347 2347
    }
2348 2348
    assert_equal(paths.map(&:encoding), encs, bug6072)
2349 2349
  end
2350

  
2351
  def test_pos_dont_move_cursor_position
2352
    bug6179 = '[ruby-core:43497]'
2353
    with_tmpdir {
2354
      str = "line one\r\nline two\r\nline three\r\n"
2355
      generate_file("tmp", str)
2356
      open("tmp", "r") do |f|
2357
        assert_equal("line one\n", f.readline)
2358
        assert_equal(10, f.pos, bug6179)
2359
        assert_equal("line two\n", f.readline, bug6179)
2360
        assert_equal(20, f.pos, bug6179)
2361
        assert_equal("line three\n", f.readline, bug6179)
2362
      end
2363
    }
2364
  end if /mswin|mingw/ =~ RUBY_PLATFORM
2350 2365
end