xref: /drstd/dlibc/src/unix/header/stdlib/mod.rs (revision a1cd34728e2d4a5d4cf41974e4db28602cbb1b1c)
1 //! stdlib implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdlib.h.html
2 
3 use core::{convert::TryFrom, intrinsics, iter, mem, ptr, slice};
4 use rand::{
5     distributions::{Alphanumeric, Distribution, Uniform},
6     prng::XorShiftRng,
7     rngs::JitterRng,
8     Rng, SeedableRng,
9 };
10 
11 use crate::unix::header::{
12     ctype,
13     errno::{self, *},
14     limits,
15     stdio::flush_io_streams,
16     string::*,
17     unistd::{self, sysconf, _SC_PAGESIZE},
18     wchar::*,
19 };
20 
21 use crate::unix::{c_str::CStr, fs::File, ld_so, platform};
22 
23 mod rand48;
24 mod random;
25 mod sort;
26 
27 pub const EXIT_FAILURE: ::c_int = 1;
28 pub const EXIT_SUCCESS: ::c_int = 0;
29 pub const RAND_MAX: ::c_int = 2_147_483_647;
30 
31 //Maximum number of bytes in a multibyte character for the current locale
32 pub const MB_CUR_MAX: ::c_int = 4;
33 //Maximum number of bytes in a multibyte characters for any locale
34 pub const MB_LEN_MAX: ::c_int = 4;
35 
36 static mut ATEXIT_FUNCS: [Option<extern "C" fn()>; 32] = [None; 32];
37 static mut L64A_BUFFER: [::c_char; 7] = [0; 7]; // up to 6 digits plus null terminator
38 static mut RNG: Option<XorShiftRng> = None;
39 
40 use lazy_static::lazy_static;
41 lazy_static! {
42     static ref RNG_SAMPLER: Uniform<::c_int> = Uniform::new_inclusive(0, RAND_MAX);
43 }
44 
45 #[no_mangle]
46 pub extern "C" fn _Exit(status: ::c_int) {
47     unistd::_exit(status);
48 }
49 
50 #[no_mangle]
51 pub unsafe extern "C" fn a64l(s: *const ::c_char) -> ::c_long {
52     // Early return upon null pointer argument
53     if s.is_null() {
54         return 0;
55     }
56 
57     // POSIX says only the low-order 32 bits are used.
58     let mut l: i32 = 0;
59 
60     // Handle up to 6 input characters (excl. null terminator)
61     for i in 0..6 {
62         let digit_char = *s.offset(i);
63 
64         let digit_value = match digit_char {
65             0 => break, // Null terminator encountered
66             46..=57 => {
67                 // ./0123456789 represents values 0 to 11. b'.' == 46
68                 digit_char - 46
69             }
70             65..=90 => {
71                 // A-Z for values 12 to 37. b'A' == 65, 65-12 == 53
72                 digit_char - 53
73             }
74             97..=122 => {
75                 // a-z for values 38 to 63. b'a' == 97, 97-38 == 59
76                 digit_char - 59
77             }
78             _ => return 0, // Early return for anything else
79         };
80 
81         l |= i32::from(digit_value) << 6 * i;
82     }
83 
84     ::c_long::from(l)
85 }
86 
87 #[no_mangle]
88 pub unsafe extern "C" fn abort() -> ! {
89     eprintln!("Abort");
90     intrinsics::abort();
91 }
92 
93 #[no_mangle]
94 pub extern "C" fn abs(i: ::c_int) -> ::c_int {
95     i.abs()
96 }
97 
98 #[no_mangle]
99 pub unsafe extern "C" fn aligned_alloc(alignment: ::size_t, size: ::size_t) -> *mut ::c_void {
100     if size % alignment == 0 {
101         /* The size-is-multiple-of-alignment requirement is the only
102          * difference between aligned_alloc() and memalign(). */
103         memalign(alignment, size)
104     } else {
105         platform::errno = ::EINVAL;
106         ptr::null_mut()
107     }
108 }
109 
110 #[no_mangle]
111 pub unsafe extern "C" fn atexit(func: Option<extern "C" fn()>) -> ::c_int {
112     for i in 0..ATEXIT_FUNCS.len() {
113         if ATEXIT_FUNCS[i] == None {
114             ATEXIT_FUNCS[i] = func;
115             return 0;
116         }
117     }
118 
119     1
120 }
121 
122 #[no_mangle]
123 pub unsafe extern "C" fn atof(s: *const ::c_char) -> ::c_double {
124     strtod(s, ptr::null_mut())
125 }
126 
127 macro_rules! dec_num_from_ascii {
128     ($s:expr, $t:ty) => {
129         unsafe {
130             let mut s = $s;
131             // Iterate past whitespace
132             while ctype::isspace(*s as ::c_int) != 0 {
133                 s = s.offset(1);
134             }
135 
136             // Find out if there is a - sign
137             let neg_sign = match *s {
138                 0x2d => {
139                     s = s.offset(1);
140                     true
141                 }
142                 // '+' increment s and continue parsing
143                 0x2b => {
144                     s = s.offset(1);
145                     false
146                 }
147                 _ => false,
148             };
149 
150             let mut n: $t = 0;
151             while ctype::isdigit(*s as ::c_int) != 0 {
152                 n = 10 * n - (*s as $t - 0x30);
153                 s = s.offset(1);
154             }
155 
156             if neg_sign {
157                 n
158             } else {
159                 -n
160             }
161         }
162     };
163 }
164 
165 #[no_mangle]
166 pub extern "C" fn atoi(s: *const ::c_char) -> ::c_int {
167     dec_num_from_ascii!(s, ::c_int)
168 }
169 
170 #[no_mangle]
171 pub extern "C" fn atol(s: *const ::c_char) -> ::c_long {
172     dec_num_from_ascii!(s, ::c_long)
173 }
174 
175 #[no_mangle]
176 pub extern "C" fn atoll(s: *const ::c_char) -> ::c_longlong {
177     dec_num_from_ascii!(s, ::c_longlong)
178 }
179 
180 unsafe extern "C" fn void_cmp(a: *const ::c_void, b: *const ::c_void) -> ::c_int {
181     *(a as *const i32) - *(b as *const i32) as ::c_int
182 }
183 
184 #[no_mangle]
185 pub unsafe extern "C" fn bsearch(
186     key: *const ::c_void,
187     base: *const ::c_void,
188     nel: ::size_t,
189     width: ::size_t,
190     compar: Option<unsafe extern "C" fn(*const ::c_void, *const ::c_void) -> ::c_int>,
191 ) -> *mut ::c_void {
192     let mut start = base;
193     let mut len = nel;
194     let cmp_fn = compar.unwrap_or(void_cmp);
195     while len > 0 {
196         let med = (start as ::size_t + (len >> 1) * width) as *const ::c_void;
197         let diff = cmp_fn(key, med);
198         if diff == 0 {
199             return med as *mut ::c_void;
200         } else if diff > 0 {
201             start = (med as usize + width) as *const ::c_void;
202             len -= 1;
203         }
204         len >>= 1;
205     }
206     ptr::null_mut()
207 }
208 
209 #[no_mangle]
210 pub unsafe extern "C" fn calloc(nelem: ::size_t, elsize: ::size_t) -> *mut ::c_void {
211     //Handle possible integer overflow in size calculation
212     match nelem.checked_mul(elsize) {
213         Some(size) => {
214             /* If allocation fails here, errno setting will be handled
215              * by malloc() */
216             let ptr = malloc(size);
217             if !ptr.is_null() {
218                 intrinsics::write_bytes(ptr as *mut u8, 0, size);
219             }
220             ptr
221         }
222         None => {
223             // For overflowing multiplication, we have to set errno here
224             platform::errno = ENOMEM;
225             ptr::null_mut()
226         }
227     }
228 }
229 
230 #[repr(C)]
231 pub struct div_t {
232     quot: ::c_int,
233     rem: ::c_int,
234 }
235 
236 #[no_mangle]
237 pub extern "C" fn div(numer: ::c_int, denom: ::c_int) -> div_t {
238     div_t {
239         quot: numer / denom,
240         rem: numer % denom,
241     }
242 }
243 
244 #[no_mangle]
245 pub unsafe extern "C" fn drand48() -> ::c_double {
246     let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI);
247     rand48::f64_from_x(new_xsubi_value)
248 }
249 
250 // #[no_mangle]
251 pub extern "C" fn ecvt(
252     _value: ::c_double,
253     _ndigit: ::c_int,
254     _decpt: *mut ::c_int,
255     _sign: *mut ::c_int,
256 ) -> *mut ::c_char {
257     unimplemented!();
258 }
259 
260 #[no_mangle]
261 pub unsafe extern "C" fn erand48(xsubi: *mut ::c_ushort) -> ::c_double {
262     let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [::c_ushort; 3]));
263     rand48::f64_from_x(new_xsubi_value)
264 }
265 
266 #[no_mangle]
267 pub unsafe extern "C" fn exit(status: ::c_int) {
268     extern "C" {
269         static __fini_array_start: extern "C" fn();
270         static __fini_array_end: extern "C" fn();
271 
272         fn pthread_terminate();
273         fn _fini();
274     }
275 
276     for i in (0..ATEXIT_FUNCS.len()).rev() {
277         if let Some(func) = ATEXIT_FUNCS[i] {
278             (func)();
279         }
280     }
281 
282     // Look for the neighbor functions in memory until the end
283     let mut f = &__fini_array_end as *const _;
284     #[allow(clippy::op_ref)]
285     while f > &__fini_array_start {
286         f = f.offset(-1);
287         (*f)();
288     }
289 
290     _fini();
291 
292     ld_so::fini();
293 
294     pthread_terminate();
295 
296     flush_io_streams();
297 
298     platform::pal::exit(status);
299 }
300 
301 // #[no_mangle]
302 pub extern "C" fn fcvt(
303     _value: ::c_double,
304     _ndigit: ::c_int,
305     _decpt: *mut ::c_int,
306     _sign: *mut ::c_int,
307 ) -> *mut ::c_char {
308     unimplemented!();
309 }
310 
311 #[no_mangle]
312 pub unsafe extern "C" fn free(ptr: *mut ::c_void) {
313     platform::free(ptr);
314 }
315 
316 // #[no_mangle]
317 pub extern "C" fn gcvt(_value: ::c_double, _ndigit: ::c_int, _buf: *mut ::c_char) -> *mut ::c_char {
318     unimplemented!();
319 }
320 
321 unsafe fn find_env(search: *const ::c_char) -> Option<(usize, *mut ::c_char)> {
322     for (i, mut item) in platform::environ_iter().enumerate() {
323         let mut search = search;
324         loop {
325             let end_of_query = *search == 0 || *search == b'=' as ::c_char;
326             assert_ne!(*item, 0, "environ has an item without value");
327             if *item == b'=' as ::c_char || end_of_query {
328                 if *item == b'=' as ::c_char && end_of_query {
329                     // Both keys env here
330                     return Some((i, item.add(1)));
331                 } else {
332                     break;
333                 }
334             }
335 
336             if *item != *search {
337                 break;
338             }
339 
340             item = item.add(1);
341             search = search.add(1);
342         }
343     }
344 
345     None
346 }
347 
348 #[no_mangle]
349 pub unsafe extern "C" fn getenv(name: *const ::c_char) -> *mut ::c_char {
350     find_env(name).map(|val| val.1).unwrap_or(ptr::null_mut())
351 }
352 
353 // #[no_mangle]
354 pub extern "C" fn getsubopt(
355     _optionp: *mut *mut ::c_char,
356     _tokens: *const *mut ::c_char,
357     _valuep: *mut *mut ::c_char,
358 ) -> ::c_int {
359     unimplemented!();
360 }
361 
362 // #[no_mangle]
363 pub extern "C" fn grantpt(_fildes: ::c_int) -> ::c_int {
364     unimplemented!();
365 }
366 
367 #[no_mangle]
368 pub unsafe extern "C" fn initstate(
369     seed: ::c_uint,
370     state: *mut ::c_char,
371     size: ::size_t,
372 ) -> *mut ::c_char {
373     // Ported from musl
374 
375     if size < 8 {
376         ptr::null_mut()
377     } else {
378         // TODO: lock?
379         let old_state = random::save_state();
380         random::N = match size {
381             0..=7 => unreachable!(), // ensured above
382             8..=31 => 0,
383             32..=63 => 7,
384             64..=127 => 15,
385             128..=255 => 31,
386             _ => 63,
387         };
388 
389         random::X_PTR = (state.cast::<[u8; 4]>()).offset(1);
390         random::seed(seed);
391         random::save_state();
392         // TODO: unlock?
393 
394         old_state.cast::<_>()
395     }
396 }
397 
398 #[no_mangle]
399 pub unsafe extern "C" fn jrand48(xsubi: *mut ::c_ushort) -> ::c_long {
400     let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [::c_ushort; 3]));
401     rand48::i32_from_x(new_xsubi_value)
402 }
403 
404 #[no_mangle]
405 pub unsafe extern "C" fn l64a(value: ::c_long) -> *mut ::c_char {
406     // POSIX says we should only consider the lower 32 bits of value.
407     let value_as_i32 = value as i32;
408 
409     /* If we pretend to extend the 32-bit value with 4 binary zeros, we
410      * would get a 36-bit integer. The number of base-64 digits to be
411      * left unused can then be found by taking the number of leading
412      * zeros, dividing by 6 and rounding down (i.e. using integer
413      * division). */
414     let num_output_digits = usize::try_from(6 - (value_as_i32.leading_zeros() + 4) / 6).unwrap();
415 
416     // Reset buffer (and have null terminator in place for any result)
417     L64A_BUFFER = [0; 7];
418 
419     for i in 0..num_output_digits {
420         // Conversion to ::c_char always succeeds for the range 0..=63
421         let digit_value = ::c_char::try_from((value_as_i32 >> 6 * i) & 63).unwrap();
422 
423         L64A_BUFFER[i] = match digit_value {
424             0..=11 => {
425                 // ./0123456789 for values 0 to 11. b'.' == 46
426                 46 + digit_value
427             }
428             12..=37 => {
429                 // A-Z for values 12 to 37. b'A' == 65, 65-12 == 53
430                 53 + digit_value
431             }
432             38..=63 => {
433                 // a-z for values 38 to 63. b'a' == 97, 97-38 == 59
434                 59 + digit_value
435             }
436             _ => unreachable!(), // Guaranteed by taking "& 63" above
437         };
438     }
439 
440     L64A_BUFFER.as_mut_ptr()
441 }
442 
443 #[no_mangle]
444 pub extern "C" fn labs(i: ::c_long) -> ::c_long {
445     i.abs()
446 }
447 
448 #[no_mangle]
449 pub unsafe extern "C" fn lcong48(param: *mut ::c_ushort) {
450     // Set DEFAULT_XSUBI buffer from elements 0-2
451     let xsubi_value = rand48::u48_from_ushort_arr3(&*(param as *const [::c_ushort; 3]));
452     rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value);
453 
454     // Set multiplier from elements 3-5
455     rand48::A = rand48::u48_from_ushort_arr3(&*(param.offset(3) as *const [::c_ushort; 3]));
456 
457     /* Set addend from element 6. Note that ::c_ushort may be more than 16
458      * bits, thus the cast. */
459     rand48::C = *param.offset(6) as u16;
460 }
461 
462 #[repr(C)]
463 pub struct ldiv_t {
464     quot: ::c_long,
465     rem: ::c_long,
466 }
467 
468 #[no_mangle]
469 pub extern "C" fn ldiv(numer: ::c_long, denom: ::c_long) -> ldiv_t {
470     ldiv_t {
471         quot: numer / denom,
472         rem: numer % denom,
473     }
474 }
475 
476 #[no_mangle]
477 pub extern "C" fn llabs(i: ::c_longlong) -> ::c_longlong {
478     i.abs()
479 }
480 
481 #[repr(C)]
482 pub struct lldiv_t {
483     quot: ::c_longlong,
484     rem: ::c_longlong,
485 }
486 
487 #[no_mangle]
488 pub extern "C" fn lldiv(numer: ::c_longlong, denom: ::c_longlong) -> lldiv_t {
489     lldiv_t {
490         quot: numer / denom,
491         rem: numer % denom,
492     }
493 }
494 
495 #[no_mangle]
496 pub unsafe extern "C" fn lrand48() -> ::c_long {
497     let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI);
498     rand48::u31_from_x(new_xsubi_value)
499 }
500 
501 #[no_mangle]
502 pub unsafe extern "C" fn malloc(size: ::size_t) -> *mut ::c_void {
503     let ptr = platform::alloc(size);
504     if ptr.is_null() {
505         platform::errno = ENOMEM;
506     }
507     ptr
508 }
509 
510 #[no_mangle]
511 pub unsafe extern "C" fn memalign(alignment: ::size_t, size: ::size_t) -> *mut ::c_void {
512     if alignment.is_power_of_two() {
513         let ptr = platform::alloc_align(size, alignment);
514         if ptr.is_null() {
515             platform::errno = ENOMEM;
516         }
517         ptr
518     } else {
519         platform::errno = EINVAL;
520         ptr::null_mut()
521     }
522 }
523 
524 #[no_mangle]
525 pub unsafe extern "C" fn mblen(s: *const ::c_char, n: ::size_t) -> ::c_int {
526     let mut wc: ::wchar_t = 0;
527     let mut state: mbstate_t = mbstate_t {};
528     let result: usize = mbrtowc(&mut wc, s, n, &mut state);
529 
530     if result == -1isize as usize {
531         return -1;
532     }
533     if result == -2isize as usize {
534         return -1;
535     }
536 
537     result as i32
538 }
539 
540 #[no_mangle]
541 pub unsafe extern "C" fn mbstowcs(
542     pwcs: *mut ::wchar_t,
543     mut s: *const ::c_char,
544     n: ::size_t,
545 ) -> ::size_t {
546     let mut state: mbstate_t = mbstate_t {};
547     mbsrtowcs(pwcs, &mut s, n, &mut state)
548 }
549 
550 #[no_mangle]
551 pub unsafe extern "C" fn mbtowc(pwc: *mut ::wchar_t, s: *const ::c_char, n: ::size_t) -> ::c_int {
552     let mut state: mbstate_t = mbstate_t {};
553     mbrtowc(pwc, s, n, &mut state) as ::c_int
554 }
555 
556 fn inner_mktemp<T, F>(name: *mut ::c_char, suffix_len: ::c_int, mut attempt: F) -> Option<T>
557 where
558     F: FnMut() -> Option<T>,
559 {
560     let len = unsafe { strlen(name) as ::c_int };
561 
562     if len < 6 || suffix_len > len - 6 {
563         unsafe { platform::errno = errno::EINVAL };
564         return None;
565     }
566 
567     for i in (len - suffix_len - 6)..(len - suffix_len) {
568         if unsafe { *name.offset(i as isize) } != b'X' as ::c_char {
569             unsafe { platform::errno = errno::EINVAL };
570             return None;
571         }
572     }
573 
574     let mut rng = JitterRng::new_with_timer(get_nstime);
575     let _ = rng.test_timer();
576 
577     for _ in 0..100 {
578         let char_iter = iter::repeat(())
579             .map(|()| rng.sample(Alphanumeric))
580             .take(6)
581             .enumerate();
582         unsafe {
583             for (i, c) in char_iter {
584                 *name.offset((len as isize) - (suffix_len as isize) - (i as isize) - 1) =
585                     c as ::c_char
586             }
587         }
588 
589         if let result @ Some(_) = attempt() {
590             return result;
591         }
592     }
593 
594     unsafe { platform::errno = errno::EEXIST }
595 
596     None
597 }
598 
599 #[no_mangle]
600 pub unsafe extern "C" fn mktemp(name: *mut ::c_char) -> *mut ::c_char {
601     if inner_mktemp(name, 0, || {
602         if platform::pal::access(name, 0) != 0 && platform::errno == ENOENT {
603             Some(())
604         } else {
605             None
606         }
607     })
608     .is_none()
609     {
610         *name = 0;
611     }
612     name
613 }
614 
615 fn get_nstime() -> u64 {
616     let mut ts = mem::MaybeUninit::uninit();
617     platform::pal::clock_gettime(::CLOCK_MONOTONIC, ts.as_mut_ptr());
618     unsafe { ts.assume_init() }.tv_nsec as u64
619 }
620 
621 #[no_mangle]
622 pub extern "C" fn mkostemps(
623     name: *mut ::c_char,
624     suffix_len: ::c_int,
625     mut flags: ::c_int,
626 ) -> ::c_int {
627     flags &= !::O_ACCMODE;
628     flags |= ::O_RDWR | ::O_CREAT | ::O_EXCL;
629 
630     inner_mktemp(name, suffix_len, || {
631         let fd = platform::pal::open(name, flags, 0o600);
632 
633         if fd >= 0 {
634             Some(fd)
635         } else {
636             None
637         }
638     })
639     .unwrap_or(-1)
640 }
641 
642 #[no_mangle]
643 pub extern "C" fn mkstemp(name: *mut ::c_char) -> ::c_int {
644     mkostemps(name, 0, 0)
645 }
646 #[no_mangle]
647 pub extern "C" fn mkostemp(name: *mut ::c_char, flags: ::c_int) -> ::c_int {
648     mkostemps(name, 0, flags)
649 }
650 #[no_mangle]
651 pub extern "C" fn mkstemps(name: *mut ::c_char, suffix_len: ::c_int) -> ::c_int {
652     mkostemps(name, suffix_len, 0)
653 }
654 
655 #[no_mangle]
656 pub unsafe extern "C" fn mrand48() -> ::c_long {
657     let new_xsubi_value = rand48::generator_step(&mut rand48::DEFAULT_XSUBI);
658     rand48::i32_from_x(new_xsubi_value)
659 }
660 
661 #[no_mangle]
662 pub unsafe extern "C" fn nrand48(xsubi: *mut ::c_ushort) -> ::c_long {
663     let new_xsubi_value = rand48::generator_step(&mut *(xsubi as *mut [::c_ushort; 3]));
664     rand48::u31_from_x(new_xsubi_value)
665 }
666 
667 #[no_mangle]
668 pub unsafe extern "C" fn posix_memalign(
669     memptr: *mut *mut ::c_void,
670     alignment: ::size_t,
671     size: ::size_t,
672 ) -> ::c_int {
673     const VOID_PTR_SIZE: usize = mem::size_of::<*mut ::c_void>();
674 
675     if alignment % VOID_PTR_SIZE == 0 && alignment.is_power_of_two() {
676         let ptr = platform::alloc_align(size, alignment);
677         *memptr = ptr;
678         if ptr.is_null() {
679             ENOMEM
680         } else {
681             0
682         }
683     } else {
684         *memptr = ptr::null_mut();
685         EINVAL
686     }
687 }
688 
689 // #[no_mangle]
690 pub extern "C" fn ptsname(_fildes: ::c_int) -> *mut ::c_char {
691     unimplemented!();
692 }
693 
694 unsafe fn put_new_env(insert: *mut ::c_char) {
695     // XXX: Another problem is that `environ` can be set to any pointer, which means there is a
696     // chance of a memory leak. But we can check if it was the same as before, like musl does.
697     if platform::environ == platform::OUR_ENVIRON.as_mut_ptr() {
698         *platform::OUR_ENVIRON.last_mut().unwrap() = insert;
699         platform::OUR_ENVIRON.push(core::ptr::null_mut());
700         // Likely a no-op but is needed due to Stacked Borrows.
701         platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
702     } else {
703         platform::OUR_ENVIRON.clear();
704         platform::OUR_ENVIRON.extend(platform::environ_iter());
705         platform::OUR_ENVIRON.push(insert);
706         platform::OUR_ENVIRON.push(core::ptr::null_mut());
707         platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
708     }
709 }
710 
711 #[no_mangle]
712 pub unsafe extern "C" fn putenv(insert: *mut ::c_char) -> ::c_int {
713     assert_ne!(insert, ptr::null_mut(), "putenv(NULL)");
714     if let Some((i, _)) = find_env(insert) {
715         // XXX: The POSIX manual states that environment variables can be *set* via the `environ`
716         // global variable. While we can check if a pointer belongs to our allocator, or check
717         // `environ` against a vector which we control, it is likely not worth the effort.
718         platform::environ.add(i).write(insert);
719     } else {
720         put_new_env(insert);
721     }
722     0
723 }
724 
725 #[no_mangle]
726 pub extern "C" fn qsort(
727     base: *mut ::c_void,
728     nel: ::size_t,
729     width: ::size_t,
730     compar: Option<extern "C" fn(*const ::c_void, *const ::c_void) -> ::c_int>,
731 ) {
732     if let Some(comp) = compar {
733         // XXX: check width too?  not specified
734         if nel > 0 {
735             // XXX: maybe try to do mergesort/timsort first and fallback to introsort if memory
736             //      allocation fails?  not sure what is ideal
737             sort::introsort(base as *mut ::c_char, nel, width, comp);
738         }
739     }
740 }
741 
742 #[no_mangle]
743 pub unsafe extern "C" fn rand() -> ::c_int {
744     match RNG {
745         Some(ref mut rng) => RNG_SAMPLER.sample(rng),
746         None => {
747             let mut rng = XorShiftRng::from_seed([1; 16]);
748             let ret = RNG_SAMPLER.sample(&mut rng);
749             RNG = Some(rng);
750             ret
751         }
752     }
753 }
754 
755 #[no_mangle]
756 pub unsafe extern "C" fn rand_r(seed: *mut ::c_uint) -> ::c_int {
757     if seed.is_null() {
758         errno::EINVAL
759     } else {
760         // set the type explicitly so this will fail if the array size for XorShiftRng changes
761         let seed_arr: [u8; 16] = mem::transmute([*seed; 16 / mem::size_of::<::c_uint>()]);
762 
763         let mut rng = XorShiftRng::from_seed(seed_arr);
764         let ret = RNG_SAMPLER.sample(&mut rng);
765 
766         *seed = ret as _;
767 
768         ret
769     }
770 }
771 
772 #[no_mangle]
773 pub unsafe extern "C" fn random() -> ::c_long {
774     // Ported from musl
775 
776     let k: u32;
777     // TODO: lock?
778     random::ensure_x_ptr_init();
779 
780     if random::N == 0 {
781         let x_old = u32::from_ne_bytes(*random::X_PTR);
782         let x_new = random::lcg31_step(x_old);
783         *random::X_PTR = x_new.to_ne_bytes();
784         k = x_new;
785     } else {
786         // The non-u32-aligned way of saying x[i] += x[j]...
787         let x_i_old = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::I)));
788         let x_j = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::J)));
789         let x_i_new = x_i_old.wrapping_add(x_j);
790         *random::X_PTR.add(usize::from(random::I)) = x_i_new.to_ne_bytes();
791 
792         k = x_i_new >> 1;
793 
794         random::I += 1;
795         if random::I == random::N {
796             random::I = 0;
797         }
798 
799         random::J += 1;
800         if random::J == random::N {
801             random::J = 0;
802         }
803     }
804     // TODO: unlock?
805 
806     /* Both branches of this function result in a "u31", which will
807      * always fit in a ::c_long. */
808     ::c_long::try_from(k).unwrap()
809 }
810 
811 #[no_mangle]
812 pub unsafe extern "C" fn realloc(ptr: *mut ::c_void, size: ::size_t) -> *mut ::c_void {
813     let new_ptr = platform::realloc(ptr, size);
814     if new_ptr.is_null() {
815         platform::errno = ENOMEM;
816     }
817     new_ptr
818 }
819 
820 #[no_mangle]
821 pub unsafe extern "C" fn reallocarray(
822     ptr: *mut ::c_void,
823     m: ::size_t,
824     n: ::size_t,
825 ) -> *mut ::c_void {
826     //Handle possible integer overflow in size calculation
827     match m.checked_mul(n) {
828         Some(size) => realloc(ptr, size),
829         None => {
830             // For overflowing multiplication, we have to set errno here
831             platform::errno = ENOMEM;
832             ptr::null_mut()
833         }
834     }
835 }
836 
837 #[no_mangle]
838 pub unsafe extern "C" fn realpath(
839     pathname: *const ::c_char,
840     resolved: *mut ::c_char,
841 ) -> *mut ::c_char {
842     let ptr = if resolved.is_null() {
843         malloc(limits::PATH_MAX) as *mut ::c_char
844     } else {
845         resolved
846     };
847 
848     let out = slice::from_raw_parts_mut(ptr as *mut u8, limits::PATH_MAX);
849     {
850         let file = match File::open(&CStr::from_ptr(pathname), ::O_PATH | ::O_CLOEXEC) {
851             Ok(file) => file,
852             Err(_) => return ptr::null_mut(),
853         };
854 
855         let len = out.len();
856         let read = platform::pal::fpath(*file, out[..len - 1].as_mut_ptr() as *const i8);
857         if read < 0 {
858             return ptr::null_mut();
859         }
860         out[read as usize] = 0;
861     }
862 
863     ptr
864 }
865 
866 #[no_mangle]
867 pub unsafe extern "C" fn seed48(seed16v: *mut ::c_ushort) -> *mut ::c_ushort {
868     rand48::reset_a_and_c();
869 
870     // Stash current DEFAULT_XSUBI value in SEED48_XSUBI
871     rand48::SEED48_XSUBI = rand48::DEFAULT_XSUBI;
872 
873     // Set DEFAULT_XSUBI from the argument provided
874     let xsubi_value = rand48::u48_from_ushort_arr3(&*(seed16v as *const [::c_ushort; 3]));
875     rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value);
876 
877     // Return the stashed value
878     rand48::SEED48_XSUBI.as_mut_ptr()
879 }
880 
881 unsafe fn copy_kv(
882     existing: *mut ::c_char,
883     key: *const ::c_char,
884     value: *const ::c_char,
885     key_len: usize,
886     value_len: usize,
887 ) {
888     core::ptr::copy_nonoverlapping(key, existing, key_len);
889     core::ptr::write(existing.add(key_len), b'=' as ::c_char);
890     core::ptr::copy_nonoverlapping(value, existing.add(key_len + 1), value_len);
891     core::ptr::write(existing.add(key_len + 1 + value_len), 0);
892 }
893 
894 #[no_mangle]
895 pub unsafe extern "C" fn setenv(
896     key: *const ::c_char,
897     value: *const ::c_char,
898     overwrite: ::c_int,
899 ) -> ::c_int {
900     let key_len = strlen(key);
901     let value_len = strlen(value);
902 
903     if let Some((i, existing)) = find_env(key) {
904         if overwrite == 0 {
905             return 0;
906         }
907 
908         let existing_len = strlen(existing);
909 
910         if existing_len >= value_len {
911             // Reuse existing element's allocation
912             core::ptr::copy_nonoverlapping(value, existing, value_len);
913             //TODO: fill to end with zeroes
914             core::ptr::write(existing.add(value_len), 0);
915         } else {
916             // Reuse platform::environ slot, but allocate a new pointer.
917             let ptr =
918                 platform::alloc(key_len as usize + 1 + value_len as usize + 1) as *mut ::c_char;
919             copy_kv(ptr, key, value, key_len, value_len);
920             platform::environ.add(i).write(ptr);
921         }
922     } else {
923         // Expand platform::environ and allocate a new pointer.
924         let ptr = platform::alloc(key_len as usize + 1 + value_len as usize + 1) as *mut ::c_char;
925         copy_kv(ptr, key, value, key_len, value_len);
926         put_new_env(ptr);
927     }
928 
929     //platform::free(platform::pal::inner_environ[index] as *mut ::c_void);
930 
931     0
932 }
933 
934 // #[no_mangle]
935 pub extern "C" fn setkey(_key: *const ::c_char) {
936     unimplemented!();
937 }
938 
939 #[no_mangle]
940 pub unsafe extern "C" fn setstate(state: *mut ::c_char) -> *mut ::c_char {
941     /* Ported from musl. The state parameter is no longer const in newer
942      * versions of POSIX. */
943 
944     // TODO: lock?
945     let old_state = random::save_state();
946     random::load_state(state.cast::<_>());
947     // TODO: unlock?
948     old_state.cast::<_>()
949 }
950 
951 #[no_mangle]
952 pub unsafe extern "C" fn srand(seed: ::c_uint) {
953     RNG = Some(XorShiftRng::from_seed([seed as u8; 16]));
954 }
955 
956 #[no_mangle]
957 pub unsafe extern "C" fn srand48(seedval: ::c_long) {
958     rand48::reset_a_and_c();
959 
960     /* Set the high 32 bits of the 48-bit X_i value to the lower 32 bits
961      * of the input argument, and the lower 16 bits to 0x330e, as
962      * specified in POSIX. */
963     let xsubi_value = (u64::from(seedval as u32) << 16) | 0x330e;
964     rand48::DEFAULT_XSUBI = rand48::ushort_arr3_from_u48(xsubi_value);
965 }
966 
967 #[no_mangle]
968 pub unsafe extern "C" fn srandom(seed: ::c_uint) {
969     // Ported from musl
970 
971     // TODO: lock?
972     random::seed(seed);
973     // TODO: unlock?
974 }
975 
976 #[no_mangle]
977 pub unsafe extern "C" fn strtod(s: *const ::c_char, endptr: *mut *mut ::c_char) -> ::c_double {
978     strto_float_impl!(f64, s, endptr)
979 }
980 #[no_mangle]
981 pub unsafe extern "C" fn strtof(s: *const ::c_char, endptr: *mut *mut ::c_char) -> ::c_float {
982     strto_float_impl!(f32, s, endptr)
983 }
984 
985 pub fn is_positive(ch: ::c_char) -> Option<(bool, isize)> {
986     match ch {
987         0 => None,
988         ch if ch == b'+' as ::c_char => Some((true, 1)),
989         ch if ch == b'-' as ::c_char => Some((false, 1)),
990         _ => Some((true, 0)),
991     }
992 }
993 
994 pub unsafe fn detect_base(s: *const ::c_char) -> Option<(::c_int, isize)> {
995     let first = *s as u8;
996     match first {
997         0 => None,
998         b'0' => {
999             let second = *s.offset(1) as u8;
1000             if second == b'X' || second == b'x' {
1001                 Some((16, 2))
1002             } else if second >= b'0' && second <= b'7' {
1003                 Some((8, 1))
1004             } else {
1005                 // in this case, the prefix (0) is going to be the number
1006                 Some((8, 0))
1007             }
1008         }
1009         _ => Some((10, 0)),
1010     }
1011 }
1012 
1013 pub unsafe fn convert_octal(s: *const ::c_char) -> Option<(::c_ulong, isize, bool)> {
1014     if *s != 0 && *s == b'0' as ::c_char {
1015         if let Some((val, idx, overflow)) = convert_integer(s.offset(1), 8) {
1016             Some((val, idx + 1, overflow))
1017         } else {
1018             // in case the prefix is not actually a prefix
1019             Some((0, 1, false))
1020         }
1021     } else {
1022         None
1023     }
1024 }
1025 
1026 pub unsafe fn convert_hex(s: *const ::c_char) -> Option<(::c_ulong, isize, bool)> {
1027     if (*s != 0 && *s == b'0' as ::c_char)
1028         && (*s.offset(1) != 0
1029             && (*s.offset(1) == b'x' as ::c_char || *s.offset(1) == b'X' as ::c_char))
1030     {
1031         convert_integer(s.offset(2), 16).map(|(val, idx, overflow)| (val, idx + 2, overflow))
1032     } else {
1033         convert_integer(s, 16).map(|(val, idx, overflow)| (val, idx, overflow))
1034     }
1035 }
1036 
1037 pub unsafe fn convert_integer(
1038     s: *const ::c_char,
1039     base: ::c_int,
1040 ) -> Option<(::c_ulong, isize, bool)> {
1041     // -1 means the character is invalid
1042     #[rustfmt::skip]
1043     const LOOKUP_TABLE: [::c_long; 256] = [
1044         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1045         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1046         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1047          0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
1048         -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1049         25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
1050         -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
1051         25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
1052         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1053         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1054         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1055         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1056         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1057         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1058         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1059         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1060     ];
1061 
1062     let mut num: ::c_ulong = 0;
1063     let mut idx = 0;
1064     let mut overflowed = false;
1065 
1066     loop {
1067         // `-1 as usize` is usize::MAX
1068         // `-1 as u8 as usize` is u8::MAX
1069         // It extends by the sign bit unless we cast it to unsigned first.
1070         let val = LOOKUP_TABLE[*s.offset(idx) as u8 as usize];
1071         if val == -1 || val as ::c_int >= base {
1072             break;
1073         } else {
1074             if let Some(res) = num
1075                 .checked_mul(base as ::c_ulong)
1076                 .and_then(|num| num.checked_add(val as ::c_ulong))
1077             {
1078                 num = res;
1079             } else {
1080                 platform::errno = ERANGE;
1081                 num = ::c_ulong::max_value();
1082                 overflowed = true;
1083             }
1084 
1085             idx += 1;
1086         }
1087     }
1088 
1089     if idx > 0 {
1090         Some((num, idx, overflowed))
1091     } else {
1092         None
1093     }
1094 }
1095 
1096 #[no_mangle]
1097 pub unsafe extern "C" fn strtoul(
1098     s: *const ::c_char,
1099     endptr: *mut *mut ::c_char,
1100     base: ::c_int,
1101 ) -> ::c_ulong {
1102     strto_impl!(
1103         ::c_ulong,
1104         false,
1105         ::c_ulong::max_value(),
1106         ::c_ulong::min_value(),
1107         s,
1108         endptr,
1109         base
1110     )
1111 }
1112 
1113 #[no_mangle]
1114 pub unsafe extern "C" fn strtol(
1115     s: *const ::c_char,
1116     endptr: *mut *mut ::c_char,
1117     base: ::c_int,
1118 ) -> ::c_long {
1119     strto_impl!(
1120         ::c_long,
1121         true,
1122         ::c_long::max_value(),
1123         ::c_long::min_value(),
1124         s,
1125         endptr,
1126         base
1127     )
1128 }
1129 
1130 #[no_mangle]
1131 pub unsafe extern "C" fn strtoull(
1132     s: *const ::c_char,
1133     endptr: *mut *mut ::c_char,
1134     base: ::c_int,
1135 ) -> ::c_ulonglong {
1136     strto_impl!(
1137         ::c_ulonglong,
1138         false,
1139         ::c_ulonglong::max_value(),
1140         ::c_ulonglong::min_value(),
1141         s,
1142         endptr,
1143         base
1144     )
1145 }
1146 
1147 #[no_mangle]
1148 pub unsafe extern "C" fn strtoll(
1149     s: *const ::c_char,
1150     endptr: *mut *mut ::c_char,
1151     base: ::c_int,
1152 ) -> ::c_longlong {
1153     strto_impl!(
1154         ::c_longlong,
1155         true,
1156         ::c_longlong::max_value(),
1157         ::c_longlong::min_value(),
1158         s,
1159         endptr,
1160         base
1161     )
1162 }
1163 
1164 #[no_mangle]
1165 pub unsafe extern "C" fn system(command: *const ::c_char) -> ::c_int {
1166     //TODO: share code with popen
1167 
1168     let child_pid = unistd::fork();
1169     if child_pid == 0 {
1170         let command_nonnull = if command.is_null() {
1171             "exit 0\0".as_ptr()
1172         } else {
1173             command as *const u8
1174         };
1175 
1176         let shell = "/bin/sh\0".as_ptr();
1177 
1178         let args = [
1179             "sh\0".as_ptr(),
1180             "-c\0".as_ptr(),
1181             command_nonnull,
1182             ptr::null(),
1183         ];
1184 
1185         unistd::execv(
1186             shell as *const ::c_char,
1187             args.as_ptr() as *const *const ::c_char,
1188         );
1189 
1190         exit(127);
1191 
1192         unreachable!();
1193     } else if child_pid > 0 {
1194         let mut wstatus = 0;
1195         if platform::pal::waitpid(child_pid, &mut wstatus, 0) == !0 {
1196             return -1;
1197         }
1198 
1199         wstatus
1200     } else {
1201         -1
1202     }
1203 }
1204 
1205 // #[no_mangle]
1206 pub extern "C" fn ttyslot() -> ::c_int {
1207     unimplemented!();
1208 }
1209 
1210 // #[no_mangle]
1211 pub extern "C" fn unlockpt(_fildes: ::c_int) -> ::c_int {
1212     unimplemented!();
1213 }
1214 
1215 #[no_mangle]
1216 pub unsafe extern "C" fn unsetenv(key: *const ::c_char) -> ::c_int {
1217     if let Some((i, _)) = find_env(key) {
1218         if platform::environ == platform::OUR_ENVIRON.as_mut_ptr() {
1219             // No need to worry about updating the pointer, this does not
1220             // reallocate in any way. And the final null is already shifted back.
1221             platform::OUR_ENVIRON.remove(i);
1222 
1223             // My UB paranoia.
1224             platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
1225         } else {
1226             platform::OUR_ENVIRON.clear();
1227             platform::OUR_ENVIRON.extend(
1228                 platform::environ_iter()
1229                     .enumerate()
1230                     .filter(|&(j, _)| j != i)
1231                     .map(|(_, v)| v),
1232             );
1233             platform::OUR_ENVIRON.push(core::ptr::null_mut());
1234             platform::environ = platform::OUR_ENVIRON.as_mut_ptr();
1235         }
1236     }
1237     0
1238 }
1239 
1240 #[no_mangle]
1241 pub unsafe extern "C" fn valloc(size: ::size_t) -> *mut ::c_void {
1242     /* sysconf(_SC_PAGESIZE) is a ::c_long and may in principle not
1243      * convert correctly to a ::size_t. */
1244     match ::size_t::try_from(sysconf(_SC_PAGESIZE)) {
1245         Ok(page_size) => {
1246             /* valloc() is not supposed to be able to set errno to
1247              * EINVAL, hence no call to memalign(). */
1248             let ptr = platform::alloc_align(size, page_size);
1249             if ptr.is_null() {
1250                 platform::errno = ENOMEM;
1251             }
1252             ptr
1253         }
1254         Err(_) => {
1255             // A corner case. No errno setting.
1256             ptr::null_mut()
1257         }
1258     }
1259 }
1260 
1261 #[no_mangle]
1262 pub extern "C" fn wcstombs(s: *mut ::c_char, mut pwcs: *const ::wchar_t, n: ::size_t) -> ::size_t {
1263     let mut state: mbstate_t = mbstate_t {};
1264     wcsrtombs(s, &mut pwcs, n, &mut state)
1265 }
1266 
1267 #[no_mangle]
1268 pub unsafe extern "C" fn wctomb(s: *mut ::c_char, wc: ::wchar_t) -> ::c_int {
1269     let mut state: mbstate_t = mbstate_t {};
1270     let result: usize = wcrtomb(s, wc, &mut state);
1271 
1272     if result == -1isize as usize {
1273         return -1;
1274     }
1275     if result == -2isize as usize {
1276         return -1;
1277     }
1278 
1279     result as ::c_int
1280 }
1281