rs_streams/
file.rs

1use crate::*;
2use rs_alloc::*;
3use libc::*;
4
5pub struct FileWriter {
6    file    : *mut ::libc::FILE,
7}
8
9impl FileWriter {
10    pub fn create(fname: &str) -> Result<Self, ()> {
11        let mut sname = String::from(fname);
12        sname.push('\0' as u8);
13        let f = unsafe { ::libc::fopen(sname.as_str().as_bytes().as_ptr() as *const i8, "wb\0".as_bytes().as_ptr() as *const i8) };
14        if f as * const _ == ::core::ptr::null() {
15            Result::Err(())
16        } else {
17            Result::Ok(Self { file: f })
18        }
19    }
20
21    pub fn write(&mut self, bytes: &[u8]) -> Result<usize, ()> {
22        let count = unsafe {  ::libc::fwrite(bytes.as_ptr() as *const c_void, 1, bytes.len(), self.file) };
23        if count < bytes.len() {
24            if unsafe { ::libc::ferror(self.file) } != 0 {
25                Result::Err(())
26            } else {
27                Result::Ok(count)
28            }
29        } else {
30            Result::Ok(count)
31        }
32    }
33
34    pub fn tell(&self) -> usize { unsafe { ::libc::ftell(self.file) as usize } }
35    pub fn size(&self) -> usize {
36        unsafe {
37            let curr = self.tell();
38            ::libc::fseek(self.file, 0, ::libc::SEEK_END);
39            let size = self.tell();
40            ::libc::fseek(self.file, curr as c_long, ::libc::SEEK_SET);
41            size
42        }
43    }
44}
45
46impl Drop for FileWriter {
47    fn drop(&mut self) {
48        unsafe { ::libc::fclose(self.file) };
49    }
50}
51
52impl Stream for FileWriter {
53    fn tell(&self) -> usize { self.tell() }
54    fn size(&self) -> usize { self.size() }
55}
56
57impl StreamSeek for FileWriter {
58    fn seek(&mut self, pos: SeekFrom) -> Result<usize, ()> {
59        unsafe {
60            match pos {
61                SeekFrom::Start(p)      => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_SET),
62                SeekFrom::End(p)        => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_END),
63                SeekFrom::Current(p)    => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_CUR)
64            }
65        };
66        Result::Ok(self.tell())
67    }
68}
69
70impl StreamWriter for FileWriter {
71    fn write(&mut self, buff: &[u8]) -> Result<usize, ()> {
72        self.write(buff)
73    }
74}
75
76////////////////////////////////////////////////////////////////////////////////
77pub struct FileReader {
78    file    : *mut ::libc::FILE,
79}
80
81impl FileReader {
82    pub fn open(fname: &str) -> Result<Self, ()> {
83        let mut sname = String::from(fname);
84        sname.push(b'\0');
85        let f = unsafe { ::libc::fopen(sname.as_str().as_bytes().as_ptr() as *const i8, "rb\0".as_bytes().as_ptr() as *const i8) };
86        if f as * const _ == ::core::ptr::null() {
87            Result::Err(())
88        } else {
89            Result::Ok(Self { file: f })
90        }
91    }
92
93    pub fn tell(&self) -> usize { unsafe { ::libc::ftell(self.file) as usize } }
94    pub fn size(&self) -> usize {
95        unsafe {
96            let curr = self.tell();
97            ::libc::fseek(self.file, 0, ::libc::SEEK_END);
98            let size = self.tell();
99            ::libc::fseek(self.file, curr as c_long, ::libc::SEEK_SET);
100            size
101        }
102    }
103
104    pub fn read(&mut self, buff: &mut [u8]) -> Result<usize, ()> {
105        let count = unsafe {  ::libc::fread(buff.as_mut_ptr() as *mut c_void, 1, buff.len(), self.file) };
106        if count < buff.len() {
107            if unsafe { ::libc::ferror(self.file) } != 0 {
108                Result::Err(())
109            } else {
110                Result::Ok(count)
111            }
112        } else {
113            Result::Ok(count)
114        }
115    }
116
117    pub fn read_line(&mut self, buff: &mut [u8]) -> Result<usize, ()> {
118        let n = unsafe { ::libc::fgets(buff.as_mut_ptr() as *mut i8, buff.len() as c_int, self.file) };
119        Result::Ok(n as usize)
120    }
121
122    pub fn read_to_string(&mut self, buf: &mut String) -> Result<usize, ()> {
123        let count   = self.size();
124        let ptr     = unsafe { alloc_array(count) };
125        let data    = unsafe { core::slice::from_raw_parts_mut(ptr, count) };
126        let r = self.read(data);
127        match r {
128            Ok(_) => {
129                *buf = String::from_raw_parts(ptr, count, count);
130                Ok(count)
131            },
132            Err(_) => Err(())
133        }
134    }
135}
136
137
138impl Drop for FileReader {
139    fn drop(&mut self) {
140        unsafe { ::libc::fclose(self.file) };
141    }
142}
143
144impl Stream for FileReader {
145    fn tell(&self) -> usize { self.tell() }
146    fn size(&self) -> usize { self.size() }
147}
148
149impl StreamSeek for FileReader {
150    fn seek(&mut self, pos: SeekFrom) -> Result<usize, ()> {
151        unsafe {
152            match pos {
153                SeekFrom::Start(p)      => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_SET),
154                SeekFrom::End(p)        => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_END),
155                SeekFrom::Current(p)    => ::libc::fseek(self.file, p as c_long, ::libc::SEEK_CUR)
156            }
157        };
158        Result::Ok(self.tell())
159    }
160}
161
162impl StreamReader for FileReader {
163    fn read(&mut self, buff: &mut [u8]) -> Result<usize, ()> {
164        self.read(buff)
165    }
166
167    fn is_eof(&self) -> bool {
168        if unsafe { ::libc::feof(self.file) } != 0 {
169            true
170        } else {
171            false
172        }
173    }
174}
175
176pub enum SeekFrom {
177    Start(u64),
178    End(i64),
179    Current(i64),
180}
181
182pub trait StreamSeek : Stream {
183    fn seek(&mut self, from: SeekFrom) -> Result<usize, ()>;
184}
185
186////////////////////////////////////////////////////////////////////////////////
187pub struct File {}
188
189impl File {
190    pub fn open(fname: &str) -> Result<FileReader, ()> {
191        FileReader::open(fname)
192    }
193
194    pub fn create(fname: &str) -> Result<FileWriter, ()> {
195        FileWriter::create(fname)
196    }
197
198    pub fn exist(fname: &str) -> bool {
199        let f = FileReader::open(fname);
200        match f {
201            Ok(_) => true,
202            _ => false,
203        }
204    }
205
206    pub fn remove(fname: &str) -> Result<(), ()> {
207        let mut sname = String::from(fname);
208        sname.push(b'\0');
209        let f = unsafe { ::libc::remove(sname.as_str().as_bytes().as_ptr() as *const i8) };
210        if f != 0 {
211            Err(())
212        } else {
213            Ok(())
214        }
215    }
216
217    pub fn rename(old_name: &str, new_name: &str) -> Result<(), ()> {
218        let mut o = String::from(old_name);
219        o.push(b'\0');
220        let mut n = String::from(new_name);
221        n.push(b'\0');
222        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) };
223        if f != 0 {
224            Err(())
225        } else {
226            Ok(())
227        }
228    }
229
230    pub fn tmpname() -> String {
231        unsafe {
232            let s = alloc_array::<i8>(::libc::L_tmpnam as usize);
233            ::libc::tmpnam(s);
234            let len = ::libc::strlen(s);
235            let slice = ::core::slice::from_raw_parts(s as *const u8, len);
236            let st = String::from(&::core::str::from_utf8(slice).unwrap());
237            free_array_ptr(s, ::libc::L_tmpnam as usize);
238            st
239        }
240    }
241}
242
243////////////////////////////////////////////////////////////////////////////////
244
245pub fn fprint_strings<'a>(f: *mut libc::FILE, arr: &[&'a str]) {
246    for s in arr {
247        unsafe { libc::fprintf(f,"%.*s\0".as_bytes().as_ptr() as *const i8, s.len(), s.as_bytes().as_ptr())};
248    }
249}
250
251#[macro_export]
252macro_rules! fprint {
253    () => {{}};
254    ($stream:expr, $arg:expr) => { fprint!($stream, "{}", $arg) };
255    ($stream:expr, $($args:expr),+) => { unsafe { $crate::fprint_strings($stream, &[rs_alloc::format!($($args),+).as_str()]) } };
256}
257
258#[macro_export]
259macro_rules! fprintln {
260    () => {};
261    ($stream:expr, $arg:expr) => { fprintln!($stream, "{}", $arg) };
262    ($stream:expr, $($args:expr),+) => { unsafe { $crate::fprint_strings($stream, &[rs_alloc::format!($($args),+).as_str(), "\n"]) } };
263}
264
265#[macro_export]
266macro_rules! print {
267    () => {};
268    ($($args:expr),+) => { fprint!($crate::console::stdout, $($args),+) };
269}
270
271#[macro_export]
272macro_rules! println {
273    () => {};
274    ($($args:expr),+) => { fprintln!($crate::console::stdout, $($args),+) };
275}
276
277#[macro_export]
278macro_rules! error {
279    () => {};
280    ($($args:expr),+) => { fprint!($crate::console::stderr, $($args),+) };
281}
282
283#[macro_export]
284macro_rules! errorln {
285    () => {};
286    ($($args:expr),+) => { fprintln!($crate::console::stderr, $($args),+) };
287}
288
289////////////////////////////////////////////////////////////////////////////////
290pub mod console {
291    #[link(name = "c")]
292    extern "C"
293    {
294        pub static mut stdin: *mut libc::FILE;
295
296        pub static mut stdout: *mut libc::FILE;
297
298        pub static mut stderr: *mut libc::FILE;
299    }
300
301    pub fn read_line(s: &mut [u8]) -> usize {
302        unsafe { ::libc::strlen(::libc::fgets(s.as_mut_ptr() as *mut i8, s.len() as super::c_int, stdin)) as usize }
303    }
304}
305
306////////////////////////////////////////////////////////////////////////////////
307
308#[cfg(test)]
309mod tests {
310    use core::{str};
311    use super::*;
312    #[test]
313    fn test_create_read_remove_file() {
314        let name = File::tmpname();
315        {
316            let mut f = FileWriter::create(name.as_str());
317            let s = "Hello File";
318            match &mut f {
319                Ok(f) => {
320                    let res = f.write(s.as_bytes());
321                    assert!(res.unwrap() == s.as_bytes().len());
322                    assert!(File::exist(name.as_str()));
323                },
324                _ => panic!("couldn't create file!")
325            }
326        }
327
328        {
329            let mut f = FileReader::open(name.as_str());
330            let s = "Hello File";
331            match &mut f {
332                Ok(f) => {
333                    assert!(f.size() == 10);
334                    let mut buff : [u8; 10] = [0; 10];
335                    let res = f.read(&mut buff);
336                    assert!(res.unwrap() == s.as_bytes().len());
337                    assert!(str::from_utf8(&buff).unwrap() == s);
338                },
339                _ => panic!("couldn't open file!")
340            }
341        }
342
343        {
344            let mut f = FileReader::open(name.as_str());
345            let s = "Hello File";
346            match &mut f {
347                Ok(f) => {
348                    let mut txt = String::new();
349                    match f.read_to_string(&mut txt) {
350                        Ok(r) => {
351                            assert_eq!(r, s.len());
352                            assert_eq!(txt.as_str(), s);
353                        },
354                        _ => panic!("invalid string!")
355                    }
356                },
357                _ => panic!("couldn't open file!")
358            }
359        }
360
361        {
362            File::remove(name.as_str()).unwrap();
363        }
364    }
365
366    #[test]
367    fn test_macros() {
368        print!(123);
369        println!(456);
370        print!("hello world {} {}", 1, 2);
371        println!("hello world {} {}", 3, 4);
372
373        error!(123);
374        errorln!(456);
375        error!("hello world {} {}", 1, 2);
376        errorln!("hello world {} {}", 3, 4);
377    }
378}