lib.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. //! stdio implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdio.h.html
  2. #![no_std]
  3. // For Vec
  4. #![feature(alloc)]
  5. // For stdin, stdout and stderr
  6. #![allow(non_upper_case_globals)]
  7. #![deny(warnings)]
  8. #[macro_use]
  9. extern crate alloc;
  10. extern crate errno;
  11. extern crate fcntl;
  12. #[macro_use]
  13. extern crate lazy_static;
  14. extern crate platform;
  15. extern crate stdlib;
  16. extern crate string;
  17. extern crate va_list as vl;
  18. use core::str;
  19. use core::ptr;
  20. use core::fmt::{self, Error, Result};
  21. use core::fmt::Write as WriteFmt;
  22. use core::sync::atomic::{AtomicBool, Ordering};
  23. use errno::STR_ERROR;
  24. use platform::types::*;
  25. use platform::{c_str, errno, Read, Write};
  26. use errno::STR_ERROR;
  27. use alloc::vec::Vec;
  28. use vl::VaList as va_list;
  29. mod scanf;
  30. mod printf;
  31. mod default;
  32. pub use default::*;
  33. mod constants;
  34. pub use constants::*;
  35. mod helpers;
  36. mod internal;
  37. ///
  38. /// This struct gets exposed to the C API.
  39. ///
  40. pub struct FILE {
  41. flags: i32,
  42. read: Option<(usize, usize)>,
  43. write: Option<(usize, usize, usize)>,
  44. fd: c_int,
  45. buf: Vec<u8>,
  46. buf_char: i8,
  47. lock: AtomicBool,
  48. unget: usize,
  49. }
  50. impl FILE {
  51. pub fn can_read(&mut self) -> bool {
  52. /*
  53. if self.flags & constants::F_BADJ > 0 {
  54. // Static and needs unget region
  55. self.buf = unsafe { self.buf.add(self.unget) };
  56. self.flags &= !constants::F_BADJ;
  57. }
  58. */
  59. if let Some(_) = self.write {
  60. self.write(&[]);
  61. }
  62. self.write = None;
  63. if self.flags & constants::F_NORD > 0 {
  64. self.flags |= constants::F_ERR;
  65. return false;
  66. }
  67. self.read = Some((self.buf.len() - 1, self.buf.len() - 1));
  68. if self.flags & constants::F_EOF > 0 {
  69. false
  70. } else {
  71. true
  72. }
  73. }
  74. pub fn can_write(&mut self) -> bool {
  75. /*
  76. if self.flags & constants::F_BADJ > 0 {
  77. // Static and needs unget region
  78. self.buf = unsafe { self.buf.add(self.unget) };
  79. self.flags &= !constants::F_BADJ;
  80. }
  81. */
  82. if self.flags & constants::F_NOWR > 0 {
  83. self.flags &= constants::F_ERR;
  84. return false;
  85. }
  86. // Buffer repositioning
  87. self.read = None;
  88. self.write = Some((self.unget, self.unget, self.buf.len() - 1));
  89. return true;
  90. }
  91. pub fn write(&mut self, to_write: &[u8]) -> usize {
  92. if let Some((wbase, wpos, _)) = self.write {
  93. let len = wpos - wbase;
  94. let mut advance = 0;
  95. let mut f_buf = &self.buf[wbase..wpos];
  96. let mut f_filled = false;
  97. let mut rem = f_buf.len() + to_write.len();
  98. loop {
  99. let mut count = if f_filled {
  100. platform::write(self.fd, &f_buf[advance..])
  101. } else {
  102. platform::write(self.fd, &f_buf[advance..]) + platform::write(self.fd, to_write)
  103. };
  104. if count == rem as isize {
  105. self.write = Some((self.unget, self.unget, self.buf.len() - 1));
  106. return to_write.len();
  107. }
  108. if count < 0 {
  109. self.write = None;
  110. self.flags |= constants::F_ERR;
  111. return 0;
  112. }
  113. rem -= count as usize;
  114. if count as usize > len {
  115. count -= len as isize;
  116. f_buf = to_write;
  117. f_filled = true;
  118. advance = 0;
  119. }
  120. advance += count as usize;
  121. }
  122. }
  123. // self.can_write() should always be called before self.write()
  124. // and should automatically fill self.write if it returns true.
  125. // Thus, we should never reach this
  126. // -- Tommoa (20/6/2018)
  127. unreachable!()
  128. }
  129. pub fn read(&mut self, buf: &mut [u8]) -> usize {
  130. let adj = !(self.buf.len() == 0) as usize;
  131. let mut file_buf = &mut self.buf[self.unget..];
  132. let count = if buf.len() <= 1 + adj {
  133. platform::read(self.fd, &mut file_buf)
  134. } else {
  135. platform::read(self.fd, buf) + platform::read(self.fd, &mut file_buf)
  136. };
  137. if count <= 0 {
  138. self.flags |= if count == 0 {
  139. constants::F_EOF
  140. } else {
  141. constants::F_ERR
  142. };
  143. return 0;
  144. }
  145. if count as usize <= buf.len() - adj {
  146. return count as usize;
  147. }
  148. // Adjust pointers
  149. self.read = Some((self.unget + 1, self.unget + (count as usize)));
  150. buf[buf.len() - 1] = file_buf[0];
  151. buf.len()
  152. }
  153. pub fn seek(&self, off: off_t, whence: c_int) -> off_t {
  154. platform::lseek(self.fd, off, whence)
  155. }
  156. }
  157. impl fmt::Write for FILE {
  158. fn write_str(&mut self, s: &str) -> Result {
  159. let s = s.as_bytes();
  160. if self.write(s) != s.len() {
  161. Err(Error)
  162. } else {
  163. Ok(())
  164. }
  165. }
  166. }
  167. impl Write for FILE {
  168. fn write_u8(&mut self, byte: u8) -> Result {
  169. if self.write(&[byte]) != 1 {
  170. Err(Error)
  171. } else {
  172. Ok(())
  173. }
  174. }
  175. }
  176. impl Read for FILE {
  177. fn read_u8(&mut self, byte: &mut u8) -> bool {
  178. let mut buf = [*byte];
  179. let n = self.read(&mut buf);
  180. *byte = buf[0];
  181. n > 0
  182. }
  183. }
  184. /// Clears EOF and ERR indicators on a stream
  185. #[no_mangle]
  186. pub extern "C" fn clearerr(stream: &mut FILE) {
  187. stream.flags &= !(F_EOF | F_ERR);
  188. }
  189. #[no_mangle]
  190. pub extern "C" fn ctermid(_s: *mut c_char) -> *mut c_char {
  191. unimplemented!();
  192. }
  193. #[no_mangle]
  194. pub extern "C" fn cuserid(_s: *mut c_char) -> *mut c_char {
  195. unimplemented!();
  196. }
  197. /// Close a file
  198. /// This function does not guarentee that the file buffer will be flushed or that the file
  199. /// descriptor will be closed, so if it is important that the file be written to, use `fflush()`
  200. /// prior to using this function.
  201. #[no_mangle]
  202. pub extern "C" fn fclose(stream: &mut FILE) -> c_int {
  203. use stdlib::free;
  204. flockfile(stream);
  205. let r = helpers::fflush_unlocked(stream) | platform::close(stream.fd);
  206. if stream.flags & constants::F_PERM == 0 {
  207. // Not one of stdin, stdout or stderr
  208. unsafe {
  209. free(stream as *mut _ as *mut _);
  210. }
  211. }
  212. r
  213. }
  214. /// Open a file from a file descriptor
  215. #[no_mangle]
  216. pub extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE {
  217. use core::ptr;
  218. if let Some(mut f) = unsafe { helpers::_fdopen(fildes, mode) } {
  219. &mut f
  220. } else {
  221. ptr::null_mut()
  222. }
  223. }
  224. /// Check for EOF
  225. #[no_mangle]
  226. pub extern "C" fn feof(stream: &mut FILE) -> c_int {
  227. flockfile(stream);
  228. let ret = stream.flags & F_EOF;
  229. funlockfile(stream);
  230. ret
  231. }
  232. /// Check for ERR
  233. #[no_mangle]
  234. pub extern "C" fn ferror(stream: &mut FILE) -> c_int {
  235. flockfile(stream);
  236. let ret = stream.flags & F_ERR;
  237. funlockfile(stream);
  238. ret
  239. }
  240. /// Flush output to stream, or sync read position
  241. /// Ensure the file is unlocked before calling this function, as it will attempt to lock the file
  242. /// itself.
  243. #[no_mangle]
  244. pub unsafe extern "C" fn fflush(stream: &mut FILE) -> c_int {
  245. flockfile(stream);
  246. let ret = helpers::fflush_unlocked(stream);
  247. funlockfile(stream);
  248. ret
  249. }
  250. /// Get a single char from a stream
  251. #[no_mangle]
  252. pub extern "C" fn fgetc(stream: &mut FILE) -> c_int {
  253. flockfile(stream);
  254. let c = getc_unlocked(stream);
  255. funlockfile(stream);
  256. c
  257. }
  258. /// Get the position of the stream and store it in pos
  259. #[no_mangle]
  260. pub extern "C" fn fgetpos(stream: &mut FILE, pos: *mut fpos_t) -> c_int {
  261. let off = internal::ftello(stream);
  262. if off < 0 {
  263. return -1;
  264. }
  265. unsafe {
  266. (*pos) = off;
  267. }
  268. 0
  269. }
  270. /// Get a string from the stream
  271. #[no_mangle]
  272. pub extern "C" fn fgets(s: *mut c_char, n: c_int, stream: &mut FILE) -> *mut c_char {
  273. use platform::c_str_n_mut;
  274. flockfile(stream);
  275. let st = unsafe { c_str_n_mut(s, n as usize) };
  276. // We can only fit one or less chars in
  277. if n <= 1 {
  278. funlockfile(stream);
  279. if n == 0 {
  280. return ptr::null_mut();
  281. }
  282. unsafe {
  283. (*s) = b'\0' as i8;
  284. }
  285. return s;
  286. }
  287. // Scope this so we can reuse stream mutably
  288. {
  289. // We can't read from this stream
  290. if !stream.can_read() {
  291. return ptr::null_mut();
  292. }
  293. }
  294. if let Some((rpos, rend)) = stream.read {
  295. let mut diff = 0;
  296. for (_, mut c) in stream.buf[rpos..rend]
  297. .iter()
  298. .enumerate()
  299. .take_while(|&(i, c)| *c != b'\n' && i < n as usize)
  300. {
  301. st[diff] = *c;
  302. diff += 1;
  303. }
  304. stream.read = Some((rpos + diff, rend));
  305. } else {
  306. return ptr::null_mut();
  307. }
  308. funlockfile(stream);
  309. s
  310. }
  311. /// Get the underlying file descriptor
  312. #[no_mangle]
  313. pub extern "C" fn fileno(stream: &mut FILE) -> c_int {
  314. flockfile(stream);
  315. funlockfile(stream);
  316. stream.fd
  317. }
  318. /// Lock the file
  319. /// Do not call any functions other than those with the `_unlocked` postfix while the file is
  320. /// locked
  321. #[no_mangle]
  322. pub extern "C" fn flockfile(file: &mut FILE) {
  323. while ftrylockfile(file) != 0 {}
  324. }
  325. /// Open the file in mode `mode`
  326. #[no_mangle]
  327. pub extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
  328. use core::ptr;
  329. let initial_mode = unsafe { *mode };
  330. if initial_mode != b'r' as i8 && initial_mode != b'w' as i8 && initial_mode != b'a' as i8 {
  331. unsafe { platform::errno = errno::EINVAL };
  332. return ptr::null_mut();
  333. }
  334. let flags = unsafe { helpers::parse_mode_flags(mode) };
  335. let fd = fcntl::sys_open(filename, flags, 0o666);
  336. if fd < 0 {
  337. return ptr::null_mut();
  338. }
  339. if flags & fcntl::O_CLOEXEC > 0 {
  340. fcntl::sys_fcntl(fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
  341. }
  342. let f = unsafe { helpers::_fdopen(fd, mode) };
  343. if let Some(mut fi) = f {
  344. &mut fi
  345. } else {
  346. platform::close(fd);
  347. return ptr::null_mut();
  348. }
  349. }
  350. /// Insert a character into the stream
  351. #[no_mangle]
  352. pub extern "C" fn fputc(c: c_int, stream: &mut FILE) -> c_int {
  353. flockfile(stream);
  354. let c = putc_unlocked(c, stream);
  355. funlockfile(stream);
  356. c
  357. }
  358. /// Insert a string into a stream
  359. #[no_mangle]
  360. pub extern "C" fn fputs(s: *const c_char, stream: &mut FILE) -> c_int {
  361. extern "C" {
  362. fn strlen(s: *const c_char) -> size_t;
  363. }
  364. let len = unsafe { strlen(s) };
  365. (fwrite(s as *const c_void, 1, len, stream) == len) as c_int - 1
  366. }
  367. /// Read `nitems` of size `size` into `ptr` from `stream`
  368. #[no_mangle]
  369. pub extern "C" fn fread(ptr: *mut c_void, size: usize, nitems: usize, stream: &mut FILE) -> usize {
  370. use core::ptr::copy_nonoverlapping;
  371. use core::slice;
  372. let mut dest = ptr as *mut u8;
  373. let len = size * nitems;
  374. let mut l = len as isize;
  375. flockfile(stream);
  376. if !stream.can_read() {
  377. return 0;
  378. }
  379. if let Some((rpos, rend)) = stream.read {
  380. if rend > rpos {
  381. // We have some buffered data that can be read
  382. let diff = rend - rpos;
  383. let k = if diff < l as usize { diff } else { l as usize };
  384. unsafe {
  385. // Copy data
  386. copy_nonoverlapping(&stream.buf[rpos..] as *const _ as *const u8, dest, k);
  387. // Reposition pointers
  388. dest = dest.add(k);
  389. }
  390. stream.read = Some((rpos + k, rend));
  391. l -= k as isize;
  392. }
  393. while l > 0 {
  394. let k = if !stream.can_read() {
  395. 0
  396. } else {
  397. stream.read(unsafe { slice::from_raw_parts_mut(dest, l as usize) })
  398. };
  399. if k == 0 {
  400. funlockfile(stream);
  401. return (len - l as usize) / 2;
  402. }
  403. l -= k as isize;
  404. unsafe {
  405. // Reposition
  406. dest = dest.add(k);
  407. }
  408. }
  409. funlockfile(stream);
  410. nitems
  411. } else {
  412. unreachable!()
  413. }
  414. }
  415. #[no_mangle]
  416. pub extern "C" fn freopen(
  417. filename: *const c_char,
  418. mode: *const c_char,
  419. stream: &mut FILE,
  420. ) -> *mut FILE {
  421. let mut flags = unsafe { helpers::parse_mode_flags(mode) };
  422. flockfile(stream);
  423. helpers::fflush_unlocked(stream);
  424. if filename.is_null() {
  425. // Reopen stream in new mode
  426. if flags & fcntl::O_CLOEXEC > 0 {
  427. fcntl::sys_fcntl(stream.fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
  428. }
  429. flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC);
  430. if fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags) < 0 {
  431. funlockfile(stream);
  432. fclose(stream);
  433. return ptr::null_mut();
  434. }
  435. } else {
  436. let new = fopen(filename, mode);
  437. if new.is_null() {
  438. funlockfile(stream);
  439. fclose(stream);
  440. return ptr::null_mut();
  441. }
  442. let new = unsafe { &mut *new }; // Should be safe, new is not null
  443. if new.fd == stream.fd {
  444. new.fd = -1;
  445. } else if platform::dup2(new.fd, stream.fd) < 0
  446. || fcntl::sys_fcntl(stream.fd, fcntl::F_SETFL, flags & fcntl::O_CLOEXEC) < 0
  447. {
  448. fclose(new);
  449. funlockfile(stream);
  450. fclose(stream);
  451. return ptr::null_mut();
  452. }
  453. stream.flags = (stream.flags & constants::F_PERM) | new.flags;
  454. fclose(new);
  455. }
  456. funlockfile(stream);
  457. stream
  458. }
  459. /// Seek to an offset `offset` from `whence`
  460. #[no_mangle]
  461. pub extern "C" fn fseek(stream: &mut FILE, offset: c_long, whence: c_int) -> c_int {
  462. if fseeko(stream, offset as off_t, whence) != -1 {
  463. return 0;
  464. }
  465. -1
  466. }
  467. /// Seek to an offset `offset` from `whence`
  468. #[no_mangle]
  469. pub extern "C" fn fseeko(stream: &mut FILE, offset: off_t, whence: c_int) -> c_int {
  470. let mut off = offset;
  471. flockfile(stream);
  472. // Adjust for what is currently in the buffer
  473. let rdiff = if let Some((rpos, rend)) = stream.read {
  474. rend - rpos
  475. } else {
  476. 0
  477. };
  478. if whence == SEEK_CUR {
  479. off -= (rdiff) as i64;
  480. }
  481. if let Some(_) = stream.write {
  482. stream.write(&[]);
  483. }
  484. stream.write = None;
  485. if stream.seek(off, whence) < 0 {
  486. return -1;
  487. }
  488. stream.read = None;
  489. stream.flags &= !F_EOF;
  490. funlockfile(stream);
  491. 0
  492. }
  493. /// Seek to a position `pos` in the file from the beginning of the file
  494. #[no_mangle]
  495. pub unsafe extern "C" fn fsetpos(stream: &mut FILE, pos: *const fpos_t) -> c_int {
  496. fseek(stream, *pos as off_t, SEEK_SET)
  497. }
  498. /// Get the current position of the cursor in the file
  499. #[no_mangle]
  500. pub extern "C" fn ftell(stream: &mut FILE) -> c_long {
  501. ftello(stream) as c_long
  502. }
  503. /// Get the current position of the cursor in the file
  504. #[no_mangle]
  505. pub extern "C" fn ftello(stream: &mut FILE) -> off_t {
  506. flockfile(stream);
  507. let pos = internal::ftello(stream);
  508. funlockfile(stream);
  509. pos
  510. }
  511. /// Try to lock the file. Returns 0 for success, 1 for failure
  512. #[no_mangle]
  513. pub extern "C" fn ftrylockfile(file: &mut FILE) -> c_int {
  514. file.lock.compare_and_swap(false, true, Ordering::Acquire) as c_int
  515. }
  516. /// Unlock the file
  517. #[no_mangle]
  518. pub extern "C" fn funlockfile(file: &mut FILE) {
  519. file.lock.store(false, Ordering::Release);
  520. }
  521. /// Write `nitems` of size `size` from `ptr` to `stream`
  522. #[no_mangle]
  523. pub extern "C" fn fwrite(
  524. ptr: *const c_void,
  525. size: usize,
  526. nitems: usize,
  527. stream: &mut FILE,
  528. ) -> usize {
  529. let l = size * nitems;
  530. let nitems = if size == 0 { 0 } else { nitems };
  531. flockfile(stream);
  532. let k = helpers::fwritex(ptr as *const u8, l, stream);
  533. funlockfile(stream);
  534. if k == l {
  535. nitems
  536. } else {
  537. k / size
  538. }
  539. }
  540. /// Get a single char from a stream
  541. #[no_mangle]
  542. pub extern "C" fn getc(stream: &mut FILE) -> c_int {
  543. flockfile(stream);
  544. let c = getc_unlocked(stream);
  545. funlockfile(stream);
  546. c
  547. }
  548. /// Get a single char from `stdin`
  549. #[no_mangle]
  550. pub extern "C" fn getchar() -> c_int {
  551. fgetc(unsafe { &mut *stdin })
  552. }
  553. /// Get a char from a stream without locking the stream
  554. #[no_mangle]
  555. pub extern "C" fn getc_unlocked(stream: &mut FILE) -> c_int {
  556. if !stream.can_read() {
  557. return -1;
  558. }
  559. if let Some((rpos, rend)) = stream.read {
  560. if rpos < rend {
  561. let ret = stream.buf[rpos] as c_int;
  562. stream.read = Some((rpos + 1, rend));
  563. ret
  564. } else {
  565. let mut c = [0u8; 1];
  566. if stream.read(&mut c) == 1 {
  567. c[0] as c_int
  568. } else {
  569. -1
  570. }
  571. }
  572. } else {
  573. // We made a prior call to can_read() and are checking it, therefore we
  574. // should never be in a case where stream.read is None
  575. // -- Tommoa (20/6/2018)
  576. unreachable!()
  577. }
  578. }
  579. /// Get a char from `stdin` without locking `stdin`
  580. #[no_mangle]
  581. pub extern "C" fn getchar_unlocked() -> c_int {
  582. getc_unlocked(unsafe { &mut *stdin })
  583. }
  584. /// Get a string from `stdin`
  585. #[no_mangle]
  586. pub extern "C" fn gets(s: *mut c_char) -> *mut c_char {
  587. use core::i32;
  588. fgets(s, i32::MAX, unsafe { &mut *stdin })
  589. }
  590. /// Get an integer from `stream`
  591. #[no_mangle]
  592. pub extern "C" fn getw(stream: &mut FILE) -> c_int {
  593. use core::mem;
  594. let mut ret: c_int = 0;
  595. if fread(
  596. &mut ret as *mut c_int as *mut c_void,
  597. mem::size_of_val(&ret),
  598. 1,
  599. stream,
  600. ) > 0
  601. {
  602. ret
  603. } else {
  604. -1
  605. }
  606. }
  607. #[no_mangle]
  608. pub extern "C" fn pclose(_stream: &mut FILE) -> c_int {
  609. unimplemented!();
  610. }
  611. #[no_mangle]
  612. pub unsafe extern "C" fn perror(s: *const c_char) {
  613. let s_str = str::from_utf8_unchecked(c_str(s));
  614. let mut w = platform::FileWriter(2);
  615. if errno >= 0 && errno < STR_ERROR.len() as c_int {
  616. w.write_fmt(format_args!("{}: {}\n", s_str, STR_ERROR[errno as usize]))
  617. .unwrap();
  618. } else {
  619. w.write_fmt(format_args!("{}: Unknown error {}\n", s_str, errno))
  620. .unwrap();
  621. }
  622. }
  623. #[no_mangle]
  624. pub extern "C" fn popen(_command: *const c_char, _mode: *const c_char) -> *mut FILE {
  625. unimplemented!();
  626. }
  627. /// Put a character `c` into `stream`
  628. #[no_mangle]
  629. pub extern "C" fn putc(c: c_int, stream: &mut FILE) -> c_int {
  630. flockfile(stream);
  631. let ret = putc_unlocked(c, stream);
  632. funlockfile(stream);
  633. ret
  634. }
  635. /// Put a character `c` into `stdout`
  636. #[no_mangle]
  637. pub extern "C" fn putchar(c: c_int) -> c_int {
  638. fputc(c, unsafe { &mut *stdout })
  639. }
  640. /// Put a character `c` into `stream` without locking `stream`
  641. #[no_mangle]
  642. pub extern "C" fn putc_unlocked(c: c_int, stream: &mut FILE) -> c_int {
  643. if stream.can_write() {
  644. if let Some((wbase, wpos, wend)) = stream.write {
  645. if c as i8 != stream.buf_char {
  646. stream.buf[wpos] = c as u8;
  647. stream.write = Some((wbase, wpos + 1, wend));
  648. c
  649. } else if stream.write(&[c as u8]) == 1 {
  650. c
  651. } else {
  652. -1
  653. }
  654. } else {
  655. -1
  656. }
  657. } else {
  658. -1
  659. }
  660. }
  661. /// Put a character `c` into `stdout` without locking `stdout`
  662. #[no_mangle]
  663. pub extern "C" fn putchar_unlocked(c: c_int) -> c_int {
  664. putc_unlocked(c, unsafe { &mut *stdout })
  665. }
  666. /// Put a string `s` into `stdout`
  667. #[no_mangle]
  668. pub extern "C" fn puts(s: *const c_char) -> c_int {
  669. let ret = (fputs(s, unsafe { &mut *stdout }) > 0) || (putchar_unlocked(b'\n' as c_int) > 0);
  670. if ret {
  671. 0
  672. } else {
  673. -1
  674. }
  675. }
  676. /// Put an integer `w` into `stream`
  677. #[no_mangle]
  678. pub extern "C" fn putw(w: c_int, stream: &mut FILE) -> c_int {
  679. use core::mem;
  680. fwrite(&w as *const i32 as _, mem::size_of_val(&w), 1, stream) as i32 - 1
  681. }
  682. /// Delete file or directory `path`
  683. #[no_mangle]
  684. pub extern "C" fn remove(path: *const c_char) -> c_int {
  685. let r = platform::unlink(path);
  686. if r == -errno::EISDIR {
  687. platform::rmdir(path)
  688. } else {
  689. r
  690. }
  691. }
  692. #[no_mangle]
  693. pub extern "C" fn rename(oldpath: *const c_char, newpath: *const c_char) -> c_int {
  694. platform::rename(oldpath, newpath)
  695. }
  696. /// Rewind `stream` back to the beginning of it
  697. #[no_mangle]
  698. pub extern "C" fn rewind(stream: &mut FILE) {
  699. fseeko(stream, 0, SEEK_SET);
  700. flockfile(stream);
  701. stream.flags &= !F_ERR;
  702. funlockfile(stream);
  703. }
  704. /// Reset `stream` to use buffer `buf`. Buffer must be `BUFSIZ` in length
  705. #[no_mangle]
  706. pub extern "C" fn setbuf(stream: &mut FILE, buf: *mut c_char) {
  707. setvbuf(
  708. stream,
  709. buf,
  710. if buf.is_null() { _IONBF } else { _IOFBF },
  711. BUFSIZ as usize,
  712. );
  713. }
  714. /// Reset `stream` to use buffer `buf` of size `size`
  715. /// If this isn't the meaning of unsafe, idk what is
  716. #[no_mangle]
  717. pub extern "C" fn setvbuf(stream: &mut FILE, buf: *mut c_char, mode: c_int, size: usize) -> c_int {
  718. // Set a buffer of size `size` if no buffer is given
  719. let buf = if buf.is_null() {
  720. if mode != _IONBF {
  721. vec![0u8; 1]
  722. } else {
  723. Vec::new()
  724. }
  725. } else {
  726. // We trust the user on this one
  727. // -- Tommoa (20/6/2018)
  728. unsafe { Vec::from_raw_parts(buf as *mut u8, size, size) }
  729. };
  730. stream.buf_char = -1;
  731. if mode == _IOLBF {
  732. stream.buf_char = b'\n' as i8;
  733. }
  734. stream.flags |= F_SVB;
  735. stream.buf = buf;
  736. 0
  737. }
  738. #[no_mangle]
  739. pub extern "C" fn tempnam(_dir: *const c_char, _pfx: *const c_char) -> *mut c_char {
  740. unimplemented!();
  741. }
  742. #[no_mangle]
  743. pub extern "C" fn tmpfile() -> *mut FILE {
  744. unimplemented!();
  745. }
  746. #[no_mangle]
  747. pub extern "C" fn tmpnam(_s: *mut c_char) -> *mut c_char {
  748. unimplemented!();
  749. }
  750. /// Push character `c` back onto `stream` so it'll be read next
  751. #[no_mangle]
  752. pub extern "C" fn ungetc(c: c_int, stream: &mut FILE) -> c_int {
  753. if c < 0 {
  754. c
  755. } else {
  756. flockfile(stream);
  757. if stream.read.is_none() {
  758. stream.can_read();
  759. }
  760. if let Some((rpos, rend)) = stream.read {
  761. if rpos == 0 {
  762. funlockfile(stream);
  763. return -1;
  764. }
  765. stream.read = Some((rpos - 1, rend));
  766. stream.buf[rpos - 1] = c as u8;
  767. stream.flags &= !F_EOF;
  768. funlockfile(stream);
  769. c
  770. } else {
  771. funlockfile(stream);
  772. -1
  773. }
  774. }
  775. }
  776. #[no_mangle]
  777. pub unsafe extern "C" fn vfprintf(file: &mut FILE, format: *const c_char, ap: va_list) -> c_int {
  778. printf::printf(file, format, ap)
  779. }
  780. #[no_mangle]
  781. pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int {
  782. vfprintf(&mut *stdout, format, ap)
  783. }
  784. #[no_mangle]
  785. pub unsafe extern "C" fn vsnprintf(
  786. s: *mut c_char,
  787. n: usize,
  788. format: *const c_char,
  789. ap: va_list,
  790. ) -> c_int {
  791. printf::printf(
  792. &mut platform::StringWriter(s as *mut u8, n as usize),
  793. format,
  794. ap,
  795. )
  796. }
  797. #[no_mangle]
  798. pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_list) -> c_int {
  799. printf::printf(&mut platform::UnsafeStringWriter(s as *mut u8), format, ap)
  800. }
  801. #[no_mangle]
  802. pub unsafe extern "C" fn vfscanf(file: &mut FILE, format: *const c_char, ap: va_list) -> c_int {
  803. scanf::scanf(file, format, ap)
  804. }
  805. #[no_mangle]
  806. pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
  807. vfscanf(&mut *stdin, format, ap)
  808. }
  809. #[no_mangle]
  810. pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int {
  811. scanf::scanf(&mut platform::UnsafeStringReader(s as *const u8), format, ap)
  812. }