2011-12-06 15:58:45 -06:00
|
|
|
/*
|
|
|
|
Module: io
|
|
|
|
|
|
|
|
Basic input/output
|
|
|
|
*/
|
|
|
|
|
2011-12-18 15:46:04 -06:00
|
|
|
import core::ctypes::fd_t;
|
|
|
|
import core::ctypes::c_int;
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2011-11-16 22:49:38 -06:00
|
|
|
#[abi = "cdecl"]
|
|
|
|
native mod rustrt {
|
2011-07-10 14:47:51 -05:00
|
|
|
fn rust_get_stdin() -> os::libc::FILE;
|
|
|
|
fn rust_get_stdout() -> os::libc::FILE;
|
2011-08-24 23:19:56 -05:00
|
|
|
fn rust_get_stderr() -> os::libc::FILE;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reading
|
|
|
|
|
|
|
|
// FIXME This is all buffered. We might need an unbuffered variant as well
|
|
|
|
tag seek_style { seek_set; seek_end; seek_cur; }
|
|
|
|
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
// The raw underlying reader iface. All readers must implement this.
|
|
|
|
iface reader {
|
|
|
|
// FIXME: Seekable really should be orthogonal.
|
|
|
|
fn read_bytes(uint) -> [u8];
|
|
|
|
fn read_byte() -> int;
|
|
|
|
fn unread_byte(int);
|
|
|
|
fn eof() -> bool;
|
|
|
|
fn seek(int, seek_style);
|
|
|
|
fn tell() -> uint;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
// Generic utility functions defined on readers
|
2011-07-29 06:31:44 -05:00
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
impl reader_util for reader {
|
2012-01-08 10:37:03 -06:00
|
|
|
fn read_chars(n: uint) -> [char] {
|
|
|
|
// returns the (consumed offset, n_req), appends characters to &chars
|
|
|
|
fn chars_from_buf(buf: [u8], &chars: [char]) -> (uint, uint) {
|
|
|
|
let i = 0u;
|
|
|
|
while i < vec::len(buf) {
|
|
|
|
let b0 = buf[i];
|
|
|
|
let w = str::utf8_char_width(b0);
|
|
|
|
let end = i + w;
|
|
|
|
i += 1u;
|
|
|
|
assert (w > 0u);
|
|
|
|
if w == 1u {
|
|
|
|
chars += [ b0 as char ];
|
|
|
|
cont;
|
|
|
|
}
|
|
|
|
// can't satisfy this char with the existing data
|
|
|
|
if end > vec::len(buf) {
|
|
|
|
ret (i - 1u, end - vec::len(buf));
|
|
|
|
}
|
|
|
|
let val = 0u;
|
|
|
|
while i < end {
|
|
|
|
let next = buf[i] as int;
|
|
|
|
i += 1u;
|
|
|
|
assert (next > -1);
|
|
|
|
assert (next & 192 == 128);
|
|
|
|
val <<= 6u;
|
|
|
|
val += next & 63 as uint;
|
|
|
|
}
|
|
|
|
// See str::char_at
|
2012-01-09 06:49:17 -06:00
|
|
|
val += (b0 << (w + 1u as u8) as uint)
|
|
|
|
<< (w - 1u) * 6u - w - 1u;
|
2012-01-08 10:37:03 -06:00
|
|
|
chars += [ val as char ];
|
|
|
|
}
|
|
|
|
ret (i, 0u);
|
|
|
|
}
|
|
|
|
let buf: [u8] = [];
|
|
|
|
let chars: [char] = [];
|
2012-01-09 06:49:17 -06:00
|
|
|
// might need more bytes, but reading n will never over-read
|
|
|
|
let nbread = n;
|
2012-01-08 10:37:03 -06:00
|
|
|
while nbread > 0u {
|
2012-01-09 06:49:17 -06:00
|
|
|
let data = self.read_bytes(nbread);
|
2012-01-08 10:37:03 -06:00
|
|
|
if vec::len(data) == 0u {
|
2012-01-09 06:49:17 -06:00
|
|
|
// eof - FIXME should we do something if
|
|
|
|
// we're split in a unicode char?
|
2012-01-08 10:37:03 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
buf += data;
|
|
|
|
let (offset, nbreq) = chars_from_buf(buf, chars);
|
|
|
|
let ncreq = n - vec::len(chars);
|
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 };
|
|
|
|
if nbread > 0u {
|
|
|
|
buf = vec::slice(buf, offset, vec::len(buf));
|
|
|
|
}
|
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
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-01-08 10:37:03 -06:00
|
|
|
let c = self.read_chars(1u);
|
|
|
|
if vec::len(c) == 0u {
|
2011-07-10 14:47:51 -05:00
|
|
|
ret -1 as char; // FIXME will this stay valid?
|
|
|
|
}
|
2012-01-08 10:37:03 -06:00
|
|
|
assert(vec::len(c) == 1u);
|
|
|
|
ret c[0];
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
fn read_line() -> str {
|
2011-08-19 17:16:48 -05:00
|
|
|
let buf: [u8] = [];
|
2012-01-11 08:15:54 -06:00
|
|
|
while true {
|
|
|
|
let ch = self.read_byte();
|
|
|
|
if ch == -1 || ch == 10 { break; }
|
|
|
|
buf += [ch as u8];
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
str::unsafe_from_bytes(buf)
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
fn read_c_str() -> str {
|
2011-08-19 17:16:48 -05:00
|
|
|
let buf: [u8] = [];
|
2012-01-11 08:15:54 -06:00
|
|
|
while true {
|
|
|
|
let ch = self.read_byte();
|
|
|
|
if ch < 1 { break; } else { buf += [ch as u8]; }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
str::unsafe_from_bytes(buf)
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME deal with eof?
|
2011-07-27 07:19:39 -05:00
|
|
|
fn read_le_uint(size: uint) -> uint {
|
2012-01-11 08:15:54 -06:00
|
|
|
let val = 0u, pos = 0u, i = size;
|
2011-11-03 04:57:54 -05:00
|
|
|
while i > 0u {
|
2012-01-11 08:15:54 -06:00
|
|
|
val += (self.read_byte() as uint) << pos;
|
2011-07-10 14:47:51 -05:00
|
|
|
pos += 8u;
|
2011-11-03 04:57:54 -05:00
|
|
|
i -= 1u;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
val
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
fn read_le_int(size: uint) -> int {
|
2011-11-03 04:57:54 -05:00
|
|
|
let val = 0u, pos = 0u, i = size;
|
|
|
|
while i > 0u {
|
2012-01-11 08:15:54 -06:00
|
|
|
val += (self.read_byte() as uint) << pos;
|
2011-07-10 14:47:51 -05:00
|
|
|
pos += 8u;
|
2011-11-03 04:57:54 -05:00
|
|
|
i -= 1u;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
val as int
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn read_be_uint(size: uint) -> uint {
|
|
|
|
let val = 0u, i = size;
|
2011-11-03 04:57:54 -05:00
|
|
|
while i > 0u {
|
|
|
|
i -= 1u;
|
2012-01-11 08:15:54 -06:00
|
|
|
val += (self.read_byte() as uint) << i * 8u;
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
val
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
|
2011-08-04 19:24:54 -05:00
|
|
|
fn read_whole_stream() -> [u8] {
|
2011-08-19 17:16:48 -05:00
|
|
|
let buf: [u8] = [];
|
2012-01-11 08:15:54 -06:00
|
|
|
while !self.eof() { buf += self.read_bytes(2048u); }
|
|
|
|
buf
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reader implementations
|
|
|
|
|
|
|
|
fn convert_whence(whence: seek_style) -> i32 {
|
|
|
|
ret alt whence {
|
|
|
|
seek_set. { 0i32 }
|
|
|
|
seek_cur. { 1i32 }
|
|
|
|
seek_end. { 2i32 }
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
impl of reader for os::libc::FILE {
|
|
|
|
fn read_bytes(len: uint) -> [u8] unsafe {
|
|
|
|
let buf = [];
|
|
|
|
vec::reserve(buf, len);
|
|
|
|
let read = os::libc::fread(vec::unsafe::to_ptr(buf), 1u, len, self);
|
|
|
|
vec::unsafe::set_len(buf, read);
|
2011-07-10 14:47:51 -05:00
|
|
|
ret buf;
|
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn read_byte() -> int { ret os::libc::fgetc(self) as int; }
|
|
|
|
fn unread_byte(byte: int) { os::libc::ungetc(byte as i32, self); }
|
|
|
|
fn eof() -> bool { ret os::libc::feof(self) != 0i32; }
|
|
|
|
fn seek(offset: int, whence: seek_style) {
|
|
|
|
assert os::libc::fseek(self, offset, convert_whence(whence)) == 0i32;
|
|
|
|
}
|
|
|
|
fn tell() -> uint { ret os::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.
|
|
|
|
// FIXME there really should be a better way to do this
|
|
|
|
impl <T: reader, C> of reader for {base: T, cleanup: C} {
|
|
|
|
fn read_bytes(len: uint) -> [u8] { self.base.read_bytes(len) }
|
|
|
|
fn read_byte() -> int { self.base.read_byte() }
|
|
|
|
fn unread_byte(byte: int) { self.base.unread_byte(byte); }
|
|
|
|
fn eof() -> bool { self.base.eof() }
|
|
|
|
fn seek(off: int, whence: seek_style) { self.base.seek(off, whence) }
|
|
|
|
fn tell() -> uint { self.base.tell() }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
resource FILE_res(f: os::libc::FILE) { os::libc::fclose(f); }
|
|
|
|
|
|
|
|
fn FILE_reader(f: os::libc::FILE, cleanup: bool) -> reader {
|
|
|
|
if cleanup {
|
|
|
|
{base: f, cleanup: FILE_res(f)} as reader
|
|
|
|
} else {
|
|
|
|
f as reader
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: this should either be an iface-less impl, a set of top-level
|
|
|
|
// functions that take a reader, or a set of default methods on reader
|
|
|
|
// (which can then be called reader)
|
|
|
|
|
|
|
|
fn stdin() -> reader { rustrt::rust_get_stdin() as reader }
|
|
|
|
|
2011-10-28 23:19:59 -05:00
|
|
|
fn file_reader(path: str) -> result::t<reader, str> {
|
2011-10-06 05:26:12 -05:00
|
|
|
let f = str::as_buf(path, {|pathbuf|
|
|
|
|
str::as_buf("r", {|modebuf|
|
|
|
|
os::libc::fopen(pathbuf, modebuf)
|
|
|
|
})
|
|
|
|
});
|
2011-10-28 23:19:59 -05:00
|
|
|
ret if f as uint == 0u { result::err("error opening " + path) }
|
|
|
|
else {
|
2012-01-11 08:15:54 -06:00
|
|
|
result::ok(FILE_reader(f, true))
|
2011-10-28 23:19:59 -05:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Byte buffer readers
|
|
|
|
|
2011-11-16 16:41:32 -06:00
|
|
|
// TODO: const u8, but this fails with rustboot.
|
2012-01-11 08:15:54 -06:00
|
|
|
type byte_buf = {buf: [u8], mutable pos: uint};
|
2011-07-27 07:19:39 -05:00
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
impl of reader for byte_buf {
|
|
|
|
fn read_bytes(len: uint) -> [u8] {
|
|
|
|
let rest = vec::len(self.buf) - self.pos;
|
2011-07-27 07:19:39 -05:00
|
|
|
let to_read = len;
|
|
|
|
if rest < to_read { to_read = rest; }
|
2012-01-11 08:15:54 -06:00
|
|
|
let range = vec::slice(self.buf, self.pos, self.pos + to_read);
|
|
|
|
self.pos += to_read;
|
2011-07-10 14:47:51 -05:00
|
|
|
ret range;
|
|
|
|
}
|
|
|
|
fn read_byte() -> int {
|
2012-01-11 08:15:54 -06:00
|
|
|
if self.pos == vec::len(self.buf) { ret -1; }
|
|
|
|
let b = self.buf[self.pos];
|
|
|
|
self.pos += 1u;
|
2011-07-10 14:47:51 -05:00
|
|
|
ret b as int;
|
|
|
|
}
|
2011-12-22 16:42:52 -06:00
|
|
|
fn unread_byte(_byte: int) { #error("TODO: unread_byte"); fail; }
|
2012-01-11 08:15:54 -06:00
|
|
|
fn eof() -> bool { self.pos == vec::len(self.buf) }
|
2011-07-27 07:19:39 -05:00
|
|
|
fn seek(offset: int, whence: seek_style) {
|
2012-01-11 08:15:54 -06:00
|
|
|
let pos = self.pos;
|
|
|
|
let len = vec::len(self.buf);
|
|
|
|
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 }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2011-12-28 02:30:04 -06:00
|
|
|
fn bytes_reader(bytes: [u8]) -> reader {
|
2012-01-11 08:15:54 -06:00
|
|
|
{buf: bytes, mutable pos: 0u} as reader
|
2011-12-28 02:30:04 -06:00
|
|
|
}
|
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn string_reader(s: str) -> reader {
|
2012-01-11 08:15:54 -06:00
|
|
|
bytes_reader(str::bytes(s))
|
2011-07-25 16:04:01 -05:00
|
|
|
}
|
|
|
|
|
2011-07-10 14:47:51 -05:00
|
|
|
|
|
|
|
// Writing
|
|
|
|
tag fileflag { append; create; truncate; none; }
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
// FIXME: Seekable really should be orthogonal.
|
|
|
|
// FIXME: eventually u64
|
|
|
|
iface writer {
|
|
|
|
fn write([const u8]);
|
|
|
|
fn seek(int, seek_style);
|
|
|
|
fn tell() -> uint;
|
|
|
|
fn flush() -> int;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl <T: writer, C> of writer for {base: T, cleanup: C} {
|
|
|
|
fn write(bs: [const u8]) { self.base.write(bs); }
|
|
|
|
fn seek(off: int, style: seek_style) { self.base.seek(off, style); }
|
|
|
|
fn tell() -> uint { self.base.tell() }
|
|
|
|
fn flush() -> int { self.base.flush() }
|
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
impl of writer for os::libc::FILE {
|
2011-12-27 18:38:48 -06:00
|
|
|
fn write(v: [const u8]) unsafe {
|
2012-01-11 08:15:54 -06:00
|
|
|
let len = vec::len(v);
|
|
|
|
let vbuf = vec::unsafe::to_ptr(v);
|
|
|
|
let nout = os::libc::fwrite(vbuf, len, 1u, self);
|
2011-12-22 16:42:52 -06:00
|
|
|
if nout < 1u { #error("error dumping buffer"); }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
fn seek(offset: int, whence: seek_style) {
|
2012-01-11 08:15:54 -06:00
|
|
|
assert os::libc::fseek(self, offset, convert_whence(whence)) == 0i32;
|
2011-11-16 16:14:18 -06:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn tell() -> uint { os::libc::ftell(self) as uint }
|
|
|
|
fn flush() -> int { os::libc::fflush(self) as int }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
fn FILE_writer(f: os::libc::FILE, cleanup: bool) -> writer {
|
|
|
|
if cleanup {
|
|
|
|
{base: f, cleanup: FILE_res(f)} as writer
|
|
|
|
} else {
|
|
|
|
f as writer
|
|
|
|
}
|
|
|
|
}
|
2011-07-29 06:31:44 -05:00
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
impl of writer for fd_t {
|
2011-12-27 18:38:48 -06:00
|
|
|
fn write(v: [const u8]) unsafe {
|
2012-01-11 08:15:54 -06:00
|
|
|
let len = vec::len(v);
|
2011-07-27 07:19:39 -05:00
|
|
|
let count = 0u;
|
|
|
|
let vbuf;
|
|
|
|
while count < len {
|
2012-01-11 08:15:54 -06:00
|
|
|
vbuf = ptr::offset(vec::unsafe::to_ptr(v), count);
|
|
|
|
let nout = os::libc::write(self, vbuf, len);
|
2011-07-27 07:19:39 -05:00
|
|
|
if nout < 0 {
|
2011-12-22 16:42:52 -06:00
|
|
|
#error("error dumping buffer");
|
2011-12-22 19:53:53 -06:00
|
|
|
log(error, sys::last_os_error());
|
2011-07-10 14:47:51 -05:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
count += nout as uint;
|
|
|
|
}
|
|
|
|
}
|
2011-08-18 03:01:39 -05:00
|
|
|
fn seek(_offset: int, _whence: seek_style) {
|
2011-12-22 16:42:52 -06:00
|
|
|
#error("need 64-bit native calls for seek, sorry");
|
2011-07-10 14:47:51 -05:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
fn tell() -> uint {
|
2011-12-22 16:42:52 -06:00
|
|
|
#error("need 64-bit native 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 }
|
|
|
|
}
|
2011-11-16 16:14:18 -06:00
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
resource fd_res(fd: fd_t) { os::libc::close(fd); }
|
2011-11-16 16:14:18 -06:00
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
fn fd_writer(fd: fd_t, cleanup: bool) -> writer {
|
|
|
|
if cleanup {
|
|
|
|
{base: fd, cleanup: fd_res(fd)} as writer
|
|
|
|
} else {
|
|
|
|
fd as writer
|
2011-11-16 16:14:18 -06:00
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
fn mk_file_writer(path: str, flags: [fileflag])
|
|
|
|
-> result::t<writer, str> {
|
2011-11-15 00:29:40 -06:00
|
|
|
let fflags: i32 =
|
2011-11-15 19:10:43 -06:00
|
|
|
os::libc_constants::O_WRONLY | os::libc_constants::O_BINARY;
|
2011-08-15 23:54:52 -05:00
|
|
|
for f: fileflag in flags {
|
2011-07-27 07:19:39 -05:00
|
|
|
alt f {
|
2011-11-15 19:10:43 -06:00
|
|
|
append. { fflags |= os::libc_constants::O_APPEND; }
|
|
|
|
create. { fflags |= os::libc_constants::O_CREAT; }
|
|
|
|
truncate. { fflags |= os::libc_constants::O_TRUNC; }
|
2011-07-27 07:19:39 -05:00
|
|
|
none. { }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
let fd = str::as_buf(path, {|pathbuf|
|
|
|
|
os::libc::open(pathbuf, fflags, os::libc_constants::S_IRUSR |
|
|
|
|
os::libc_constants::S_IWUSR)
|
|
|
|
});
|
|
|
|
if fd < 0i32 {
|
|
|
|
// FIXME don't log this! put it in the returned error string
|
2011-12-22 19:53:53 -06:00
|
|
|
log(error, sys::last_os_error());
|
2011-10-28 23:19:59 -05:00
|
|
|
result::err("error opening " + path)
|
|
|
|
} else {
|
2012-01-11 08:15:54 -06:00
|
|
|
result::ok(fd_writer(fd, true))
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-04 19:24:54 -05:00
|
|
|
fn uint_to_le_bytes(n: uint, size: uint) -> [u8] {
|
2011-11-03 04:57:54 -05:00
|
|
|
let bytes: [u8] = [], i = size, n = n;
|
|
|
|
while i > 0u { bytes += [n & 255u as u8]; n >>= 8u; i -= 1u; }
|
2011-07-10 14:47:51 -05:00
|
|
|
ret bytes;
|
|
|
|
}
|
|
|
|
|
2011-08-04 19:24:54 -05:00
|
|
|
fn uint_to_be_bytes(n: uint, size: uint) -> [u8] {
|
2011-08-19 17:16:48 -05:00
|
|
|
let bytes: [u8] = [];
|
2011-07-27 07:19:39 -05:00
|
|
|
let i = size - 1u as int;
|
2011-08-19 17:16:48 -05:00
|
|
|
while i >= 0 { bytes += [n >> (i * 8 as uint) & 255u as u8]; i -= 1; }
|
2011-07-10 14:47:51 -05:00
|
|
|
ret bytes;
|
|
|
|
}
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
impl writer_util for writer {
|
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 {
|
|
|
|
self.write([ch as u8]);
|
|
|
|
} else {
|
|
|
|
self.write(str::bytes(str::from_char(ch)));
|
|
|
|
}
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn write_str(s: str) { self.write(str::bytes(s)); }
|
|
|
|
fn write_line(s: str) { self.write(str::bytes(s + "\n")); }
|
|
|
|
fn write_int(n: int) { self.write(str::bytes(int::to_str(n, 10u))); }
|
|
|
|
fn write_uint(n: uint) { self.write(str::bytes(uint::to_str(n, 10u))); }
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn write_le_uint(n: uint, size: uint) {
|
2012-01-11 08:15:54 -06:00
|
|
|
self.write(uint_to_le_bytes(n, size));
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
fn write_le_int(n: int, size: uint) {
|
2012-01-11 08:15:54 -06:00
|
|
|
self.write(uint_to_le_bytes(n as uint, size));
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
fn write_be_uint(n: uint, size: uint) {
|
2012-01-11 08:15:54 -06:00
|
|
|
self.write(uint_to_be_bytes(n, size));
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-28 23:19:59 -05:00
|
|
|
fn file_writer(path: str, flags: [fileflag]) -> result::t<writer, str> {
|
2012-01-11 08:15:54 -06:00
|
|
|
result::chain(mk_file_writer(path, flags), { |w| result::ok(w)})
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// FIXME: fileflags
|
2012-01-11 08:15:54 -06:00
|
|
|
fn buffered_file_writer(path: str) -> result::t<writer, str> {
|
|
|
|
let f = str::as_buf(path, {|pathbuf|
|
|
|
|
str::as_buf("w", {|modebuf| os::libc::fopen(pathbuf, modebuf) })
|
|
|
|
});
|
2011-10-28 23:19:59 -05:00
|
|
|
ret if f as uint == 0u { result::err("error opening " + path) }
|
2012-01-11 08:15:54 -06:00
|
|
|
else { result::ok(FILE_writer(f, true)) }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME it would be great if this could be a const
|
2012-01-11 08:15:54 -06:00
|
|
|
fn stdout() -> writer { fd_writer(1i32, false) }
|
|
|
|
fn stderr() -> writer { fd_writer(2i32, false) }
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2011-10-14 05:44:40 -05:00
|
|
|
fn print(s: str) { stdout().write_str(s); }
|
2012-01-11 08:15:54 -06:00
|
|
|
fn println(s: str) { stdout().write_line(s); }
|
2011-12-28 02:30:04 -06:00
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
type mem_buffer = @{mutable buf: [mutable u8],
|
|
|
|
mutable pos: uint};
|
2011-07-10 14:47:51 -05:00
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
impl of writer for mem_buffer {
|
2011-12-27 18:38:48 -06:00
|
|
|
fn write(v: [const u8]) {
|
2011-07-10 14:47:51 -05:00
|
|
|
// Fast path.
|
2012-01-11 08:15:54 -06:00
|
|
|
if self.pos == vec::len(self.buf) {
|
|
|
|
for b: u8 in v { self.buf += [mutable b]; }
|
|
|
|
self.pos += vec::len(v);
|
2011-07-10 14:47:51 -05:00
|
|
|
ret;
|
|
|
|
}
|
|
|
|
// FIXME: Optimize: These should be unique pointers.
|
2012-01-11 08:15:54 -06:00
|
|
|
let vlen = vec::len(v);
|
2011-07-27 07:19:39 -05:00
|
|
|
let vpos = 0u;
|
|
|
|
while vpos < vlen {
|
2011-08-19 17:16:48 -05:00
|
|
|
let b = v[vpos];
|
2012-01-11 08:15:54 -06:00
|
|
|
if self.pos == vec::len(self.buf) {
|
|
|
|
self.buf += [mutable b];
|
|
|
|
} else { self.buf[self.pos] = b; }
|
|
|
|
self.pos += 1u;
|
2011-07-10 14:47:51 -05:00
|
|
|
vpos += 1u;
|
|
|
|
}
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
fn seek(offset: int, whence: seek_style) {
|
2012-01-11 08:15:54 -06:00
|
|
|
let pos = self.pos;
|
|
|
|
let len = vec::len(self.buf);
|
|
|
|
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 }
|
2011-07-10 14:47:51 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
fn mk_mem_buffer() -> mem_buffer {
|
|
|
|
@{mutable buf: [mutable], mutable pos: 0u}
|
2011-12-28 02:30:04 -06:00
|
|
|
}
|
2012-01-11 08:15:54 -06:00
|
|
|
fn mem_buffer_writer(b: mem_buffer) -> writer { b as writer }
|
|
|
|
fn mem_buffer_buf(b: mem_buffer) -> [u8] { vec::from_mut(b.buf) }
|
|
|
|
fn mem_buffer_str(b: mem_buffer) -> str { str::unsafe_from_bytes(b.buf) }
|
2011-07-10 14:47:51 -05:00
|
|
|
|
|
|
|
// Utility functions
|
2011-07-27 07:19:39 -05:00
|
|
|
fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) ->
|
|
|
|
uint {
|
|
|
|
let bpos = pos as int;
|
|
|
|
let blen = len as int;
|
|
|
|
alt whence {
|
|
|
|
seek_set. { bpos = offset; }
|
|
|
|
seek_cur. { bpos += offset; }
|
|
|
|
seek_end. { 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; }
|
2011-07-10 14:47:51 -05:00
|
|
|
ret bpos as uint;
|
|
|
|
}
|
2011-08-01 17:53:14 -05:00
|
|
|
|
2011-10-28 23:19:59 -05:00
|
|
|
fn read_whole_file_str(file: str) -> result::t<str, str> {
|
|
|
|
result::chain(read_whole_file(file), { |bytes|
|
|
|
|
result::ok(str::unsafe_from_bytes(bytes))
|
|
|
|
})
|
2011-08-01 17:53:14 -05:00
|
|
|
}
|
|
|
|
|
2012-01-11 08:15:54 -06:00
|
|
|
// FIXME implement this in a low-level way. Going through the abstractions is
|
|
|
|
// pointless.
|
2011-10-28 23:19:59 -05:00
|
|
|
fn read_whole_file(file: str) -> result::t<[u8], str> {
|
|
|
|
result::chain(file_reader(file), { |rdr|
|
|
|
|
result::ok(rdr.read_whole_stream())
|
|
|
|
})
|
2011-08-01 17:53:14 -05:00
|
|
|
}
|
|
|
|
|
2011-11-16 16:14:18 -06:00
|
|
|
// fsync related
|
|
|
|
|
|
|
|
mod fsync {
|
|
|
|
|
|
|
|
tag level {
|
|
|
|
// whatever fsync does on that platform
|
|
|
|
fsync;
|
|
|
|
|
|
|
|
// fdatasync on linux, similiar or more on other platforms
|
|
|
|
fdatasync;
|
|
|
|
|
|
|
|
// full fsync
|
|
|
|
//
|
|
|
|
// You must additionally sync the parent directory as well!
|
|
|
|
fullfsync;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Resource of artifacts that need to fsync on destruction
|
|
|
|
resource res<t>(arg: arg<t>) {
|
|
|
|
alt arg.opt_level {
|
2012-01-11 08:15:54 -06:00
|
|
|
option::none. { }
|
|
|
|
option::some(level) {
|
2011-11-16 16:14:18 -06:00
|
|
|
// fail hard if not succesful
|
|
|
|
assert(arg.fsync_fn(arg.val, level) != -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type arg<t> = {
|
|
|
|
val: t,
|
|
|
|
opt_level: option::t<level>,
|
|
|
|
fsync_fn: fn(t, level) -> int
|
|
|
|
};
|
|
|
|
|
|
|
|
// fsync file after executing blk
|
|
|
|
// FIXME find better way to create resources within lifetime of outer res
|
|
|
|
fn FILE_res_sync(&&file: FILE_res, opt_level: option::t<level>,
|
|
|
|
blk: block(&&res<os::libc::FILE>)) {
|
|
|
|
blk(res({
|
|
|
|
val: *file, opt_level: opt_level,
|
|
|
|
fsync_fn: fn(&&file: os::libc::FILE, l: level) -> int {
|
|
|
|
ret os::fsync_fd(os::libc::fileno(file), l) as int;
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
// fsync fd after executing blk
|
|
|
|
fn fd_res_sync(&&fd: fd_res, opt_level: option::t<level>,
|
|
|
|
blk: block(&&res<fd_t>)) {
|
|
|
|
blk(res({
|
|
|
|
val: *fd, opt_level: opt_level,
|
|
|
|
fsync_fn: fn(&&fd: fd_t, l: level) -> int {
|
|
|
|
ret os::fsync_fd(fd, l) as int;
|
|
|
|
}
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Type of objects that may want to fsync
|
2012-01-11 08:15:54 -06:00
|
|
|
iface t { fn fsync(l: level) -> int; }
|
2011-11-16 16:14:18 -06:00
|
|
|
|
|
|
|
// Call o.fsync after executing blk
|
|
|
|
fn obj_sync(&&o: t, opt_level: option::t<level>, blk: block(&&res<t>)) {
|
|
|
|
blk(res({
|
|
|
|
val: o, opt_level: opt_level,
|
|
|
|
fsync_fn: fn(&&o: t, l: level) -> int { ret o.fsync(l); }
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
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:
|
|
|
|
//
|