mod.rs 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177
  1. //! stdio implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdio.h.html
  2. use alloc::{
  3. borrow::{Borrow, BorrowMut},
  4. boxed::Box,
  5. vec::Vec,
  6. };
  7. use core::{
  8. cmp,
  9. ffi::VaList as va_list,
  10. fmt::{self, Write as WriteFmt},
  11. i32, mem,
  12. ops::{Deref, DerefMut},
  13. ptr, slice, str,
  14. };
  15. use crate::{
  16. c_str::CStr,
  17. c_vec::CVec,
  18. fs::File,
  19. header::{
  20. errno::{self, STR_ERROR},
  21. fcntl, stdlib,
  22. string::{self, strlen},
  23. unistd,
  24. },
  25. io::{self, BufRead, BufWriter, LineWriter, Read, Write},
  26. platform::{self, errno, types::*, Pal, Sys, WriteByte},
  27. sync::Mutex,
  28. };
  29. pub use self::constants::*;
  30. mod constants;
  31. pub use self::default::*;
  32. mod default;
  33. pub use self::getdelim::*;
  34. mod getdelim;
  35. mod ext;
  36. mod helpers;
  37. mod lookaheadreader;
  38. mod printf;
  39. mod scanf;
  40. use lookaheadreader::LookAheadReader;
  41. static mut TMPNAM_BUF: [c_char; L_tmpnam as usize + 1] = [0; L_tmpnam as usize + 1];
  42. enum Buffer<'a> {
  43. Borrowed(&'a mut [u8]),
  44. Owned(Vec<u8>),
  45. }
  46. impl<'a> Deref for Buffer<'a> {
  47. type Target = [u8];
  48. fn deref(&self) -> &Self::Target {
  49. match self {
  50. Buffer::Borrowed(inner) => inner,
  51. Buffer::Owned(inner) => inner.borrow(),
  52. }
  53. }
  54. }
  55. impl<'a> DerefMut for Buffer<'a> {
  56. fn deref_mut(&mut self) -> &mut Self::Target {
  57. match self {
  58. Buffer::Borrowed(inner) => inner,
  59. Buffer::Owned(inner) => inner.borrow_mut(),
  60. }
  61. }
  62. }
  63. pub trait Pending {
  64. fn pending(&self) -> size_t;
  65. }
  66. impl<W: core_io::Write> Pending for BufWriter<W> {
  67. fn pending(&self) -> size_t {
  68. self.buf.len() as size_t
  69. }
  70. }
  71. impl<W: core_io::Write> Pending for LineWriter<W> {
  72. fn pending(&self) -> size_t {
  73. self.inner.buf.len() as size_t
  74. }
  75. }
  76. pub trait Writer: Write + Pending {}
  77. impl<W: core_io::Write> Writer for BufWriter<W> {}
  78. impl<W: core_io::Write> Writer for LineWriter<W> {}
  79. /// This struct gets exposed to the C API.
  80. pub struct FILE {
  81. lock: Mutex<()>,
  82. file: File,
  83. // pub for stdio_ext
  84. pub(crate) flags: c_int,
  85. read_buf: Buffer<'static>,
  86. read_pos: usize,
  87. read_size: usize,
  88. unget: Vec<u8>,
  89. // pub for stdio_ext
  90. pub(crate) writer: Box<dyn Writer + Send>,
  91. // Optional pid for use with popen/pclose
  92. pid: Option<c_int>,
  93. // wchar support
  94. pub(crate) orientation: c_int,
  95. }
  96. impl Read for FILE {
  97. fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
  98. let unget_read_size = cmp::min(out.len(), self.unget.len());
  99. for i in 0..unget_read_size {
  100. out[i] = self.unget.pop().unwrap();
  101. }
  102. if unget_read_size != 0 {
  103. return Ok(unget_read_size);
  104. }
  105. let len = {
  106. let buf = self.fill_buf()?;
  107. let len = buf.len().min(out.len());
  108. out[..len].copy_from_slice(&buf[..len]);
  109. len
  110. };
  111. self.consume(len);
  112. Ok(len)
  113. }
  114. }
  115. impl BufRead for FILE {
  116. fn fill_buf(&mut self) -> io::Result<&[u8]> {
  117. if self.read_pos == self.read_size {
  118. self.read_size = match self.file.read(&mut self.read_buf) {
  119. Ok(0) => {
  120. self.flags |= F_EOF;
  121. 0
  122. }
  123. Ok(n) => n,
  124. Err(err) => {
  125. self.flags |= F_ERR;
  126. return Err(err);
  127. }
  128. };
  129. self.read_pos = 0;
  130. }
  131. Ok(&self.read_buf[self.read_pos..self.read_size])
  132. }
  133. fn consume(&mut self, i: usize) {
  134. self.read_pos = (self.read_pos + i).min(self.read_size);
  135. }
  136. }
  137. impl Write for FILE {
  138. fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  139. match self.writer.write(buf) {
  140. Ok(n) => Ok(n),
  141. Err(err) => {
  142. self.flags |= F_ERR;
  143. Err(err)
  144. }
  145. }
  146. }
  147. fn flush(&mut self) -> io::Result<()> {
  148. match self.writer.flush() {
  149. Ok(()) => Ok(()),
  150. Err(err) => {
  151. self.flags |= F_ERR;
  152. Err(err)
  153. }
  154. }
  155. }
  156. }
  157. impl WriteFmt for FILE {
  158. fn write_str(&mut self, s: &str) -> fmt::Result {
  159. self.write_all(s.as_bytes())
  160. .map(|_| ())
  161. .map_err(|_| fmt::Error)
  162. }
  163. }
  164. impl WriteByte for FILE {
  165. fn write_u8(&mut self, c: u8) -> fmt::Result {
  166. self.write_all(&[c]).map(|_| ()).map_err(|_| fmt::Error)
  167. }
  168. }
  169. impl FILE {
  170. pub fn lock(&mut self) -> LockGuard {
  171. unsafe {
  172. flockfile(self);
  173. }
  174. LockGuard(self)
  175. }
  176. pub fn try_set_orientation(&mut self, mode: c_int) -> c_int {
  177. let stream = self.lock();
  178. stream.0.try_set_orientation_unlocked(mode)
  179. }
  180. pub fn try_set_orientation_unlocked(&mut self, mode: c_int) -> c_int {
  181. if self.orientation == 0 {
  182. self.orientation = match mode {
  183. 1..=i32::MAX => 1,
  184. i32::MIN..=-1 => -1,
  185. 0 => self.orientation,
  186. };
  187. }
  188. self.orientation
  189. }
  190. pub fn try_set_byte_orientation_unlocked(&mut self) -> core::result::Result<(), c_int> {
  191. match self.try_set_orientation_unlocked(-1) {
  192. i32::MIN..=-1 => Ok(()),
  193. x => Err(x),
  194. }
  195. }
  196. }
  197. pub struct LockGuard<'a>(&'a mut FILE);
  198. impl<'a> Deref for LockGuard<'a> {
  199. type Target = FILE;
  200. fn deref(&self) -> &Self::Target {
  201. &self.0
  202. }
  203. }
  204. impl<'a> DerefMut for LockGuard<'a> {
  205. fn deref_mut(&mut self) -> &mut Self::Target {
  206. self.0
  207. }
  208. }
  209. impl<'a> Drop for LockGuard<'a> {
  210. fn drop(&mut self) {
  211. unsafe {
  212. funlockfile(self.0);
  213. }
  214. }
  215. }
  216. /// Clears EOF and ERR indicators on a stream
  217. #[no_mangle]
  218. pub unsafe extern "C" fn clearerr(stream: *mut FILE) {
  219. let mut stream = (*stream).lock();
  220. stream.flags &= !(F_EOF | F_ERR);
  221. }
  222. // #[no_mangle]
  223. pub extern "C" fn ctermid(_s: *mut c_char) -> *mut c_char {
  224. unimplemented!();
  225. }
  226. // #[no_mangle]
  227. pub extern "C" fn cuserid(_s: *mut c_char) -> *mut c_char {
  228. unimplemented!();
  229. }
  230. /// Close a file
  231. /// This function does not guarentee that the file buffer will be flushed or that the file
  232. /// descriptor will be closed, so if it is important that the file be written to, use `fflush()`
  233. /// prior to using this function.
  234. #[no_mangle]
  235. pub unsafe extern "C" fn fclose(stream: *mut FILE) -> c_int {
  236. let stream = &mut *stream;
  237. flockfile(stream);
  238. let mut r = stream.flush().is_err();
  239. let close = Sys::close(*stream.file) < 0;
  240. r = r || close;
  241. if stream.flags & constants::F_PERM == 0 {
  242. // Not one of stdin, stdout or stderr
  243. let mut stream = Box::from_raw(stream);
  244. // Reference files aren't closed on drop, so pretend to be a reference
  245. stream.file.reference = true;
  246. } else {
  247. funlockfile(stream);
  248. }
  249. r as c_int
  250. }
  251. /// Open a file from a file descriptor
  252. #[no_mangle]
  253. pub unsafe extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE {
  254. if let Some(f) = helpers::_fdopen(fildes, mode) {
  255. f
  256. } else {
  257. ptr::null_mut()
  258. }
  259. }
  260. /// Check for EOF
  261. #[no_mangle]
  262. pub unsafe extern "C" fn feof(stream: *mut FILE) -> c_int {
  263. let stream = (*stream).lock();
  264. stream.flags & F_EOF
  265. }
  266. /// Check for ERR
  267. #[no_mangle]
  268. pub unsafe extern "C" fn ferror(stream: *mut FILE) -> c_int {
  269. let stream = (*stream).lock();
  270. stream.flags & F_ERR
  271. }
  272. /// Flush output to stream, or sync read position
  273. /// Ensure the file is unlocked before calling this function, as it will attempt to lock the file
  274. /// itself.
  275. #[no_mangle]
  276. pub unsafe extern "C" fn fflush(stream: *mut FILE) -> c_int {
  277. if stream.is_null() {
  278. //TODO: flush all files!
  279. if fflush(stdout) != 0 {
  280. return EOF;
  281. }
  282. if fflush(stderr) != 0 {
  283. return EOF;
  284. }
  285. } else {
  286. let mut stream = (*stream).lock();
  287. if stream.flush().is_err() {
  288. return EOF;
  289. }
  290. }
  291. 0
  292. }
  293. /// Get a single char from a stream
  294. #[no_mangle]
  295. pub unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int {
  296. let mut stream = (*stream).lock();
  297. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  298. return -1;
  299. }
  300. getc_unlocked(&mut *stream)
  301. }
  302. /// Get the position of the stream and store it in pos
  303. #[no_mangle]
  304. pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int {
  305. let off = ftello(stream);
  306. if off < 0 {
  307. return -1;
  308. }
  309. *pos = off;
  310. 0
  311. }
  312. /// Get a string from the stream
  313. #[no_mangle]
  314. pub unsafe extern "C" fn fgets(
  315. original: *mut c_char,
  316. max: c_int,
  317. stream: *mut FILE,
  318. ) -> *mut c_char {
  319. let mut stream = (*stream).lock();
  320. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  321. return ptr::null_mut();
  322. }
  323. let mut out = original;
  324. let max = max as usize;
  325. let mut left = max.saturating_sub(1); // Make space for the terminating NUL-byte
  326. let mut wrote = false;
  327. if left >= 1 {
  328. let unget_read_size = cmp::min(left, stream.unget.len());
  329. for _ in 0..unget_read_size {
  330. *out = stream.unget.pop().unwrap() as i8;
  331. out = out.offset(1);
  332. }
  333. left -= unget_read_size;
  334. }
  335. loop {
  336. if left == 0 {
  337. break;
  338. }
  339. // TODO: When NLL is a thing, this block can be flattened out
  340. let (read, exit) = {
  341. let buf = match stream.fill_buf() {
  342. Ok(buf) => buf,
  343. Err(_) => return ptr::null_mut(),
  344. };
  345. if buf.is_empty() {
  346. break;
  347. }
  348. wrote = true;
  349. let len = buf.len().min(left);
  350. let newline = buf[..len].iter().position(|&c| c == b'\n');
  351. let len = newline.map(|i| i + 1).unwrap_or(len);
  352. ptr::copy_nonoverlapping(buf.as_ptr(), out as *mut u8, len);
  353. (len, newline.is_some())
  354. };
  355. stream.consume(read);
  356. out = out.add(read);
  357. left -= read;
  358. if exit {
  359. break;
  360. }
  361. }
  362. if max >= 1 {
  363. // Write the NUL byte
  364. *out = 0;
  365. }
  366. if wrote {
  367. original
  368. } else {
  369. ptr::null_mut()
  370. }
  371. }
  372. /// Get the underlying file descriptor
  373. #[no_mangle]
  374. pub unsafe extern "C" fn fileno(stream: *mut FILE) -> c_int {
  375. let stream = (*stream).lock();
  376. *stream.file
  377. }
  378. /// Lock the file
  379. /// Do not call any functions other than those with the `_unlocked` postfix while the file is
  380. /// locked
  381. #[no_mangle]
  382. pub unsafe extern "C" fn flockfile(file: *mut FILE) {
  383. (*file).lock.manual_lock();
  384. }
  385. /// Open the file in mode `mode`
  386. #[no_mangle]
  387. pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
  388. let initial_mode = *mode;
  389. if initial_mode != b'r' as i8 && initial_mode != b'w' as i8 && initial_mode != b'a' as i8 {
  390. platform::errno = errno::EINVAL;
  391. return ptr::null_mut();
  392. }
  393. let flags = helpers::parse_mode_flags(mode);
  394. let new_mode = if flags & fcntl::O_CREAT == fcntl::O_CREAT {
  395. 0o666
  396. } else {
  397. 0
  398. };
  399. let fd = fcntl::sys_open(filename, flags, new_mode);
  400. if fd < 0 {
  401. return ptr::null_mut();
  402. }
  403. if flags & fcntl::O_CLOEXEC > 0 {
  404. fcntl::sys_fcntl(fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
  405. }
  406. if let Some(f) = helpers::_fdopen(fd, mode) {
  407. f
  408. } else {
  409. Sys::close(fd);
  410. ptr::null_mut()
  411. }
  412. }
  413. /// Insert a character into the stream
  414. #[no_mangle]
  415. pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
  416. let mut stream = (*stream).lock();
  417. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  418. return -1;
  419. }
  420. putc_unlocked(c, &mut *stream)
  421. }
  422. /// Insert a string into a stream
  423. #[no_mangle]
  424. pub unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int {
  425. let mut stream = (*stream).lock();
  426. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  427. return -1;
  428. }
  429. let buf = slice::from_raw_parts(s as *mut u8, strlen(s));
  430. if stream.write_all(&buf).is_ok() {
  431. 0
  432. } else {
  433. -1
  434. }
  435. }
  436. /// Read `nitems` of size `size` into `ptr` from `stream`
  437. #[no_mangle]
  438. pub unsafe extern "C" fn fread(
  439. ptr: *mut c_void,
  440. size: size_t,
  441. nitems: size_t,
  442. stream: *mut FILE,
  443. ) -> size_t {
  444. if size == 0 || nitems == 0 {
  445. return 0;
  446. }
  447. let mut stream = (*stream).lock();
  448. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  449. return 0;
  450. }
  451. let buf = slice::from_raw_parts_mut(ptr as *mut u8, size as usize * nitems as usize);
  452. let mut read = 0;
  453. while read < buf.len() {
  454. match stream.read(&mut buf[read..]) {
  455. Ok(0) | Err(_) => break,
  456. Ok(n) => read += n,
  457. }
  458. }
  459. (read / size as usize) as size_t
  460. }
  461. #[no_mangle]
  462. pub unsafe extern "C" fn freopen(
  463. filename: *const c_char,
  464. mode: *const c_char,
  465. stream: &mut FILE,
  466. ) -> *mut FILE {
  467. let mut flags = helpers::parse_mode_flags(mode);
  468. flockfile(stream);
  469. let _ = stream.flush();
  470. if filename.is_null() {
  471. // Reopen stream in new mode
  472. if flags & fcntl::O_CLOEXEC > 0 {
  473. fcntl::sys_fcntl(*stream.file, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
  474. }
  475. flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC);
  476. if fcntl::sys_fcntl(*stream.file, fcntl::F_SETFL, flags) < 0 {
  477. funlockfile(stream);
  478. fclose(stream);
  479. return ptr::null_mut();
  480. }
  481. } else {
  482. let new = fopen(filename, mode);
  483. if new.is_null() {
  484. funlockfile(stream);
  485. fclose(stream);
  486. return ptr::null_mut();
  487. }
  488. let new = &mut *new; // Should be safe, new is not null
  489. if *new.file == *stream.file {
  490. new.file.fd = -1;
  491. } else if Sys::dup2(*new.file, *stream.file) < 0
  492. || fcntl::sys_fcntl(*stream.file, fcntl::F_SETFL, flags & fcntl::O_CLOEXEC) < 0
  493. {
  494. funlockfile(stream);
  495. fclose(new);
  496. fclose(stream);
  497. return ptr::null_mut();
  498. }
  499. stream.flags = (stream.flags & constants::F_PERM) | new.flags;
  500. fclose(new);
  501. }
  502. stream.orientation = 0;
  503. funlockfile(stream);
  504. stream
  505. }
  506. /// Seek to an offset `offset` from `whence`
  507. #[no_mangle]
  508. pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int {
  509. fseeko(stream, offset as off_t, whence)
  510. }
  511. /// Seek to an offset `offset` from `whence`
  512. #[no_mangle]
  513. pub unsafe extern "C" fn fseeko(stream: *mut FILE, off: off_t, whence: c_int) -> c_int {
  514. let mut stream = (*stream).lock();
  515. fseek_locked(&mut *stream, off, whence)
  516. }
  517. pub unsafe fn fseek_locked(stream: &mut FILE, mut off: off_t, whence: c_int) -> c_int {
  518. if whence == SEEK_CUR {
  519. // Since it's a buffered writer, our actual cursor isn't where the user
  520. // thinks
  521. off -= (stream.read_size - stream.read_pos) as off_t;
  522. }
  523. // Flush write buffer before seek
  524. if stream.flush().is_err() {
  525. return -1;
  526. }
  527. let err = Sys::lseek(*stream.file, off, whence);
  528. if err < 0 {
  529. return err as c_int;
  530. }
  531. stream.flags &= !(F_EOF | F_ERR);
  532. stream.read_pos = 0;
  533. stream.read_size = 0;
  534. stream.unget = Vec::new();
  535. 0
  536. }
  537. /// Seek to a position `pos` in the file from the beginning of the file
  538. #[no_mangle]
  539. pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> c_int {
  540. fseeko(stream, *pos, SEEK_SET)
  541. }
  542. /// Get the current position of the cursor in the file
  543. #[no_mangle]
  544. pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long {
  545. ftello(stream) as c_long
  546. }
  547. /// Get the current position of the cursor in the file
  548. #[no_mangle]
  549. pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t {
  550. let mut stream = (*stream).lock();
  551. ftell_locked(&mut *stream)
  552. }
  553. pub unsafe extern "C" fn ftell_locked(stream: &mut FILE) -> off_t {
  554. let pos = Sys::lseek(*stream.file, 0, SEEK_CUR);
  555. if pos < 0 {
  556. return -1;
  557. }
  558. pos - (stream.read_size - stream.read_pos) as off_t - stream.unget.len() as off_t
  559. }
  560. /// Try to lock the file. Returns 0 for success, 1 for failure
  561. #[no_mangle]
  562. pub unsafe extern "C" fn ftrylockfile(file: *mut FILE) -> c_int {
  563. if (*file).lock.manual_try_lock().is_ok() {
  564. 0
  565. } else {
  566. 1
  567. }
  568. }
  569. /// Unlock the file
  570. #[no_mangle]
  571. pub unsafe extern "C" fn funlockfile(file: *mut FILE) {
  572. (*file).lock.manual_unlock();
  573. }
  574. /// Write `nitems` of size `size` from `ptr` to `stream`
  575. #[no_mangle]
  576. pub unsafe extern "C" fn fwrite(
  577. ptr: *const c_void,
  578. size: size_t,
  579. nitems: size_t,
  580. stream: *mut FILE,
  581. ) -> size_t {
  582. if size == 0 || nitems == 0 {
  583. return 0;
  584. }
  585. let mut stream = (*stream).lock();
  586. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  587. return 0;
  588. }
  589. let buf = slice::from_raw_parts(ptr as *const u8, size as usize * nitems as usize);
  590. let mut written = 0;
  591. while written < buf.len() {
  592. match stream.write(&buf[written..]) {
  593. Ok(0) | Err(_) => break,
  594. Ok(n) => written += n,
  595. }
  596. }
  597. (written / size as usize) as size_t
  598. }
  599. /// Get a single char from a stream
  600. #[no_mangle]
  601. pub unsafe extern "C" fn getc(stream: *mut FILE) -> c_int {
  602. let mut stream = (*stream).lock();
  603. getc_unlocked(&mut *stream)
  604. }
  605. /// Get a single char from `stdin`
  606. #[no_mangle]
  607. pub unsafe extern "C" fn getchar() -> c_int {
  608. fgetc(&mut *stdin)
  609. }
  610. /// Get a char from a stream without locking the stream
  611. #[no_mangle]
  612. pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int {
  613. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  614. return -1;
  615. }
  616. let mut buf = [0];
  617. match (*stream).read(&mut buf) {
  618. Ok(0) | Err(_) => EOF,
  619. Ok(_) => buf[0] as c_int,
  620. }
  621. }
  622. /// Get a char from `stdin` without locking `stdin`
  623. #[no_mangle]
  624. pub unsafe extern "C" fn getchar_unlocked() -> c_int {
  625. getc_unlocked(&mut *stdin)
  626. }
  627. /// Get a string from `stdin`
  628. #[no_mangle]
  629. pub unsafe extern "C" fn gets(s: *mut c_char) -> *mut c_char {
  630. fgets(s, c_int::max_value(), &mut *stdin)
  631. }
  632. /// Get an integer from `stream`
  633. #[no_mangle]
  634. pub unsafe extern "C" fn getw(stream: *mut FILE) -> c_int {
  635. let mut ret: c_int = 0;
  636. if fread(
  637. &mut ret as *mut _ as *mut c_void,
  638. mem::size_of_val(&ret),
  639. 1,
  640. stream,
  641. ) > 0
  642. {
  643. ret
  644. } else {
  645. -1
  646. }
  647. }
  648. #[no_mangle]
  649. pub unsafe extern "C" fn pclose(stream: *mut FILE) -> c_int {
  650. let pid = {
  651. let mut stream = (*stream).lock();
  652. if let Some(pid) = stream.pid.take() {
  653. pid
  654. } else {
  655. errno = errno::ECHILD;
  656. return -1;
  657. }
  658. };
  659. fclose(stream);
  660. let mut wstatus = 0;
  661. if Sys::waitpid(pid, &mut wstatus, 0) < 0 {
  662. return -1;
  663. }
  664. wstatus
  665. }
  666. #[no_mangle]
  667. pub unsafe extern "C" fn perror(s: *const c_char) {
  668. let s_cstr = CStr::from_ptr(s);
  669. let s_str = str::from_utf8_unchecked(s_cstr.to_bytes());
  670. let mut w = platform::FileWriter(2);
  671. if errno >= 0 && errno < STR_ERROR.len() as c_int {
  672. w.write_fmt(format_args!("{}: {}\n", s_str, STR_ERROR[errno as usize]))
  673. .unwrap();
  674. } else {
  675. w.write_fmt(format_args!("{}: Unknown error {}\n", s_str, errno))
  676. .unwrap();
  677. }
  678. }
  679. #[no_mangle]
  680. pub unsafe extern "C" fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE {
  681. //TODO: share code with system
  682. let mode = CStr::from_ptr(mode);
  683. let mut cloexec = false;
  684. let mut write_opt = None;
  685. for b in mode.to_bytes().iter() {
  686. match b {
  687. b'e' => cloexec = true,
  688. b'r' if write_opt.is_none() => write_opt = Some(false),
  689. b'w' if write_opt.is_none() => write_opt = Some(true),
  690. _ => {
  691. errno = errno::EINVAL;
  692. return ptr::null_mut();
  693. }
  694. }
  695. }
  696. let write = match write_opt {
  697. Some(some) => some,
  698. None => {
  699. errno = errno::EINVAL;
  700. return ptr::null_mut();
  701. }
  702. };
  703. let mut pipes = [-1, -1];
  704. if unistd::pipe(pipes.as_mut_ptr()) != 0 {
  705. return ptr::null_mut();
  706. }
  707. let child_pid = unistd::fork();
  708. if child_pid == 0 {
  709. let command_nonnull = if command.is_null() {
  710. "exit 0\0".as_ptr()
  711. } else {
  712. command as *const u8
  713. };
  714. let shell = "/bin/sh\0".as_ptr();
  715. let args = [
  716. "sh\0".as_ptr(),
  717. "-c\0".as_ptr(),
  718. command_nonnull,
  719. ptr::null(),
  720. ];
  721. // Setup up stdin or stdout
  722. //TODO: dup errors are ignored, should they be?
  723. {
  724. if write {
  725. unistd::dup2(0, pipes[0]);
  726. } else {
  727. unistd::dup2(1, pipes[1]);
  728. }
  729. unistd::close(pipes[0]);
  730. unistd::close(pipes[1]);
  731. }
  732. unistd::execv(shell as *const c_char, args.as_ptr() as *const *mut c_char);
  733. stdlib::exit(127);
  734. unreachable!();
  735. } else if child_pid > 0 {
  736. let (fd, fd_mode) = if write {
  737. unistd::close(pipes[0]);
  738. (pipes[1], if cloexec { c_str!("we") } else { c_str!("w") })
  739. } else {
  740. unistd::close(pipes[1]);
  741. (pipes[0], if cloexec { c_str!("re") } else { c_str!("r") })
  742. };
  743. if let Some(f) = helpers::_fdopen(fd, fd_mode.as_ptr()) {
  744. (*f).pid = Some(child_pid);
  745. f
  746. } else {
  747. ptr::null_mut()
  748. }
  749. } else {
  750. ptr::null_mut()
  751. }
  752. }
  753. /// Put a character `c` into `stream`
  754. #[no_mangle]
  755. pub unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int {
  756. let mut stream = (*stream).lock();
  757. putc_unlocked(c, &mut *stream)
  758. }
  759. /// Put a character `c` into `stdout`
  760. #[no_mangle]
  761. pub unsafe extern "C" fn putchar(c: c_int) -> c_int {
  762. fputc(c, &mut *stdout)
  763. }
  764. /// Put a character `c` into `stream` without locking `stream`
  765. #[no_mangle]
  766. pub unsafe extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int {
  767. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  768. return -1;
  769. }
  770. match (*stream).write(&[c as u8]) {
  771. Ok(0) | Err(_) => EOF,
  772. Ok(_) => c,
  773. }
  774. }
  775. /// Put a character `c` into `stdout` without locking `stdout`
  776. #[no_mangle]
  777. pub unsafe extern "C" fn putchar_unlocked(c: c_int) -> c_int {
  778. putc_unlocked(c, stdout)
  779. }
  780. /// Put a string `s` into `stdout`
  781. #[no_mangle]
  782. pub unsafe extern "C" fn puts(s: *const c_char) -> c_int {
  783. let mut stream = (&mut *stdout).lock();
  784. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  785. return -1;
  786. }
  787. let buf = slice::from_raw_parts(s as *mut u8, strlen(s));
  788. if stream.write_all(&buf).is_err() {
  789. return -1;
  790. }
  791. if stream.write(&[b'\n']).is_err() {
  792. return -1;
  793. }
  794. 0
  795. }
  796. /// Put an integer `w` into `stream`
  797. #[no_mangle]
  798. pub unsafe extern "C" fn putw(w: c_int, stream: *mut FILE) -> c_int {
  799. fwrite(&w as *const c_int as _, mem::size_of_val(&w), 1, stream) as i32 - 1
  800. }
  801. /// Delete file or directory `path`
  802. #[no_mangle]
  803. pub unsafe extern "C" fn remove(path: *const c_char) -> c_int {
  804. let path = CStr::from_ptr(path);
  805. let r = Sys::unlink(path);
  806. if r == -errno::EISDIR {
  807. Sys::rmdir(path)
  808. } else {
  809. r
  810. }
  811. }
  812. #[no_mangle]
  813. pub unsafe extern "C" fn rename(oldpath: *const c_char, newpath: *const c_char) -> c_int {
  814. let oldpath = CStr::from_ptr(oldpath);
  815. let newpath = CStr::from_ptr(newpath);
  816. Sys::rename(oldpath, newpath)
  817. }
  818. /// Rewind `stream` back to the beginning of it
  819. #[no_mangle]
  820. pub unsafe extern "C" fn rewind(stream: *mut FILE) {
  821. fseeko(stream, 0, SEEK_SET);
  822. }
  823. /// Reset `stream` to use buffer `buf`. Buffer must be `BUFSIZ` in length
  824. #[no_mangle]
  825. pub unsafe extern "C" fn setbuf(stream: *mut FILE, buf: *mut c_char) {
  826. setvbuf(
  827. stream,
  828. buf,
  829. if buf.is_null() { _IONBF } else { _IOFBF },
  830. BUFSIZ as usize,
  831. );
  832. }
  833. /// Reset `stream` to use buffer `buf` of size `size`
  834. /// If this isn't the meaning of unsafe, idk what is
  835. #[no_mangle]
  836. pub unsafe extern "C" fn setvbuf(
  837. stream: *mut FILE,
  838. buf: *mut c_char,
  839. mode: c_int,
  840. mut size: size_t,
  841. ) -> c_int {
  842. let mut stream = (*stream).lock();
  843. // Set a buffer of size `size` if no buffer is given
  844. stream.read_buf = if buf.is_null() || size == 0 {
  845. if size == 0 {
  846. size = BUFSIZ as usize;
  847. }
  848. // TODO: Make it unbuffered if _IONBF
  849. // if mode == _IONBF {
  850. // } else {
  851. Buffer::Owned(vec![0; size as usize])
  852. // }
  853. } else {
  854. Buffer::Borrowed(slice::from_raw_parts_mut(buf as *mut u8, size))
  855. };
  856. stream.flags |= F_SVB;
  857. 0
  858. }
  859. #[no_mangle]
  860. pub unsafe extern "C" fn tempnam(dir: *const c_char, pfx: *const c_char) -> *mut c_char {
  861. unsafe fn is_appropriate(pos_dir: *const c_char) -> bool {
  862. !pos_dir.is_null() && unistd::access(pos_dir, unistd::W_OK) == 0
  863. }
  864. // directory search order is env!(TMPDIR), dir, P_tmpdir, "/tmp"
  865. let dirname = {
  866. let tmpdir = stdlib::getenv(b"TMPDIR\0".as_ptr() as _);
  867. [tmpdir, dir, P_tmpdir.as_ptr() as _]
  868. .iter()
  869. .copied()
  870. .skip_while(|&d| !is_appropriate(d))
  871. .next()
  872. .unwrap_or(b"/tmp\0".as_ptr() as _)
  873. };
  874. let dirname_len = string::strlen(dirname);
  875. let prefix_len = string::strnlen_s(pfx, 5);
  876. // allocate enough for dirname "/" prefix "XXXXXX\0"
  877. let mut out_buf =
  878. platform::alloc(dirname_len + 1 + prefix_len + L_tmpnam as usize + 1) as *mut c_char;
  879. if !out_buf.is_null() {
  880. // copy the directory name and prefix into the allocated buffer
  881. out_buf.copy_from_nonoverlapping(dirname, dirname_len);
  882. *out_buf.add(dirname_len) = b'/' as _;
  883. out_buf
  884. .add(dirname_len + 1)
  885. .copy_from_nonoverlapping(pfx, prefix_len);
  886. // use the same mechanism as tmpnam to get the file name
  887. if tmpnam_inner(out_buf, dirname_len + 1 + prefix_len).is_null() {
  888. // failed to find a valid file name, so we need to free the buffer
  889. platform::free(out_buf as _);
  890. out_buf = ptr::null_mut();
  891. }
  892. }
  893. out_buf
  894. }
  895. #[no_mangle]
  896. pub unsafe extern "C" fn tmpfile() -> *mut FILE {
  897. let mut file_name = *b"/tmp/tmpfileXXXXXX\0";
  898. let file_name = file_name.as_mut_ptr() as *mut c_char;
  899. let fd = stdlib::mkstemp(file_name);
  900. if fd < 0 {
  901. return ptr::null_mut();
  902. }
  903. let fp = fdopen(fd, c_str!("w+").as_ptr());
  904. {
  905. let file_name = CStr::from_ptr(file_name);
  906. Sys::unlink(file_name);
  907. }
  908. if fp.is_null() {
  909. Sys::close(fd);
  910. }
  911. fp
  912. }
  913. #[no_mangle]
  914. pub unsafe extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char {
  915. let buf = if s.is_null() {
  916. TMPNAM_BUF.as_mut_ptr()
  917. } else {
  918. s
  919. };
  920. *buf = b'/' as _;
  921. tmpnam_inner(buf, 1)
  922. }
  923. unsafe extern "C" fn tmpnam_inner(buf: *mut c_char, offset: usize) -> *mut c_char {
  924. const TEMPLATE: &[u8] = b"XXXXXX\0";
  925. buf.add(offset)
  926. .copy_from_nonoverlapping(TEMPLATE.as_ptr() as _, TEMPLATE.len());
  927. let err = platform::errno;
  928. stdlib::mktemp(buf);
  929. platform::errno = err;
  930. if *buf == 0 {
  931. ptr::null_mut()
  932. } else {
  933. buf
  934. }
  935. }
  936. /// Push character `c` back onto `stream` so it'll be read next
  937. #[no_mangle]
  938. pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
  939. let mut stream = (*stream).lock();
  940. if let Err(_) = (*stream).try_set_byte_orientation_unlocked() {
  941. return -1;
  942. }
  943. stream.unget.push(c as u8);
  944. c
  945. }
  946. #[no_mangle]
  947. pub unsafe extern "C" fn vfprintf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
  948. let mut file = (*file).lock();
  949. if let Err(_) = file.try_set_byte_orientation_unlocked() {
  950. return -1;
  951. }
  952. printf::printf(&mut *file, format, ap)
  953. }
  954. #[no_mangle]
  955. pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int {
  956. vfprintf(&mut *stdout, format, ap)
  957. }
  958. #[no_mangle]
  959. pub unsafe extern "C" fn vasprintf(
  960. strp: *mut *mut c_char,
  961. format: *const c_char,
  962. ap: va_list,
  963. ) -> c_int {
  964. let mut alloc_writer = CVec::new();
  965. let ret = printf::printf(&mut alloc_writer, format, ap);
  966. alloc_writer.push(0).unwrap();
  967. alloc_writer.shrink_to_fit().unwrap();
  968. *strp = alloc_writer.leak() as *mut c_char;
  969. ret
  970. }
  971. #[no_mangle]
  972. pub unsafe extern "C" fn vsnprintf(
  973. s: *mut c_char,
  974. n: size_t,
  975. format: *const c_char,
  976. ap: va_list,
  977. ) -> c_int {
  978. printf::printf(
  979. &mut platform::StringWriter(s as *mut u8, n as usize),
  980. format,
  981. ap,
  982. )
  983. }
  984. #[no_mangle]
  985. pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_list) -> c_int {
  986. printf::printf(&mut platform::UnsafeStringWriter(s as *mut u8), format, ap)
  987. }
  988. #[no_mangle]
  989. pub unsafe extern "C" fn vfscanf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
  990. let ret = {
  991. let mut file = (*file).lock();
  992. if let Err(_) = file.try_set_byte_orientation_unlocked() {
  993. return -1;
  994. }
  995. let f: &mut FILE = &mut *file;
  996. let reader: LookAheadReader = f.into();
  997. scanf::scanf(reader, format, ap)
  998. };
  999. ret
  1000. }
  1001. #[no_mangle]
  1002. pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
  1003. vfscanf(&mut *stdin, format, ap)
  1004. }
  1005. #[no_mangle]
  1006. pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int {
  1007. let reader = (s as *const u8).into();
  1008. scanf::scanf(reader, format, ap)
  1009. }
  1010. pub unsafe fn flush_io_streams() {
  1011. let flush = |stream: *mut FILE| {
  1012. let stream = &mut *stream;
  1013. stream.flush()
  1014. };
  1015. flush(stdout);
  1016. flush(stderr);
  1017. }