mod.rs 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034
  1. //! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html
  2. use core::{intrinsics, iter, mem, ptr, slice};
  3. use rand::distributions::{Alphanumeric, Distribution, Uniform};
  4. use rand::prng::XorShiftRng;
  5. use rand::rngs::JitterRng;
  6. use rand::{Rng, SeedableRng};
  7. use c_str::CStr;
  8. use fs::File;
  9. use header::errno::*;
  10. use header::fcntl::*;
  11. use header::limits;
  12. use header::string::*;
  13. use header::time::constants::CLOCK_MONOTONIC;
  14. use header::time::timespec;
  15. use header::wchar::*;
  16. use header::{ctype, errno, unistd};
  17. use platform;
  18. use platform::types::*;
  19. use platform::{Pal, Sys};
  20. mod sort;
  21. pub const EXIT_FAILURE: c_int = 1;
  22. pub const EXIT_SUCCESS: c_int = 0;
  23. pub const RAND_MAX: c_int = 2_147_483_647;
  24. //Maximum number of bytes in a multibyte character for the current locale
  25. pub const MB_CUR_MAX: c_int = 4;
  26. //Maximum number of bytes in a multibyte characters for any locale
  27. pub const MB_LEN_MAX: c_int = 4;
  28. static mut ATEXIT_FUNCS: [Option<extern "C" fn()>; 32] = [None; 32];
  29. static mut RNG: Option<XorShiftRng> = None;
  30. lazy_static! {
  31. static ref RNG_SAMPLER: Uniform<c_int> = Uniform::new_inclusive(0, RAND_MAX);
  32. }
  33. #[no_mangle]
  34. pub extern "C" fn _Exit(status: c_int) {
  35. unistd::_exit(status);
  36. }
  37. #[no_mangle]
  38. pub unsafe extern "C" fn a64l(s: *const c_char) -> c_long {
  39. if s.is_null() {
  40. return 0;
  41. }
  42. let mut l: c_long = 0;
  43. // a64l does not support more than 6 characters at once
  44. for x in 0..6 {
  45. let c = *s.offset(x);
  46. if c == 0 {
  47. // string is null terminated
  48. return l;
  49. }
  50. // ASCII to base64 conversion:
  51. let mut bits: c_long = if c < 58 {
  52. (c - 46) as c_long // ./0123456789
  53. } else if c < 91 {
  54. (c - 53) as c_long // A-Z
  55. } else {
  56. (c - 59) as c_long // a-z
  57. };
  58. bits <<= 6 * x;
  59. l |= bits;
  60. }
  61. l
  62. }
  63. #[no_mangle]
  64. pub unsafe extern "C" fn abort() {
  65. intrinsics::abort();
  66. }
  67. #[no_mangle]
  68. pub extern "C" fn abs(i: c_int) -> c_int {
  69. i.abs()
  70. }
  71. #[no_mangle]
  72. pub unsafe extern "C" fn aligned_alloc(alignment: size_t, size: size_t) -> *mut c_void {
  73. if size % alignment == 0 {
  74. /* The size-is-multiple-of-alignment requirement is the only
  75. * difference between aligned_alloc() and memalign(). */
  76. memalign(alignment, size)
  77. } else {
  78. platform::errno = errno::EINVAL;
  79. ptr::null_mut()
  80. }
  81. }
  82. #[no_mangle]
  83. pub unsafe extern "C" fn atexit(func: Option<extern "C" fn()>) -> c_int {
  84. for i in 0..ATEXIT_FUNCS.len() {
  85. if ATEXIT_FUNCS[i] == None {
  86. ATEXIT_FUNCS[i] = func;
  87. return 0;
  88. }
  89. }
  90. 1
  91. }
  92. #[no_mangle]
  93. pub unsafe extern "C" fn atof(s: *const c_char) -> c_double {
  94. strtod(s, ptr::null_mut())
  95. }
  96. macro_rules! dec_num_from_ascii {
  97. ($s:expr, $t:ty) => {
  98. unsafe {
  99. let mut s = $s;
  100. // Iterate past whitespace
  101. while ctype::isspace(*s as c_int) != 0 {
  102. s = s.offset(1);
  103. }
  104. // Find out if there is a - sign
  105. let neg_sign = match *s {
  106. 0x2d => {
  107. s = s.offset(1);
  108. true
  109. }
  110. // '+' increment s and continue parsing
  111. 0x2b => {
  112. s = s.offset(1);
  113. false
  114. }
  115. _ => false,
  116. };
  117. let mut n: $t = 0;
  118. while ctype::isdigit(*s as c_int) != 0 {
  119. n = 10 * n - (*s as $t - 0x30);
  120. s = s.offset(1);
  121. }
  122. if neg_sign {
  123. n
  124. } else {
  125. -n
  126. }
  127. }
  128. };
  129. }
  130. #[no_mangle]
  131. pub extern "C" fn atoi(s: *const c_char) -> c_int {
  132. dec_num_from_ascii!(s, c_int)
  133. }
  134. #[no_mangle]
  135. pub extern "C" fn atol(s: *const c_char) -> c_long {
  136. dec_num_from_ascii!(s, c_long)
  137. }
  138. #[no_mangle]
  139. pub extern "C" fn atoll(s: *const c_char) -> c_longlong {
  140. dec_num_from_ascii!(s, c_longlong)
  141. }
  142. unsafe extern "C" fn void_cmp(a: *const c_void, b: *const c_void) -> c_int {
  143. *(a as *const i32) - *(b as *const i32) as c_int
  144. }
  145. #[no_mangle]
  146. pub unsafe extern "C" fn bsearch(
  147. key: *const c_void,
  148. base: *const c_void,
  149. nel: size_t,
  150. width: size_t,
  151. compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
  152. ) -> *mut c_void {
  153. let mut start = base;
  154. let mut len = nel;
  155. let cmp_fn = compar.unwrap_or(void_cmp);
  156. while len > 0 {
  157. let med = (start as size_t + (len >> 1) * width) as *const c_void;
  158. let diff = cmp_fn(key, med);
  159. if diff == 0 {
  160. return med as *mut c_void;
  161. } else if diff > 0 {
  162. start = (med as usize + width) as *const c_void;
  163. len -= 1;
  164. }
  165. len >>= 1;
  166. }
  167. ptr::null_mut()
  168. }
  169. #[no_mangle]
  170. pub unsafe extern "C" fn calloc(nelem: size_t, elsize: size_t) -> *mut c_void {
  171. //Handle possible integer overflow in size calculation
  172. let size_result = nelem.checked_mul(elsize);
  173. match size_result {
  174. Some(size) => {
  175. /* If allocation fails here, errno setting will be handled
  176. * by malloc() */
  177. let ptr = malloc(size);
  178. if !ptr.is_null() {
  179. intrinsics::write_bytes(ptr as *mut u8, 0, size);
  180. }
  181. ptr
  182. }
  183. None => {
  184. // For overflowing multiplication, we have to set errno here
  185. platform::errno = errno::ENOMEM;
  186. ptr::null_mut()
  187. }
  188. }
  189. }
  190. #[repr(C)]
  191. pub struct div_t {
  192. quot: c_int,
  193. rem: c_int,
  194. }
  195. #[no_mangle]
  196. pub extern "C" fn div(numer: c_int, denom: c_int) -> div_t {
  197. div_t {
  198. quot: numer / denom,
  199. rem: numer % denom,
  200. }
  201. }
  202. // #[no_mangle]
  203. pub extern "C" fn drand48() -> c_double {
  204. unimplemented!();
  205. }
  206. // #[no_mangle]
  207. pub extern "C" fn ecvt(
  208. value: c_double,
  209. ndigit: c_int,
  210. decpt: *mut c_int,
  211. sign: *mut c_int,
  212. ) -> *mut c_char {
  213. unimplemented!();
  214. }
  215. // #[no_mangle]
  216. pub extern "C" fn erand(xsubi: [c_ushort; 3]) -> c_double {
  217. unimplemented!();
  218. }
  219. #[no_mangle]
  220. pub unsafe extern "C" fn exit(status: c_int) {
  221. extern "C" {
  222. static __fini_array_start: extern "C" fn();
  223. static __fini_array_end: extern "C" fn();
  224. fn pthread_terminate();
  225. fn _fini();
  226. }
  227. for i in (0..ATEXIT_FUNCS.len()).rev() {
  228. if let Some(func) = ATEXIT_FUNCS[i] {
  229. (func)();
  230. }
  231. }
  232. // Look for the neighbor functions in memory until the end
  233. let mut f = &__fini_array_end as *const _;
  234. #[allow(clippy::op_ref)]
  235. while f > &__fini_array_start {
  236. f = f.offset(-1);
  237. (*f)();
  238. }
  239. _fini();
  240. pthread_terminate();
  241. Sys::exit(status);
  242. }
  243. // #[no_mangle]
  244. pub extern "C" fn fcvt(
  245. value: c_double,
  246. ndigit: c_int,
  247. decpt: *mut c_int,
  248. sign: *mut c_int,
  249. ) -> *mut c_char {
  250. unimplemented!();
  251. }
  252. #[no_mangle]
  253. pub unsafe extern "C" fn free(ptr: *mut c_void) {
  254. platform::free(ptr);
  255. }
  256. // #[no_mangle]
  257. pub extern "C" fn gcvt(value: c_double, ndigit: c_int, buf: *mut c_char) -> *mut c_char {
  258. unimplemented!();
  259. }
  260. unsafe fn find_env(search: *const c_char) -> Option<(usize, *mut c_char)> {
  261. for (i, item) in platform::inner_environ.iter().enumerate() {
  262. let mut item = *item;
  263. if item.is_null() {
  264. assert_eq!(
  265. i,
  266. platform::inner_environ.len() - 1,
  267. "an early null pointer in environ vector"
  268. );
  269. break;
  270. }
  271. let mut search = search;
  272. loop {
  273. let end_of_query = *search == 0 || *search == b'=' as c_char;
  274. assert_ne!(*item, 0, "environ has an item without value");
  275. if *item == b'=' as c_char || end_of_query {
  276. if *item == b'=' as c_char && end_of_query {
  277. // Both keys env here
  278. return Some((i, item.offset(1)));
  279. } else {
  280. break;
  281. }
  282. }
  283. if *item != *search {
  284. break;
  285. }
  286. item = item.offset(1);
  287. search = search.offset(1);
  288. }
  289. }
  290. None
  291. }
  292. #[no_mangle]
  293. pub unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char {
  294. find_env(name).map(|val| val.1).unwrap_or(ptr::null_mut())
  295. }
  296. // #[no_mangle]
  297. pub extern "C" fn getsubopt(
  298. optionp: *mut *mut c_char,
  299. tokens: *const *mut c_char,
  300. valuep: *mut *mut c_char,
  301. ) -> c_int {
  302. unimplemented!();
  303. }
  304. // #[no_mangle]
  305. pub extern "C" fn grantpt(fildes: c_int) -> c_int {
  306. unimplemented!();
  307. }
  308. // #[no_mangle]
  309. pub extern "C" fn initstate(seec: c_uint, state: *mut c_char, size: size_t) -> *mut c_char {
  310. unimplemented!();
  311. }
  312. // #[no_mangle]
  313. pub extern "C" fn jrand48(xsubi: [c_ushort; 3]) -> c_long {
  314. unimplemented!();
  315. }
  316. // #[no_mangle]
  317. pub extern "C" fn l64a(value: c_long) -> *mut c_char {
  318. unimplemented!();
  319. }
  320. #[no_mangle]
  321. pub extern "C" fn labs(i: c_long) -> c_long {
  322. i.abs()
  323. }
  324. // #[no_mangle]
  325. pub extern "C" fn lcong48(param: [c_ushort; 7]) {
  326. unimplemented!();
  327. }
  328. #[repr(C)]
  329. pub struct ldiv_t {
  330. quot: c_long,
  331. rem: c_long,
  332. }
  333. #[no_mangle]
  334. pub extern "C" fn ldiv(numer: c_long, denom: c_long) -> ldiv_t {
  335. ldiv_t {
  336. quot: numer / denom,
  337. rem: numer % denom,
  338. }
  339. }
  340. #[no_mangle]
  341. pub extern "C" fn llabs(i: c_longlong) -> c_longlong {
  342. i.abs()
  343. }
  344. #[repr(C)]
  345. pub struct lldiv_t {
  346. quot: c_longlong,
  347. rem: c_longlong,
  348. }
  349. #[no_mangle]
  350. pub extern "C" fn lldiv(numer: c_longlong, denom: c_longlong) -> lldiv_t {
  351. lldiv_t {
  352. quot: numer / denom,
  353. rem: numer % denom,
  354. }
  355. }
  356. // #[no_mangle]
  357. pub extern "C" fn lrand48() -> c_long {
  358. unimplemented!();
  359. }
  360. #[no_mangle]
  361. pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
  362. let ptr = platform::alloc(size);
  363. if ptr.is_null() {
  364. platform::errno = errno::ENOMEM;
  365. }
  366. ptr
  367. }
  368. #[no_mangle]
  369. pub unsafe extern "C" fn memalign(alignment: size_t, size: size_t) -> *mut c_void {
  370. /* Check if alignment is a (positive) power of two. The second
  371. * expression will never underflow, due to Rust's lazy boolean
  372. * operators. */
  373. if alignment > 0 && (alignment & (alignment - 1)) == 0 {
  374. let ptr = platform::alloc_align(size, alignment);
  375. if ptr.is_null() {
  376. platform::errno = errno::ENOMEM;
  377. }
  378. ptr
  379. } else {
  380. platform::errno = errno::EINVAL;
  381. ptr::null_mut()
  382. }
  383. }
  384. #[no_mangle]
  385. pub unsafe extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int {
  386. let mut wc: wchar_t = 0;
  387. let mut state: mbstate_t = mbstate_t {};
  388. let result: usize = mbrtowc(&mut wc, s, n, &mut state);
  389. if result == -1isize as usize {
  390. return -1;
  391. }
  392. if result == -2isize as usize {
  393. return -1;
  394. }
  395. result as i32
  396. }
  397. #[no_mangle]
  398. pub unsafe extern "C" fn mbstowcs(pwcs: *mut wchar_t, mut s: *const c_char, n: size_t) -> size_t {
  399. let mut state: mbstate_t = mbstate_t {};
  400. mbsrtowcs(pwcs, &mut s, n, &mut state)
  401. }
  402. #[no_mangle]
  403. pub unsafe extern "C" fn mbtowc(pwc: *mut wchar_t, s: *const c_char, n: size_t) -> c_int {
  404. let mut state: mbstate_t = mbstate_t {};
  405. mbrtowc(pwc, s, n, &mut state) as c_int
  406. }
  407. fn inner_mktemp<T, F>(name: *mut c_char, suffix_len: c_int, mut attempt: F) -> Option<T>
  408. where
  409. F: FnMut() -> Option<T>,
  410. {
  411. let len = unsafe { strlen(name) as c_int };
  412. if len < 6 || suffix_len > len - 6 {
  413. unsafe { platform::errno = errno::EINVAL };
  414. return None;
  415. }
  416. for i in (len - suffix_len - 6)..(len - suffix_len) {
  417. if unsafe { *name.offset(i as isize) } != b'X' as c_char {
  418. unsafe { platform::errno = errno::EINVAL };
  419. return None;
  420. }
  421. }
  422. let mut rng = JitterRng::new_with_timer(get_nstime);
  423. let _ = rng.test_timer();
  424. for _ in 0..100 {
  425. let char_iter = iter::repeat(())
  426. .map(|()| rng.sample(Alphanumeric))
  427. .take(6)
  428. .enumerate();
  429. unsafe {
  430. for (i, c) in char_iter {
  431. *name.offset((len as isize) - (suffix_len as isize) - (i as isize) - 1) =
  432. c as c_char
  433. }
  434. }
  435. if let result @ Some(_) = attempt() {
  436. return result;
  437. }
  438. }
  439. unsafe { platform::errno = errno::EEXIST }
  440. None
  441. }
  442. #[no_mangle]
  443. pub unsafe extern "C" fn mktemp(name: *mut c_char) -> *mut c_char {
  444. if inner_mktemp(name, 0, || {
  445. let name = CStr::from_ptr(name);
  446. if Sys::access(name, 0) != 0 && platform::errno == ENOENT {
  447. Some(())
  448. } else {
  449. None
  450. }
  451. })
  452. .is_none()
  453. {
  454. *name = 0;
  455. }
  456. name
  457. }
  458. fn get_nstime() -> u64 {
  459. let mut ts: timespec = unsafe { mem::uninitialized() };
  460. Sys::clock_gettime(CLOCK_MONOTONIC, &mut ts);
  461. ts.tv_nsec as u64
  462. }
  463. #[no_mangle]
  464. pub extern "C" fn mkostemps(name: *mut c_char, suffix_len: c_int, mut flags: c_int) -> c_int {
  465. flags &= !O_ACCMODE;
  466. flags |= O_RDWR | O_CREAT | O_EXCL;
  467. inner_mktemp(name, suffix_len, || {
  468. let name = unsafe { CStr::from_ptr(name) };
  469. let fd = Sys::open(name, flags, 0o600);
  470. if fd >= 0 {
  471. Some(fd)
  472. } else {
  473. None
  474. }
  475. })
  476. .unwrap_or(-1)
  477. }
  478. #[no_mangle]
  479. pub extern "C" fn mkstemp(name: *mut c_char) -> c_int {
  480. mkostemps(name, 0, 0)
  481. }
  482. #[no_mangle]
  483. pub extern "C" fn mkostemp(name: *mut c_char, flags: c_int) -> c_int {
  484. mkostemps(name, 0, flags)
  485. }
  486. #[no_mangle]
  487. pub extern "C" fn mkstemps(name: *mut c_char, suffix_len: c_int) -> c_int {
  488. mkostemps(name, suffix_len, 0)
  489. }
  490. // #[no_mangle]
  491. pub extern "C" fn mrand48() -> c_long {
  492. unimplemented!();
  493. }
  494. // #[no_mangle]
  495. pub extern "C" fn nrand48(xsubi: [c_ushort; 3]) -> c_long {
  496. unimplemented!();
  497. }
  498. // #[no_mangle]
  499. pub extern "C" fn ptsname(fildes: c_int) -> *mut c_char {
  500. unimplemented!();
  501. }
  502. #[no_mangle]
  503. pub unsafe extern "C" fn putenv(insert: *mut c_char) -> c_int {
  504. assert_ne!(insert, ptr::null_mut(), "putenv(NULL)");
  505. if let Some((i, _)) = find_env(insert) {
  506. //TODO: find out why this crashes: platform::free(platform::inner_environ[i] as *mut c_void);
  507. platform::inner_environ[i] = insert;
  508. } else {
  509. let i = platform::inner_environ.len() - 1;
  510. assert_eq!(
  511. platform::inner_environ[i],
  512. ptr::null_mut(),
  513. "environ did not end with null"
  514. );
  515. platform::inner_environ[i] = insert;
  516. platform::inner_environ.push(ptr::null_mut());
  517. platform::environ = platform::inner_environ.as_mut_ptr();
  518. }
  519. 0
  520. }
  521. #[no_mangle]
  522. pub extern "C" fn qsort(
  523. base: *mut c_void,
  524. nel: size_t,
  525. width: size_t,
  526. compar: Option<extern "C" fn(*const c_void, *const c_void) -> c_int>,
  527. ) {
  528. if let Some(comp) = compar {
  529. // XXX: check width too? not specified
  530. if nel > 0 {
  531. // XXX: maybe try to do mergesort/timsort first and fallback to introsort if memory
  532. // allocation fails? not sure what is ideal
  533. sort::introsort(base as *mut c_char, nel, width, comp);
  534. }
  535. }
  536. }
  537. #[no_mangle]
  538. pub unsafe extern "C" fn rand() -> c_int {
  539. match RNG {
  540. Some(ref mut rng) => RNG_SAMPLER.sample(rng),
  541. None => {
  542. let mut rng = XorShiftRng::from_seed([1; 16]);
  543. let ret = RNG_SAMPLER.sample(&mut rng);
  544. RNG = Some(rng);
  545. ret
  546. }
  547. }
  548. }
  549. #[no_mangle]
  550. pub unsafe extern "C" fn rand_r(seed: *mut c_uint) -> c_int {
  551. if seed.is_null() {
  552. errno::EINVAL
  553. } else {
  554. // set the type explicitly so this will fail if the array size for XorShiftRng changes
  555. let seed_arr: [u8; 16] = mem::transmute([*seed; 16 / mem::size_of::<c_uint>()]);
  556. let mut rng = XorShiftRng::from_seed(seed_arr);
  557. let ret = RNG_SAMPLER.sample(&mut rng);
  558. *seed = ret as _;
  559. ret
  560. }
  561. }
  562. // #[no_mangle]
  563. pub extern "C" fn random() -> c_long {
  564. unimplemented!();
  565. }
  566. #[no_mangle]
  567. pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
  568. let ptr = platform::realloc(ptr, size);
  569. if ptr.is_null() {
  570. platform::errno = errno::ENOMEM;
  571. }
  572. ptr
  573. }
  574. #[no_mangle]
  575. pub unsafe extern "C" fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char {
  576. let ptr = if resolved.is_null() {
  577. malloc(limits::PATH_MAX) as *mut c_char
  578. } else {
  579. resolved
  580. };
  581. let out = slice::from_raw_parts_mut(ptr as *mut u8, limits::PATH_MAX);
  582. {
  583. let file = match File::open(&CStr::from_ptr(pathname), O_PATH | O_CLOEXEC) {
  584. Ok(file) => file,
  585. Err(_) => return ptr::null_mut(),
  586. };
  587. let len = out.len();
  588. let read = Sys::fpath(*file, &mut out[..len - 1]);
  589. if read < 0 {
  590. return ptr::null_mut();
  591. }
  592. out[read as usize] = 0;
  593. }
  594. ptr
  595. }
  596. // #[no_mangle]
  597. pub extern "C" fn seed48(seed16v: [c_ushort; 3]) -> c_ushort {
  598. unimplemented!();
  599. }
  600. #[no_mangle]
  601. pub unsafe extern "C" fn setenv(
  602. mut key: *const c_char,
  603. mut value: *const c_char,
  604. overwrite: c_int,
  605. ) -> c_int {
  606. let mut key_len = 0;
  607. while *key.offset(key_len) != 0 {
  608. key_len += 1;
  609. }
  610. let mut value_len = 0;
  611. while *value.offset(value_len) != 0 {
  612. value_len += 1;
  613. }
  614. let index = if let Some((i, existing)) = find_env(key) {
  615. if overwrite == 0 {
  616. return 0;
  617. }
  618. let mut existing_len = 0;
  619. while *existing.offset(existing_len) != 0 {
  620. existing_len += 1;
  621. }
  622. if existing_len >= value_len {
  623. // Reuse existing element's allocation
  624. for i in 0..=value_len {
  625. *existing.offset(i) = *value.offset(i);
  626. }
  627. return 0;
  628. } else {
  629. i
  630. }
  631. } else {
  632. let i = platform::inner_environ.len() - 1;
  633. assert_eq!(
  634. platform::inner_environ[i],
  635. ptr::null_mut(),
  636. "environ did not end with null"
  637. );
  638. platform::inner_environ.push(ptr::null_mut());
  639. platform::environ = platform::inner_environ.as_mut_ptr();
  640. i
  641. };
  642. //platform::free(platform::inner_environ[index] as *mut c_void);
  643. let mut ptr = platform::alloc(key_len as usize + 1 + value_len as usize) as *mut c_char;
  644. platform::inner_environ[index] = ptr;
  645. while *key != 0 {
  646. *ptr = *key;
  647. ptr = ptr.offset(1);
  648. key = key.offset(1);
  649. }
  650. *ptr = b'=' as c_char;
  651. ptr = ptr.offset(1);
  652. while *value != 0 {
  653. *ptr = *value;
  654. ptr = ptr.offset(1);
  655. value = value.offset(1);
  656. }
  657. *ptr = 0;
  658. 0
  659. }
  660. // #[no_mangle]
  661. pub extern "C" fn setkey(key: *const c_char) {
  662. unimplemented!();
  663. }
  664. // #[no_mangle]
  665. pub extern "C" fn setstate(state: *const c_char) -> *mut c_char {
  666. unimplemented!();
  667. }
  668. #[no_mangle]
  669. pub unsafe extern "C" fn srand(seed: c_uint) {
  670. RNG = Some(XorShiftRng::from_seed([seed as u8; 16]));
  671. }
  672. // #[no_mangle]
  673. pub extern "C" fn srand48(seed: c_long) {
  674. unimplemented!();
  675. }
  676. // #[no_mangle]
  677. pub extern "C" fn srandom(seed: c_uint) {
  678. unimplemented!();
  679. }
  680. #[no_mangle]
  681. pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
  682. strto_float_impl!(c_double, s, endptr)
  683. }
  684. #[no_mangle]
  685. pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_float {
  686. strto_float_impl!(c_float, s, endptr)
  687. }
  688. pub fn is_positive(ch: c_char) -> Option<(bool, isize)> {
  689. match ch {
  690. 0 => None,
  691. ch if ch == b'+' as c_char => Some((true, 1)),
  692. ch if ch == b'-' as c_char => Some((false, 1)),
  693. _ => Some((true, 0)),
  694. }
  695. }
  696. pub unsafe fn detect_base(s: *const c_char) -> Option<(c_int, isize)> {
  697. let first = *s as u8;
  698. match first {
  699. 0 => None,
  700. b'0' => {
  701. let second = *s.offset(1) as u8;
  702. if second == b'X' || second == b'x' {
  703. Some((16, 2))
  704. } else if second >= b'0' && second <= b'7' {
  705. Some((8, 1))
  706. } else {
  707. // in this case, the prefix (0) is going to be the number
  708. Some((8, 0))
  709. }
  710. }
  711. _ => Some((10, 0)),
  712. }
  713. }
  714. pub unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
  715. if *s != 0 && *s == b'0' as c_char {
  716. if let Some((val, idx, overflow)) = convert_integer(s.offset(1), 8) {
  717. Some((val, idx + 1, overflow))
  718. } else {
  719. // in case the prefix is not actually a prefix
  720. Some((0, 1, false))
  721. }
  722. } else {
  723. None
  724. }
  725. }
  726. pub unsafe fn convert_hex(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
  727. if (*s != 0 && *s == b'0' as c_char)
  728. && (*s.offset(1) != 0 && (*s.offset(1) == b'x' as c_char || *s.offset(1) == b'X' as c_char))
  729. {
  730. convert_integer(s.offset(2), 16).map(|(val, idx, overflow)| (val, idx + 2, overflow))
  731. } else {
  732. convert_integer(s, 16).map(|(val, idx, overflow)| (val, idx, overflow))
  733. }
  734. }
  735. pub unsafe fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong, isize, bool)> {
  736. // -1 means the character is invalid
  737. #[rustfmt::skip]
  738. const LOOKUP_TABLE: [c_long; 256] = [
  739. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  740. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  741. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  742. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
  743. -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
  744. 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
  745. -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
  746. 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
  747. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  748. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  749. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  750. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  751. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  752. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  753. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  754. -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
  755. ];
  756. let mut num: c_ulong = 0;
  757. let mut idx = 0;
  758. let mut overflowed = false;
  759. loop {
  760. // `-1 as usize` is usize::MAX
  761. // `-1 as u8 as usize` is u8::MAX
  762. // It extends by the sign bit unless we cast it to unsigned first.
  763. let val = LOOKUP_TABLE[*s.offset(idx) as u8 as usize];
  764. if val == -1 || val as c_int >= base {
  765. break;
  766. } else {
  767. if let Some(res) = num
  768. .checked_mul(base as c_ulong)
  769. .and_then(|num| num.checked_add(val as c_ulong))
  770. {
  771. num = res;
  772. } else {
  773. platform::errno = ERANGE;
  774. num = c_ulong::max_value();
  775. overflowed = true;
  776. }
  777. idx += 1;
  778. }
  779. }
  780. if idx > 0 {
  781. Some((num, idx, overflowed))
  782. } else {
  783. None
  784. }
  785. }
  786. #[no_mangle]
  787. pub unsafe extern "C" fn strtoul(
  788. s: *const c_char,
  789. endptr: *mut *mut c_char,
  790. base: c_int,
  791. ) -> c_ulong {
  792. strto_impl!(
  793. c_ulong,
  794. false,
  795. c_ulong::max_value(),
  796. c_ulong::min_value(),
  797. s,
  798. endptr,
  799. base
  800. )
  801. }
  802. #[no_mangle]
  803. pub unsafe extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
  804. strto_impl!(
  805. c_long,
  806. true,
  807. c_long::max_value(),
  808. c_long::min_value(),
  809. s,
  810. endptr,
  811. base
  812. )
  813. }
  814. #[no_mangle]
  815. pub unsafe extern "C" fn strtoull(
  816. s: *const c_char,
  817. endptr: *mut *mut c_char,
  818. base: c_int,
  819. ) -> c_ulonglong {
  820. strtoul(s, endptr, base)
  821. }
  822. #[no_mangle]
  823. pub unsafe extern "C" fn strtoll(
  824. s: *const c_char,
  825. endptr: *mut *mut c_char,
  826. base: c_int,
  827. ) -> c_longlong {
  828. strtol(s, endptr, base)
  829. }
  830. #[no_mangle]
  831. pub unsafe extern "C" fn system(command: *const c_char) -> c_int {
  832. //TODO: share code with popen
  833. let child_pid = unistd::fork();
  834. if child_pid == 0 {
  835. let command_nonnull = if command.is_null() {
  836. "exit 0\0".as_ptr()
  837. } else {
  838. command as *const u8
  839. };
  840. let shell = "/bin/sh\0".as_ptr();
  841. let args = [
  842. "sh\0".as_ptr(),
  843. "-c\0".as_ptr(),
  844. command_nonnull,
  845. ptr::null(),
  846. ];
  847. unistd::execv(shell as *const c_char, args.as_ptr() as *const *mut c_char);
  848. exit(127);
  849. unreachable!();
  850. } else if child_pid > 0 {
  851. let mut wstatus = 0;
  852. if Sys::waitpid(child_pid, &mut wstatus, 0) == !0 {
  853. return -1;
  854. }
  855. wstatus
  856. } else {
  857. -1
  858. }
  859. }
  860. // #[no_mangle]
  861. pub extern "C" fn ttyslot() -> c_int {
  862. unimplemented!();
  863. }
  864. // #[no_mangle]
  865. pub extern "C" fn unlockpt(fildes: c_int) -> c_int {
  866. unimplemented!();
  867. }
  868. #[no_mangle]
  869. pub unsafe extern "C" fn unsetenv(key: *const c_char) -> c_int {
  870. if let Some((i, _)) = find_env(key) {
  871. // No need to worry about updating the pointer, this does not
  872. // reallocate in any way. And the final null is already shifted back.
  873. platform::inner_environ.remove(i);
  874. }
  875. 0
  876. }
  877. #[no_mangle]
  878. pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void {
  879. memalign(4096, size)
  880. }
  881. #[no_mangle]
  882. pub extern "C" fn wcstombs(s: *mut c_char, pwcs: *mut *const wchar_t, n: size_t) -> size_t {
  883. let mut state: mbstate_t = mbstate_t {};
  884. wcsrtombs(s, pwcs, n, &mut state)
  885. }
  886. #[no_mangle]
  887. pub unsafe extern "C" fn wctomb(s: *mut c_char, wc: wchar_t) -> c_int {
  888. let mut state: mbstate_t = mbstate_t {};
  889. let result: usize = wcrtomb(s, wc, &mut state);
  890. if result == -1isize as usize {
  891. return -1;
  892. }
  893. if result == -2isize as usize {
  894. return -1;
  895. }
  896. result as c_int
  897. }