mod.rs 26 KB

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