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
76pub 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
186pub 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
243pub 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
289pub 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#[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}