123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984 |
- //! stdio implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdio.h.html
- use alloc::vec::Vec;
- use core::fmt::Write as WriteFmt;
- use core::fmt::{self, Error};
- use core::sync::atomic::{AtomicBool, Ordering};
- use core::{ptr, str};
- use va_list::VaList as va_list;
- use header::errno::{self, STR_ERROR};
- use header::fcntl;
- use header::stdlib::mkstemp;
- use header::string::strlen;
- use platform;
- use platform::types::*;
- use platform::{c_str, errno, Read, Write};
- use platform::{Pal, Sys};
- mod printf;
- mod scanf;
- pub use self::default::*;
- mod default;
- pub use self::constants::*;
- mod constants;
- mod helpers;
- mod internal;
- ///
- /// This struct gets exposed to the C API.
- ///
- pub struct FILE {
- flags: i32,
- read: Option<(usize, usize)>,
- write: Option<(usize, usize, usize)>,
- fd: c_int,
- buf: Vec<u8>,
- buf_char: i8,
- lock: AtomicBool,
- unget: usize,
- }
- impl FILE {
- pub fn can_read(&mut self) -> bool {
- /*
- if self.flags & constants::F_BADJ > 0 {
- // Static and needs unget region
- self.buf = unsafe { self.buf.add(self.unget) };
- self.flags &= !constants::F_BADJ;
- }
- */
- if let Some(_) = self.read {
- return true;
- }
- if let Some(_) = self.write {
- self.write(&[]);
- }
- self.write = None;
- if self.flags & constants::F_NORD > 0 {
- self.flags |= constants::F_ERR;
- return false;
- }
- self.read = if self.buf.len() == 0 {
- Some((0, 0))
- } else {
- Some((self.buf.len() - 1, self.buf.len() - 1))
- };
- if self.flags & constants::F_EOF > 0 {
- false
- } else {
- true
- }
- }
- pub fn can_write(&mut self) -> bool {
- /*
- if self.flags & constants::F_BADJ > 0 {
- // Static and needs unget region
- self.buf = unsafe { self.buf.add(self.unget) };
- self.flags &= !constants::F_BADJ;
- }
- */
- if self.flags & constants::F_NOWR > 0 {
- self.flags &= constants::F_ERR;
- return false;
- }
- // Buffer repositioning
- if let Some(_) = self.write {
- return true;
- }
- self.read = None;
- self.write = if self.buf.len() == 0 {
- Some((0, 0, 0))
- } else {
- Some((self.unget, self.unget, self.buf.len() - 1))
- };
- return true;
- }
- pub fn write(&mut self, to_write: &[u8]) -> usize {
- if let Some((wbase, wpos, _)) = self.write {
- let len = wpos - wbase;
- let mut advance = 0;
- let mut f_buf = &self.buf[wbase..wpos];
- let mut f_filled = false;
- let mut rem = f_buf.len() + to_write.len();
- loop {
- let mut count = if f_filled {
- Sys::write(self.fd, &f_buf[advance..])
- } else {
- Sys::write(self.fd, &f_buf[advance..]) + Sys::write(self.fd, to_write)
- };
- if count == rem as isize {
- self.write = if self.buf.len() == 0 {
- Some((0, 0, 0))
- } else {
- Some((self.unget, self.unget, self.buf.len() - 1))
- };
- return to_write.len();
- }
- if count < 0 {
- self.write = None;
- self.flags |= constants::F_ERR;
- return 0;
- }
- rem -= count as usize;
- if count as usize > len {
- count -= len as isize;
- f_buf = to_write;
- f_filled = true;
- advance = 0;
- }
- advance += count as usize;
- }
- }
- // self.can_write() should always be called before self.write()
- // and should automatically fill self.write if it returns true.
- // Thus, we should never reach this
- // -- Tommoa (20/6/2018)
- unreachable!()
- }
- pub fn read(&mut self, buf: &mut [u8]) -> usize {
- let adj = if self.buf.len() > 0 { 0 } else { 1 };
- let mut file_buf = &mut self.buf[self.unget..];
- let count = if buf.len() <= 1 - adj {
- Sys::read(self.fd, &mut file_buf)
- } else {
- Sys::read(self.fd, buf) + Sys::read(self.fd, &mut file_buf)
- };
- if count <= 0 {
- self.flags |= if count == 0 {
- constants::F_EOF
- } else {
- constants::F_ERR
- };
- return 0;
- }
- if count as usize <= buf.len() - adj {
- return count as usize;
- }
- // Adjust pointers
- if file_buf.len() == 0 {
- self.read = Some((0, 0));
- } else if buf.len() > 0 {
- self.read = Some((self.unget + 1, self.unget + (count as usize)));
- buf[buf.len() - 1] = file_buf[0];
- } else {
- self.read = Some((self.unget, self.unget + (count as usize)));
- }
- buf.len()
- }
- pub fn seek(&self, off: off_t, whence: c_int) -> off_t {
- Sys::lseek(self.fd, off, whence)
- }
- pub fn lock(&mut self) -> LockGuard {
- flockfile(self);
- LockGuard(self)
- }
- }
- pub struct LockGuard<'a>(&'a mut FILE);
- impl<'a> Drop for LockGuard<'a> {
- fn drop(&mut self) {
- funlockfile(self.0);
- }
- }
- impl<'a> fmt::Write for LockGuard<'a> {
- fn write_str(&mut self, s: &str) -> fmt::Result {
- if !self.0.can_write() {
- return Err(Error);
- }
- let s = s.as_bytes();
- if self.0.write(s) != s.len() {
- Err(Error)
- } else {
- Ok(())
- }
- }
- }
- impl<'a> Write for LockGuard<'a> {
- fn write_u8(&mut self, byte: u8) -> fmt::Result {
- if !self.0.can_write() {
- return Err(Error);
- }
- if self.0.write(&[byte]) != 1 {
- Err(Error)
- } else {
- Ok(())
- }
- }
- }
- impl<'a> Read for LockGuard<'a> {
- fn read_u8(&mut self) -> Result<Option<u8>, ()> {
- let mut buf = [0];
- match self.0.read(&mut buf) {
- 0 => Ok(None),
- _ => Ok(Some(buf[0])),
- }
- }
- }
- impl Drop for FILE {
- fn drop(&mut self) {
- // Flush
- if let Some(_) = self.write {
- self.write(&[]);
- }
- }
- }
- /// Clears EOF and ERR indicators on a stream
- #[no_mangle]
- pub extern "C" fn clearerr(stream: &mut FILE) {
- stream.flags &= !(F_EOF | F_ERR);
- }
- // #[no_mangle]
- pub extern "C" fn ctermid(_s: *mut c_char) -> *mut c_char {
- unimplemented!();
- }
- // #[no_mangle]
- pub extern "C" fn cuserid(_s: *mut c_char) -> *mut c_char {
- unimplemented!();
- }
- /// Close a file
- /// This function does not guarentee that the file buffer will be flushed or that the file
- /// descriptor will be closed, so if it is important that the file be written to, use `fflush()`
- /// prior to using this function.
- #[no_mangle]
- pub extern "C" fn fclose(stream: &mut FILE) -> c_int {
- flockfile(stream);
- let r = helpers::fflush_unlocked(stream) | Sys::close(stream.fd);
- if stream.flags & constants::F_PERM == 0 {
- // Not one of stdin, stdout or stderr
- unsafe {
- platform::free(stream as *mut FILE as *mut c_void);
- }
- } else {
- funlockfile(stream);
- }
- r
- }
- /// Open a file from a file descriptor
- #[no_mangle]
- pub extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE {
- use core::ptr;
- if let Some(f) = unsafe { helpers::_fdopen(fildes, mode) } {
- f
- } else {
- ptr::null_mut()
- }
- }
- /// Check for EOF
- #[no_mangle]
- pub extern "C" fn feof(stream: &mut FILE) -> c_int {
- flockfile(stream);
- let ret = stream.flags & F_EOF;
- funlockfile(stream);
- ret
- }
- /// Check for ERR
- #[no_mangle]
- pub extern "C" fn ferror(stream: &mut FILE) -> c_int {
- flockfile(stream);
- let ret = stream.flags & F_ERR;
- funlockfile(stream);
- ret
- }
- /// Flush output to stream, or sync read position
- /// Ensure the file is unlocked before calling this function, as it will attempt to lock the file
- /// itself.
- #[no_mangle]
- pub unsafe extern "C" fn fflush(stream: &mut FILE) -> c_int {
- flockfile(stream);
- let ret = helpers::fflush_unlocked(stream);
- funlockfile(stream);
- ret
- }
- /// Get a single char from a stream
- #[no_mangle]
- pub extern "C" fn fgetc(stream: &mut FILE) -> c_int {
- flockfile(stream);
- let c = getc_unlocked(stream);
- funlockfile(stream);
- c
- }
- /// Get the position of the stream and store it in pos
- #[no_mangle]
- pub extern "C" fn fgetpos(stream: &mut FILE, pos: Option<&mut fpos_t>) -> c_int {
- let off = internal::ftello(stream);
- if off < 0 {
- return -1;
- }
- if let Some(pos) = pos {
- *pos = off;
- 0
- } else {
- -1
- }
- }
- /// Get a string from the stream
- #[no_mangle]
- pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: &mut FILE) -> *mut c_char {
- use core::slice;
- flockfile(stream);
- let st = unsafe { slice::from_raw_parts_mut(s as *mut u8, n as usize) };
- let mut len = n;
- // We can only fit one or less chars in
- if n <= 1 {
- funlockfile(stream);
- if n <= 0 {
- return ptr::null_mut();
- }
- unsafe {
- (*s) = b'\0' as i8;
- }
- return s;
- }
- // Scope this so we can reuse stream mutably
- {
- // We can't read from this stream
- if !stream.can_read() {
- return ptr::null_mut();
- }
- }
- // TODO: Look at this later to determine correctness and efficiency
- 'outer: while stream.read(&mut []) == 0 && stream.flags & F_ERR == 0 {
- if let Some((rpos, rend)) = stream.read {
- let mut idiff = 0usize;
- for _ in (0..(len - 1) as usize).take_while(|x| rpos + x < rend) {
- let pos = (n - len) as usize;
- st[pos] = stream.buf[rpos + idiff];
- idiff += 1;
- len -= 1;
- if st[pos] == b'\n' || st[pos] as i8 == stream.buf_char {
- break 'outer;
- }
- }
- stream.read = Some((rpos + idiff, rend));
- if rend - rpos == 0 {
- len -= stream.read(&mut st[((n - len) as usize)..]) as i32;
- break;
- }
- if len <= 1 {
- break;
- }
- }
- // We can read, there's been no errors. We should have stream.read setbuf
- // -- Tommoa (3/7/2018)
- unreachable!()
- }
- st[(n - len) as usize] = 0;
- funlockfile(stream);
- s
- }
- /// Get the underlying file descriptor
- #[no_mangle]
- pub extern "C" fn fileno(stream: &mut FILE) -> c_int {
- flockfile(stream);
- funlockfile(stream);
- stream.fd
- }
- /// Lock the file
- /// Do not call any functions other than those with the `_unlocked` postfix while the file is
- /// locked
- #[no_mangle]
- pub extern "C" fn flockfile(file: &mut FILE) {
- while ftrylockfile(file) != 0 {}
- }
- /// Open the file in mode `mode`
- #[no_mangle]
- pub extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
- use core::ptr;
- let initial_mode = unsafe { *mode };
- if initial_mode != b'r' as i8 && initial_mode != b'w' as i8 && initial_mode != b'a' as i8 {
- unsafe { platform::errno = errno::EINVAL };
- return ptr::null_mut();
- }
- let flags = unsafe { helpers::parse_mode_flags(mode) };
- let fd = fcntl::sys_open(filename, flags, 0o666);
- if fd < 0 {
- return ptr::null_mut();
- }
- if flags & fcntl::O_CLOEXEC > 0 {
- fcntl::sys_fcntl(fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
- }
- if let Some(f) = unsafe { helpers::_fdopen(fd, mode) } {
- f
- } else {
- Sys::close(fd);
- ptr::null_mut()
- }
- }
- /// Insert a character into the stream
- #[no_mangle]
- pub extern "C" fn fputc(c: c_int, stream: &mut FILE) -> c_int {
- flockfile(stream);
- let c = putc_unlocked(c, stream);
- funlockfile(stream);
- c
- }
- /// Insert a string into a stream
- #[no_mangle]
- pub extern "C" fn fputs(s: *const c_char, stream: &mut FILE) -> c_int {
- let len = unsafe { strlen(s) };
- (fwrite(s as *const c_void, 1, len, stream) == len) as c_int - 1
- }
- /// Read `nitems` of size `size` into `ptr` from `stream`
- #[no_mangle]
- pub extern "C" fn fread(ptr: *mut c_void, size: usize, nitems: usize, stream: &mut FILE) -> usize {
- use core::ptr::copy_nonoverlapping;
- use core::slice;
- let mut dest = ptr as *mut u8;
- let len = size * nitems;
- let mut l = len as isize;
- flockfile(stream);
- if !stream.can_read() {
- return 0;
- }
- if let Some((rpos, rend)) = stream.read {
- if rend > rpos {
- // We have some buffered data that can be read
- let diff = rend - rpos;
- let k = if diff < l as usize { diff } else { l as usize };
- unsafe {
- // Copy data
- copy_nonoverlapping(&stream.buf[rpos..] as *const _ as *const u8, dest, k);
- // Reposition pointers
- dest = dest.add(k);
- }
- stream.read = Some((rpos + k, rend));
- l -= k as isize;
- }
- while l > 0 {
- let k = if !stream.can_read() {
- 0
- } else {
- stream.read(unsafe { slice::from_raw_parts_mut(dest, l as usize) })
- };
- if k == 0 {
- funlockfile(stream);
- return (len - l as usize) / 2;
- }
- l -= k as isize;
- unsafe {
- // Reposition
- dest = dest.add(k);
- }
- }
- funlockfile(stream);
- nitems
- } else {
- unreachable!()
- }
- }
- #[no_mangle]
- pub extern "C" fn freopen(
- filename: *const c_char,
- mode: *const c_char,
- stream: &mut FILE,
- ) -> *mut FILE {
- let mut flags = unsafe { helpers::parse_mode_flags(mode) };
- flockfile(stream);
- helpers::fflush_unlocked(stream);
- if filename.is_null() {
- // Reopen stream in new mode
- if flags & fcntl::O_CLOEXEC > 0 {
- fcntl::sys_fcntl(stream.fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
- }
- flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC);
- if fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags) < 0 {
- funlockfile(stream);
- fclose(stream);
- return ptr::null_mut();
- }
- } else {
- let new = fopen(filename, mode);
- if new.is_null() {
- funlockfile(stream);
- fclose(stream);
- return ptr::null_mut();
- }
- let new = unsafe { &mut *new }; // Should be safe, new is not null
- if new.fd == stream.fd {
- new.fd = -1;
- } else if Sys::dup2(new.fd, stream.fd) < 0
- || fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags & fcntl::O_CLOEXEC) < 0
- {
- fclose(new);
- funlockfile(stream);
- fclose(stream);
- return ptr::null_mut();
- }
- stream.flags = (stream.flags & constants::F_PERM) | new.flags;
- fclose(new);
- }
- funlockfile(stream);
- stream
- }
- /// Seek to an offset `offset` from `whence`
- #[no_mangle]
- pub extern "C" fn fseek(stream: &mut FILE, offset: c_long, whence: c_int) -> c_int {
- if fseeko(stream, offset as off_t, whence) != -1 {
- return 0;
- }
- -1
- }
- /// Seek to an offset `offset` from `whence`
- #[no_mangle]
- pub extern "C" fn fseeko(stream: &mut FILE, offset: off_t, whence: c_int) -> c_int {
- let mut off = offset;
- flockfile(stream);
- // Adjust for what is currently in the buffer
- let rdiff = if let Some((rpos, rend)) = stream.read {
- rend - rpos
- } else {
- 0
- };
- if whence == SEEK_CUR {
- off -= (rdiff) as i64;
- }
- if let Some(_) = stream.write {
- stream.write(&[]);
- }
- stream.write = None;
- if stream.seek(off, whence) < 0 {
- return -1;
- }
- stream.read = None;
- stream.flags &= !F_EOF;
- funlockfile(stream);
- 0
- }
- /// Seek to a position `pos` in the file from the beginning of the file
- #[no_mangle]
- pub unsafe extern "C" fn fsetpos(stream: &mut FILE, pos: Option<&fpos_t>) -> c_int {
- fseek(
- stream,
- *pos.expect("You must specify a valid position"),
- SEEK_SET,
- )
- }
- /// Get the current position of the cursor in the file
- #[no_mangle]
- pub extern "C" fn ftell(stream: &mut FILE) -> c_long {
- ftello(stream) as c_long
- }
- /// Get the current position of the cursor in the file
- #[no_mangle]
- pub extern "C" fn ftello(stream: &mut FILE) -> off_t {
- flockfile(stream);
- let pos = internal::ftello(stream);
- funlockfile(stream);
- pos
- }
- /// Try to lock the file. Returns 0 for success, 1 for failure
- #[no_mangle]
- pub extern "C" fn ftrylockfile(file: &mut FILE) -> c_int {
- file.lock.compare_and_swap(false, true, Ordering::Acquire) as c_int
- }
- /// Unlock the file
- #[no_mangle]
- pub extern "C" fn funlockfile(file: &mut FILE) {
- file.lock.store(false, Ordering::Release);
- }
- /// Write `nitems` of size `size` from `ptr` to `stream`
- #[no_mangle]
- pub extern "C" fn fwrite(
- ptr: *const c_void,
- size: usize,
- nitems: usize,
- stream: &mut FILE,
- ) -> usize {
- let l = size * nitems;
- let nitems = if size == 0 { 0 } else { nitems };
- flockfile(stream);
- let k = helpers::fwritex(ptr as *const u8, l, stream);
- funlockfile(stream);
- if k == l {
- nitems
- } else {
- k / size
- }
- }
- /// Get a single char from a stream
- #[no_mangle]
- pub extern "C" fn getc(stream: &mut FILE) -> c_int {
- flockfile(stream);
- let c = getc_unlocked(stream);
- funlockfile(stream);
- c
- }
- /// Get a single char from `stdin`
- #[no_mangle]
- pub extern "C" fn getchar() -> c_int {
- fgetc(unsafe { &mut *stdin })
- }
- /// Get a char from a stream without locking the stream
- #[no_mangle]
- pub extern "C" fn getc_unlocked(stream: &mut FILE) -> c_int {
- if !stream.can_read() {
- return -1;
- }
- if let Some((rpos, rend)) = stream.read {
- if rpos < rend {
- let ret = stream.buf[rpos] as c_int;
- stream.read = Some((rpos + 1, rend));
- ret
- } else {
- let mut c = [0u8; 1];
- if stream.read(&mut c) == 1 {
- c[0] as c_int
- } else {
- -1
- }
- }
- } else {
- // We made a prior call to can_read() and are checking it, therefore we
- // should never be in a case where stream.read is None
- // -- Tommoa (20/6/2018)
- unreachable!()
- }
- }
- /// Get a char from `stdin` without locking `stdin`
- #[no_mangle]
- pub extern "C" fn getchar_unlocked() -> c_int {
- getc_unlocked(unsafe { &mut *stdin })
- }
- /// Get a string from `stdin`
- #[no_mangle]
- pub extern "C" fn gets(s: *mut c_char) -> *mut c_char {
- use core::i32;
- fgets(s, i32::MAX, unsafe { &mut *stdin })
- }
- /// Get an integer from `stream`
- #[no_mangle]
- pub extern "C" fn getw(stream: &mut FILE) -> c_int {
- use core::mem;
- let mut ret: c_int = 0;
- if fread(
- &mut ret as *mut c_int as *mut c_void,
- mem::size_of_val(&ret),
- 1,
- stream,
- ) > 0
- {
- ret
- } else {
- -1
- }
- }
- // #[no_mangle]
- pub extern "C" fn pclose(_stream: &mut FILE) -> c_int {
- unimplemented!();
- }
- #[no_mangle]
- pub unsafe extern "C" fn perror(s: *const c_char) {
- let s_str = str::from_utf8_unchecked(c_str(s));
- let mut w = platform::FileWriter(2);
- if errno >= 0 && errno < STR_ERROR.len() as c_int {
- w.write_fmt(format_args!("{}: {}\n", s_str, STR_ERROR[errno as usize]))
- .unwrap();
- } else {
- w.write_fmt(format_args!("{}: Unknown error {}\n", s_str, errno))
- .unwrap();
- }
- }
- // #[no_mangle]
- pub extern "C" fn popen(_command: *const c_char, _mode: *const c_char) -> *mut FILE {
- unimplemented!();
- }
- /// Put a character `c` into `stream`
- #[no_mangle]
- pub extern "C" fn putc(c: c_int, stream: &mut FILE) -> c_int {
- flockfile(stream);
- let ret = putc_unlocked(c, stream);
- funlockfile(stream);
- ret
- }
- /// Put a character `c` into `stdout`
- #[no_mangle]
- pub extern "C" fn putchar(c: c_int) -> c_int {
- fputc(c, unsafe { &mut *stdout })
- }
- /// Put a character `c` into `stream` without locking `stream`
- #[no_mangle]
- pub extern "C" fn putc_unlocked(c: c_int, stream: &mut FILE) -> c_int {
- if stream.can_write() {
- if let Some((wbase, wpos, wend)) = stream.write {
- if c as i8 != stream.buf_char {
- stream.buf[wpos] = c as u8;
- stream.write = Some((wbase, wpos + 1, wend));
- c
- } else if stream.write(&[c as u8]) == 1 {
- c
- } else {
- -1
- }
- } else {
- -1
- }
- } else {
- -1
- }
- }
- /// Put a character `c` into `stdout` without locking `stdout`
- #[no_mangle]
- pub extern "C" fn putchar_unlocked(c: c_int) -> c_int {
- putc_unlocked(c, unsafe { &mut *stdout })
- }
- /// Put a string `s` into `stdout`
- #[no_mangle]
- pub extern "C" fn puts(s: *const c_char) -> c_int {
- let ret = (fputs(s, unsafe { &mut *stdout }) > 0) || (putchar_unlocked(b'\n' as c_int) > 0);
- if ret {
- 0
- } else {
- -1
- }
- }
- /// Put an integer `w` into `stream`
- #[no_mangle]
- pub extern "C" fn putw(w: c_int, stream: &mut FILE) -> c_int {
- use core::mem;
- fwrite(&w as *const i32 as _, mem::size_of_val(&w), 1, stream) as i32 - 1
- }
- /// Delete file or directory `path`
- #[no_mangle]
- pub extern "C" fn remove(path: *const c_char) -> c_int {
- let r = Sys::unlink(path);
- if r == -errno::EISDIR {
- Sys::rmdir(path)
- } else {
- r
- }
- }
- #[no_mangle]
- pub extern "C" fn rename(oldpath: *const c_char, newpath: *const c_char) -> c_int {
- Sys::rename(oldpath, newpath)
- }
- /// Rewind `stream` back to the beginning of it
- #[no_mangle]
- pub extern "C" fn rewind(stream: &mut FILE) {
- fseeko(stream, 0, SEEK_SET);
- flockfile(stream);
- stream.flags &= !F_ERR;
- funlockfile(stream);
- }
- /// Reset `stream` to use buffer `buf`. Buffer must be `BUFSIZ` in length
- #[no_mangle]
- pub extern "C" fn setbuf(stream: &mut FILE, buf: *mut c_char) {
- setvbuf(
- stream,
- buf,
- if buf.is_null() { _IONBF } else { _IOFBF },
- BUFSIZ as usize,
- );
- }
- /// Reset `stream` to use buffer `buf` of size `size`
- /// If this isn't the meaning of unsafe, idk what is
- #[no_mangle]
- pub extern "C" fn setvbuf(stream: &mut FILE, buf: *mut c_char, mode: c_int, size: usize) -> c_int {
- // Set a buffer of size `size` if no buffer is given
- let buf = if buf.is_null() {
- if mode != _IONBF {
- vec![0u8; 1]
- } else {
- stream.unget = 0;
- if let Some(_) = stream.write {
- stream.write = Some((0, 0, 0));
- } else if let Some(_) = stream.read {
- stream.read = Some((0, 0));
- }
- Vec::new()
- }
- } else {
- // We trust the user on this one
- // -- Tommoa (20/6/2018)
- unsafe { Vec::from_raw_parts(buf as *mut u8, size, size) }
- };
- stream.buf_char = -1;
- if mode == _IOLBF {
- stream.buf_char = b'\n' as i8;
- }
- stream.flags |= F_SVB;
- stream.buf = buf;
- 0
- }
- // #[no_mangle]
- pub extern "C" fn tempnam(_dir: *const c_char, _pfx: *const c_char) -> *mut c_char {
- unimplemented!();
- }
- #[no_mangle]
- pub extern "C" fn tmpfile() -> *mut FILE {
- let mut file_name = *b"/tmp/tmpfileXXXXXX";
- let file_name = file_name.as_mut_ptr() as *mut c_char;
- let fd = unsafe { mkstemp(file_name) };
- if fd < 0 {
- return ptr::null_mut();
- }
- let fp = fdopen(fd, b"w+".as_ptr() as *const i8);
- Sys::unlink(file_name);
- if fp == ptr::null_mut() {
- Sys::close(fd);
- }
- fp
- }
- // #[no_mangle]
- pub extern "C" fn tmpnam(_s: *mut c_char) -> *mut c_char {
- unimplemented!();
- }
- /// Push character `c` back onto `stream` so it'll be read next
- #[no_mangle]
- pub extern "C" fn ungetc(c: c_int, stream: &mut FILE) -> c_int {
- if c < 0 {
- c
- } else {
- flockfile(stream);
- if stream.read.is_none() {
- stream.can_read();
- }
- if let Some((rpos, rend)) = stream.read {
- if rpos == 0 {
- funlockfile(stream);
- return -1;
- }
- stream.read = Some((rpos - 1, rend));
- stream.buf[rpos - 1] = c as u8;
- stream.flags &= !F_EOF;
- funlockfile(stream);
- c
- } else {
- funlockfile(stream);
- -1
- }
- }
- }
- #[no_mangle]
- pub unsafe extern "C" fn vfprintf(file: &mut FILE, format: *const c_char, ap: va_list) -> c_int {
- printf::printf(file.lock(), format, ap)
- }
- #[no_mangle]
- pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int {
- vfprintf(&mut *stdout, format, ap)
- }
- #[no_mangle]
- pub unsafe extern "C" fn vsnprintf(
- s: *mut c_char,
- n: usize,
- format: *const c_char,
- ap: va_list,
- ) -> c_int {
- printf::printf(
- &mut platform::StringWriter(s as *mut u8, n as usize),
- format,
- ap,
- )
- }
- #[no_mangle]
- pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_list) -> c_int {
- printf::printf(&mut platform::UnsafeStringWriter(s as *mut u8), format, ap)
- }
- #[no_mangle]
- pub unsafe extern "C" fn vfscanf(file: &mut FILE, format: *const c_char, ap: va_list) -> c_int {
- scanf::scanf(file.lock(), format, ap)
- }
- #[no_mangle]
- pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
- vfscanf(&mut *stdin, format, ap)
- }
- #[no_mangle]
- pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int {
- scanf::scanf(
- &mut platform::UnsafeStringReader(s as *const u8),
- format,
- ap,
- )
- }
|