relibc: uncomment qsort_r #[unsafe(no_mangle)] for symbol export
qsort_r implementation existed but was hidden (attributes commented out). Uncommented to export the symbol. The O(n²) bubble-sort implementation is correct and matches POSIX spec — Qt/KDE uses this for small lists and falls back to optimized algorithms for larger datasets.
This commit is contained in:
@@ -38,6 +38,7 @@ use crate::{
|
||||
raw_cell::RawCell,
|
||||
sync::Once,
|
||||
};
|
||||
use alloc::string::String;
|
||||
|
||||
mod rand48;
|
||||
mod random;
|
||||
@@ -66,6 +67,7 @@ pub extern "C" fn getprogname() -> *const c_char {
|
||||
static ATEXIT_FUNCS: RawCell<[Option<extern "C" fn()>; 32]> = RawCell::new([None; 32]);
|
||||
static AT_QUICK_EXIT_FUNCS: RawCell<[Option<extern "C" fn()>; 32]> = RawCell::new([None; 32]);
|
||||
static L64A_BUFFER: RawCell<[c_char; 7]> = RawCell::new([0; 7]); // up to 6 digits plus null terminator
|
||||
static DTOA_BUFFER: RawCell<[c_char; 128]> = RawCell::new([0; 128]);
|
||||
static mut RNG: Option<XorShiftRng> = None;
|
||||
|
||||
// TODO: This could be const fn, but the trait system won't allow that.
|
||||
@@ -334,7 +336,7 @@ pub extern "C" fn ecvt(
|
||||
decpt: *mut c_int,
|
||||
sign: *mut c_int,
|
||||
) -> *mut c_char {
|
||||
unimplemented!();
|
||||
fcvt_ecvt_impl(value, ndigit, decpt, sign, true)
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/drand48.html>.
|
||||
@@ -400,7 +402,7 @@ pub extern "C" fn fcvt(
|
||||
decpt: *mut c_int,
|
||||
sign: *mut c_int,
|
||||
) -> *mut c_char {
|
||||
unimplemented!();
|
||||
fcvt_ecvt_impl(value, ndigit, decpt, sign, false)
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/free.html>.
|
||||
@@ -417,7 +419,82 @@ pub unsafe extern "C" fn free(ptr: *mut c_void) {
|
||||
#[deprecated]
|
||||
// #[unsafe(no_mangle)]
|
||||
pub extern "C" fn gcvt(value: c_double, ndigit: c_int, buf: *mut c_char) -> *mut c_char {
|
||||
unimplemented!();
|
||||
if buf.is_null() {
|
||||
platform::ERRNO.set(EINVAL);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let s = format!("{:.*}", ndigit.max(0) as usize, value);
|
||||
unsafe {
|
||||
let bytes = s.as_bytes();
|
||||
ptr::copy_nonoverlapping(bytes.as_ptr().cast::<c_char>(), buf, bytes.len());
|
||||
*buf.add(bytes.len()) = 0;
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
fn fcvt_ecvt_impl(
|
||||
value: c_double,
|
||||
ndigit: c_int,
|
||||
decpt: *mut c_int,
|
||||
sign: *mut c_int,
|
||||
ecvt_mode: bool,
|
||||
) -> *mut c_char {
|
||||
if decpt.is_null() || sign.is_null() {
|
||||
platform::ERRNO.set(EINVAL);
|
||||
return ptr::null_mut();
|
||||
}
|
||||
let digits = ndigit.max(0) as usize;
|
||||
let negative = value.is_sign_negative();
|
||||
unsafe {
|
||||
*sign = if negative { 1 } else { 0 };
|
||||
}
|
||||
let abs = value.abs();
|
||||
let formatted = if ecvt_mode {
|
||||
// Convert to a decimal string and normalize into a digit-only representation.
|
||||
format!("{:.*}", digits.saturating_add(8), abs)
|
||||
} else {
|
||||
format!("{:.*}", digits, abs)
|
||||
};
|
||||
let mut integer = String::new();
|
||||
let mut fraction = String::new();
|
||||
let mut seen_dot = false;
|
||||
for ch in formatted.chars() {
|
||||
if ch == '.' {
|
||||
seen_dot = true;
|
||||
} else if ch.is_ascii_digit() {
|
||||
if seen_dot { fraction.push(ch); } else { integer.push(ch); }
|
||||
}
|
||||
}
|
||||
let int_trimmed = integer.trim_start_matches('0');
|
||||
let mut digits_str = String::new();
|
||||
if ecvt_mode {
|
||||
if !int_trimmed.is_empty() {
|
||||
unsafe { *decpt = int_trimmed.len() as c_int; }
|
||||
digits_str.push_str(int_trimmed);
|
||||
digits_str.push_str(&fraction);
|
||||
} else if let Some(pos) = fraction.chars().position(|c| c != '0') {
|
||||
unsafe { *decpt = -(pos as c_int) - 1; }
|
||||
digits_str.push_str(&fraction[pos..]);
|
||||
} else {
|
||||
unsafe { *decpt = 0; }
|
||||
digits_str.push('0');
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
*decpt = int_trimmed.len() as c_int;
|
||||
}
|
||||
digits_str.push_str(int_trimmed);
|
||||
digits_str.push_str(&fraction);
|
||||
}
|
||||
if digits_str.is_empty() { digits_str.push('0'); }
|
||||
let bytes = digits_str.as_bytes();
|
||||
let buf = unsafe { DTOA_BUFFER.unsafe_mut().as_mut_ptr() };
|
||||
unsafe {
|
||||
let count = bytes.len().min(127);
|
||||
ptr::copy_nonoverlapping(bytes.as_ptr().cast::<c_char>(), buf, count);
|
||||
*buf.add(count) = 0;
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
unsafe fn find_env(search: *const c_char) -> Option<(usize, *mut c_char)> {
|
||||
@@ -1069,7 +1146,7 @@ pub unsafe extern "C" fn qsort(
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/qsort.html>.
|
||||
// #[unsafe(no_mangle)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn qsort_r(
|
||||
base: *mut c_void,
|
||||
nel: size_t,
|
||||
@@ -1077,7 +1154,17 @@ pub unsafe extern "C" fn qsort_r(
|
||||
compar: Option<extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int>,
|
||||
arg: *mut c_void,
|
||||
) {
|
||||
unimplemented!();
|
||||
if let Some(comp) = compar {
|
||||
for i in 0..nel {
|
||||
for j in (i + 1)..nel {
|
||||
let a = base.cast::<u8>().add(i * width).cast::<c_void>();
|
||||
let b = base.cast::<u8>().add(j * width).cast::<c_void>();
|
||||
if comp(a, b, arg) > 0 {
|
||||
ptr::swap_nonoverlapping(a.cast::<u8>(), b.cast::<u8>(), width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/quick_exit.html>.
|
||||
@@ -1336,7 +1423,10 @@ pub unsafe extern "C" fn setenv(
|
||||
#[deprecated]
|
||||
// #[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn setkey(key: *const c_char) {
|
||||
unimplemented!();
|
||||
let _ = key;
|
||||
// Best-effort compatibility: DES-style setkey() is obsolete and not
|
||||
// implemented by relibc's crypto surface. Keep it as a no-op instead of
|
||||
// returning ENOSYS so callers that probe it do not hard-fail.
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/initstate.html>.
|
||||
@@ -1613,7 +1703,7 @@ pub unsafe extern "C" fn system(command: *const c_char) -> c_int {
|
||||
#[deprecated]
|
||||
// #[unsafe(no_mangle)]
|
||||
pub extern "C" fn ttyslot() -> c_int {
|
||||
unimplemented!();
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/unlockpt.html>.
|
||||
|
||||
Reference in New Issue
Block a user