1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
23 use libc::{c_int, c_long, c_uint, c_void, size_t, ssize_t};
24 use libc::consts::os::posix88::*;
25 use libc::consts::os::extra::*;
35 #[allow(non_camel_case_types)] // not sure what to do about this
36 pub type fd_t = c_int;
40 unsafe fn rust_get_stdin() -> *libc::FILE;
41 unsafe fn rust_get_stdout() -> *libc::FILE;
42 unsafe fn rust_get_stderr() -> *libc::FILE;
47 // FIXME (#2004): This is all buffered. We might need an unbuffered variant
49 pub enum SeekStyle { SeekSet, SeekEnd, SeekCur, }
52 /// The raw underlying reader trait. All readers must implement this.
54 // FIXME (#2004): Seekable really should be orthogonal.
56 /// Read up to len bytes (or EOF) and put them into bytes (which
57 /// must be at least len bytes long). Return number of bytes read.
58 // FIXME (#2982): This should probably return an error.
59 fn read(&self, bytes: &mut [u8], len: uint) -> uint;
61 /// Read a single byte, returning a negative value for EOF or read error.
62 fn read_byte(&self) -> int;
64 /// Return whether the stream is currently at EOF position.
65 fn eof(&self) -> bool;
67 /// Move the current position within the stream. The second parameter
68 /// determines the position that the first parameter is relative to.
69 fn seek(&self, position: int, style: SeekStyle);
71 /// Return the current position within the stream.
72 fn tell(&self) -> uint;
75 /// Generic utility functions defined on readers.
76 pub trait ReaderUtil {
78 /// Read len bytes into a new vec.
79 fn read_bytes(&self, len: uint) -> ~[u8];
81 /// Read up until the first '\n' char (which is not returned), or EOF.
82 fn read_line(&self) -> ~str;
84 /// Read n utf-8 encoded chars.
85 fn read_chars(&self, n: uint) -> ~[char];
87 /// Read a single utf-8 encoded char.
88 fn read_char(&self) -> char;
90 /// Read up until the first null byte (which is not returned), or EOF.
91 fn read_c_str(&self) -> ~str;
93 /// Read all the data remaining in the stream in one go.
94 fn read_whole_stream(&self) -> ~[u8];
96 /// Iterate over every byte until the iterator breaks or EOF.
97 fn each_byte(&self, it: fn(int) -> bool);
99 /// Iterate over every char until the iterator breaks or EOF.
100 fn each_char(&self, it: fn(char) -> bool);
102 /// Iterate over every line until the iterator breaks or EOF.
103 fn each_line(&self, it: fn(&str) -> bool);
105 /// Read n (between 1 and 8) little-endian unsigned integer bytes.
106 fn read_le_uint_n(&self, nbytes: uint) -> u64;
108 /// Read n (between 1 and 8) little-endian signed integer bytes.
109 fn read_le_int_n(&self, nbytes: uint) -> i64;
111 /// Read n (between 1 and 8) big-endian unsigned integer bytes.
112 fn read_be_uint_n(&self, nbytes: uint) -> u64;
114 /// Read n (between 1 and 8) big-endian signed integer bytes.
115 fn read_be_int_n(&self, nbytes: uint) -> i64;
117 /// Read a little-endian uint (number of bytes depends on system).
118 fn read_le_uint(&self) -> uint;
120 /// Read a little-endian int (number of bytes depends on system).
121 fn read_le_int(&self) -> int;
123 /// Read a big-endian uint (number of bytes depends on system).
124 fn read_be_uint(&self) -> uint;
126 /// Read a big-endian int (number of bytes depends on system).
127 fn read_be_int(&self) -> int;
129 /// Read a big-endian u64 (8 bytes).
130 fn read_be_u64(&self) -> u64;
132 /// Read a big-endian u32 (4 bytes).
133 fn read_be_u32(&self) -> u32;
135 /// Read a big-endian u16 (2 bytes).
136 fn read_be_u16(&self) -> u16;
138 /// Read a big-endian i64 (8 bytes).
139 fn read_be_i64(&self) -> i64;
141 /// Read a big-endian i32 (4 bytes).
142 fn read_be_i32(&self) -> i32;
144 /// Read a big-endian i16 (2 bytes).
145 fn read_be_i16(&self) -> i16;
147 /// Read a little-endian u64 (8 bytes).
148 fn read_le_u64(&self) -> u64;
150 /// Read a little-endian u32 (4 bytes).
151 fn read_le_u32(&self) -> u32;
153 /// Read a little-endian u16 (2 bytes).
154 fn read_le_u16(&self) -> u16;
156 /// Read a litle-endian i64 (8 bytes).
157 fn read_le_i64(&self) -> i64;
159 /// Read a litle-endian i32 (4 bytes).
160 fn read_le_i32(&self) -> i32;
162 /// Read a litle-endian i16 (2 bytes).
163 fn read_le_i16(&self) -> i16;
165 /// Read a u8 (1 byte).
166 fn read_u8(&self) -> u8;
168 /// Read a i8 (1 byte).
169 fn read_i8(&self) -> i8;
172 impl<T:Reader> ReaderUtil for T {
174 fn read_bytes(&self,len: uint) -> ~[u8] {
175 let mut bytes = vec::with_capacity(len);
176 unsafe { vec::raw::set_len(&mut bytes, len); }
178 let count = self.read(bytes, len);
180 unsafe { vec::raw::set_len(&mut bytes, count); }
184 fn read_line(&self) -> ~str {
187 let ch = self.read_byte();
188 if ch == -1 || ch == 10 { break; }
189 bytes.push(ch as u8);
191 str::from_bytes(bytes)
194 fn read_chars(&self, n: uint) -> ~[char] {
195 // returns the (consumed offset, n_req), appends characters to &chars
196 fn chars_from_bytes<T:Reader>(bytes: &~[u8], chars: &mut ~[char])
199 let bytes_len = bytes.len();
200 while i < bytes_len {
202 let w = str::utf8_char_width(b0);
207 chars.push(b0 as char);
210 // can't satisfy this char with the existing data
212 return (i - 1, end - bytes_len);
216 let next = bytes[i] as int;
219 assert (next & 192 == 128);
221 val += (next & 63) as uint;
224 val += ((b0 << ((w + 1) as u8)) as uint)
225 << (w - 1) * 6 - w - 1u;
226 chars.push(val as char);
232 // might need more bytes, but reading n will never over-read
235 let data = self.read_bytes(nbread);
237 // eof - FIXME (#2004): should we do something if
238 // we're split in a unicode char?
241 bytes.push_all(data);
242 let (offset, nbreq) = chars_from_bytes::<T>(&bytes, &mut chars);
243 let ncreq = n - chars.len();
244 // again we either know we need a certain number of bytes
245 // to complete a character, or we make sure we don't
246 // over-read by reading 1-byte per char needed
247 nbread = if ncreq > nbreq { ncreq } else { nbreq };
249 bytes = vec::slice(bytes, offset, bytes.len()).to_vec();
255 fn read_char(&self) -> char {
256 let c = self.read_chars(1);
257 if vec::len(c) == 0 {
258 return -1 as char; // FIXME will this stay valid? // #2004
260 assert(vec::len(c) == 1);
264 fn read_c_str(&self) -> ~str {
265 let mut bytes: ~[u8] = ~[];
267 let ch = self.read_byte();
268 if ch < 1 { break; } else { bytes.push(ch as u8); }
270 str::from_bytes(bytes)
273 fn read_whole_stream(&self) -> ~[u8] {
274 let mut bytes: ~[u8] = ~[];
275 while !self.eof() { bytes.push_all(self.read_bytes(2048u)); }
279 fn each_byte(&self, it: fn(int) -> bool) {
281 if !it(self.read_byte()) { break; }
285 fn each_char(&self, it: fn(char) -> bool) {
287 if !it(self.read_char()) { break; }
291 fn each_line(&self, it: fn(s: &str) -> bool) {
293 if !it(self.read_line()) { break; }
297 // FIXME int reading methods need to deal with eof - issue #2004
299 fn read_le_uint_n(&self, nbytes: uint) -> u64 {
300 assert nbytes > 0 && nbytes <= 8;
302 let mut val = 0u64, pos = 0, i = nbytes;
304 val += (self.read_u8() as u64) << pos;
311 fn read_le_int_n(&self, nbytes: uint) -> i64 {
312 extend_sign(self.read_le_uint_n(nbytes), nbytes)
315 fn read_be_uint_n(&self, nbytes: uint) -> u64 {
316 assert nbytes > 0 && nbytes <= 8;
318 let mut val = 0u64, i = nbytes;
321 val += (self.read_u8() as u64) << i * 8;
326 fn read_be_int_n(&self, nbytes: uint) -> i64 {
327 extend_sign(self.read_be_uint_n(nbytes), nbytes)
330 fn read_le_uint(&self) -> uint {
331 self.read_le_uint_n(uint::bytes) as uint
334 fn read_le_int(&self) -> int {
335 self.read_le_int_n(int::bytes) as int
338 fn read_be_uint(&self) -> uint {
339 self.read_be_uint_n(uint::bytes) as uint
342 fn read_be_int(&self) -> int {
343 self.read_be_int_n(int::bytes) as int
346 fn read_be_u64(&self) -> u64 {
347 self.read_be_uint_n(8) as u64
350 fn read_be_u32(&self) -> u32 {
351 self.read_be_uint_n(4) as u32
354 fn read_be_u16(&self) -> u16 {
355 self.read_be_uint_n(2) as u16
358 fn read_be_i64(&self) -> i64 {
359 self.read_be_int_n(8) as i64
362 fn read_be_i32(&self) -> i32 {
363 self.read_be_int_n(4) as i32
366 fn read_be_i16(&self) -> i16 {
367 self.read_be_int_n(2) as i16
370 fn read_le_u64(&self) -> u64 {
371 self.read_le_uint_n(8) as u64
374 fn read_le_u32(&self) -> u32 {
375 self.read_le_uint_n(4) as u32
378 fn read_le_u16(&self) -> u16 {
379 self.read_le_uint_n(2) as u16
382 fn read_le_i64(&self) -> i64 {
383 self.read_le_int_n(8) as i64
386 fn read_le_i32(&self) -> i32 {
387 self.read_le_int_n(4) as i32
390 fn read_le_i16(&self) -> i16 {
391 self.read_le_int_n(2) as i16
394 fn read_u8(&self) -> u8 {
395 self.read_byte() as u8
398 fn read_i8(&self) -> i8 {
399 self.read_byte() as i8
403 fn extend_sign(val: u64, nbytes: uint) -> i64 {
404 let shift = (8 - nbytes) * 8;
405 (val << shift) as i64 >> shift
408 // Reader implementations
410 fn convert_whence(whence: SeekStyle) -> i32 {
411 return match whence {
418 impl Reader for *libc::FILE {
419 fn read(&self, bytes: &mut [u8], len: uint) -> uint {
421 do vec::as_mut_buf(bytes) |buf_p, buf_len| {
422 assert buf_len >= len;
424 let count = libc::fread(buf_p as *mut c_void, 1u as size_t,
425 len as size_t, *self);
431 fn read_byte(&self) -> int {
433 libc::fgetc(*self) as int
436 fn eof(&self) -> bool {
438 return libc::feof(*self) != 0 as c_int;
441 fn seek(&self, offset: int, whence: SeekStyle) {
443 assert libc::fseek(*self,
445 convert_whence(whence)) == 0 as c_int;
448 fn tell(&self) -> uint {
450 return libc::ftell(*self) as uint;
455 struct Wrapper<T, C> {
460 // A forwarding impl of reader that also holds on to a resource for the
461 // duration of its lifetime.
462 // FIXME there really should be a better way to do this // #2004
463 impl<R:Reader,C> Reader for Wrapper<R, C> {
464 fn read(&self, bytes: &mut [u8], len: uint) -> uint {
465 self.base.read(bytes, len)
467 fn read_byte(&self) -> int { self.base.read_byte() }
468 fn eof(&self) -> bool { self.base.eof() }
469 fn seek(&self, off: int, whence: SeekStyle) {
470 self.base.seek(off, whence)
472 fn tell(&self) -> uint { self.base.tell() }
479 impl Drop for FILERes {
482 libc::fclose(self.f);
487 pub fn FILERes(f: *libc::FILE) -> FILERes {
493 pub fn FILE_reader(f: *libc::FILE, cleanup: bool) -> @Reader {
495 @Wrapper { base: f, cleanup: FILERes(f) } as @Reader
501 // FIXME (#2004): this should either be an trait-less impl, a set of
502 // top-level functions that take a reader, or a set of default methods on
503 // reader (which can then be called reader)
505 pub fn stdin() -> @Reader {
507 @rustrt::rust_get_stdin() as @Reader
511 pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
513 let f = os::as_c_charp(path.to_str(), |pathbuf| {
514 os::as_c_charp("r", |modebuf|
515 libc::fopen(pathbuf, modebuf)
518 return if f as uint == 0u { result::Err(~"error opening "
521 result::Ok(FILE_reader(f, true))
528 pub struct BytesReader {
533 impl Reader for BytesReader {
534 fn read(&self, bytes: &mut [u8], len: uint) -> uint {
535 let count = uint::min(len, self.bytes.len() - self.pos);
537 let view = vec::slice(self.bytes, self.pos, self.bytes.len());
538 vec::bytes::copy_memory(bytes, view, count);
544 fn read_byte(&self) -> int {
545 if self.pos == self.bytes.len() { return -1; }
546 let b = self.bytes[self.pos];
550 fn eof(&self) -> bool { self.pos == self.bytes.len() }
551 fn seek(&self, offset: int, whence: SeekStyle) {
553 self.pos = seek_in_buf(offset, pos, self.bytes.len(), whence);
555 fn tell(&self) -> uint { self.pos }
558 pub pure fn with_bytes_reader<t>(bytes: &[u8], f: fn(@Reader) -> t) -> t {
559 f(@BytesReader { bytes: bytes, pos: 0u } as @Reader)
562 pub pure fn with_str_reader<T>(s: &str, f: fn(@Reader) -> T) -> T {
563 str::byte_slice(s, |bytes| with_bytes_reader(bytes, f))
567 pub enum FileFlag { Append, Create, Truncate, NoFlag, }
569 // What type of writer are we?
571 pub enum WriterType { Screen, File }
573 // FIXME (#2004): Seekable really should be orthogonal.
574 // FIXME (#2004): eventually u64
575 /// The raw underlying writer trait. All writers must implement this.
578 /// Write all of the given bytes.
579 fn write(&self, v: &[const u8]);
581 /// Move the current position within the stream. The second parameter
582 /// determines the position that the first parameter is relative to.
583 fn seek(&self, int, SeekStyle);
585 /// Return the current position within the stream.
586 fn tell(&self) -> uint;
588 /// Flush the output buffer for this stream (if there is one).
589 fn flush(&self) -> int;
591 /// Determine if this Writer is writing to a file or not.
592 fn get_type(&self) -> WriterType;
595 impl<W:Writer,C> Writer for Wrapper<W, C> {
596 fn write(&self, bs: &[const u8]) { self.base.write(bs); }
597 fn seek(&self, off: int, style: SeekStyle) { self.base.seek(off, style); }
598 fn tell(&self) -> uint { self.base.tell() }
599 fn flush(&self) -> int { self.base.flush() }
600 fn get_type(&self) -> WriterType { File }
603 impl Writer for *libc::FILE {
604 fn write(&self, v: &[const u8]) {
606 do vec::as_const_buf(v) |vbuf, len| {
607 let nout = libc::fwrite(vbuf as *c_void,
611 if nout != len as size_t {
612 error!("error writing buffer");
613 log(error, os::last_os_error());
619 fn seek(&self, offset: int, whence: SeekStyle) {
621 assert libc::fseek(*self,
623 convert_whence(whence)) == 0 as c_int;
626 fn tell(&self) -> uint {
628 libc::ftell(*self) as uint
631 fn flush(&self) -> int {
633 libc::fflush(*self) as int
636 fn get_type(&self) -> WriterType {
638 let fd = libc::fileno(*self);
639 if libc::isatty(fd) == 0 { File }
645 pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> @Writer {
647 @Wrapper { base: f, cleanup: FILERes(f) } as @Writer
653 impl Writer for fd_t {
654 fn write(&self, v: &[const u8]) {
657 do vec::as_const_buf(v) |vbuf, len| {
659 let vb = ptr::const_offset(vbuf, count) as *c_void;
660 let nout = libc::write(*self, vb, len as size_t);
661 if nout < 0 as ssize_t {
662 error!("error writing buffer");
663 log(error, os::last_os_error());
666 count += nout as uint;
671 fn seek(&self, _offset: int, _whence: SeekStyle) {
672 error!("need 64-bit foreign calls for seek, sorry");
675 fn tell(&self) -> uint {
676 error!("need 64-bit foreign calls for tell, sorry");
679 fn flush(&self) -> int { 0 }
680 fn get_type(&self) -> WriterType {
682 if libc::isatty(*self) == 0 { File } else { Screen }
691 impl Drop for FdRes {
694 libc::close(self.fd);
699 pub fn FdRes(fd: fd_t) -> FdRes {
705 pub fn fd_writer(fd: fd_t, cleanup: bool) -> @Writer {
707 @Wrapper { base: fd, cleanup: FdRes(fd) } as @Writer
714 pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
715 -> Result<Writer, ~str> {
718 fn wb() -> c_int { (O_WRONLY | O_BINARY) as c_int }
721 fn wb() -> c_int { O_WRONLY as c_int }
723 let mut fflags: c_int = wb();
724 for vec::each(flags) |f| {
726 Append => fflags |= O_APPEND as c_int,
727 Create => fflags |= O_CREAT as c_int,
728 Truncate => fflags |= O_TRUNC as c_int,
733 do os::as_c_charp(path.to_str()) |pathbuf| {
734 libc::open(pathbuf, fflags,
735 (S_IRUSR | S_IWUSR) as c_int)
738 if fd < (0 as c_int) {
739 result::Err(fmt!("error opening %s: %s", path.to_str(),
740 os::last_os_error()))
742 result::Ok(fd_writer(fd, true))
746 pub fn u64_to_le_bytes<T>(n: u64, size: uint,
747 f: fn(v: &[u8]) -> T) -> T {
767 let mut bytes: ~[u8] = ~[], i = size, n = n;
769 bytes.push((n & 255_u64) as u8);
778 pub fn u64_to_be_bytes<T>(n: u64, size: uint,
779 f: fn(v: &[u8]) -> T) -> T {
783 2u => f(&[(n >> 8) as u8,
785 4u => f(&[(n >> 24) as u8,
789 8u => f(&[(n >> 56) as u8,
798 let mut bytes: ~[u8] = ~[];
801 let shift = ((i - 1u) * 8u) as u64;
802 bytes.push((n >> shift) as u8);
810 pub fn u64_from_be_bytes(data: &[const u8],
811 start: uint, size: uint) -> u64 {
818 val += (data[pos] as u64) << ((sz * 8u) as u64);
824 // FIXME: #3048 combine trait+impl (or just move these to
825 // default methods on writer)
826 /// Generic utility functions defined on writers.
827 pub trait WriterUtil {
829 /// Write a single utf-8 encoded char.
830 fn write_char(&self, ch: char);
832 /// Write every char in the given str, encoded as utf-8.
833 fn write_str(&self, s: &str);
835 /// Write the given str, as utf-8, followed by '\n'.
836 fn write_line(&self, s: &str);
838 /// Write the result of passing n through `int::to_str_bytes`.
839 fn write_int(&self, n: int);
841 /// Write the result of passing n through `uint::to_str_bytes`.
842 fn write_uint(&self, n: uint);
844 /// Write a little-endian uint (number of bytes depends on system).
845 fn write_le_uint(&self, n: uint);
847 /// Write a little-endian int (number of bytes depends on system).
848 fn write_le_int(&self, n: int);
850 /// Write a big-endian uint (number of bytes depends on system).
851 fn write_be_uint(&self, n: uint);
853 /// Write a big-endian int (number of bytes depends on system).
854 fn write_be_int(&self, n: int);
856 /// Write a big-endian u64 (8 bytes).
857 fn write_be_u64(&self, n: u64);
859 /// Write a big-endian u32 (4 bytes).
860 fn write_be_u32(&self, n: u32);
862 /// Write a big-endian u16 (2 bytes).
863 fn write_be_u16(&self, n: u16);
865 /// Write a big-endian i64 (8 bytes).
866 fn write_be_i64(&self, n: i64);
868 /// Write a big-endian i32 (4 bytes).
869 fn write_be_i32(&self, n: i32);
871 /// Write a big-endian i16 (2 bytes).
872 fn write_be_i16(&self, n: i16);
874 /// Write a little-endian u64 (8 bytes).
875 fn write_le_u64(&self, n: u64);
877 /// Write a little-endian u32 (4 bytes).
878 fn write_le_u32(&self, n: u32);
880 /// Write a little-endian u16 (2 bytes).
881 fn write_le_u16(&self, n: u16);
883 /// Write a little-endian i64 (8 bytes).
884 fn write_le_i64(&self, n: i64);
886 /// Write a little-endian i32 (4 bytes).
887 fn write_le_i32(&self, n: i32);
889 /// Write a little-endian i16 (2 bytes).
890 fn write_le_i16(&self, n: i16);
892 /// Write a u8 (1 byte).
893 fn write_u8(&self, n: u8);
895 /// Write a i8 (1 byte).
896 fn write_i8(&self, n: i8);
899 impl<T:Writer> WriterUtil for T {
900 fn write_char(&self, ch: char) {
901 if ch as uint < 128u {
902 self.write(&[ch as u8]);
904 self.write_str(str::from_char(ch));
907 fn write_str(&self, s: &str) { str::byte_slice(s, |v| self.write(v)) }
908 fn write_line(&self, s: &str) {
910 self.write_str(&"\n");
912 fn write_int(&self, n: int) {
913 int::to_str_bytes(n, 10u, |bytes| self.write(bytes))
915 fn write_uint(&self, n: uint) {
916 uint::to_str_bytes(n, 10u, |bytes| self.write(bytes))
918 fn write_le_uint(&self, n: uint) {
919 u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v))
921 fn write_le_int(&self, n: int) {
922 u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v))
924 fn write_be_uint(&self, n: uint) {
925 u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v))
927 fn write_be_int(&self, n: int) {
928 u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v))
930 fn write_be_u64(&self, n: u64) {
931 u64_to_be_bytes(n, 8u, |v| self.write(v))
933 fn write_be_u32(&self, n: u32) {
934 u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
936 fn write_be_u16(&self, n: u16) {
937 u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
939 fn write_be_i64(&self, n: i64) {
940 u64_to_be_bytes(n as u64, 8u, |v| self.write(v))
942 fn write_be_i32(&self, n: i32) {
943 u64_to_be_bytes(n as u64, 4u, |v| self.write(v))
945 fn write_be_i16(&self, n: i16) {
946 u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
948 fn write_le_u64(&self, n: u64) {
949 u64_to_le_bytes(n, 8u, |v| self.write(v))
951 fn write_le_u32(&self, n: u32) {
952 u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
954 fn write_le_u16(&self, n: u16) {
955 u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
957 fn write_le_i64(&self, n: i64) {
958 u64_to_le_bytes(n as u64, 8u, |v| self.write(v))
960 fn write_le_i32(&self, n: i32) {
961 u64_to_le_bytes(n as u64, 4u, |v| self.write(v))
963 fn write_le_i16(&self, n: i16) {
964 u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
967 fn write_u8(&self, n: u8) { self.write([n]) }
968 fn write_i8(&self, n: i8) { self.write([n as u8]) }
971 #[allow(non_implicitly_copyable_typarams)]
972 pub fn file_writer(path: &Path, flags: &[FileFlag]) -> Result<Writer, ~str> {
973 mk_file_writer(path, flags).chain(|w| result::Ok(w))
977 // FIXME: fileflags // #2004
978 pub fn buffered_file_writer(path: &Path) -> Result<Writer, ~str> {
980 let f = do os::as_c_charp(path.to_str()) |pathbuf| {
981 do os::as_c_charp("w") |modebuf| {
982 libc::fopen(pathbuf, modebuf)
985 return if f as uint == 0u { result::Err(~"error opening "
987 else { result::Ok(FILE_writer(f, true)) }
991 // FIXME (#2004) it would be great if this could be a const
992 // FIXME (#2004) why are these different from the way stdin() is
994 pub fn stdout() -> Writer { fd_writer(libc::STDOUT_FILENO as c_int, false) }
995 pub fn stderr() -> Writer { fd_writer(libc::STDERR_FILENO as c_int, false) }
997 pub fn print(s: &str) { stdout().write_str(s); }
998 pub fn println(s: &str) { stdout().write_line(s); }
1000 pub struct BytesWriter {
1005 impl Writer for BytesWriter {
1006 fn write(&self, v: &[const u8]) {
1007 do self.bytes.swap |bytes| {
1008 let mut bytes = bytes;
1009 let v_len = v.len();
1010 let bytes_len = bytes.len();
1012 let count = uint::max(bytes_len, self.pos + v_len);
1013 vec::reserve(&mut bytes, count);
1014 unsafe { vec::raw::set_len(&mut bytes, count); }
1017 let view = vec::mut_slice(bytes, self.pos, count);
1018 vec::bytes::copy_memory(view, v, v_len);
1026 fn seek(&self, offset: int, whence: SeekStyle) {
1028 let len = self.bytes.len();
1029 self.pos = seek_in_buf(offset, pos, len, whence);
1031 fn tell(&self) -> uint { self.pos }
1032 fn flush(&self) -> int { 0 }
1033 fn get_type(&self) -> WriterType { File }
1036 pub pure fn BytesWriter() -> BytesWriter {
1037 BytesWriter { bytes: DVec(), mut pos: 0u }
1040 pub pure fn with_bytes_writer(f: fn(Writer)) -> ~[u8] {
1041 let wr = @BytesWriter();
1043 // FIXME (#3758): This should not be needed.
1044 unsafe { wr.bytes.check_out(|bytes| bytes) }
1047 pub pure fn with_str_writer(f: fn(Writer)) -> ~str {
1048 let mut v = with_bytes_writer(f);
1050 // FIXME (#3758): This should not be needed.
1052 // Make sure the vector has a trailing null and is proper utf8.
1055 assert str::is_utf8(v);
1057 unsafe { ::cast::transmute(v) }
1060 // Utility functions
1061 pub fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
1063 let mut bpos = pos as int;
1064 let blen = len as int;
1066 SeekSet => bpos = offset,
1067 SeekCur => bpos += offset,
1068 SeekEnd => bpos = blen + offset
1070 if bpos < 0 { bpos = 0; } else if bpos > blen { bpos = blen; }
1071 return bpos as uint;
1074 #[allow(non_implicitly_copyable_typarams)]
1075 pub fn read_whole_file_str(file: &Path) -> Result<~str, ~str> {
1076 result::chain(read_whole_file(file), |bytes| {
1077 if str::is_utf8(bytes) {
1078 result::Ok(str::from_bytes(bytes))
1080 result::Err(file.to_str() + ~" is not UTF-8")
1085 // FIXME (#2004): implement this in a low-level way. Going through the
1086 // abstractions is pointless.
1087 #[allow(non_implicitly_copyable_typarams)]
1088 pub fn read_whole_file(file: &Path) -> Result<~[u8], ~str> {
1089 result::chain(file_reader(file), |rdr| {
1090 result::Ok(rdr.read_whole_stream())
1098 use io::{FILERes, FdRes, fd_t};
1103 // whatever fsync does on that platform
1106 // fdatasync on linux, similiar or more on other platforms
1111 // You must additionally sync the parent directory as well!
1116 // Artifacts that need to fsync on destruction
1121 impl<T:Copy> Drop for Res<T> {
1122 fn finalize(&self) {
1123 match self.arg.opt_level {
1126 // fail hard if not succesful
1127 assert((self.arg.fsync_fn)(self.arg.val, level) != -1);
1133 pub fn Res<t: Copy>(arg: Arg<t>) -> Res<t>{
1141 opt_level: Option<Level>,
1142 fsync_fn: @fn(f: t, Level) -> int,
1145 // fsync file after executing blk
1146 // FIXME (#2004) find better way to create resources within lifetime of
1148 pub fn FILE_res_sync(file: &FILERes, opt_level: Option<Level>,
1149 blk: fn(v: Res<*libc::FILE>)) {
1152 val: file.f, opt_level: opt_level,
1153 fsync_fn: |file, l| {
1155 os::fsync_fd(libc::fileno(file), l) as int
1162 // fsync fd after executing blk
1163 pub fn fd_res_sync(fd: &FdRes, opt_level: Option<Level>,
1164 blk: fn(v: Res<fd_t>)) {
1166 val: fd.fd, opt_level: opt_level,
1167 fsync_fn: |fd, l| os::fsync_fd(fd, l) as int
1171 // Type of objects that may want to fsync
1172 pub trait FSyncable { fn fsync(&self, l: Level) -> int; }
1174 // Call o.fsync after executing blk
1175 pub fn obj_sync(o: FSyncable, opt_level: Option<Level>,
1176 blk: fn(v: Res<FSyncable>)) {
1178 val: o, opt_level: opt_level,
1179 fsync_fn: |o, l| o.fsync(l)
1188 use io::{BytesWriter, SeekCur, SeekEnd, SeekSet};
1198 let tmpfile = &Path("tmp/lib-io-test-simple.tmp");
1199 log(debug, tmpfile);
1201 ~"A hoopy frood who really knows where his towel is.";
1202 log(debug, copy frood);
1204 let out: io::Writer =
1206 &io::file_writer(tmpfile, ~[io::Create, io::Truncate]));
1207 out.write_str(frood);
1209 let inp: io::Reader = result::get(&io::file_reader(tmpfile));
1210 let frood2: ~str = inp.read_c_str();
1211 log(debug, copy frood2);
1212 assert frood == frood2;
1216 fn test_readchars_empty() {
1217 do io::with_str_reader(~"") |inp| {
1218 let res : ~[char] = inp.read_chars(128);
1219 assert(vec::len(res) == 0);
1224 fn test_read_line_utf8() {
1225 do io::with_str_reader(~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤") |inp| {
1226 let line = inp.read_line();
1227 assert line == ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤";
1232 fn test_readchars_wide() {
1233 let wide_test = ~"生锈的汤匙切肉汤hello生锈的汤匙切肉汤";
1234 let ivals : ~[int] = ~[
1235 29983, 38152, 30340, 27748,
1236 21273, 20999, 32905, 27748,
1237 104, 101, 108, 108, 111,
1238 29983, 38152, 30340, 27748,
1239 21273, 20999, 32905, 27748];
1240 fn check_read_ln(len : uint, s: &str, ivals: &[int]) {
1241 do io::with_str_reader(s) |inp| {
1242 let res : ~[char] = inp.read_chars(len);
1243 if (len <= vec::len(ivals)) {
1244 assert(vec::len(res) == len);
1246 assert(vec::slice(ivals, 0u, vec::len(res)) ==
1247 vec::map(res, |x| *x as int));
1252 check_read_ln(i, wide_test, ivals);
1255 // check a long read for good measure
1256 check_read_ln(128, wide_test, ivals);
1260 fn test_readchar() {
1261 do io::with_str_reader(~"生") |inp| {
1262 let res : char = inp.read_char();
1263 assert(res as int == 29983);
1268 fn test_readchar_empty() {
1269 do io::with_str_reader(~"") |inp| {
1270 let res : char = inp.read_char();
1271 assert(res as int == -1);
1276 fn file_reader_not_exist() {
1277 match io::file_reader(&Path("not a file")) {
1278 result::Err(copy e) => {
1279 assert e == ~"error opening not a file";
1281 result::Ok(_) => fail!()
1287 #[ignore(cfg(windows))]
1288 fn test_read_buffer_too_small() {
1289 let path = &Path("tmp/lib-io-test-read-buffer-too-small.tmp");
1290 // ensure the file exists
1291 io::file_writer(path, [io::Create]).get();
1293 let file = io::file_reader(path).get();
1294 let mut buf = vec::from_elem(5, 0);
1295 file.read(buf, 6); // this should fail because buf is too small
1299 fn test_read_buffer_big_enough() {
1300 let path = &Path("tmp/lib-io-test-read-buffer-big-enough.tmp");
1301 // ensure the file exists
1302 io::file_writer(path, [io::Create]).get();
1304 let file = io::file_reader(path).get();
1305 let mut buf = vec::from_elem(5, 0);
1306 file.read(buf, 4); // this should succeed because buf is big enough
1310 fn test_write_empty() {
1311 let file = io::file_writer(&Path("tmp/lib-io-test-write-empty.tmp"),
1312 [io::Create]).get();
1317 fn file_writer_bad_name() {
1318 match io::file_writer(&Path("?/?"), ~[]) {
1319 result::Err(copy e) => {
1320 assert str::starts_with(e, "error opening");
1322 result::Ok(_) => fail!()
1327 fn buffered_file_writer_bad_name() {
1328 match io::buffered_file_writer(&Path("?/?")) {
1329 result::Err(copy e) => {
1330 assert str::starts_with(e, "error opening");
1332 result::Ok(_) => fail!()
1337 fn bytes_buffer_overwrite() {
1338 let wr = BytesWriter();
1339 wr.write(~[0u8, 1u8, 2u8, 3u8]);
1340 assert wr.bytes.borrow(|bytes| bytes == ~[0u8, 1u8, 2u8, 3u8]);
1341 wr.seek(-2, SeekCur);
1342 wr.write(~[4u8, 5u8, 6u8, 7u8]);
1343 assert wr.bytes.borrow(|bytes| bytes ==
1344 ~[0u8, 1u8, 4u8, 5u8, 6u8, 7u8]);
1345 wr.seek(-2, SeekEnd);
1347 wr.seek(1, SeekSet);
1349 assert wr.bytes.borrow(|bytes| bytes ==
1350 ~[0u8, 9u8, 4u8, 5u8, 8u8, 7u8]);
1354 fn test_read_write_le() {
1355 let path = Path("tmp/lib-io-test-read-write-le.tmp");
1356 let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value];
1358 // write the ints to the file
1360 let file = io::file_writer(&path, [io::Create]).get();
1361 for uints.each |i| {
1362 file.write_le_u64(*i);
1366 // then read them back and check that they are the same
1368 let file = io::file_reader(&path).get();
1369 for uints.each |i| {
1370 assert file.read_le_u64() == *i;
1376 fn test_read_write_be() {
1377 let path = Path("tmp/lib-io-test-read-write-be.tmp");
1378 let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value];
1380 // write the ints to the file
1382 let file = io::file_writer(&path, [io::Create]).get();
1383 for uints.each |i| {
1384 file.write_be_u64(*i);
1388 // then read them back and check that they are the same
1390 let file = io::file_reader(&path).get();
1391 for uints.each |i| {
1392 assert file.read_be_u64() == *i;
1398 fn test_read_be_int_n() {
1399 let path = Path("tmp/lib-io-test-read-be-int-n.tmp");
1400 let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value];
1402 // write the ints to the file
1404 let file = io::file_writer(&path, [io::Create]).get();
1406 file.write_be_i32(*i);
1410 // then read them back and check that they are the same
1412 let file = io::file_reader(&path).get();
1414 // this tests that the sign extension is working
1415 // (comparing the values as i32 would not test this)
1416 assert file.read_be_int_n(4) == *i as i64;
1427 // indent-tabs-mode: nil
1428 // c-basic-offset: 4
1429 // buffer-file-coding-system: utf-8-unix