use crate::*;
use rs_alloc::*;
use libc::*;
pub struct FileWriter {
file : *mut ::libc::FILE,
}
impl FileWriter {
pub fn create(fname: &str) -> Result<Self, ()> {
let mut sname = String::from(fname);
sname.push('\0' as u8);
let f = unsafe { ::libc::fopen(sname.as_str().as_bytes().as_ptr() as *const i8, "wb\0".as_bytes().as_ptr() as *const i8) };
if f as * const _ == ::core::ptr::null() {
Result::Err(())
} else {
Result::Ok(Self { file: f })
}
}
pub fn write(&mut self, bytes: &[u8]) -> Result<usize, ()> {
let count = unsafe { ::libc::fwrite(bytes.as_ptr() as *const c_void, 1, bytes.len(), self.file) };
if count < bytes.len() {
if unsafe { ::libc::ferror(self.file) } != 0 {
Result::Err(())
} else {
Result::Ok(count)
}
} else {
Result::Ok(count)
}
}
pub fn tell(&self) -> usize { unsafe { ::libc::ftell(self.file) as usize } }
pub fn size(&self) -> usize {
unsafe {
let curr = self.tell();
::libc::fseek(self.file, 0, ::libc::SEEK_END);
let size = self.tell();
::libc::fseek(self.file, curr as c_long, ::libc::SEEK_SET);
size
}
}
}
impl Drop for FileWriter {
fn drop(&mut self) {
unsafe { ::libc::fclose(self.file) };
}
}
impl Stream for FileWriter {
fn tell(&self) -> usize { self.tell() }
fn size(&self) -> usize { self.size() }
}
impl StreamSeek for FileWriter {
fn seek(&mut self, pos: SeekFrom) -> Result<usize, ()> {
unsafe {
match pos {
SeekFrom::Start(p) => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_SET),
SeekFrom::End(p) => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_END),
SeekFrom::Current(p) => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_CUR)
}
};
Result::Ok(self.tell())
}
}
impl StreamWriter for FileWriter {
fn write(&mut self, buff: &[u8]) -> Result<usize, ()> {
self.write(buff)
}
}
pub struct FileReader {
file : *mut ::libc::FILE,
}
impl FileReader {
pub fn open(fname: &str) -> Result<Self, ()> {
let mut sname = String::from(fname);
sname.push(b'\0');
let f = unsafe { ::libc::fopen(sname.as_str().as_bytes().as_ptr() as *const i8, "rb\0".as_bytes().as_ptr() as *const i8) };
if f as * const _ == ::core::ptr::null() {
Result::Err(())
} else {
Result::Ok(Self { file: f })
}
}
pub fn tell(&self) -> usize { unsafe { ::libc::ftell(self.file) as usize } }
pub fn size(&self) -> usize {
unsafe {
let curr = self.tell();
::libc::fseek(self.file, 0, ::libc::SEEK_END);
let size = self.tell();
::libc::fseek(self.file, curr as c_long, ::libc::SEEK_SET);
size
}
}
pub fn read(&mut self, buff: &mut [u8]) -> Result<usize, ()> {
let count = unsafe { ::libc::fread(buff.as_mut_ptr() as *mut c_void, 1, buff.len(), self.file) };
if count < buff.len() {
if unsafe { ::libc::ferror(self.file) } != 0 {
Result::Err(())
} else {
Result::Ok(count)
}
} else {
Result::Ok(count)
}
}
pub fn read_line(&mut self, buff: &mut [u8]) -> Result<usize, ()> {
let n = unsafe { ::libc::fgets(buff.as_mut_ptr() as *mut i8, buff.len() as c_int, self.file) };
Result::Ok(n as usize)
}
pub fn read_to_string(&mut self, buf: &mut String) -> Result<usize, ()> {
let count = self.size();
let ptr = unsafe { alloc_array(count) };
let data = unsafe { core::slice::from_raw_parts_mut(ptr, count) };
let r = self.read(data);
match r {
Ok(_) => {
*buf = String::from_raw_parts(ptr, count, count);
Ok(count)
},
Err(_) => Err(())
}
}
}
impl Drop for FileReader {
fn drop(&mut self) {
unsafe { ::libc::fclose(self.file) };
}
}
impl Stream for FileReader {
fn tell(&self) -> usize { self.tell() }
fn size(&self) -> usize { self.size() }
}
impl StreamSeek for FileReader {
fn seek(&mut self, pos: SeekFrom) -> Result<usize, ()> {
unsafe {
match pos {
SeekFrom::Start(p) => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_SET),
SeekFrom::End(p) => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_END),
SeekFrom::Current(p) => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_CUR)
}
};
Result::Ok(self.tell())
}
}
impl StreamReader for FileReader {
fn read(&mut self, buff: &mut [u8]) -> Result<usize, ()> {
self.read(buff)
}
fn is_eof(&self) -> bool {
if unsafe { ::libc::feof(self.file) } != 0 {
true
} else {
false
}
}
}
pub enum SeekFrom {
Start(u64),
End(i64),
Current(i64),
}
pub trait StreamSeek : Stream {
fn seek(&mut self, from: SeekFrom) -> Result<usize, ()>;
}
pub struct File {}
impl File {
pub fn open(fname: &str) -> Result<FileReader, ()> {
FileReader::open(fname)
}
pub fn create(fname: &str) -> Result<FileWriter, ()> {
FileWriter::create(fname)
}
pub fn exist(fname: &str) -> bool {
let f = FileReader::open(fname);
match f {
Ok(_) => true,
_ => false,
}
}
pub fn remove(fname: &str) -> Result<(), ()> {
let mut sname = String::from(fname);
sname.push(b'\0');
let f = unsafe { ::libc::remove(sname.as_str().as_bytes().as_ptr() as *const i8) };
if f != 0 {
Err(())
} else {
Ok(())
}
}
pub fn rename(old_name: &str, new_name: &str) -> Result<(), ()> {
let mut o = String::from(old_name);
o.push(b'\0');
let mut n = String::from(new_name);
n.push(b'\0');
let f = unsafe { ::libc::rename(o.as_str().as_bytes().as_ptr() as *const i8, n.as_str().as_bytes().as_ptr() as *const i8) };
if f != 0 {
Err(())
} else {
Ok(())
}
}
pub fn tmpname() -> String {
unsafe {
let s = alloc_array::<i8>(::libc::L_tmpnam as usize);
::libc::tmpnam(s);
let len = ::libc::strlen(s);
let slice = ::core::slice::from_raw_parts(s as *const u8, len);
let st = String::from(&::core::str::from_utf8(slice).unwrap());
free_array_ptr(s, ::libc::L_tmpnam as usize);
st
}
}
}
pub fn fprint_strings<'a>(f: *mut libc::FILE, arr: &[&'a str]) {
for s in arr {
unsafe { libc::fprintf(f,"%.*s\0".as_bytes().as_ptr() as *const i8, s.len(), s.as_bytes().as_ptr())};
}
}
#[macro_export]
macro_rules! fprint {
() => {{}};
($stream:expr, $arg:expr) => { fprint!($stream, "{}", $arg) };
($stream:expr, $($args:expr),+) => { unsafe { $crate::fprint_strings($stream, &[rs_alloc::format!($($args),+).as_str()]) } };
}
#[macro_export]
macro_rules! fprintln {
() => {};
($stream:expr, $arg:expr) => { fprintln!($stream, "{}", $arg) };
($stream:expr, $($args:expr),+) => { unsafe { $crate::fprint_strings($stream, &[rs_alloc::format!($($args),+).as_str(), "\n"]) } };
}
#[macro_export]
macro_rules! print {
() => {};
($($args:expr),+) => { fprint!($crate::console::stdout, $($args),+) };
}
#[macro_export]
macro_rules! println {
() => {};
($($args:expr),+) => { fprintln!($crate::console::stdout, $($args),+) };
}
#[macro_export]
macro_rules! error {
() => {};
($($args:expr),+) => { fprint!($crate::console::stderr, $($args),+) };
}
#[macro_export]
macro_rules! errorln {
() => {};
($($args:expr),+) => { fprintln!($crate::console::stderr, $($args),+) };
}
pub mod console {
#[link(name = "c")]
extern "C"
{
pub static mut stdin: *mut libc::FILE;
pub static mut stdout: *mut libc::FILE;
pub static mut stderr: *mut libc::FILE;
}
pub fn read_line(s: &mut [u8]) -> usize {
unsafe { ::libc::strlen(::libc::fgets(s.as_mut_ptr() as *mut i8, s.len() as super::c_int, stdin)) as usize }
}
}
#[cfg(test)]
mod tests {
use core::{str};
use super::*;
#[test]
fn test_create_read_remove_file() {
let name = File::tmpname();
{
let mut f = FileWriter::create(name.as_str());
let s = "Hello File";
match &mut f {
Ok(f) => {
let res = f.write(s.as_bytes());
assert!(res.unwrap() == s.as_bytes().len());
assert!(File::exist(name.as_str()));
},
_ => panic!("couldn't create file!")
}
}
{
let mut f = FileReader::open(name.as_str());
let s = "Hello File";
match &mut f {
Ok(f) => {
assert!(f.size() == 10);
let mut buff : [u8; 10] = [0; 10];
let res = f.read(&mut buff);
assert!(res.unwrap() == s.as_bytes().len());
assert!(str::from_utf8(&buff).unwrap() == s);
},
_ => panic!("couldn't open file!")
}
}
{
let mut f = FileReader::open(name.as_str());
let s = "Hello File";
match &mut f {
Ok(f) => {
let mut txt = String::new();
match f.read_to_string(&mut txt) {
Ok(r) => {
assert_eq!(r, s.len());
assert_eq!(txt.as_str(), s);
},
_ => panic!("invalid string!")
}
},
_ => panic!("couldn't open file!")
}
}
{
File::remove(name.as_str()).unwrap();
}
}
#[test]
fn test_macros() {
print!(123);
println!(456);
print!("hello world {} {}", 1, 2);
println!("hello world {} {}", 3, 4);
error!(123);
errorln!(456);
error!("hello world {} {}", 1, 2);
errorln!("hello world {} {}", 3, 4);
}
}