#![cfg(target_arch = "wasm32")]
use core::ffi::{c_char, c_int, c_void};
const HEADER: usize = 16;
#[no_mangle]
pub unsafe extern "C" fn malloc(size: usize) -> *mut c_void {
if size == 0 {
return malloc(1);
}
let total = size + HEADER;
let layout = match core::alloc::Layout::from_size_align(total, HEADER) {
Ok(l) => l,
Err(_) => return core::ptr::null_mut(),
};
let base = alloc::alloc::alloc(layout);
if base.is_null() {
return core::ptr::null_mut();
}
*(base as *mut usize) = size;
base.add(HEADER) as *mut c_void
}
#[no_mangle]
pub unsafe extern "C" fn free(ptr: *mut c_void) {
if ptr.is_null() {
return;
}
let base = (ptr as *mut u8).sub(HEADER);
let size = *(base as *mut usize);
let layout = core::alloc::Layout::from_size_align_unchecked(size + HEADER, HEADER);
alloc::alloc::dealloc(base, layout);
}
#[no_mangle]
pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
if ptr.is_null() {
return malloc(size);
}
if size == 0 {
free(ptr);
return core::ptr::null_mut();
}
let base = (ptr as *mut u8).sub(HEADER);
let old_size = *(base as *mut usize);
let old_layout = core::alloc::Layout::from_size_align_unchecked(old_size + HEADER, HEADER);
let new_base = alloc::alloc::realloc(base, old_layout, size + HEADER);
if new_base.is_null() {
return core::ptr::null_mut();
}
*(new_base as *mut usize) = size;
new_base.add(HEADER) as *mut c_void
}
#[no_mangle]
pub unsafe extern "C" fn strchr(s: *const c_char, c: c_int) -> *mut c_char {
let target = c as u8 as c_char;
let mut p = s;
loop {
let ch = *p;
if ch == target {
return p as *mut c_char;
}
if ch == 0 {
return core::ptr::null_mut();
}
p = p.add(1);
}
}
#[no_mangle]
pub unsafe extern "C" fn time(t: *mut i64) -> i64 {
const REFERENCE_EPOCH: i64 = 1_704_067_200;
if !t.is_null() {
*t = REFERENCE_EPOCH;
}
REFERENCE_EPOCH
}
#[no_mangle]
pub unsafe extern "C" fn clock() -> core::ffi::c_long {
0
}
#[no_mangle]
pub unsafe extern "C" fn sysconf(_name: c_int) -> core::ffi::c_long {
65536
}
#[no_mangle]
pub unsafe extern "C" fn strtoul(
nptr: *const c_char,
endptr: *mut *mut c_char,
base: c_int,
) -> core::ffi::c_ulong {
use core::ffi::c_ulong;
if nptr.is_null() {
if !endptr.is_null() {
*endptr = nptr as *mut c_char;
}
return 0;
}
let mut p = nptr;
while matches!(*p as u8, b' ' | b'\t' | b'\n' | 0x0b | 0x0c | b'\r') {
p = p.add(1);
}
let mut neg = false;
match *p as u8 {
b'+' => p = p.add(1),
b'-' => {
neg = true;
p = p.add(1);
}
_ => {}
}
let mut base = base;
if (base == 0 || base == 16) && *p as u8 == b'0' && matches!(*p.add(1) as u8, b'x' | b'X') {
p = p.add(2);
base = 16;
} else if base == 0 {
base = if *p as u8 == b'0' { 8 } else { 10 };
}
let radix = base as c_ulong;
let mut acc: c_ulong = 0;
let mut any = false;
let mut overflow = false;
loop {
let c = *p as u8;
let digit = match c {
b'0'..=b'9' => (c - b'0') as c_ulong,
b'a'..=b'z' => (c - b'a' + 10) as c_ulong,
b'A'..=b'Z' => (c - b'A' + 10) as c_ulong,
_ => break,
};
if digit >= radix {
break;
}
let (mul, o1) = acc.overflowing_mul(radix);
let (add, o2) = mul.overflowing_add(digit);
if o1 || o2 {
overflow = true;
}
acc = add;
any = true;
p = p.add(1);
}
if !endptr.is_null() {
*endptr = (if any { p } else { nptr }) as *mut c_char;
}
if overflow {
return c_ulong::MAX;
}
if neg {
acc.wrapping_neg()
} else {
acc
}
}
#[no_mangle]
pub unsafe extern "C" fn mmap(
_addr: *mut c_void,
_len: usize,
_prot: c_int,
_flags: c_int,
_fd: c_int,
_off: i64,
) -> *mut c_void {
usize::MAX as *mut c_void
}
#[no_mangle]
pub unsafe extern "C" fn munmap(_addr: *mut c_void, _len: usize) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn mprotect(_addr: *mut c_void, _len: usize, _prot: c_int) -> c_int {
0
}
#[no_mangle]
pub unsafe extern "C" fn strtoull(
nptr: *const c_char,
endptr: *mut *mut c_char,
mut base: c_int,
) -> u64 {
let mut p = nptr as *const u8;
while matches!(*p, b' ' | b'\t' | b'\n' | 0x0b | 0x0c | b'\r') {
p = p.add(1);
}
let mut negate = false;
if *p == b'+' {
p = p.add(1);
} else if *p == b'-' {
negate = true;
p = p.add(1);
}
if (base == 0 || base == 16) && *p == b'0' && matches!(*p.add(1), b'x' | b'X') {
p = p.add(2);
base = 16;
} else if base == 0 {
base = 10;
}
let radix = base as u64;
let mut acc: u64 = 0;
let start = p;
loop {
let digit = match *p {
c @ b'0'..=b'9' => (c - b'0') as u64,
c @ b'a'..=b'z' => (c - b'a' + 10) as u64,
c @ b'A'..=b'Z' => (c - b'A' + 10) as u64,
_ => break,
};
if digit >= radix {
break;
}
acc = acc.wrapping_mul(radix).wrapping_add(digit);
p = p.add(1);
}
if !endptr.is_null() {
let end = if p == start { nptr } else { p as *const c_char };
*endptr = end as *mut c_char;
}
if negate {
acc.wrapping_neg()
} else {
acc
}
}
#[repr(C)]
pub struct Tm {
pub tm_sec: c_int,
pub tm_min: c_int,
pub tm_hour: c_int,
pub tm_mday: c_int,
pub tm_mon: c_int,
pub tm_year: c_int,
pub tm_wday: c_int,
pub tm_yday: c_int,
pub tm_isdst: c_int,
}
unsafe fn fill_tm(secs: i64, result: *mut Tm) {
let days = secs.div_euclid(86_400);
let rem = secs.rem_euclid(86_400);
(*result).tm_hour = (rem / 3600) as c_int;
(*result).tm_min = ((rem % 3600) / 60) as c_int;
(*result).tm_sec = (rem % 60) as c_int;
(*result).tm_wday = (((days % 7) + 4 + 7) % 7) as c_int;
let z = days + 719_468;
let era = if z >= 0 { z } else { z - 146_096 } / 146_097;
let doe = z - era * 146_097; let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; let y = yoe + era * 400;
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); let mp = (5 * doy + 2) / 153; let d = doy - (153 * mp + 2) / 5 + 1; let m = if mp < 10 { mp + 3 } else { mp - 9 }; let year = if m <= 2 { y + 1 } else { y };
(*result).tm_year = (year - 1900) as c_int;
(*result).tm_mon = (m - 1) as c_int;
(*result).tm_mday = d as c_int;
let jan1 = days_from_civil(year, 1, 1);
(*result).tm_yday = (days - jan1) as c_int;
(*result).tm_isdst = 0;
}
fn days_from_civil(y: i64, m: i64, d: i64) -> i64 {
let y = if m <= 2 { y - 1 } else { y };
let era = if y >= 0 { y } else { y - 399 } / 400;
let yoe = y - era * 400;
let doy = (153 * (if m > 2 { m - 3 } else { m + 9 }) + 2) / 5 + d - 1;
let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
era * 146_097 + doe - 719_468
}
#[no_mangle]
pub unsafe extern "C" fn gmtime_r(timep: *const i64, result: *mut Tm) -> *mut Tm {
if timep.is_null() || result.is_null() {
return core::ptr::null_mut();
}
fill_tm(*timep, result);
result
}
#[no_mangle]
pub unsafe extern "C" fn localtime_r(timep: *const i64, result: *mut Tm) -> *mut Tm {
gmtime_r(timep, result)
}