2012-09-19 18:52:32 -05:00
|
|
|
/*!
|
2011-12-06 15:58:45 -06:00
|
|
|
|
|
|
|
Basic input/output
|
2012-09-19 18:52:32 -05:00
|
|
|
|
2011-12-06 15:58:45 -06:00
|
|
|
*/
|
|
|
|
|
2012-10-03 16:52:09 -05:00
|
|
|
#[forbid(deprecated_mode)];
|
|
|
|
#[forbid(deprecated_pattern)];
|
|
|
|
|
2012-09-04 13:12:17 -05:00
|
|
|
use result::Result;
|
2012-03-16 17:14:37 -05:00
|
|
|
|
2012-09-04 13:12:17 -05:00
|
|
|
use cmp::Eq;
|
|
|
|
use dvec::DVec;
|
|
|
|
use libc::{c_int, c_long, c_uint, c_void, size_t, ssize_t};
|
|
|
|
use libc::consts::os::posix88::*;
|
|
|
|
use libc::consts::os::extra::*;
|
2012-03-12 22:04:27 -05:00
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
#[allow(non_camel_case_types)] // not sure what to do about this
|
2012-03-12 22:04:27 -05:00
|
|
|
type fd_t = c_int;
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2011-11-16 22:49:38 -06:00
|
|
|
#[abi = "cdecl"]
|
2012-07-03 18:11:00 -05:00
|
|
|
extern mod rustrt {
|
2012-03-12 22:04:27 -05:00
|
|
|
fn rust_get_stdin() -> *libc::FILE;
|
|
|
|
fn rust_get_stdout() -> *libc::FILE;
|
|
|
|
fn rust_get_stderr() -> *libc::FILE;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reading
|
|
|
|
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2004): This is all buffered. We might need an unbuffered variant
|
|
|
|
// as well
|
2012-10-01 16:02:10 -05:00
|
|
|
pub enum SeekStyle { SeekSet, SeekEnd, SeekCur, }
|
2011-07-10 14:47:51 -05:00
|
|
|
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// The raw underlying reader trait. All readers must implement this.
|
2012-10-01 16:02:10 -05:00
|
|
|
pub trait Reader {
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2004): Seekable really should be orthogonal.
|
2012-07-20 23:49:20 -05:00
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read up to len bytes (or EOF) and put them into bytes (which
|
|
|
|
/// must be at least len bytes long). Return number of bytes read.
|
2012-07-20 23:49:20 -05:00
|
|
|
// FIXME (#2982): This should probably return an error.
|
2012-10-18 11:10:37 -05:00
|
|
|
fn read(bytes: &[mut u8], len: uint) -> uint;
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Read a single byte, returning a negative value for EOF or read error.
|
2012-01-11 08:15:54 -06:00
|
|
|
fn read_byte() -> int;
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Return whether the stream is currently at EOF position.
|
2012-01-11 08:15:54 -06:00
|
|
|
fn eof() -> bool;
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Move the current position within the stream. The second parameter
|
|
|
|
/// determines the position that the first parameter is relative to.
|
|
|
|
fn seek(position: int, style: SeekStyle);
|
|
|
|
|
|
|
|
/// Return the current position within the stream.
|
2012-01-11 08:15:54 -06:00
|
|
|
fn tell() -> uint;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Generic utility functions defined on readers.
|
2012-10-01 16:02:10 -05:00
|
|
|
pub trait ReaderUtil {
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Read len bytes into a new vec.
|
2012-08-25 20:42:36 -05:00
|
|
|
fn read_bytes(len: uint) -> ~[u8];
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Read up until the first '\n' char (which is not returned), or EOF.
|
2012-08-25 20:42:36 -05:00
|
|
|
fn read_line() -> ~str;
|
2012-09-25 12:16:43 -05:00
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read n utf-8 encoded chars.
|
2012-09-25 12:16:43 -05:00
|
|
|
fn read_chars(n: uint) -> ~[char];
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Read a single utf-8 encoded char.
|
2012-09-25 12:16:43 -05:00
|
|
|
fn read_char() -> char;
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Read up until the first null byte (which is not returned), or EOF.
|
2012-09-25 12:16:43 -05:00
|
|
|
fn read_c_str() -> ~str;
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Read all the data remaining in the stream in one go.
|
2012-09-25 12:16:43 -05:00
|
|
|
fn read_whole_stream() -> ~[u8];
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Iterate over every byte until the iterator breaks or EOF.
|
2012-09-25 12:16:43 -05:00
|
|
|
fn each_byte(it: fn(int) -> bool);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Iterate over every char until the iterator breaks or EOF.
|
2012-09-25 12:16:43 -05:00
|
|
|
fn each_char(it: fn(char) -> bool);
|
2012-11-04 04:14:49 -06:00
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Iterate over every line until the iterator breaks or EOF.
|
|
|
|
fn each_line(it: fn(&str) -> bool);
|
|
|
|
|
|
|
|
/// Read n (between 1 and 8) little-endian unsigned integer bytes.
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_uint_n(nbytes: uint) -> u64;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read n (between 1 and 8) little-endian signed integer bytes.
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_int_n(nbytes: uint) -> i64;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read n (between 1 and 8) big-endian unsigned integer bytes.
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_uint_n(nbytes: uint) -> u64;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read n (between 1 and 8) big-endian signed integer bytes.
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_int_n(nbytes: uint) -> i64;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a little-endian uint (number of bytes depends on system).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_uint() -> uint;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a little-endian int (number of bytes depends on system).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_int() -> int;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a big-endian uint (number of bytes depends on system).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_uint() -> uint;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a big-endian int (number of bytes depends on system).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_int() -> int;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a big-endian u64 (8 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_u64() -> u64;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a big-endian u32 (4 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_u32() -> u32;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a big-endian u16 (2 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_u16() -> u16;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a big-endian i64 (8 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_i64() -> i64;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a big-endian i32 (4 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_i32() -> i32;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a big-endian i16 (2 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_be_i16() -> i16;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a little-endian u64 (8 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_u64() -> u64;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a little-endian u32 (4 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_u32() -> u32;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a little-endian u16 (2 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_u16() -> u16;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a litle-endian i64 (8 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_i64() -> i64;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a litle-endian i32 (4 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_i32() -> i32;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a litle-endian i16 (2 bytes).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_le_i16() -> i16;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a u8 (1 byte).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_u8() -> u8;
|
|
|
|
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Read a i8 (1 byte).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn read_i8() -> i8;
|
2012-08-25 20:42:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Reader> T : ReaderUtil {
|
2012-11-04 04:14:49 -06:00
|
|
|
|
2012-07-20 23:49:20 -05:00
|
|
|
fn read_bytes(len: uint) -> ~[u8] {
|
2012-10-18 11:10:37 -05:00
|
|
|
let mut bytes = vec::with_capacity(len);
|
|
|
|
unsafe { vec::raw::set_len(&mut bytes, len); }
|
2012-07-20 23:49:20 -05:00
|
|
|
|
2012-10-18 11:10:37 -05:00
|
|
|
let count = self.read(bytes, len);
|
2012-07-20 23:49:20 -05:00
|
|
|
|
2012-10-18 11:10:37 -05:00
|
|
|
unsafe { vec::raw::set_len(&mut bytes, count); }
|
|
|
|
move bytes
|
2012-07-20 23:49:20 -05:00
|
|
|
}
|
2012-11-04 04:14:49 -06:00
|
|
|
|
2012-08-25 20:42:36 -05:00
|
|
|
fn read_line() -> ~str {
|
2012-10-18 11:10:37 -05:00
|
|
|
let mut bytes = ~[];
|
2012-08-25 20:42:36 -05:00
|
|
|
loop {
|
|
|
|
let ch = self.read_byte();
|
|
|
|
if ch == -1 || ch == 10 { break; }
|
2012-10-18 11:10:37 -05:00
|
|
|
bytes.push(ch as u8);
|
2012-08-25 20:42:36 -05:00
|
|
|
}
|
2012-10-18 11:10:37 -05:00
|
|
|
str::from_bytes(bytes)
|
2012-08-25 20:42:36 -05:00
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn read_chars(n: uint) -> ~[char] {
|
2012-01-08 10:37:03 -06:00
|
|
|
// returns the (consumed offset, n_req), appends characters to &chars
|
2012-10-18 11:10:37 -05:00
|
|
|
fn chars_from_bytes<T: Reader>(bytes: &~[u8], chars: &mut ~[char])
|
2012-09-26 12:13:43 -05:00
|
|
|
-> (uint, uint) {
|
|
|
|
let mut i = 0;
|
2012-10-18 11:10:37 -05:00
|
|
|
let bytes_len = bytes.len();
|
|
|
|
while i < bytes_len {
|
|
|
|
let b0 = bytes[i];
|
2012-01-08 10:37:03 -06:00
|
|
|
let w = str::utf8_char_width(b0);
|
|
|
|
let end = i + w;
|
2012-09-26 12:13:43 -05:00
|
|
|
i += 1;
|
|
|
|
assert (w > 0);
|
|
|
|
if w == 1 {
|
2012-09-26 19:33:34 -05:00
|
|
|
chars.push(b0 as char);
|
2012-09-07 17:32:04 -05:00
|
|
|
loop;
|
2012-01-08 10:37:03 -06:00
|
|
|
}
|
|
|
|
// can't satisfy this char with the existing data
|
2012-10-18 11:10:37 -05:00
|
|
|
if end > bytes_len {
|
|
|
|
return (i - 1, end - bytes_len);
|
2012-01-08 10:37:03 -06:00
|
|
|
}
|
2012-09-26 12:13:43 -05:00
|
|
|
let mut val = 0;
|
2012-01-08 10:37:03 -06:00
|
|
|
while i < end {
|
2012-10-18 11:10:37 -05:00
|
|
|
let next = bytes[i] as int;
|
2012-09-26 12:13:43 -05:00
|
|
|
i += 1;
|
2012-01-08 10:37:03 -06:00
|
|
|
assert (next > -1);
|
|
|
|
assert (next & 192 == 128);
|
2012-09-26 12:13:43 -05:00
|
|
|
val <<= 6;
|
2012-02-09 04:50:54 -06:00
|
|
|
val += (next & 63) as uint;
|
2012-01-08 10:37:03 -06:00
|
|
|
}
|
|
|
|
// See str::char_at
|
2012-09-26 12:13:43 -05:00
|
|
|
val += ((b0 << ((w + 1) as u8)) as uint)
|
|
|
|
<< (w - 1) * 6 - w - 1u;
|
2012-09-26 19:33:34 -05:00
|
|
|
chars.push(val as char);
|
2012-01-08 10:37:03 -06:00
|
|
|
}
|
2012-09-26 12:13:43 -05:00
|
|
|
return (i, 0);
|
2012-01-08 10:37:03 -06:00
|
|
|
}
|
2012-10-18 11:14:11 -05:00
|
|
|
let mut bytes = ~[];
|
|
|
|
let mut chars = ~[];
|
2012-01-09 06:49:17 -06:00
|
|
|
// might need more bytes, but reading n will never over-read
|
2012-03-12 22:04:27 -05:00
|
|
|
let mut nbread = n;
|
2012-09-26 12:13:43 -05:00
|
|
|
while nbread > 0 {
|
2012-01-09 06:49:17 -06:00
|
|
|
let data = self.read_bytes(nbread);
|
2012-09-26 12:13:43 -05:00
|
|
|
if data.is_empty() {
|
2012-06-21 18:44:10 -05:00
|
|
|
// eof - FIXME (#2004): should we do something if
|
|
|
|
// we're split in a unicode char?
|
2012-01-08 10:37:03 -06:00
|
|
|
break;
|
|
|
|
}
|
2012-10-18 11:10:37 -05:00
|
|
|
bytes.push_all(data);
|
|
|
|
let (offset, nbreq) = chars_from_bytes::<T>(&bytes, &mut chars);
|
2012-09-26 12:13:43 -05:00
|
|
|
let ncreq = n - chars.len();
|
2012-01-09 06:49:17 -06:00
|
|
|
// again we either know we need a certain number of bytes
|
|
|
|
// to complete a character, or we make sure we don't
|
|
|
|
// over-read by reading 1-byte per char needed
|
2012-01-08 10:37:03 -06:00
|
|
|
nbread = if ncreq > nbreq { ncreq } else { nbreq };
|
2012-09-26 12:13:43 -05:00
|
|
|
if nbread > 0 {
|
2012-10-18 11:10:37 -05:00
|
|
|
bytes = vec::slice(bytes, offset, bytes.len());
|
2012-01-08 10:37:03 -06:00
|
|
|
}
|
|
|
|
}
|
2012-09-10 18:31:00 -05:00
|
|
|
move chars
|
2012-01-08 10:37:03 -06:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
|
2011-07-10 14:47:51 -05:00
|
|
|
fn read_char() -> char {
|
2012-09-26 12:13:43 -05:00
|
|
|
let c = self.read_chars(1);
|
|
|
|
if vec::len(c) == 0 {
|
2012-08-01 19:30:05 -05:00
|
|
|
return -1 as char; // FIXME will this stay valid? // #2004
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-09-26 12:13:43 -05:00
|
|
|
assert(vec::len(c) == 1);
|
2012-08-01 19:30:05 -05:00
|
|
|
return c[0];
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn read_c_str() -> ~str {
|
2012-10-18 11:10:37 -05:00
|
|
|
let mut bytes: ~[u8] = ~[];
|
2012-04-19 20:04:41 -05:00
|
|
|
loop {
|
2012-01-11 08:15:54 -06:00
|
|
|
let ch = self.read_byte();
|
2012-10-18 11:10:37 -05:00
|
|
|
if ch < 1 { break; } else { bytes.push(ch as u8); }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-10-18 11:10:37 -05:00
|
|
|
str::from_bytes(bytes)
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
fn read_whole_stream() -> ~[u8] {
|
2012-10-18 11:10:37 -05:00
|
|
|
let mut bytes: ~[u8] = ~[];
|
|
|
|
while !self.eof() { bytes.push_all(self.read_bytes(2048u)); }
|
|
|
|
move bytes
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
2012-05-01 10:14:56 -05:00
|
|
|
|
|
|
|
fn each_byte(it: fn(int) -> bool) {
|
|
|
|
while !self.eof() {
|
|
|
|
if !it(self.read_byte()) { break; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn each_char(it: fn(char) -> bool) {
|
|
|
|
while !self.eof() {
|
|
|
|
if !it(self.read_char()) { break; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-26 12:13:43 -05:00
|
|
|
fn each_line(it: fn(s: &str) -> bool) {
|
2012-05-01 10:14:56 -05:00
|
|
|
while !self.eof() {
|
|
|
|
if !it(self.read_line()) { break; }
|
|
|
|
}
|
|
|
|
}
|
2012-11-04 04:14:49 -06:00
|
|
|
|
|
|
|
// FIXME int reading methods need to deal with eof - issue #2004
|
|
|
|
|
|
|
|
fn read_le_uint_n(nbytes: uint) -> u64 {
|
|
|
|
assert nbytes > 0 && nbytes <= 8;
|
|
|
|
|
|
|
|
let mut val = 0u64, pos = 0, i = nbytes;
|
|
|
|
while i > 0 {
|
|
|
|
val += (self.read_u8() as u64) << pos;
|
|
|
|
pos += 8;
|
|
|
|
i -= 1;
|
|
|
|
}
|
|
|
|
val
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_int_n(nbytes: uint) -> i64 {
|
|
|
|
extend_sign(self.read_le_uint_n(nbytes), nbytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_uint_n(nbytes: uint) -> u64 {
|
|
|
|
assert nbytes > 0 && nbytes <= 8;
|
|
|
|
|
|
|
|
let mut val = 0u64, i = nbytes;
|
|
|
|
while i > 0 {
|
|
|
|
i -= 1;
|
|
|
|
val += (self.read_u8() as u64) << i * 8;
|
|
|
|
}
|
|
|
|
val
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_int_n(nbytes: uint) -> i64 {
|
|
|
|
extend_sign(self.read_be_uint_n(nbytes), nbytes)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_uint() -> uint {
|
|
|
|
self.read_le_uint_n(uint::bytes) as uint
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_int() -> int {
|
|
|
|
self.read_le_int_n(int::bytes) as int
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_uint() -> uint {
|
|
|
|
self.read_be_uint_n(uint::bytes) as uint
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_int() -> int {
|
|
|
|
self.read_be_int_n(int::bytes) as int
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_u64() -> u64 {
|
|
|
|
self.read_be_uint_n(8) as u64
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_u32() -> u32 {
|
|
|
|
self.read_be_uint_n(4) as u32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_u16() -> u16 {
|
|
|
|
self.read_be_uint_n(2) as u16
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_i64() -> i64 {
|
|
|
|
self.read_be_int_n(8) as i64
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_i32() -> i32 {
|
|
|
|
self.read_be_int_n(4) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_be_i16() -> i16 {
|
|
|
|
self.read_be_int_n(2) as i16
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_u64() -> u64 {
|
|
|
|
self.read_le_uint_n(8) as u64
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_u32() -> u32 {
|
|
|
|
self.read_le_uint_n(4) as u32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_u16() -> u16 {
|
|
|
|
self.read_le_uint_n(2) as u16
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_i64() -> i64 {
|
|
|
|
self.read_le_int_n(8) as i64
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_i32() -> i32 {
|
|
|
|
self.read_le_int_n(4) as i32
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_le_i16() -> i16 {
|
|
|
|
self.read_le_int_n(2) as i16
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_u8() -> u8 {
|
|
|
|
self.read_byte() as u8
|
|
|
|
}
|
|
|
|
|
|
|
|
fn read_i8() -> i8 {
|
|
|
|
self.read_byte() as i8
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn extend_sign(val: u64, nbytes: uint) -> i64 {
|
|
|
|
let shift = (8 - nbytes) * 8;
|
|
|
|
(val << shift) as i64 >> shift
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reader implementations
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
fn convert_whence(whence: SeekStyle) -> i32 {
|
2012-08-06 14:34:08 -05:00
|
|
|
return match whence {
|
2012-08-14 15:38:35 -05:00
|
|
|
SeekSet => 0i32,
|
|
|
|
SeekCur => 1i32,
|
|
|
|
SeekEnd => 2i32
|
2012-01-11 08:15:54 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
impl *libc::FILE: Reader {
|
2012-10-18 11:10:37 -05:00
|
|
|
fn read(bytes: &[mut u8], len: uint) -> uint {
|
|
|
|
do vec::as_mut_buf(bytes) |buf_p, buf_len| {
|
2012-11-24 09:19:51 -06:00
|
|
|
assert buf_len >= len;
|
2012-07-20 23:49:20 -05:00
|
|
|
|
|
|
|
let count = libc::fread(buf_p as *mut c_void, 1u as size_t,
|
|
|
|
len as size_t, self);
|
|
|
|
|
|
|
|
count as uint
|
2012-03-12 22:04:27 -05:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
fn read_byte() -> int { return libc::fgetc(self) as int; }
|
|
|
|
fn eof() -> bool { return libc::feof(self) != 0 as c_int; }
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(offset: int, whence: SeekStyle) {
|
2012-06-04 19:26:17 -05:00
|
|
|
assert libc::fseek(self, offset as c_long, convert_whence(whence))
|
2012-03-12 22:04:27 -05:00
|
|
|
== 0 as c_int;
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
fn tell() -> uint { return libc::ftell(self) as uint; }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
// A forwarding impl of reader that also holds on to a resource for the
|
|
|
|
// duration of its lifetime.
|
2012-03-15 23:04:17 -05:00
|
|
|
// FIXME there really should be a better way to do this // #2004
|
2012-08-14 15:38:35 -05:00
|
|
|
impl<T: Reader, C> {base: T, cleanup: C}: Reader {
|
2012-10-18 11:10:37 -05:00
|
|
|
fn read(bytes: &[mut u8], len: uint) -> uint {
|
|
|
|
self.base.read(bytes, len)
|
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn read_byte() -> int { self.base.read_byte() }
|
|
|
|
fn eof() -> bool { self.base.eof() }
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(off: int, whence: SeekStyle) { self.base.seek(off, whence) }
|
2012-01-11 08:15:54 -06:00
|
|
|
fn tell() -> uint { self.base.tell() }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-08-15 20:46:55 -05:00
|
|
|
struct FILERes {
|
2012-09-06 21:40:15 -05:00
|
|
|
f: *libc::FILE,
|
2012-06-21 23:30:16 -05:00
|
|
|
drop { libc::fclose(self.f); }
|
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
|
2012-09-04 17:23:28 -05:00
|
|
|
fn FILERes(f: *libc::FILE) -> FILERes {
|
|
|
|
FILERes {
|
|
|
|
f: f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> Reader {
|
2012-01-11 08:15:54 -06:00
|
|
|
if cleanup {
|
2012-08-14 15:38:35 -05:00
|
|
|
{base: f, cleanup: FILERes(f)} as Reader
|
2012-01-11 08:15:54 -06:00
|
|
|
} else {
|
2012-08-14 15:38:35 -05:00
|
|
|
f as Reader
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-31 12:27:51 -05:00
|
|
|
// FIXME (#2004): this should either be an trait-less impl, a set of
|
2012-06-21 18:44:10 -05:00
|
|
|
// top-level functions that take a reader, or a set of default methods on
|
|
|
|
// reader (which can then be called reader)
|
2012-01-11 08:15:54 -06:00
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn stdin() -> Reader { rustrt::rust_get_stdin() as Reader }
|
2012-01-11 08:15:54 -06:00
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn file_reader(path: &Path) -> Result<Reader, ~str> {
|
2012-08-24 17:28:43 -05:00
|
|
|
let f = os::as_c_charp(path.to_str(), |pathbuf| {
|
|
|
|
os::as_c_charp("r", |modebuf|
|
2012-03-12 22:04:27 -05:00
|
|
|
libc::fopen(pathbuf, modebuf)
|
2012-06-30 18:19:07 -05:00
|
|
|
)
|
2011-10-06 05:26:12 -05:00
|
|
|
});
|
2012-08-26 18:54:31 -05:00
|
|
|
return if f as uint == 0u { result::Err(~"error opening "
|
2012-08-24 17:28:43 -05:00
|
|
|
+ path.to_str()) }
|
2011-10-28 23:19:59 -05:00
|
|
|
else {
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Ok(FILE_reader(f, true))
|
2011-10-28 23:19:59 -05:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-10-18 11:06:53 -05:00
|
|
|
// Byte readers
|
|
|
|
pub struct BytesReader {
|
|
|
|
bytes: &[u8],
|
|
|
|
mut pos: uint
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
|
2012-10-18 11:06:53 -05:00
|
|
|
impl BytesReader: Reader {
|
|
|
|
fn read(bytes: &[mut u8], len: uint) -> uint {
|
|
|
|
let count = uint::min(len, self.bytes.len() - self.pos);
|
2012-07-20 23:49:20 -05:00
|
|
|
|
2012-10-18 11:06:53 -05:00
|
|
|
let view = vec::view(self.bytes, self.pos, self.bytes.len());
|
|
|
|
vec::bytes::memcpy(bytes, view, count);
|
2012-07-20 23:49:20 -05:00
|
|
|
|
|
|
|
self.pos += count;
|
|
|
|
|
|
|
|
count
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
fn read_byte() -> int {
|
2012-10-18 11:06:53 -05:00
|
|
|
if self.pos == self.bytes.len() { return -1; }
|
|
|
|
let b = self.bytes[self.pos];
|
2012-01-11 08:15:54 -06:00
|
|
|
self.pos += 1u;
|
2012-08-01 19:30:05 -05:00
|
|
|
return b as int;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-10-18 11:06:53 -05:00
|
|
|
fn eof() -> bool { self.pos == self.bytes.len() }
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(offset: int, whence: SeekStyle) {
|
2012-01-11 08:15:54 -06:00
|
|
|
let pos = self.pos;
|
2012-10-18 11:06:53 -05:00
|
|
|
self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence);
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn tell() -> uint { self.pos }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-10-18 11:04:47 -05:00
|
|
|
pub pure fn with_bytes_reader<t>(bytes: &[u8], f: fn(Reader) -> t) -> t {
|
2012-10-18 11:06:53 -05:00
|
|
|
f(BytesReader { bytes: bytes, pos: 0u } as Reader)
|
2012-02-29 12:48:57 -06:00
|
|
|
}
|
|
|
|
|
2012-11-17 12:13:11 -06:00
|
|
|
pub pure fn with_str_reader<T>(s: &str, f: fn(Reader) -> T) -> T {
|
2012-08-21 20:32:23 -05:00
|
|
|
str::byte_slice(s, |bytes| with_bytes_reader(bytes, f))
|
2012-02-29 12:48:57 -06:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
|
|
|
|
// Writing
|
2012-10-01 16:02:10 -05:00
|
|
|
pub enum FileFlag { Append, Create, Truncate, NoFlag, }
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2012-07-26 16:47:51 -05:00
|
|
|
// What type of writer are we?
|
2012-10-01 16:02:10 -05:00
|
|
|
pub enum WriterType { Screen, File }
|
2012-07-26 16:47:51 -05:00
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub impl WriterType : Eq {
|
2012-11-14 20:59:30 -06:00
|
|
|
pure fn eq(&self, other: &WriterType) -> bool {
|
|
|
|
match ((*self), (*other)) {
|
|
|
|
(Screen, Screen) | (File, File) => true,
|
|
|
|
(Screen, _) | (File, _) => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pure fn ne(&self, other: &WriterType) -> bool { !(*self).eq(other) }
|
2012-09-19 20:00:26 -05:00
|
|
|
}
|
2012-08-27 18:26:35 -05:00
|
|
|
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2004): Seekable really should be orthogonal.
|
|
|
|
// FIXME (#2004): eventually u64
|
2012-11-04 12:11:37 -06:00
|
|
|
/// The raw underlying writer trait. All writers must implement this.
|
2012-10-01 16:02:10 -05:00
|
|
|
pub trait Writer {
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write all of the given bytes.
|
2012-06-29 18:26:56 -05:00
|
|
|
fn write(v: &[const u8]);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Move the current position within the stream. The second parameter
|
|
|
|
/// determines the position that the first parameter is relative to.
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(int, SeekStyle);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Return the current position within the stream.
|
2012-01-11 08:15:54 -06:00
|
|
|
fn tell() -> uint;
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Flush the output buffer for this stream (if there is one).
|
2012-01-11 08:15:54 -06:00
|
|
|
fn flush() -> int;
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Determine if this Writer is writing to a file or not.
|
2012-08-14 15:38:35 -05:00
|
|
|
fn get_type() -> WriterType;
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
impl<T: Writer, C> {base: T, cleanup: C}: Writer {
|
2012-06-29 18:26:56 -05:00
|
|
|
fn write(bs: &[const u8]) { self.base.write(bs); }
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(off: int, style: SeekStyle) { self.base.seek(off, style); }
|
2012-01-11 08:15:54 -06:00
|
|
|
fn tell() -> uint { self.base.tell() }
|
|
|
|
fn flush() -> int { self.base.flush() }
|
2012-08-14 15:38:35 -05:00
|
|
|
fn get_type() -> WriterType { File }
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
impl *libc::FILE: Writer {
|
2012-06-29 18:26:56 -05:00
|
|
|
fn write(v: &[const u8]) {
|
2012-07-24 14:35:34 -05:00
|
|
|
do vec::as_const_buf(v) |vbuf, len| {
|
2012-11-03 13:48:02 -05:00
|
|
|
let nout = libc::fwrite(vbuf as *c_void, 1, len as size_t, self);
|
|
|
|
if nout != len as size_t {
|
2012-08-22 19:24:52 -05:00
|
|
|
error!("error writing buffer");
|
2012-04-19 03:23:00 -05:00
|
|
|
log(error, os::last_os_error());
|
2012-03-12 22:04:27 -05:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(offset: int, whence: SeekStyle) {
|
2012-06-04 19:26:17 -05:00
|
|
|
assert libc::fseek(self, offset as c_long, convert_whence(whence))
|
2012-03-12 22:04:27 -05:00
|
|
|
== 0 as c_int;
|
2011-11-16 16:14:18 -06:00
|
|
|
}
|
2012-03-12 22:04:27 -05:00
|
|
|
fn tell() -> uint { libc::ftell(self) as uint }
|
|
|
|
fn flush() -> int { libc::fflush(self) as int }
|
2012-08-14 15:38:35 -05:00
|
|
|
fn get_type() -> WriterType {
|
2012-07-26 16:47:51 -05:00
|
|
|
let fd = libc::fileno(self);
|
2012-08-14 15:38:35 -05:00
|
|
|
if libc::isatty(fd) == 0 { File }
|
|
|
|
else { Screen }
|
2012-07-26 16:47:51 -05:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> Writer {
|
2012-01-11 08:15:54 -06:00
|
|
|
if cleanup {
|
2012-08-14 15:38:35 -05:00
|
|
|
{base: f, cleanup: FILERes(f)} as Writer
|
2012-01-11 08:15:54 -06:00
|
|
|
} else {
|
2012-08-14 15:38:35 -05:00
|
|
|
f as Writer
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
|
|
|
}
|
2011-07-29 06:31:44 -05:00
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
impl fd_t: Writer {
|
2012-06-29 18:26:56 -05:00
|
|
|
fn write(v: &[const u8]) {
|
2012-03-12 22:04:27 -05:00
|
|
|
let mut count = 0u;
|
2012-07-24 14:35:34 -05:00
|
|
|
do vec::as_const_buf(v) |vbuf, len| {
|
2012-03-12 22:04:27 -05:00
|
|
|
while count < len {
|
2012-06-02 21:03:28 -05:00
|
|
|
let vb = ptr::const_offset(vbuf, count) as *c_void;
|
2012-06-04 19:26:17 -05:00
|
|
|
let nout = libc::write(self, vb, len as size_t);
|
2012-03-12 22:04:27 -05:00
|
|
|
if nout < 0 as ssize_t {
|
2012-08-22 19:24:52 -05:00
|
|
|
error!("error writing buffer");
|
2012-04-19 03:23:00 -05:00
|
|
|
log(error, os::last_os_error());
|
2012-03-12 22:04:27 -05:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
count += nout as uint;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(_offset: int, _whence: SeekStyle) {
|
2012-08-22 19:24:52 -05:00
|
|
|
error!("need 64-bit foreign calls for seek, sorry");
|
2011-07-10 14:47:51 -05:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
fn tell() -> uint {
|
2012-08-22 19:24:52 -05:00
|
|
|
error!("need 64-bit foreign calls for tell, sorry");
|
2011-07-10 14:47:51 -05:00
|
|
|
fail;
|
2011-07-27 10:05:34 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn flush() -> int { 0 }
|
2012-08-14 15:38:35 -05:00
|
|
|
fn get_type() -> WriterType {
|
|
|
|
if libc::isatty(self) == 0 { File } else { Screen }
|
2012-07-26 16:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
2011-11-16 16:14:18 -06:00
|
|
|
|
2012-08-15 20:46:55 -05:00
|
|
|
struct FdRes {
|
2012-09-06 21:40:15 -05:00
|
|
|
fd: fd_t,
|
2012-06-21 23:30:16 -05:00
|
|
|
drop { libc::close(self.fd); }
|
|
|
|
}
|
2011-11-16 16:14:18 -06:00
|
|
|
|
2012-09-04 17:23:28 -05:00
|
|
|
fn FdRes(fd: fd_t) -> FdRes {
|
|
|
|
FdRes {
|
|
|
|
fd: fd
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn fd_writer(fd: fd_t, cleanup: bool) -> Writer {
|
2012-01-11 08:15:54 -06:00
|
|
|
if cleanup {
|
2012-08-14 15:38:35 -05:00
|
|
|
{base: fd, cleanup: FdRes(fd)} as Writer
|
2012-01-11 08:15:54 -06:00
|
|
|
} else {
|
2012-08-14 15:38:35 -05:00
|
|
|
fd as Writer
|
2011-11-16 16:14:18 -06:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-03-12 22:04:27 -05:00
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
|
2012-08-26 18:54:31 -05:00
|
|
|
-> Result<Writer, ~str> {
|
2012-03-12 22:04:27 -05:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-03-12 22:04:27 -05:00
|
|
|
fn wb() -> c_int { (O_WRONLY | O_BINARY) as c_int }
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-03-12 22:04:27 -05:00
|
|
|
fn wb() -> c_int { O_WRONLY as c_int }
|
|
|
|
|
|
|
|
let mut fflags: c_int = wb();
|
2012-09-18 23:41:13 -05:00
|
|
|
for vec::each(flags) |f| {
|
2012-09-18 23:41:37 -05:00
|
|
|
match *f {
|
2012-08-14 15:38:35 -05:00
|
|
|
Append => fflags |= O_APPEND as c_int,
|
|
|
|
Create => fflags |= O_CREAT as c_int,
|
|
|
|
Truncate => fflags |= O_TRUNC as c_int,
|
|
|
|
NoFlag => ()
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-24 17:28:43 -05:00
|
|
|
let fd = do os::as_c_charp(path.to_str()) |pathbuf| {
|
2012-03-12 22:04:27 -05:00
|
|
|
libc::open(pathbuf, fflags,
|
|
|
|
(S_IRUSR | S_IWUSR) as c_int)
|
|
|
|
};
|
|
|
|
if fd < (0 as c_int) {
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Err(fmt!("error opening %s: %s", path.to_str(),
|
2012-08-24 17:28:43 -05:00
|
|
|
os::last_os_error()))
|
2011-10-28 23:19:59 -05:00
|
|
|
} else {
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Ok(fd_writer(fd, true))
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn u64_to_le_bytes<T>(n: u64, size: uint,
|
|
|
|
f: fn(v: &[u8]) -> T) -> T {
|
2012-04-25 19:18:06 -05:00
|
|
|
assert size <= 8u;
|
2012-08-06 14:34:08 -05:00
|
|
|
match size {
|
2012-08-03 21:59:04 -05:00
|
|
|
1u => f(&[n as u8]),
|
|
|
|
2u => f(&[n as u8,
|
|
|
|
(n >> 8) as u8]),
|
|
|
|
4u => f(&[n as u8,
|
2012-04-25 19:18:06 -05:00
|
|
|
(n >> 8) as u8,
|
|
|
|
(n >> 16) as u8,
|
2012-08-03 21:59:04 -05:00
|
|
|
(n >> 24) as u8]),
|
|
|
|
8u => f(&[n as u8,
|
2012-04-25 19:18:06 -05:00
|
|
|
(n >> 8) as u8,
|
|
|
|
(n >> 16) as u8,
|
|
|
|
(n >> 24) as u8,
|
|
|
|
(n >> 32) as u8,
|
|
|
|
(n >> 40) as u8,
|
|
|
|
(n >> 48) as u8,
|
2012-08-03 21:59:04 -05:00
|
|
|
(n >> 56) as u8]),
|
|
|
|
_ => {
|
2012-04-25 19:18:06 -05:00
|
|
|
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut bytes: ~[u8] = ~[], i = size, n = n;
|
2012-04-25 19:18:06 -05:00
|
|
|
while i > 0u {
|
2012-09-26 19:33:34 -05:00
|
|
|
bytes.push((n & 255_u64) as u8);
|
2012-04-25 19:18:06 -05:00
|
|
|
n >>= 8_u64;
|
|
|
|
i -= 1u;
|
|
|
|
}
|
|
|
|
f(bytes)
|
|
|
|
}
|
2012-02-14 17:21:53 -06:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn u64_to_be_bytes<T>(n: u64, size: uint,
|
|
|
|
f: fn(v: &[u8]) -> T) -> T {
|
2012-02-14 17:21:53 -06:00
|
|
|
assert size <= 8u;
|
2012-08-06 14:34:08 -05:00
|
|
|
match size {
|
2012-08-03 21:59:04 -05:00
|
|
|
1u => f(&[n as u8]),
|
|
|
|
2u => f(&[(n >> 8) as u8,
|
|
|
|
n as u8]),
|
|
|
|
4u => f(&[(n >> 24) as u8,
|
2012-04-25 19:18:06 -05:00
|
|
|
(n >> 16) as u8,
|
|
|
|
(n >> 8) as u8,
|
2012-08-03 21:59:04 -05:00
|
|
|
n as u8]),
|
|
|
|
8u => f(&[(n >> 56) as u8,
|
2012-04-25 19:18:06 -05:00
|
|
|
(n >> 48) as u8,
|
|
|
|
(n >> 40) as u8,
|
|
|
|
(n >> 32) as u8,
|
|
|
|
(n >> 24) as u8,
|
|
|
|
(n >> 16) as u8,
|
|
|
|
(n >> 8) as u8,
|
2012-08-03 21:59:04 -05:00
|
|
|
n as u8]),
|
|
|
|
_ => {
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut bytes: ~[u8] = ~[];
|
2012-04-25 19:18:06 -05:00
|
|
|
let mut i = size;
|
|
|
|
while i > 0u {
|
|
|
|
let shift = ((i - 1u) * 8u) as u64;
|
2012-09-26 19:33:34 -05:00
|
|
|
bytes.push((n >> shift) as u8);
|
2012-04-25 19:18:06 -05:00
|
|
|
i -= 1u;
|
|
|
|
}
|
|
|
|
f(bytes)
|
|
|
|
}
|
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn u64_from_be_bytes(data: &[const u8],
|
|
|
|
start: uint, size: uint) -> u64 {
|
2012-03-12 22:04:27 -05:00
|
|
|
let mut sz = size;
|
2012-02-14 17:21:53 -06:00
|
|
|
assert (sz <= 8u);
|
2012-03-12 22:04:27 -05:00
|
|
|
let mut val = 0_u64;
|
|
|
|
let mut pos = start;
|
2012-02-14 17:21:53 -06:00
|
|
|
while sz > 0u {
|
|
|
|
sz -= 1u;
|
|
|
|
val += (data[pos] as u64) << ((sz * 8u) as u64);
|
|
|
|
pos += 1u;
|
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return val;
|
2012-02-14 17:21:53 -06:00
|
|
|
}
|
|
|
|
|
2012-08-02 19:17:07 -05:00
|
|
|
// FIXME: #3048 combine trait+impl (or just move these to
|
|
|
|
// default methods on writer)
|
2012-11-04 12:11:37 -06:00
|
|
|
/// Generic utility functions defined on writers.
|
2012-10-01 16:02:10 -05:00
|
|
|
pub trait WriterUtil {
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a single utf-8 encoded char.
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_char(ch: char);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write every char in the given str, encoded as utf-8.
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_str(s: &str);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write the given str, as utf-8, followed by '\n'.
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_line(s: &str);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write the result of passing n through `int::to_str_bytes`.
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_int(n: int);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write the result of passing n through `uint::to_str_bytes`.
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_uint(n: uint);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a little-endian uint (number of bytes depends on system).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_uint(n: uint);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a little-endian int (number of bytes depends on system).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_int(n: int);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a big-endian uint (number of bytes depends on system).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_uint(n: uint);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a big-endian int (number of bytes depends on system).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_int(n: int);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a big-endian u64 (8 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_u64(n: u64);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a big-endian u32 (4 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_u32(n: u32);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a big-endian u16 (2 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_u16(n: u16);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a big-endian i64 (8 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_i64(n: i64);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a big-endian i32 (4 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_i32(n: i32);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a big-endian i16 (2 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_i16(n: i16);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a little-endian u64 (8 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_u64(n: u64);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a little-endian u32 (4 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_u32(n: u32);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a little-endian u16 (2 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_u16(n: u16);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a little-endian i64 (8 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_i64(n: i64);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a little-endian i32 (4 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_i32(n: i32);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a little-endian i16 (2 bytes).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_i16(n: i16);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a u8 (1 byte).
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_u8(n: u8);
|
2012-11-04 12:11:37 -06:00
|
|
|
|
|
|
|
/// Write a i8 (1 byte).
|
2012-11-04 04:14:49 -06:00
|
|
|
fn write_i8(n: i8);
|
2012-08-02 19:17:07 -05:00
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
impl<T: Writer> T : WriterUtil {
|
2011-07-27 07:19:39 -05:00
|
|
|
fn write_char(ch: char) {
|
2012-01-11 08:15:54 -06:00
|
|
|
if ch as uint < 128u {
|
2012-06-29 18:26:56 -05:00
|
|
|
self.write(&[ch as u8]);
|
2012-01-11 08:15:54 -06:00
|
|
|
} else {
|
2012-04-25 19:18:06 -05:00
|
|
|
self.write_str(str::from_char(ch));
|
2012-01-11 08:15:54 -06:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-07-14 00:57:48 -05:00
|
|
|
fn write_str(s: &str) { str::byte_slice(s, |v| self.write(v)) }
|
|
|
|
fn write_line(s: &str) {
|
2012-04-25 19:18:06 -05:00
|
|
|
self.write_str(s);
|
2012-07-14 00:57:48 -05:00
|
|
|
self.write_str(&"\n");
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
2012-06-04 20:05:34 -05:00
|
|
|
fn write_int(n: int) {
|
2012-10-18 11:10:37 -05:00
|
|
|
int::to_str_bytes(n, 10u, |bytes| self.write(bytes))
|
2012-06-04 20:05:34 -05:00
|
|
|
}
|
|
|
|
fn write_uint(n: uint) {
|
2012-10-18 11:10:37 -05:00
|
|
|
uint::to_str_bytes(false, n, 10u, |bytes| self.write(bytes))
|
2012-06-04 20:05:34 -05:00
|
|
|
}
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_uint(n: uint) {
|
|
|
|
u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v))
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_le_int(n: int) {
|
|
|
|
u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v))
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_uint(n: uint) {
|
|
|
|
u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v))
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-08-02 19:17:07 -05:00
|
|
|
fn write_be_int(n: int) {
|
|
|
|
u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_be_u64(n: u64) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_be_bytes(n, 8u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_be_u32(n: u32) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_be_u16(n: u16) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_be_i64(n: i64) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_be_bytes(n as u64, 8u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_be_i32(n: i32) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_be_i16(n: i16) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_le_u64(n: u64) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_le_bytes(n, 8u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_le_u32(n: u32) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_le_u16(n: u16) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_le_i64(n: i64) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_le_bytes(n as u64, 8u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_le_i32(n: i32) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
|
2012-04-25 19:18:06 -05:00
|
|
|
}
|
|
|
|
fn write_le_i16(n: i16) {
|
2012-06-30 18:19:07 -05:00
|
|
|
u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
|
2012-02-14 17:21:53 -06:00
|
|
|
}
|
|
|
|
|
2012-11-04 04:14:49 -06:00
|
|
|
fn write_u8(n: u8) { self.write([n]) }
|
|
|
|
fn write_i8(n: i8) { self.write([n as u8]) }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-09-02 17:37:15 -05:00
|
|
|
#[allow(non_implicitly_copyable_typarams)]
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<Writer, ~str> {
|
2012-09-25 18:23:04 -05:00
|
|
|
mk_file_writer(path, flags).chain(|w| result::Ok(w))
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-15 23:04:17 -05:00
|
|
|
// FIXME: fileflags // #2004
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn buffered_file_writer(path: &Path) -> Result<Writer, ~str> {
|
2012-08-24 17:28:43 -05:00
|
|
|
let f = do os::as_c_charp(path.to_str()) |pathbuf| {
|
|
|
|
do os::as_c_charp("w") |modebuf| {
|
2012-03-12 22:04:27 -05:00
|
|
|
libc::fopen(pathbuf, modebuf)
|
|
|
|
}
|
|
|
|
};
|
2012-08-26 18:54:31 -05:00
|
|
|
return if f as uint == 0u { result::Err(~"error opening "
|
2012-08-24 17:28:43 -05:00
|
|
|
+ path.to_str()) }
|
2012-08-26 18:54:31 -05:00
|
|
|
else { result::Ok(FILE_writer(f, true)) }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2004) it would be great if this could be a const
|
|
|
|
// FIXME (#2004) why are these different from the way stdin() is
|
|
|
|
// implemented?
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn stdout() -> Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) }
|
|
|
|
pub fn stderr() -> Writer { fd_writer(libc::STDERR_FILENO as c_int, false) }
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn print(s: &str) { stdout().write_str(s); }
|
|
|
|
pub fn println(s: &str) { stdout().write_line(s); }
|
2011-12-28 02:30:04 -06:00
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub struct BytesWriter {
|
2012-10-18 11:10:37 -05:00
|
|
|
bytes: DVec<u8>,
|
2012-09-14 11:40:28 -05:00
|
|
|
mut pos: uint,
|
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2012-09-20 13:17:15 -05:00
|
|
|
impl BytesWriter: Writer {
|
2012-06-29 18:26:56 -05:00
|
|
|
fn write(v: &[const u8]) {
|
2012-10-18 11:10:37 -05:00
|
|
|
do self.bytes.swap |bytes| {
|
2012-10-23 13:11:23 -05:00
|
|
|
let mut bytes = move bytes;
|
2012-08-26 23:21:59 -05:00
|
|
|
let v_len = v.len();
|
2012-10-18 11:10:37 -05:00
|
|
|
let bytes_len = bytes.len();
|
2012-08-26 23:21:59 -05:00
|
|
|
|
2012-10-18 11:10:37 -05:00
|
|
|
let count = uint::max(bytes_len, self.pos + v_len);
|
|
|
|
vec::reserve(&mut bytes, count);
|
|
|
|
unsafe { vec::raw::set_len(&mut bytes, count); }
|
2012-08-26 23:21:59 -05:00
|
|
|
|
2012-09-26 23:19:57 -05:00
|
|
|
{
|
2012-10-18 11:10:37 -05:00
|
|
|
let view = vec::mut_view(bytes, self.pos, count);
|
2012-09-26 23:19:57 -05:00
|
|
|
vec::bytes::memcpy(view, v, v_len);
|
|
|
|
}
|
2012-08-26 23:21:59 -05:00
|
|
|
|
|
|
|
self.pos += v_len;
|
2012-05-11 12:44:57 -05:00
|
|
|
|
2012-10-18 11:10:37 -05:00
|
|
|
move bytes
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
}
|
2012-08-14 15:38:35 -05:00
|
|
|
fn seek(offset: int, whence: SeekStyle) {
|
2012-01-11 08:15:54 -06:00
|
|
|
let pos = self.pos;
|
2012-10-18 11:10:37 -05:00
|
|
|
let len = self.bytes.len();
|
2012-01-11 08:15:54 -06:00
|
|
|
self.pos = seek_in_buf(offset, pos, len, whence);
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn tell() -> uint { self.pos }
|
|
|
|
fn flush() -> int { 0 }
|
2012-08-14 15:38:35 -05:00
|
|
|
fn get_type() -> WriterType { File }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-09-20 13:17:15 -05:00
|
|
|
impl @BytesWriter : Writer {
|
|
|
|
fn write(v: &[const u8]) { (*self).write(v) }
|
|
|
|
fn seek(offset: int, whence: SeekStyle) { (*self).seek(offset, whence) }
|
|
|
|
fn tell() -> uint { (*self).tell() }
|
|
|
|
fn flush() -> int { (*self).flush() }
|
|
|
|
fn get_type() -> WriterType { (*self).get_type() }
|
|
|
|
}
|
|
|
|
|
2012-10-18 11:04:47 -05:00
|
|
|
pub pure fn BytesWriter() -> BytesWriter {
|
2012-10-18 11:10:37 -05:00
|
|
|
BytesWriter { bytes: DVec(), mut pos: 0u }
|
2011-12-28 02:30:04 -06:00
|
|
|
}
|
2012-09-14 11:40:28 -05:00
|
|
|
|
2012-10-18 11:04:47 -05:00
|
|
|
pub pure fn with_bytes_writer(f: fn(Writer)) -> ~[u8] {
|
2012-09-20 13:17:15 -05:00
|
|
|
let wr = @BytesWriter();
|
2012-09-14 11:40:28 -05:00
|
|
|
f(wr as Writer);
|
2012-10-18 11:04:47 -05:00
|
|
|
// FIXME (#3758): This should not be needed.
|
2012-10-18 11:10:37 -05:00
|
|
|
unsafe { wr.bytes.check_out(|bytes| move bytes) }
|
2012-02-21 11:23:01 -06:00
|
|
|
}
|
2012-02-21 11:22:50 -06:00
|
|
|
|
2012-10-18 11:04:47 -05:00
|
|
|
pub pure fn with_str_writer(f: fn(Writer)) -> ~str {
|
2012-09-14 11:40:28 -05:00
|
|
|
let mut v = with_bytes_writer(f);
|
|
|
|
|
2012-10-18 11:04:47 -05:00
|
|
|
// FIXME (#3758): This should not be needed.
|
|
|
|
unsafe {
|
|
|
|
// Make sure the vector has a trailing null and is proper utf8.
|
|
|
|
v.push(0);
|
|
|
|
}
|
2012-09-14 11:40:28 -05:00
|
|
|
assert str::is_utf8(v);
|
2012-02-21 11:22:50 -06:00
|
|
|
|
2012-09-19 00:35:28 -05:00
|
|
|
unsafe { move ::cast::transmute(move v) }
|
2012-01-25 03:41:23 -06:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
|
|
|
|
// Utility functions
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
|
2011-07-27 07:19:39 -05:00
|
|
|
uint {
|
2012-03-12 22:04:27 -05:00
|
|
|
let mut bpos = pos as int;
|
2011-07-27 07:19:39 -05:00
|
|
|
let blen = len as int;
|
2012-08-06 14:34:08 -05:00
|
|
|
match whence {
|
2012-08-14 15:38:35 -05:00
|
|
|
SeekSet => bpos = offset,
|
|
|
|
SeekCur => bpos += offset,
|
|
|
|
SeekEnd => bpos = blen + offset
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2011-08-19 17:16:48 -05:00
|
|
|
if bpos < 0 { bpos = 0; } else if bpos > blen { bpos = blen; }
|
2012-08-01 19:30:05 -05:00
|
|
|
return bpos as uint;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2011-08-01 17:53:14 -05:00
|
|
|
|
2012-09-02 17:37:15 -05:00
|
|
|
#[allow(non_implicitly_copyable_typarams)]
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
|
2012-06-30 18:19:07 -05:00
|
|
|
result::chain(read_whole_file(file), |bytes| {
|
2012-07-25 16:58:48 -05:00
|
|
|
if str::is_utf8(bytes) {
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Ok(str::from_bytes(bytes))
|
2012-07-25 16:58:48 -05:00
|
|
|
} else {
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Err(file.to_str() + ~" is not UTF-8")
|
2012-07-25 16:58:48 -05:00
|
|
|
}
|
2011-10-28 23:19:59 -05:00
|
|
|
})
|
2011-08-01 17:53:14 -05:00
|
|
|
}
|
|
|
|
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2004): implement this in a low-level way. Going through the
|
|
|
|
// abstractions is pointless.
|
2012-09-02 17:37:15 -05:00
|
|
|
#[allow(non_implicitly_copyable_typarams)]
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> {
|
2012-06-30 18:19:07 -05:00
|
|
|
result::chain(file_reader(file), |rdr| {
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Ok(rdr.read_whole_stream())
|
2011-10-28 23:19:59 -05:00
|
|
|
})
|
2011-08-01 17:53:14 -05:00
|
|
|
}
|
|
|
|
|
2011-11-16 16:14:18 -06:00
|
|
|
// fsync related
|
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub mod fsync {
|
2011-11-16 16:14:18 -06:00
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub enum Level {
|
2011-11-16 16:14:18 -06:00
|
|
|
// whatever fsync does on that platform
|
2012-08-14 15:38:35 -05:00
|
|
|
FSync,
|
2011-11-16 16:14:18 -06:00
|
|
|
|
|
|
|
// fdatasync on linux, similiar or more on other platforms
|
2012-08-14 15:38:35 -05:00
|
|
|
FDataSync,
|
2011-11-16 16:14:18 -06:00
|
|
|
|
|
|
|
// full fsync
|
|
|
|
//
|
|
|
|
// You must additionally sync the parent directory as well!
|
2012-08-14 15:38:35 -05:00
|
|
|
FullFSync,
|
2011-11-16 16:14:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-21 23:30:16 -05:00
|
|
|
// Artifacts that need to fsync on destruction
|
2012-10-01 16:02:10 -05:00
|
|
|
pub struct Res<t: Copy> {
|
2012-09-06 21:40:15 -05:00
|
|
|
arg: Arg<t>,
|
2012-06-21 23:30:16 -05:00
|
|
|
drop {
|
2012-08-06 14:34:08 -05:00
|
|
|
match self.arg.opt_level {
|
2012-08-20 14:23:37 -05:00
|
|
|
option::None => (),
|
|
|
|
option::Some(level) => {
|
2012-06-21 23:30:16 -05:00
|
|
|
// fail hard if not succesful
|
2012-11-30 13:18:25 -06:00
|
|
|
assert((self.arg.fsync_fn)(self.arg.val, level) != -1);
|
2012-06-21 23:30:16 -05:00
|
|
|
}
|
2011-11-16 16:14:18 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-02 13:37:37 -05:00
|
|
|
pub fn Res<t: Copy>(arg: Arg<t>) -> Res<t>{
|
2012-09-04 17:23:28 -05:00
|
|
|
Res {
|
|
|
|
arg: move arg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-01 16:02:10 -05:00
|
|
|
pub type Arg<t> = {
|
2011-11-16 16:14:18 -06:00
|
|
|
val: t,
|
2012-08-20 14:23:37 -05:00
|
|
|
opt_level: Option<Level>,
|
2012-10-02 13:37:37 -05:00
|
|
|
fsync_fn: fn@(f: t, Level) -> int
|
2011-11-16 16:14:18 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
// fsync file after executing blk
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2004) find better way to create resources within lifetime of
|
|
|
|
// outer res
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>,
|
2012-10-02 13:37:37 -05:00
|
|
|
blk: fn(v: Res<*libc::FILE>)) {
|
2012-09-26 12:13:43 -05:00
|
|
|
blk(move Res({
|
2012-06-21 23:30:16 -05:00
|
|
|
val: file.f, opt_level: opt_level,
|
2012-10-02 13:37:37 -05:00
|
|
|
fsync_fn: fn@(file: *libc::FILE, l: Level) -> int {
|
2012-08-01 19:30:05 -05:00
|
|
|
return os::fsync_fd(libc::fileno(file), l) as int;
|
2011-11-16 16:14:18 -06:00
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
// fsync fd after executing blk
|
2012-10-01 16:02:10 -05:00
|
|
|
pub fn fd_res_sync(fd: &FdRes, opt_level: Option<Level>,
|
2012-10-02 13:37:37 -05:00
|
|
|
blk: fn(v: Res<fd_t>)) {
|
2012-09-26 12:13:43 -05:00
|
|
|
blk(move Res({
|
2012-06-21 23:30:16 -05:00
|
|
|
val: fd.fd, opt_level: opt_level,
|
2012-10-02 13:37:37 -05:00
|
|
|
fsync_fn: fn@(fd: fd_t, l: Level) -> int {
|
2012-08-01 19:30:05 -05:00
|
|
|
return os::fsync_fd(fd, l) as int;
|
2011-11-16 16:14:18 -06:00
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Type of objects that may want to fsync
|
2012-10-01 16:02:10 -05:00
|
|
|
pub trait FSyncable { fn fsync(l: Level) -> int; }
|
2011-11-16 16:14:18 -06:00
|
|
|
|
|
|
|
// Call o.fsync after executing blk
|
2012-10-02 13:37:37 -05:00
|
|
|
pub fn obj_sync(o: FSyncable, opt_level: Option<Level>,
|
|
|
|
blk: fn(v: Res<FSyncable>)) {
|
2012-08-14 15:38:35 -05:00
|
|
|
blk(Res({
|
2011-11-16 16:14:18 -06:00
|
|
|
val: o, opt_level: opt_level,
|
2012-10-02 13:37:37 -05:00
|
|
|
fsync_fn: fn@(o: FSyncable, l: Level) -> int {
|
2012-08-14 15:38:35 -05:00
|
|
|
return o.fsync(l);
|
|
|
|
}
|
2011-11-16 16:14:18 -06:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
2011-08-01 17:53:14 -05:00
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_simple() {
|
2012-08-24 17:28:43 -05:00
|
|
|
let tmpfile = &Path("tmp/lib-io-test-simple.tmp");
|
2012-01-17 21:05:07 -06:00
|
|
|
log(debug, tmpfile);
|
2012-07-14 00:57:48 -05:00
|
|
|
let frood: ~str =
|
|
|
|
~"A hoopy frood who really knows where his towel is.";
|
2012-01-17 21:05:07 -06:00
|
|
|
log(debug, frood);
|
|
|
|
{
|
2012-08-14 15:38:35 -05:00
|
|
|
let out: io::Writer =
|
2012-01-17 21:05:07 -06:00
|
|
|
result::get(
|
2012-09-25 18:23:04 -05:00
|
|
|
&io::file_writer(tmpfile, ~[io::Create, io::Truncate]));
|
2012-01-17 21:05:07 -06:00
|
|
|
out.write_str(frood);
|
|
|
|
}
|
2012-09-25 18:23:04 -05:00
|
|
|
let inp: io::Reader = result::get(&io::file_reader(tmpfile));
|
2012-07-14 00:57:48 -05:00
|
|
|
let frood2: ~str = inp.read_c_str();
|
2012-01-17 21:05:07 -06:00
|
|
|
log(debug, frood2);
|
2012-08-02 17:42:56 -05:00
|
|
|
assert frood == frood2;
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_readchars_empty() {
|
2012-08-21 20:32:23 -05:00
|
|
|
do io::with_str_reader(~"") |inp| {
|
2012-09-28 23:51:14 -05:00
|
|
|
let res : ~[char] = inp.read_chars(128);
|
|
|
|
assert(vec::len(res) == 0);
|
2012-08-21 20:32:23 -05:00
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_readchars_wide() {
|
2012-07-14 00:57:48 -05:00
|
|
|
let wide_test = ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤";
|
2012-06-29 18:26:56 -05:00
|
|
|
let ivals : ~[int] = ~[
|
2012-01-17 21:05:07 -06:00
|
|
|
29983, 38152, 30340, 27748,
|
|
|
|
21273, 20999, 32905, 27748,
|
|
|
|
104, 101, 108, 108, 111,
|
|
|
|
29983, 38152, 30340, 27748,
|
2012-06-29 18:26:56 -05:00
|
|
|
21273, 20999, 32905, 27748];
|
2012-09-28 23:51:14 -05:00
|
|
|
fn check_read_ln(len : uint, s: &str, ivals: &[int]) {
|
2012-08-21 20:32:23 -05:00
|
|
|
do io::with_str_reader(s) |inp| {
|
|
|
|
let res : ~[char] = inp.read_chars(len);
|
|
|
|
if (len <= vec::len(ivals)) {
|
|
|
|
assert(vec::len(res) == len);
|
|
|
|
}
|
|
|
|
assert(vec::slice(ivals, 0u, vec::len(res)) ==
|
2012-09-21 20:43:30 -05:00
|
|
|
vec::map(res, |x| *x as int));
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
}
|
2012-09-28 23:51:14 -05:00
|
|
|
let mut i = 0;
|
|
|
|
while i < 8 {
|
2012-01-17 21:05:07 -06:00
|
|
|
check_read_ln(i, wide_test, ivals);
|
2012-09-28 23:51:14 -05:00
|
|
|
i += 1;
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
// check a long read for good measure
|
2012-09-28 23:51:14 -05:00
|
|
|
check_read_ln(128, wide_test, ivals);
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_readchar() {
|
2012-08-21 20:32:23 -05:00
|
|
|
do io::with_str_reader(~"生") |inp| {
|
|
|
|
let res : char = inp.read_char();
|
|
|
|
assert(res as int == 29983);
|
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_readchar_empty() {
|
2012-08-21 20:32:23 -05:00
|
|
|
do io::with_str_reader(~"") |inp| {
|
|
|
|
let res : char = inp.read_char();
|
|
|
|
assert(res as int == -1);
|
|
|
|
}
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn file_reader_not_exist() {
|
2012-08-24 17:28:43 -05:00
|
|
|
match io::file_reader(&Path("not a file")) {
|
2012-09-28 15:00:07 -05:00
|
|
|
result::Err(copy e) => {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert e == ~"error opening not a file";
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Ok(_) => fail
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-24 09:19:51 -06:00
|
|
|
#[test]
|
|
|
|
#[should_fail]
|
2012-11-25 15:51:43 -06:00
|
|
|
#[ignore(cfg(windows))]
|
2012-11-24 09:19:51 -06:00
|
|
|
fn test_read_buffer_too_small() {
|
|
|
|
let path = &Path("tmp/lib-io-test-read-buffer-too-small.tmp");
|
|
|
|
// ensure the file exists
|
|
|
|
io::file_writer(path, [io::Create]).get();
|
|
|
|
|
|
|
|
let file = io::file_reader(path).get();
|
|
|
|
let mut buf = vec::from_elem(5, 0);
|
|
|
|
file.read(buf, 6); // this should fail because buf is too small
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_read_buffer_big_enough() {
|
|
|
|
let path = &Path("tmp/lib-io-test-read-buffer-big-enough.tmp");
|
|
|
|
// ensure the file exists
|
|
|
|
io::file_writer(path, [io::Create]).get();
|
|
|
|
|
|
|
|
let file = io::file_reader(path).get();
|
|
|
|
let mut buf = vec::from_elem(5, 0);
|
|
|
|
file.read(buf, 4); // this should succeed because buf is big enough
|
|
|
|
}
|
|
|
|
|
2012-11-03 13:48:02 -05:00
|
|
|
#[test]
|
|
|
|
fn test_write_empty() {
|
|
|
|
let file = io::file_writer(&Path("tmp/lib-io-test-write-empty.tmp"),
|
|
|
|
[io::Create]).get();
|
|
|
|
file.write([]);
|
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
#[test]
|
|
|
|
fn file_writer_bad_name() {
|
2012-08-24 17:28:43 -05:00
|
|
|
match io::file_writer(&Path("?/?"), ~[]) {
|
2012-09-28 15:00:07 -05:00
|
|
|
result::Err(copy e) => {
|
2012-08-24 17:28:43 -05:00
|
|
|
assert str::starts_with(e, "error opening");
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Ok(_) => fail
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn buffered_file_writer_bad_name() {
|
2012-08-24 17:28:43 -05:00
|
|
|
match io::buffered_file_writer(&Path("?/?")) {
|
2012-09-28 15:00:07 -05:00
|
|
|
result::Err(copy e) => {
|
2012-08-24 17:28:43 -05:00
|
|
|
assert str::starts_with(e, "error opening");
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
2012-08-26 18:54:31 -05:00
|
|
|
result::Ok(_) => fail
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
|
|
|
}
|
2012-05-11 12:44:57 -05:00
|
|
|
|
|
|
|
#[test]
|
2012-09-14 11:40:28 -05:00
|
|
|
fn bytes_buffer_overwrite() {
|
|
|
|
let wr = BytesWriter();
|
|
|
|
wr.write(~[0u8, 1u8, 2u8, 3u8]);
|
2012-10-18 11:10:37 -05:00
|
|
|
assert wr.bytes.borrow(|bytes| bytes == ~[0u8, 1u8, 2u8, 3u8]);
|
2012-09-14 11:40:28 -05:00
|
|
|
wr.seek(-2, SeekCur);
|
|
|
|
wr.write(~[4u8, 5u8, 6u8, 7u8]);
|
2012-10-18 11:10:37 -05:00
|
|
|
assert wr.bytes.borrow(|bytes| bytes ==
|
|
|
|
~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]);
|
2012-09-14 11:40:28 -05:00
|
|
|
wr.seek(-2, SeekEnd);
|
|
|
|
wr.write(~[8u8]);
|
|
|
|
wr.seek(1, SeekSet);
|
|
|
|
wr.write(~[9u8]);
|
2012-10-18 11:10:37 -05:00
|
|
|
assert wr.bytes.borrow(|bytes| bytes ==
|
|
|
|
~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]);
|
2012-05-11 12:44:57 -05:00
|
|
|
}
|
2012-11-04 04:14:49 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_read_write_le() {
|
|
|
|
let path = Path("tmp/lib-io-test-read-write-le.tmp");
|
|
|
|
let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value];
|
|
|
|
|
|
|
|
// write the ints to the file
|
|
|
|
{
|
|
|
|
let file = io::file_writer(&path, [io::Create]).get();
|
|
|
|
for uints.each |i| {
|
|
|
|
file.write_le_u64(*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// then read them back and check that they are the same
|
|
|
|
{
|
|
|
|
let file = io::file_reader(&path).get();
|
|
|
|
for uints.each |i| {
|
|
|
|
assert file.read_le_u64() == *i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_read_write_be() {
|
|
|
|
let path = Path("tmp/lib-io-test-read-write-be.tmp");
|
|
|
|
let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value];
|
|
|
|
|
|
|
|
// write the ints to the file
|
|
|
|
{
|
|
|
|
let file = io::file_writer(&path, [io::Create]).get();
|
|
|
|
for uints.each |i| {
|
|
|
|
file.write_be_u64(*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// then read them back and check that they are the same
|
|
|
|
{
|
|
|
|
let file = io::file_reader(&path).get();
|
|
|
|
for uints.each |i| {
|
|
|
|
assert file.read_be_u64() == *i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_read_be_int_n() {
|
|
|
|
let path = Path("tmp/lib-io-test-read-be-int-n.tmp");
|
|
|
|
let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value];
|
|
|
|
|
|
|
|
// write the ints to the file
|
|
|
|
{
|
|
|
|
let file = io::file_writer(&path, [io::Create]).get();
|
|
|
|
for ints.each |i| {
|
|
|
|
file.write_be_i32(*i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// then read them back and check that they are the same
|
|
|
|
{
|
|
|
|
let file = io::file_reader(&path).get();
|
|
|
|
for ints.each |i| {
|
|
|
|
// this tests that the sign extension is working
|
|
|
|
// (comparing the values as i32 would not test this)
|
|
|
|
assert file.read_be_int_n(4) == *i as i64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-17 21:05:07 -06:00
|
|
|
}
|
2011-08-01 17:53:14 -05:00
|
|
|
|
2011-07-10 14:47:51 -05:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|