Skip to main content

c/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![feature(c_variadic)]
3#![feature(linkage)]
4#![cfg_attr(target_arch = "aarch64", feature(f128))]
5#![cfg_attr(target_arch = "riscv64", feature(f128))]
6#![allow(dead_code, non_camel_case_types)]
7// A libc necessarily keeps mutable global state (stdio tables, passwd/group
8// buffers, resolver state).  References to it are deliberate and confined to
9// the C ABI entry points.
10#![allow(static_mut_refs)]
11// C `_Complex` values are passed as two floating-point registers on every
12// supported target; Rust tuples use the same SysV/AAPCS classification.
13#![allow(improper_ctypes_definitions)]
14
15use core::ffi::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ulonglong, c_void, VaList};
16use core::ptr::null_mut;
17use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
18
19include!("encoding_tables.rs");
20include!("math_helpers.rs");
21include!("math_bitmanip.rs");
22include!("math_sqrtfmod.rs");
23include!("math_trig.rs");
24include!("math_exp.rs");
25include!("math_erf.rs");
26include!("math_lgamma.rs");
27include!("math_tgamma.rs");
28include!("math_bessel.rs");
29include!("alloc.rs");
30include!("math_log.rs");
31include!("math_pow.rs");
32include!("math_hypot.rs");
33include!("math_hyperbolic.rs");
34include!("math_invtrig.rs");
35include!("math_lrint.rs");
36include!("math_long_double.rs");
37
38// ============================================================
39// errno
40// ============================================================
41
42const EILSEQ: c_int = 84;
43const EINVAL: c_int = 22;
44const EFAULT: c_int = 14;
45const E2BIG: c_int = 7;
46
47const LC_CTYPE: c_int = 0;
48const LC_NUMERIC: c_int = 1;
49const LC_TIME: c_int = 2;
50const LC_COLLATE: c_int = 3;
51const LC_MONETARY: c_int = 4;
52const LC_MESSAGES: c_int = 5;
53const LC_ALL: c_int = 6;
54const ENOMEM: c_int = 12;
55const EINTR: c_int = 4;
56const EPERM: c_int = 1;
57const EAGAIN: c_int = 11;
58const EBUSY: c_int = 16;
59const EDEADLK: c_int = 35;
60const ETIMEDOUT: c_int = 110;
61const ECANCELED: c_int = 125;
62const EOVERFLOW: c_int = 75;
63const EOWNERDEAD: c_int = 130;
64const ENOTRECOVERABLE: c_int = 131;
65
66static mut ERRNO: c_int = 0;
67
68#[no_mangle]
69pub unsafe extern "C" fn __errno_location() -> *mut c_int {
70    core::ptr::addr_of_mut!(ERRNO)
71}
72
73#[cfg(not(test))]
74#[panic_handler]
75fn panic(_: &core::panic::PanicInfo) -> ! {
76    loop {}
77}
78
79// Required by the Rust runtime; panic=abort never unwinds.
80#[cfg(not(test))]
81#[no_mangle]
82pub extern "C" fn rust_eh_personality() {}
83
84// ============================================================
85// Constants
86// ============================================================
87
88const PROT_READ: i32 = 1;
89const PROT_WRITE: i32 = 2;
90const MAP_SHARED: i32 = 0x01;
91const MAP_PRIVATE: i32 = 0x02;
92const MAP_ANONYMOUS: i32 = 0x20;
93
94// ============================================================
95// Architecture abstraction for syscalls
96// ============================================================
97
98trait Syscalls {
99    unsafe fn syscall0(n: i64) -> i64;
100    unsafe fn syscall1(n: i64, a1: i64) -> i64;
101    unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64;
102    unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64;
103    unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64;
104    unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64;
105    unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64;
106    unsafe fn syscall_noreturn1(n: i64, a1: i64) -> !;
107}
108
109struct X86_64;
110struct Aarch64;
111struct Riscv64;
112
113#[cfg(target_arch = "x86_64")]
114impl Syscalls for X86_64 {
115    #[inline(always)]
116    unsafe fn syscall0(n: i64) -> i64 {
117        let result: i64;
118        core::arch::asm!(
119            "syscall",
120            inlateout("rax") n => result,
121            lateout("rcx") _,
122            lateout("r11") _,
123        );
124        result
125    }
126    #[inline(always)]
127    unsafe fn syscall1(n: i64, a1: i64) -> i64 {
128        let result: i64;
129        core::arch::asm!(
130            "syscall",
131            inlateout("rax") n => result,
132            in("rdi") a1,
133            lateout("rcx") _,
134            lateout("r11") _,
135        );
136        result
137    }
138    #[inline(always)]
139    unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64 {
140        let result: i64;
141        core::arch::asm!(
142            "syscall",
143            inlateout("rax") n => result,
144            in("rdi") a1,
145            in("rsi") a2,
146            lateout("rcx") _,
147            lateout("r11") _,
148        );
149        result
150    }
151    #[inline(always)]
152    unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64 {
153        let result: i64;
154        core::arch::asm!(
155            "syscall",
156            inlateout("rax") n => result,
157            in("rdi") a1,
158            in("rsi") a2,
159            in("rdx") a3,
160            lateout("rcx") _,
161            lateout("r11") _,
162        );
163        result
164    }
165    #[inline(always)]
166    unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64 {
167        let result: i64;
168        core::arch::asm!(
169            "syscall",
170            inlateout("rax") n => result,
171            in("rdi") a1,
172            in("rsi") a2,
173            in("rdx") a3,
174            in("r10") a4,
175            lateout("rcx") _,
176            lateout("r11") _,
177        );
178        result
179    }
180    #[inline(always)]
181    unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64 {
182        let result: i64;
183        core::arch::asm!(
184            "syscall",
185            inlateout("rax") n => result,
186            in("rdi") a1,
187            in("rsi") a2,
188            in("rdx") a3,
189            in("r10") a4,
190            in("r8") a5,
191            lateout("rcx") _,
192            lateout("r11") _,
193        );
194        result
195    }
196    #[inline(always)]
197    unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64 {
198        let result: i64;
199        core::arch::asm!(
200            "syscall",
201            inlateout("rax") n => result,
202            in("rdi") a1,
203            in("rsi") a2,
204            in("rdx") a3,
205            in("r10") a4,
206            in("r8") a5,
207            in("r9") a6,
208            lateout("rcx") _,
209            lateout("r11") _,
210        );
211        result
212    }
213    #[inline(always)]
214    unsafe fn syscall_noreturn1(n: i64, a1: i64) -> ! {
215        core::arch::asm!(
216            "syscall",
217            in("rax") n,
218            in("rdi") a1,
219            options(noreturn)
220        );
221    }
222}
223
224#[cfg(target_arch = "aarch64")]
225impl Syscalls for Aarch64 {
226    #[inline(always)]
227    unsafe fn syscall0(n: i64) -> i64 {
228        let result: i64;
229        core::arch::asm!(
230            "svc #0",
231            inlateout("x8") n => _,
232            lateout("x0") result,
233            options(nostack),
234        );
235        result
236    }
237    #[inline(always)]
238    unsafe fn syscall1(n: i64, a1: i64) -> i64 {
239        let result: i64;
240        core::arch::asm!(
241            "svc #0",
242            inlateout("x8") n => _,
243            inlateout("x0") a1 => result,
244            options(nostack),
245        );
246        result
247    }
248    #[inline(always)]
249    unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64 {
250        let result: i64;
251        core::arch::asm!(
252            "svc #0",
253            inlateout("x8") n => _,
254            inlateout("x0") a1 => result,
255            inlateout("x1") a2 => _,
256            options(nostack),
257        );
258        result
259    }
260    #[inline(always)]
261    unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64 {
262        let result: i64;
263        core::arch::asm!(
264            "svc #0",
265            inlateout("x8") n => _,
266            inlateout("x0") a1 => result,
267            inlateout("x1") a2 => _,
268            inlateout("x2") a3 => _,
269            options(nostack),
270        );
271        result
272    }
273    #[inline(always)]
274    unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64 {
275        let result: i64;
276        core::arch::asm!(
277            "svc #0",
278            inlateout("x8") n => _,
279            inlateout("x0") a1 => result,
280            inlateout("x1") a2 => _,
281            inlateout("x2") a3 => _,
282            inlateout("x3") a4 => _,
283            options(nostack),
284        );
285        result
286    }
287    #[inline(always)]
288    unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64 {
289        let result: i64;
290        core::arch::asm!(
291            "svc #0",
292            inlateout("x8") n => _,
293            inlateout("x0") a1 => result,
294            inlateout("x1") a2 => _,
295            inlateout("x2") a3 => _,
296            inlateout("x3") a4 => _,
297            inlateout("x4") a5 => _,
298            options(nostack),
299        );
300        result
301    }
302    #[inline(always)]
303    unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64 {
304        let result: i64;
305        core::arch::asm!(
306            "svc #0",
307            inlateout("x8") n => _,
308            inlateout("x0") a1 => result,
309            inlateout("x1") a2 => _,
310            inlateout("x2") a3 => _,
311            inlateout("x3") a4 => _,
312            inlateout("x4") a5 => _,
313            inlateout("x5") a6 => _,
314            options(nostack),
315        );
316        result
317    }
318    #[inline(always)]
319    unsafe fn syscall_noreturn1(n: i64, a1: i64) -> ! {
320        core::arch::asm!(
321            "svc #0",
322            in("x8") n,
323            in("x0") a1,
324            options(noreturn, nostack),
325        );
326    }
327}
328
329#[cfg(target_arch = "riscv64")]
330impl Syscalls for Riscv64 {
331    #[inline(always)]
332    unsafe fn syscall0(n: i64) -> i64 {
333        let result: i64;
334        core::arch::asm!(
335            "ecall",
336            inlateout("a7") n => _,
337            lateout("a0") result,
338            options(nostack),
339        );
340        result
341    }
342    #[inline(always)]
343    unsafe fn syscall1(n: i64, a1: i64) -> i64 {
344        let result: i64;
345        core::arch::asm!(
346            "ecall",
347            inlateout("a7") n => _,
348            inlateout("a0") a1 => result,
349            options(nostack),
350        );
351        result
352    }
353    #[inline(always)]
354    unsafe fn syscall2(n: i64, a1: i64, a2: i64) -> i64 {
355        let result: i64;
356        core::arch::asm!(
357            "ecall",
358            inlateout("a7") n => _,
359            inlateout("a0") a1 => result,
360            inlateout("a1") a2 => _,
361            options(nostack),
362        );
363        result
364    }
365    #[inline(always)]
366    unsafe fn syscall3(n: i64, a1: i64, a2: i64, a3: i64) -> i64 {
367        let result: i64;
368        core::arch::asm!(
369            "ecall",
370            inlateout("a7") n => _,
371            inlateout("a0") a1 => result,
372            inlateout("a1") a2 => _,
373            inlateout("a2") a3 => _,
374            options(nostack),
375        );
376        result
377    }
378    #[inline(always)]
379    unsafe fn syscall4(n: i64, a1: i64, a2: i64, a3: i64, a4: i64) -> i64 {
380        let result: i64;
381        core::arch::asm!(
382            "ecall",
383            inlateout("a7") n => _,
384            inlateout("a0") a1 => result,
385            inlateout("a1") a2 => _,
386            inlateout("a2") a3 => _,
387            inlateout("a3") a4 => _,
388            options(nostack),
389        );
390        result
391    }
392    #[inline(always)]
393    unsafe fn syscall5(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64) -> i64 {
394        let result: i64;
395        core::arch::asm!(
396            "ecall",
397            inlateout("a7") n => _,
398            inlateout("a0") a1 => result,
399            inlateout("a1") a2 => _,
400            inlateout("a2") a3 => _,
401            inlateout("a3") a4 => _,
402            inlateout("a4") a5 => _,
403            options(nostack),
404        );
405        result
406    }
407    #[inline(always)]
408    unsafe fn syscall6(n: i64, a1: i64, a2: i64, a3: i64, a4: i64, a5: i64, a6: i64) -> i64 {
409        let result: i64;
410        core::arch::asm!(
411            "ecall",
412            inlateout("a7") n => _,
413            inlateout("a0") a1 => result,
414            inlateout("a1") a2 => _,
415            inlateout("a2") a3 => _,
416            inlateout("a3") a4 => _,
417            inlateout("a4") a5 => _,
418            inlateout("a5") a6 => _,
419            options(nostack),
420        );
421        result
422    }
423    #[inline(always)]
424    unsafe fn syscall_noreturn1(n: i64, a1: i64) -> ! {
425        core::arch::asm!(
426            "ecall",
427            in("a7") n,
428            in("a0") a1,
429            options(noreturn, nostack),
430        );
431    }
432}
433
434#[cfg(target_arch = "x86_64")]
435type Arch = X86_64;
436#[cfg(target_arch = "aarch64")]
437type Arch = Aarch64;
438#[cfg(target_arch = "riscv64")]
439type Arch = Riscv64;
440
441
442
443// Architecture-specific syscall numbers
444#[cfg(target_arch = "x86_64")]
445mod sysnr {
446    pub const SYS_READ: i64 = 0;
447    pub const SYS_WRITE: i64 = 1;
448    pub const SYS_OPEN: i64 = 2;
449    pub const SYS_CLOSE: i64 = 3;
450    pub const SYS_STAT: i64 = 4;
451    pub const SYS_FSTAT: i64 = 5;
452    pub const SYS_LSEEK: i64 = 8;
453    pub const SYS_MMAP: i64 = 9;
454    pub const SYS_MUNMAP: i64 = 11;
455    pub const SYS_MPROTECT: i64 = 10;
456    pub const SYS_RT_SIGACTION: i64 = 13;
457    pub const SYS_RT_SIGPROCMASK: i64 = 14;
458    pub const SYS_IOCTL: i64 = 16;
459    pub const SYS_ACCESS: i64 = 21;
460    pub const SYS_SHMGET: i64 = 29;
461    pub const SYS_SHMAT: i64 = 30;
462    pub const SYS_SHMCTL: i64 = 31;
463    pub const SYS_DUP: i64 = 32;
464    pub const SYS_NANOSLEEP: i64 = 35;
465    pub const SYS_SETITIMER: i64 = 38;
466    pub const SYS_ALARM: i64 = 37;
467    pub const SYS_SOCKET: i64 = 41;
468    pub const SYS_CONNECT: i64 = 42;
469    pub const SYS_ACCEPT: i64 = 43;
470    pub const SYS_ACCEPT4: i64 = 288;
471    pub const SYS_SENDTO: i64 = 44;
472    pub const SYS_RECVFROM: i64 = 45;
473    pub const SYS_SENDMSG: i64 = 46;
474    pub const SYS_RECVMSG: i64 = 47;
475    pub const SYS_SHUTDOWN: i64 = 48;
476    pub const SYS_BIND: i64 = 49;
477    pub const SYS_LISTEN: i64 = 50;
478    pub const SYS_GETSOCKNAME: i64 = 51;
479    pub const SYS_SOCKETPAIR: i64 = 53;
480    pub const SYS_SETSOCKOPT: i64 = 54;
481    pub const SYS_EXECVE: i64 = 59;
482    pub const SYS_WAIT4: i64 = 61;
483    pub const SYS_KILL: i64 = 62;
484    pub const SYS_UNAME: i64 = 63;
485    pub const SYS_SEMGET: i64 = 64;
486    pub const SYS_SEMOP: i64 = 65;
487    pub const SYS_SEMCTL: i64 = 66;
488    pub const SYS_SHMDT: i64 = 67;
489    pub const SYS_MSGGET: i64 = 68;
490    pub const SYS_MSGSND: i64 = 69;
491    pub const SYS_MSGRCV: i64 = 70;
492    pub const SYS_MSGCTL: i64 = 71;
493    pub const SYS_FCNTL: i64 = 72;
494    pub const SYS_FSYNC: i64 = 74;
495    pub const SYS_TRUNCATE: i64 = 76;
496    pub const SYS_FTRUNCATE: i64 = 77;
497    pub const SYS_GETCWD: i64 = 79;
498    pub const SYS_CHDIR: i64 = 80;
499    pub const SYS_SYMLINK: i64 = 88;
500    pub const SYS_FCHMOD: i64 = 91;
501    pub const SYS_UMASK: i64 = 95;
502    pub const SYS_GETRLIMIT: i64 = 97;
503    pub const SYS_SETUID: i64 = 105;
504    pub const SYS_SETGID: i64 = 106;
505    pub const SYS_SETPGID: i64 = 109;
506    pub const SYS_GETGROUPS: i64 = 115;
507    pub const SYS_GETPGID: i64 = 121;
508    pub const SYS_GETSID: i64 = 124;
509    pub const SYS_RT_SIGPENDING: i64 = 127;
510    pub const SYS_RT_SIGTIMEDWAIT: i64 = 128;
511    pub const SYS_RT_SIGSUSPEND: i64 = 130;
512    pub const SYS_SIGALTSTACK: i64 = 131;
513    pub const SYS_SETRLIMIT: i64 = 160;
514    pub const SYS_SETHOSTNAME: i64 = 170;
515    pub const SYS_FUTEX: i64 = 202;
516    pub const SYS_CLOCK_GETTIME: i64 = 228;
517    pub const SYS_CLOCK_GETRES: i64 = 229;
518    pub const SYS_CLOCK_NANOSLEEP: i64 = 230;
519    pub const SYS_EXIT_GROUP: i64 = 231;
520    pub const SYS_TGKILL: i64 = 234;
521    pub const SYS_MKDIRAT: i64 = 258;
522    pub const SYS_NEWFSTATAT: i64 = 262;
523    pub const SYS_UNLINKAT: i64 = 263;
524    pub const SYS_LINKAT: i64 = 265;
525    pub const SYS_SYMLINKAT: i64 = 266;
526    pub const SYS_READLINKAT: i64 = 267;
527    pub const SYS_FCHMODAT: i64 = 268;
528    pub const SYS_SET_ROBUST_LIST: i64 = 273;
529    pub const SYS_UTIMENSAT: i64 = 280;
530    pub const SYS_OPENAT: i64 = 257;
531    pub const SYS_FACCESSAT: i64 = 269;
532    pub const SYS_DUP3: i64 = 292;
533    pub const SYS_PIPE2: i64 = 293;
534    pub const SYS_SYNCFS: i64 = 306;
535    pub const SYS_RENAMEAT2: i64 = 316;
536    pub const SYS_STATFS: i64 = 137;
537    pub const SYS_FSTATFS: i64 = 138;
538    pub const SYS_FDATASYNC: i64 = 75;
539    pub const SYS_PAUSE: i64 = 34;
540    pub const SYS_POLL: i64 = 7;
541    pub const SYS_PPOLL: i64 = 271;
542    pub const SYS_PSELECT6: i64 = 270;
543    pub const SYS_GETPID: i64 = 39;
544    pub const SYS_FORK: i64 = 57;
545    pub const SYS_EXIT: i64 = 60;
546    pub const SYS_GETPPID: i64 = 110;
547    pub const SYS_SETSID: i64 = 112;
548    pub const SYS_SYNC: i64 = 162;
549    pub const SYS_GETUID: i64 = 102;
550    pub const SYS_GETGID: i64 = 104;
551    pub const SYS_GETEUID: i64 = 107;
552    pub const SYS_GETEGID: i64 = 108;
553    pub const SYS_GETTID: i64 = 186;
554    pub const SYS_CLOCK_SETTIME: i64 = 227;
555    pub const SYS_CLONE: i64 = 56;
556    pub const SYS_PREAD64: i64 = 17;
557    pub const SYS_MREMAP: i64 = 25;
558    pub const SYS_SYSINFO: i64 = 99;
559    pub const SYS_MEMBARRIER: i64 = 324;
560    pub const SYS_VHANGUP: i64 = 153;
561    pub const SYS_VMSPLICE: i64 = 278;
562    pub const SYS_GETDENTS64: i64 = 217;
563    pub const SYS_EPOLL_CREATE: i64 = 232;
564    pub const SYS_EPOLL_CREATE1: i64 = 291;
565    pub const SYS_EPOLL_CTL: i64 = 233;
566    pub const SYS_EPOLL_WAIT: i64 = 234;
567    pub const SYS_EVENTFD2: i64 = 290;
568    pub const SYS_SIGNALFD4: i64 = 289;
569    pub const SYS_TIMERFD_CREATE: i64 = 283;
570    pub const SYS_TIMERFD_SETTIME: i64 = 286;
571    pub const SYS_TIMERFD_GETTIME: i64 = 287;
572    pub const SYS_PRCTL: i64 = 157;
573    pub const SYS_FALLOCATE: i64 = 285;
574    pub const SYS_FLOCK: i64 = 73;
575    pub const SYS_SETGROUPS: i64 = 116;
576    pub const SYS_SETRESUID: i64 = 117;
577    pub const SYS_SETRESGID: i64 = 119;
578    pub const SYS_GETRESUID: i64 = 118;
579    pub const SYS_GETRESGID: i64 = 120;
580    pub const SYS_MKNOD: i64 = 133;
581    pub const SYS_FCHDIR: i64 = 81;
582    pub const SYS_FCHOWN: i64 = 93;
583    pub const SYS_ACCT: i64 = 163;
584    pub const SYS_ADJTIMEX: i64 = 159;
585    pub const SYS_CAPGET: i64 = 125;
586    pub const SYS_CAPSET: i64 = 126;
587    pub const SYS_CHROOT: i64 = 161;
588    pub const SYS_COPY_FILE_RANGE: i64 = 326;
589    pub const SYS_DELETE_MODULE: i64 = 176;
590    pub const SYS_INIT_MODULE: i64 = 175;
591    pub const SYS_FCHOWNAT: i64 = 260;
592    pub const SYS_MKNODAT: i64 = 259;
593    pub const SYS_SETNS: i64 = 308;
594    pub const SYS_UNSHARE: i64 = 272;
595    pub const SYS_REBOOT: i64 = 169;
596    pub const SYS_NICE: i64 = 34;
597    pub const SYS_SETPRIORITY: i64 = 140;
598    pub const SYS_GETPRIORITY: i64 = 140;
599    pub const SYS_IOPERM: i64 = 173;
600    pub const SYS_IOPL: i64 = 172;
601    pub const SYS_SWAPON: i64 = 167;
602    pub const SYS_SWAPOFF: i64 = 168;
603    pub const SYS_MOUNT: i64 = 165;
604    pub const SYS_UMOUNT2: i64 = 166;
605    pub const SYS_PIVOT_ROOT: i64 = 155;
606    pub const SYS_SETTIMEOFDAY: i64 = 164;
607    pub const SYS_GETTIMEOFDAY: i64 = 96;
608}
609#[cfg(target_arch = "aarch64")]
610mod sysnr {
611    pub const SYS_READ: i64 = 63;
612    pub const SYS_WRITE: i64 = 64;
613    // pub const SYS_OPEN: i64 = ???; // missing in aarch64 table
614    pub const SYS_CLOSE: i64 = 57;
615    // pub const SYS_STAT: i64 = ???; // missing in aarch64 table
616    pub const SYS_FSTAT: i64 = 80;
617    pub const SYS_LSEEK: i64 = 62;
618    pub const SYS_MMAP: i64 = 222;
619    pub const SYS_MUNMAP: i64 = 215;
620    pub const SYS_RT_SIGACTION: i64 = 134;
621    pub const SYS_RT_SIGPROCMASK: i64 = 135;
622    pub const SYS_IOCTL: i64 = 29;
623    // pub const SYS_ACCESS: i64 = ???; // missing in aarch64 table
624    pub const SYS_SHMGET: i64 = 194;
625    pub const SYS_SHMAT: i64 = 196;
626    pub const SYS_SHMCTL: i64 = 195;
627    pub const SYS_DUP: i64 = 23;
628    pub const SYS_NANOSLEEP: i64 = 101;
629    pub const SYS_SETITIMER: i64 = 103;
630    // pub const SYS_ALARM: i64 = ???; // missing in aarch64 table
631    pub const SYS_SOCKET: i64 = 198;
632    pub const SYS_CONNECT: i64 = 203;
633    pub const SYS_ACCEPT: i64 = 202;
634    pub const SYS_SENDTO: i64 = 206;
635    pub const SYS_RECVFROM: i64 = 207;
636    pub const SYS_SHUTDOWN: i64 = 210;
637    pub const SYS_BIND: i64 = 200;
638    pub const SYS_LISTEN: i64 = 201;
639    pub const SYS_GETSOCKNAME: i64 = 204;
640    pub const SYS_SOCKETPAIR: i64 = 199;
641    pub const SYS_SETSOCKOPT: i64 = 208;
642    pub const SYS_EXECVE: i64 = 221;
643    pub const SYS_WAIT4: i64 = 260;
644    pub const SYS_KILL: i64 = 129;
645    pub const SYS_UNAME: i64 = 160;
646    pub const SYS_SEMGET: i64 = 190;
647    pub const SYS_SEMOP: i64 = 193;
648    pub const SYS_SEMCTL: i64 = 191;
649    pub const SYS_SHMDT: i64 = 197;
650    pub const SYS_MSGGET: i64 = 186;
651    pub const SYS_MSGSND: i64 = 189;
652    pub const SYS_MSGRCV: i64 = 188;
653    pub const SYS_MSGCTL: i64 = 187;
654    pub const SYS_FCNTL: i64 = 25;
655    pub const SYS_FSYNC: i64 = 82;
656    pub const SYS_TRUNCATE: i64 = 45;
657    pub const SYS_FTRUNCATE: i64 = 46;
658    pub const SYS_GETCWD: i64 = 17;
659    pub const SYS_CHDIR: i64 = 49;
660    // pub const SYS_SYMLINK: i64 = ???; // missing in aarch64 table
661    pub const SYS_FCHMOD: i64 = 52;
662    pub const SYS_UMASK: i64 = 166;
663    pub const SYS_GETRLIMIT: i64 = 163;
664    pub const SYS_SETUID: i64 = 146;
665    pub const SYS_SETGID: i64 = 144;
666    pub const SYS_SETPGID: i64 = 154;
667    pub const SYS_GETGROUPS: i64 = 158;
668    pub const SYS_GETPGID: i64 = 155;
669    pub const SYS_GETSID: i64 = 156;
670    pub const SYS_RT_SIGPENDING: i64 = 136;
671    pub const SYS_RT_SIGTIMEDWAIT: i64 = 137;
672    pub const SYS_RT_SIGSUSPEND: i64 = 133;
673    pub const SYS_SIGALTSTACK: i64 = 132;
674    pub const SYS_SETRLIMIT: i64 = 164;
675    pub const SYS_SETHOSTNAME: i64 = 161;
676    pub const SYS_FUTEX: i64 = 98;
677    pub const SYS_CLOCK_GETTIME: i64 = 113;
678    pub const SYS_CLOCK_GETRES: i64 = 114;
679    pub const SYS_CLOCK_NANOSLEEP: i64 = 115;
680    pub const SYS_EXIT_GROUP: i64 = 94;
681    pub const SYS_TGKILL: i64 = 131;
682    pub const SYS_MKDIRAT: i64 = 34;
683    pub const SYS_NEWFSTATAT: i64 = 79;
684    pub const SYS_UNLINKAT: i64 = 35;
685    pub const SYS_LINKAT: i64 = 37;
686    pub const SYS_SYMLINKAT: i64 = 36;
687    pub const SYS_READLINKAT: i64 = 78;
688    pub const SYS_FCHMODAT: i64 = 53;
689    pub const SYS_SET_ROBUST_LIST: i64 = 99;
690    pub const SYS_UTIMENSAT: i64 = 88;
691    pub const SYS_OPENAT: i64 = 56;
692    pub const SYS_FACCESSAT: i64 = 48;
693    pub const SYS_DUP3: i64 = 24;
694    pub const SYS_PIPE2: i64 = 59;
695    pub const SYS_SYNCFS: i64 = 267;
696    pub const SYS_RENAMEAT2: i64 = 276;
697    pub const SYS_STATFS: i64 = 43;
698    pub const SYS_FSTATFS: i64 = 44;
699    pub const SYS_FDATASYNC: i64 = 83;
700    pub const SYS_GETPID: i64 = 172;
701    pub const SYS_EXIT: i64 = 93;
702    pub const SYS_GETPPID: i64 = 173;
703    pub const SYS_SETSID: i64 = 157;
704    pub const SYS_SYNC: i64 = 81;
705    pub const SYS_GETUID: i64 = 174;
706    pub const SYS_GETGID: i64 = 176;
707    pub const SYS_GETEUID: i64 = 175;
708    pub const SYS_GETEGID: i64 = 177;
709    pub const SYS_GETTID: i64 = 178;
710    pub const SYS_CLOCK_SETTIME: i64 = 112;
711    pub const SYS_CLONE: i64 = 220;
712    pub const SYS_PPOLL: i64 = 73;
713    pub const SYS_PREAD64: i64 = 67;
714    pub const SYS_MREMAP: i64 = 216;
715    pub const SYS_SYSINFO: i64 = 179;
716    pub const SYS_MEMBARRIER: i64 = 283;
717    pub const SYS_VHANGUP: i64 = 58;
718    pub const SYS_VMSPLICE: i64 = 75;
719    pub const SYS_GETTIMEOFDAY: i64 = 169;
720    pub const SYS_SETTIMEOFDAY: i64 = 170;
721    pub const SYS_ADJTIMEX: i64 = 171;
722    pub const SYS_EPOLL_CREATE1: i64 = 20;
723    pub const SYS_EPOLL_CTL: i64 = 21;
724    pub const SYS_EPOLL_WAIT: i64 = 22;
725    pub const SYS_EVENTFD2: i64 = 19;
726    pub const SYS_SIGNALFD4: i64 = 74;
727    pub const SYS_TIMERFD_CREATE: i64 = 85;
728    pub const SYS_TIMERFD_SETTIME: i64 = 86;
729    pub const SYS_TIMERFD_GETTIME: i64 = 87;
730    pub const SYS_ACCEPT4: i64 = 242;
731    pub const SYS_ACCT: i64 = 89;
732    pub const SYS_CAPGET: i64 = 90;
733    pub const SYS_CAPSET: i64 = 91;
734    pub const SYS_CHROOT: i64 = 51;
735    pub const SYS_COPY_FILE_RANGE: i64 = 285;
736    pub const SYS_DELETE_MODULE: i64 = 106;
737    pub const SYS_FALLOCATE: i64 = 47;
738    pub const SYS_FCHDIR: i64 = 50;
739    pub const SYS_FCHOWN: i64 = 55;
740    pub const SYS_FCHOWNAT: i64 = 54;
741    pub const SYS_FLOCK: i64 = 32;
742    pub const SYS_GETDENTS64: i64 = 61;
743    pub const SYS_GETPRIORITY: i64 = 141;
744    pub const SYS_GETRESGID: i64 = 150;
745    pub const SYS_GETRESUID: i64 = 148;
746    pub const SYS_INIT_MODULE: i64 = 105;
747    pub const SYS_MKNODAT: i64 = 33;
748    pub const SYS_MOUNT: i64 = 40;
749    pub const SYS_MPROTECT: i64 = 226;
750    pub const SYS_PIVOT_ROOT: i64 = 41;
751    pub const SYS_PRCTL: i64 = 167;
752    pub const SYS_PSELECT6: i64 = 72;
753    pub const SYS_REBOOT: i64 = 142;
754    pub const SYS_RECVMSG: i64 = 212;
755    pub const SYS_SENDMSG: i64 = 211;
756    pub const SYS_SETGROUPS: i64 = 159;
757    pub const SYS_SETNS: i64 = 268;
758    pub const SYS_SETPRIORITY: i64 = 140;
759    pub const SYS_SETRESGID: i64 = 149;
760    pub const SYS_SETRESUID: i64 = 147;
761    pub const SYS_SWAPOFF: i64 = 225;
762    pub const SYS_SWAPON: i64 = 224;
763    pub const SYS_UMOUNT2: i64 = 39;
764    pub const SYS_UNSHARE: i64 = 97;
765}
766// riscv64 uses the same new-style syscall table as aarch64
767#[cfg(target_arch = "riscv64")]
768mod sysnr {
769    pub const SYS_READ: i64 = 63;
770    pub const SYS_WRITE: i64 = 64;
771    pub const SYS_CLOSE: i64 = 57;
772    pub const SYS_FSTAT: i64 = 80;
773    pub const SYS_LSEEK: i64 = 62;
774    pub const SYS_MMAP: i64 = 222;
775    pub const SYS_MUNMAP: i64 = 215;
776    pub const SYS_RT_SIGACTION: i64 = 134;
777    pub const SYS_RT_SIGPROCMASK: i64 = 135;
778    pub const SYS_IOCTL: i64 = 29;
779    pub const SYS_SHMGET: i64 = 194;
780    pub const SYS_SHMAT: i64 = 196;
781    pub const SYS_SHMCTL: i64 = 195;
782    pub const SYS_DUP: i64 = 23;
783    pub const SYS_NANOSLEEP: i64 = 101;
784    pub const SYS_SETITIMER: i64 = 103;
785    pub const SYS_SOCKET: i64 = 198;
786    pub const SYS_CONNECT: i64 = 203;
787    pub const SYS_ACCEPT: i64 = 202;
788    pub const SYS_SENDTO: i64 = 206;
789    pub const SYS_RECVFROM: i64 = 207;
790    pub const SYS_SHUTDOWN: i64 = 210;
791    pub const SYS_BIND: i64 = 200;
792    pub const SYS_LISTEN: i64 = 201;
793    pub const SYS_GETSOCKNAME: i64 = 204;
794    pub const SYS_SOCKETPAIR: i64 = 199;
795    pub const SYS_SETSOCKOPT: i64 = 208;
796    pub const SYS_EXECVE: i64 = 221;
797    pub const SYS_WAIT4: i64 = 260;
798    pub const SYS_KILL: i64 = 129;
799    pub const SYS_UNAME: i64 = 160;
800    pub const SYS_SEMGET: i64 = 190;
801    pub const SYS_SEMOP: i64 = 193;
802    pub const SYS_SEMCTL: i64 = 191;
803    pub const SYS_SHMDT: i64 = 197;
804    pub const SYS_MSGGET: i64 = 186;
805    pub const SYS_MSGSND: i64 = 189;
806    pub const SYS_MSGRCV: i64 = 188;
807    pub const SYS_MSGCTL: i64 = 187;
808    pub const SYS_FCNTL: i64 = 25;
809    pub const SYS_FSYNC: i64 = 82;
810    pub const SYS_TRUNCATE: i64 = 45;
811    pub const SYS_FTRUNCATE: i64 = 46;
812    pub const SYS_GETCWD: i64 = 17;
813    pub const SYS_CHDIR: i64 = 49;
814    pub const SYS_FCHMOD: i64 = 52;
815    pub const SYS_UMASK: i64 = 166;
816    pub const SYS_GETRLIMIT: i64 = 163;
817    pub const SYS_SETUID: i64 = 146;
818    pub const SYS_SETGID: i64 = 144;
819    pub const SYS_SETPGID: i64 = 154;
820    pub const SYS_GETGROUPS: i64 = 158;
821    pub const SYS_GETPGID: i64 = 155;
822    pub const SYS_GETSID: i64 = 156;
823    pub const SYS_RT_SIGPENDING: i64 = 136;
824    pub const SYS_RT_SIGTIMEDWAIT: i64 = 137;
825    pub const SYS_RT_SIGSUSPEND: i64 = 133;
826    pub const SYS_SIGALTSTACK: i64 = 132;
827    pub const SYS_SETRLIMIT: i64 = 164;
828    pub const SYS_SETHOSTNAME: i64 = 161;
829    pub const SYS_FUTEX: i64 = 98;
830    pub const SYS_CLOCK_GETTIME: i64 = 113;
831    pub const SYS_CLOCK_GETRES: i64 = 114;
832    pub const SYS_CLOCK_NANOSLEEP: i64 = 115;
833    pub const SYS_EXIT_GROUP: i64 = 94;
834    pub const SYS_TGKILL: i64 = 131;
835    pub const SYS_MKDIRAT: i64 = 34;
836    pub const SYS_NEWFSTATAT: i64 = 79;
837    pub const SYS_UNLINKAT: i64 = 35;
838    pub const SYS_LINKAT: i64 = 37;
839    pub const SYS_SYMLINKAT: i64 = 36;
840    pub const SYS_READLINKAT: i64 = 78;
841    pub const SYS_FCHMODAT: i64 = 53;
842    pub const SYS_SET_ROBUST_LIST: i64 = 99;
843    pub const SYS_UTIMENSAT: i64 = 88;
844    pub const SYS_OPENAT: i64 = 56;
845    pub const SYS_FACCESSAT: i64 = 48;
846    pub const SYS_DUP3: i64 = 24;
847    pub const SYS_PIPE2: i64 = 59;
848    pub const SYS_SYNCFS: i64 = 267;
849    pub const SYS_RENAMEAT2: i64 = 276;
850    pub const SYS_STATFS: i64 = 43;
851    pub const SYS_FSTATFS: i64 = 44;
852    pub const SYS_FDATASYNC: i64 = 83;
853    pub const SYS_GETPID: i64 = 172;
854    pub const SYS_EXIT: i64 = 93;
855    pub const SYS_GETPPID: i64 = 173;
856    pub const SYS_SETSID: i64 = 157;
857    pub const SYS_SYNC: i64 = 81;
858    pub const SYS_GETUID: i64 = 174;
859    pub const SYS_GETGID: i64 = 176;
860    pub const SYS_GETEUID: i64 = 175;
861    pub const SYS_GETEGID: i64 = 177;
862    pub const SYS_GETTID: i64 = 178;
863    pub const SYS_CLOCK_SETTIME: i64 = 112;
864    pub const SYS_CLONE: i64 = 220;
865    pub const SYS_PPOLL: i64 = 73;
866    pub const SYS_PREAD64: i64 = 67;
867    pub const SYS_MREMAP: i64 = 216;
868    pub const SYS_SYSINFO: i64 = 179;
869    pub const SYS_MEMBARRIER: i64 = 283;
870    pub const SYS_VHANGUP: i64 = 58;
871    pub const SYS_VMSPLICE: i64 = 75;
872    pub const SYS_GETTIMEOFDAY: i64 = 169;
873    pub const SYS_SETTIMEOFDAY: i64 = 170;
874    pub const SYS_ADJTIMEX: i64 = 171;
875    pub const SYS_EPOLL_CREATE1: i64 = 20;
876    pub const SYS_EPOLL_CTL: i64 = 21;
877    pub const SYS_EPOLL_WAIT: i64 = 22;
878    pub const SYS_EVENTFD2: i64 = 19;
879    pub const SYS_SIGNALFD4: i64 = 74;
880    pub const SYS_TIMERFD_CREATE: i64 = 85;
881    pub const SYS_TIMERFD_SETTIME: i64 = 86;
882    pub const SYS_TIMERFD_GETTIME: i64 = 87;
883    pub const SYS_ACCEPT4: i64 = 242;
884    pub const SYS_ACCT: i64 = 89;
885    pub const SYS_CAPGET: i64 = 90;
886    pub const SYS_CAPSET: i64 = 91;
887    pub const SYS_CHROOT: i64 = 51;
888    pub const SYS_COPY_FILE_RANGE: i64 = 285;
889    pub const SYS_DELETE_MODULE: i64 = 106;
890    pub const SYS_FALLOCATE: i64 = 47;
891    pub const SYS_FCHDIR: i64 = 50;
892    pub const SYS_FCHOWN: i64 = 55;
893    pub const SYS_FCHOWNAT: i64 = 54;
894    pub const SYS_FLOCK: i64 = 32;
895    pub const SYS_GETDENTS64: i64 = 61;
896    pub const SYS_GETPRIORITY: i64 = 141;
897    pub const SYS_GETRESGID: i64 = 150;
898    pub const SYS_GETRESUID: i64 = 148;
899    pub const SYS_INIT_MODULE: i64 = 105;
900    pub const SYS_MKNODAT: i64 = 33;
901    pub const SYS_MOUNT: i64 = 40;
902    pub const SYS_MPROTECT: i64 = 226;
903    pub const SYS_PIVOT_ROOT: i64 = 41;
904    pub const SYS_PRCTL: i64 = 167;
905    pub const SYS_PSELECT6: i64 = 72;
906    pub const SYS_REBOOT: i64 = 142;
907    pub const SYS_RECVMSG: i64 = 212;
908    pub const SYS_SENDMSG: i64 = 211;
909    pub const SYS_SETGROUPS: i64 = 159;
910    pub const SYS_SETNS: i64 = 268;
911    pub const SYS_SETPRIORITY: i64 = 140;
912    pub const SYS_SETRESGID: i64 = 149;
913    pub const SYS_SETRESUID: i64 = 147;
914    pub const SYS_SWAPOFF: i64 = 225;
915    pub const SYS_SWAPON: i64 = 224;
916    pub const SYS_UMOUNT2: i64 = 39;
917    pub const SYS_UNSHARE: i64 = 97;
918}
919pub use sysnr::*;
920
921// ============================================================
922// Syscall wrappers (raw, no_std)
923// ============================================================
924
925#[inline]
926unsafe fn sys_write(fd: i64, buf: *const u8, count: usize) -> i64 {
927    <Arch as Syscalls>::syscall3(SYS_WRITE, fd as i64, buf as i64, count as i64)
928}
929
930#[inline]
931unsafe fn sys_read(fd: i64, buf: *mut u8, count: usize) -> i64 {
932    <Arch as Syscalls>::syscall3(SYS_READ, fd as i64, buf as i64, count as i64)
933}
934
935#[inline]
936unsafe fn sys_open(path: *const u8, flags: i64, mode: i64) -> i64 {
937    <Arch as Syscalls>::syscall4(SYS_OPENAT, AT_FDCWD as i64, path as i64, flags as i64, mode as i64)
938}
939
940#[inline]
941unsafe fn sys_close(fd: i64) {
942    let _ = <Arch as Syscalls>::syscall1(SYS_CLOSE, fd as i64);
943}
944
945#[inline]
946unsafe fn sys_lseek(fd: i64, offset: i64, whence: i64) -> i64 {
947    <Arch as Syscalls>::syscall3(SYS_LSEEK, fd as i64, offset as i64, whence as i64)
948}
949
950unsafe fn sys_mmap(
951    addr: *mut u8,
952    length: usize,
953    prot: i32,
954    flags: i32,
955    fd: i32,
956    offset: i64,
957) -> *mut u8 {
958    let result = <Arch as Syscalls>::syscall6(SYS_MMAP, addr as i64, length as i64, prot as i64, flags as i64, fd as i64, offset);
959    if result < 0 && result > -4096 {
960        ERRNO = (-result) as c_int;
961        return MMAP_FAILED;
962    }
963    result as *mut u8
964}
965
966unsafe fn sys_munmap(addr: *mut u8, length: usize) -> i64 {
967    <Arch as Syscalls>::syscall2(SYS_MUNMAP, addr as i64, length as i64)
968}
969
970// ============================================================
971// String/memory functions
972// ============================================================
973
974#[no_mangle]
975pub unsafe extern "C" fn strlen(s: *const c_char) -> usize {
976    let s = s as *const u8;
977    let mut len = 0;
978    while *s.add(len) != 0 {
979        len += 1;
980    }
981    len
982}
983
984#[no_mangle]
985pub unsafe extern "C" fn memcpy(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
986    let dst = dst as *mut u8;
987    let src = src as *const u8;
988    let mut i = 0;
989    while i < n {
990        *dst.add(i) = *src.add(i);
991        i += 1;
992    }
993    dst as *mut c_void
994}
995
996#[no_mangle]
997pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: usize) -> *mut c_void {
998    let s = s as *mut u8;
999    let mut i = 0;
1000    while i < n {
1001        *s.add(i) = c as u8;
1002        i += 1;
1003    }
1004    s as *mut c_void
1005}
1006
1007#[no_mangle]
1008pub unsafe extern "C" fn memmove(dst: *mut c_void, src: *const c_void, n: usize) -> *mut c_void {
1009    let dst = dst as *mut u8;
1010    let src = src as *const u8;
1011    if (dst as usize) < (src as usize) {
1012        let mut i = 0;
1013        while i < n {
1014            *dst.add(i) = *src.add(i);
1015            i += 1;
1016        }
1017    } else {
1018        let mut i = n;
1019        while i > 0 {
1020            i -= 1;
1021            *dst.add(i) = *src.add(i);
1022        }
1023    }
1024    dst as *mut c_void
1025}
1026
1027#[no_mangle]
1028pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
1029    let s1 = s1 as *const u8;
1030    let s2 = s2 as *const u8;
1031    let mut i = 0;
1032    while i < n {
1033        let a = *s1.add(i);
1034        let b = *s2.add(i);
1035        if a != b {
1036            return a as c_int - b as c_int;
1037        }
1038        i += 1;
1039    }
1040    0
1041}
1042
1043#[no_mangle]
1044pub unsafe extern "C" fn bcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
1045    memcmp(s1, s2, n)
1046}
1047
1048#[no_mangle]
1049pub unsafe extern "C" fn strcmp(s1: *const u8, s2: *const u8) -> c_int {
1050    let mut i = 0;
1051    loop {
1052        let a = *s1.add(i);
1053        let b = *s2.add(i);
1054        if a != b {
1055            return a as c_int - b as c_int;
1056        }
1057        if a == 0 {
1058            return 0;
1059        }
1060        i += 1;
1061    }
1062}
1063
1064#[no_mangle]
1065pub unsafe extern "C" fn strncmp(s1: *const u8, s2: *const u8, n: usize) -> c_int {
1066    let mut i = 0;
1067    while i < n {
1068        let a = *s1.add(i);
1069        let b = *s2.add(i);
1070        if a != b {
1071            return a as c_int - b as c_int;
1072        }
1073        if a == 0 {
1074            return 0;
1075        }
1076        i += 1;
1077    }
1078    0
1079}
1080
1081#[no_mangle]
1082pub unsafe extern "C" fn strcpy(dst: *mut u8, src: *const u8) -> *mut u8 {
1083    let mut i = 0;
1084    loop {
1085        let c = *src.add(i);
1086        *dst.add(i) = c;
1087        if c == 0 {
1088            break;
1089        }
1090        i += 1;
1091    }
1092    dst
1093}
1094
1095#[no_mangle]
1096pub unsafe extern "C" fn strncpy(dst: *mut u8, src: *const u8, n: usize) -> *mut u8 {
1097    let mut i = 0;
1098    while i < n && *src.add(i) != 0 {
1099        *dst.add(i) = *src.add(i);
1100        i += 1;
1101    }
1102    while i < n {
1103        *dst.add(i) = 0;
1104        i += 1;
1105    }
1106    dst
1107}
1108
1109#[no_mangle]
1110pub unsafe extern "C" fn strcat(dst: *mut u8, src: *const u8) -> *mut u8 {
1111    let mut i = 0;
1112    while *dst.add(i) != 0 {
1113        i += 1;
1114    }
1115    let mut j = 0;
1116    loop {
1117        let c = *src.add(j);
1118        *dst.add(i + j) = c;
1119        if c == 0 {
1120            break;
1121        }
1122        j += 1;
1123    }
1124    dst
1125}
1126
1127#[no_mangle]
1128pub unsafe extern "C" fn strncat(dst: *mut u8, src: *const u8, n: usize) -> *mut u8 {
1129    let mut i = 0;
1130    while *dst.add(i) != 0 {
1131        i += 1;
1132    }
1133    let mut j = 0;
1134    while j < n && *src.add(j) != 0 {
1135        *dst.add(i + j) = *src.add(j);
1136        j += 1;
1137    }
1138    *dst.add(i + j) = 0;
1139    dst
1140}
1141
1142#[no_mangle]
1143pub unsafe extern "C" fn strlcpy(dst: *mut u8, src: *const u8, n: usize) -> usize {
1144    let l = strlen(src as *const c_char);
1145    if n > 0 {
1146        let c = if l < n { l } else { n - 1 };
1147        core::ptr::copy_nonoverlapping(src, dst, c);
1148        *dst.add(c) = 0;
1149    }
1150    l
1151}
1152
1153#[no_mangle]
1154pub unsafe extern "C" fn strlcat(dst: *mut u8, src: *const u8, n: usize) -> usize {
1155    let dl = strlen(dst as *const c_char);
1156    let sl = strlen(src as *const c_char);
1157    if dl >= n { return n + sl; }
1158    let c = if sl < n - dl { sl } else { n - dl - 1 };
1159    core::ptr::copy_nonoverlapping(src, dst.add(dl), c);
1160    *dst.add(dl + c) = 0;
1161    dl + sl
1162}
1163
1164#[no_mangle]
1165pub unsafe extern "C" fn bcopy(src: *const c_void, dst: *mut c_void, n: usize) {
1166    core::ptr::copy(src as *const u8, dst as *mut u8, n);
1167}
1168
1169#[no_mangle]
1170pub unsafe extern "C" fn bzero(s: *mut c_void, n: usize) {
1171    core::ptr::write_bytes(s as *mut u8, 0, n);
1172}
1173
1174#[no_mangle]
1175pub unsafe extern "C" fn strndup(s: *const c_char, n: usize) -> *mut c_char {
1176    let mut len = 0;
1177    while len < n && *s.add(len) != 0 {
1178        len += 1;
1179    }
1180    let p = malloc(len + 1) as *mut c_char;
1181    if p.is_null() {
1182        return core::ptr::null_mut();
1183    }
1184    core::ptr::copy_nonoverlapping(s, p, len);
1185    *p.add(len) = 0;
1186    p
1187}
1188
1189#[no_mangle]
1190pub unsafe extern "C" fn strchr(s: *const u8, c: c_int) -> *mut u8 {
1191    let target = c as u8;
1192    let mut i = 0;
1193    loop {
1194        let ch = *s.add(i);
1195        if ch == target {
1196            return s.add(i) as *mut u8;
1197        }
1198        if ch == 0 {
1199            return null_mut();
1200        }
1201        i += 1;
1202    }
1203}
1204
1205#[no_mangle]
1206pub unsafe extern "C" fn strrchr(s: *const u8, c: c_int) -> *mut u8 {
1207    let target = c as u8;
1208    let mut i = 0;
1209    let mut last: *mut u8 = null_mut();
1210    loop {
1211        let ch = *s.add(i);
1212        if ch == target {
1213            last = s.add(i) as *mut u8;
1214        }
1215        if ch == 0 {
1216            return last;
1217        }
1218        i += 1;
1219    }
1220}
1221
1222#[no_mangle]
1223pub unsafe extern "C" fn strnlen(s: *const u8, maxlen: usize) -> usize {
1224    let mut i = 0;
1225    while i < maxlen && *s.add(i) != 0 {
1226        i += 1;
1227    }
1228    i
1229}
1230
1231#[no_mangle]
1232pub unsafe extern "C" fn strcspn(s: *const u8, reject: *const u8) -> usize {
1233    let mut i = 0;
1234    loop {
1235        let c = *s.add(i);
1236        if c == 0 {
1237            return i;
1238        }
1239        let mut j = 0;
1240        loop {
1241            let r = *reject.add(j);
1242            if r == 0 {
1243                break;
1244            }
1245            if c == r {
1246                return i;
1247            }
1248            j += 1;
1249        }
1250        i += 1;
1251    }
1252}
1253
1254#[no_mangle]
1255pub unsafe extern "C" fn strspn(s: *const u8, accept: *const u8) -> usize {
1256    let mut i = 0;
1257    loop {
1258        let c = *s.add(i);
1259        if c == 0 {
1260            return i;
1261        }
1262        let mut found = false;
1263        let mut j = 0;
1264        loop {
1265            let a = *accept.add(j);
1266            if a == 0 {
1267                break;
1268            }
1269            if c == a {
1270                found = true;
1271                break;
1272            }
1273            j += 1;
1274        }
1275        if !found {
1276            return i;
1277        }
1278        i += 1;
1279    }
1280}
1281
1282#[no_mangle]
1283pub unsafe extern "C" fn strpbrk(s: *const u8, accept: *const u8) -> *mut u8 {
1284    let mut i = 0;
1285    loop {
1286        let c = *s.add(i);
1287        if c == 0 {
1288            return null_mut();
1289        }
1290        let mut j = 0;
1291        loop {
1292            let a = *accept.add(j);
1293            if a == 0 {
1294                break;
1295            }
1296            if c == a {
1297                return s.add(i) as *mut u8;
1298            }
1299            j += 1;
1300        }
1301        i += 1;
1302    }
1303}
1304
1305#[no_mangle]
1306pub unsafe extern "C" fn strstr(haystack: *const u8, needle: *const u8) -> *mut u8 {
1307    if *needle == 0 {
1308        return haystack as *mut u8;
1309    }
1310    let mut i = 0;
1311    loop {
1312        let h = *haystack.add(i);
1313        if h == 0 {
1314            return null_mut();
1315        }
1316        if h == *needle {
1317            let mut j = 0;
1318            loop {
1319                let n = *needle.add(j);
1320                if n == 0 {
1321                    return haystack.add(i) as *mut u8;
1322                }
1323                if *haystack.add(i + j) != n {
1324                    break;
1325                }
1326                j += 1;
1327            }
1328        }
1329        i += 1;
1330    }
1331}
1332
1333#[no_mangle]
1334pub unsafe extern "C" fn memchr(s: *const u8, c: c_int, n: usize) -> *mut u8 {
1335    let target = c as u8;
1336    let mut i = 0;
1337    while i < n {
1338        if *s.add(i) == target {
1339            return s.add(i) as *mut u8;
1340        }
1341        i += 1;
1342    }
1343    null_mut()
1344}
1345
1346#[no_mangle]
1347pub unsafe extern "C" fn memrchr(s: *const u8, c: c_int, n: usize) -> *mut u8 {
1348    let target = c as u8;
1349    let mut i = n;
1350    while i > 0 {
1351        i -= 1;
1352        if *s.add(i) == target {
1353            return s.add(i) as *mut u8;
1354        }
1355    }
1356    null_mut()
1357}
1358
1359#[no_mangle]
1360pub unsafe extern "C" fn memmem(
1361    haystack: *const c_void, haystacklen: usize,
1362    needle: *const c_void, needlelen: usize,
1363) -> *mut c_void {
1364    if needlelen == 0 { return haystack as *mut c_void; }
1365    if haystacklen < needlelen { return null_mut(); }
1366    let h = haystack as *const u8;
1367    let n = needle as *const u8;
1368    let last = haystacklen - needlelen;
1369    for i in 0..=last {
1370        if *h.add(i) == *n && memcmp(h.add(i) as *const c_void, n as *const c_void, needlelen) == 0 {
1371            return h.add(i) as *mut c_void;
1372        }
1373    }
1374    null_mut()
1375}
1376
1377#[no_mangle]
1378pub unsafe extern "C" fn strtok(s: *mut u8, delim: *const u8) -> *mut u8 {
1379    static mut STATE: *mut u8 = core::ptr::null_mut();
1380    let mut p = if s.is_null() { STATE } else { s };
1381    if p.is_null() {
1382        return core::ptr::null_mut();
1383    }
1384    loop {
1385        let c = *p;
1386        if c == 0 {
1387            STATE = core::ptr::null_mut();
1388            return core::ptr::null_mut();
1389        }
1390        let mut is_delim = false;
1391        let mut i = 0;
1392        loop {
1393            let d = *delim.add(i);
1394            if d == 0 {
1395                break;
1396            }
1397            if c == d {
1398                is_delim = true;
1399                break;
1400            }
1401            i += 1;
1402        }
1403        if !is_delim {
1404            break;
1405        }
1406        p = p.add(1);
1407    }
1408    let start = p;
1409    loop {
1410        let c = *p;
1411        if c == 0 {
1412            STATE = core::ptr::null_mut();
1413            return start;
1414        }
1415        let mut is_delim = false;
1416        let mut i = 0;
1417        loop {
1418            let d = *delim.add(i);
1419            if d == 0 {
1420                break;
1421            }
1422            if c == d {
1423                is_delim = true;
1424                break;
1425            }
1426            i += 1;
1427        }
1428        if is_delim {
1429            *p = 0;
1430            STATE = p.add(1);
1431            return start;
1432        }
1433        p = p.add(1);
1434    }
1435}
1436
1437// ============================================================
1438// C type aliases
1439// ============================================================
1440
1441type SizeT = usize;
1442type SSizeT = isize;
1443type mode_t = c_uint;
1444type TimeT = c_long;
1445type ClockT = c_long;
1446type wchar_t = c_int;
1447type wint_t = c_uint;
1448type wctype_t = *const c_int;
1449type wctrans_t = *const c_int;
1450
1451const WEOF: wint_t = 0xffffffff;
1452
1453#[repr(C)]
1454pub struct tm {
1455    pub tm_sec: c_int,
1456    pub tm_min: c_int,
1457    pub tm_hour: c_int,
1458    pub tm_mday: c_int,
1459    pub tm_mon: c_int,
1460    pub tm_year: c_int,
1461    pub tm_wday: c_int,
1462    pub tm_yday: c_int,
1463    pub tm_isdst: c_int,
1464    pub tm_gmtoff: c_long,
1465    pub tm_zone: *const c_char,
1466}
1467
1468#[repr(C)]
1469pub struct timeval {
1470    pub tv_sec: TimeT,
1471    pub tv_usec: c_long,
1472}
1473
1474#[repr(C)]
1475pub struct Timeb {
1476    pub time: TimeT,
1477    pub millitm: u16,
1478    pub timezone: i16,
1479    pub dstflag: u16,
1480}
1481
1482// ============================================================
1483// ctype.h
1484// ============================================================
1485
1486const CT_UPPER: u8 = 1 << 0;
1487const CT_LOWER: u8 = 1 << 1;
1488const CT_DIGIT: u8 = 1 << 2;
1489const CT_SPACE: u8 = 1 << 3;
1490const CT_PUNCT: u8 = 1 << 4;
1491const CT_CNTRL: u8 = 1 << 5;
1492const CT_BLANK: u8 = 1 << 6;
1493const CT_XDIGIT: u8 = 1 << 7;
1494
1495const CT_TABLE: [u8; 128] = {
1496    let mut t = [0u8; 128];
1497    let mut i = 0;
1498    while i < 128 {
1499        let c = i as u8;
1500        let mut flags = 0u8;
1501        if c >= b'A' && c <= b'Z' {
1502            flags |= CT_UPPER;
1503        }
1504        if c >= b'a' && c <= b'z' {
1505            flags |= CT_LOWER;
1506        }
1507        if c >= b'0' && c <= b'9' {
1508            flags |= CT_DIGIT;
1509        }
1510        if c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == b'\x0c' || c == b'\x0b' {
1511            flags |= CT_SPACE;
1512        }
1513        if (c >= b'!' && c <= b'/')
1514            || (c >= b':' && c <= b'@')
1515            || (c >= b'[' && c <= b'`')
1516            || (c >= b'{' && c <= b'~')
1517        {
1518            flags |= CT_PUNCT;
1519        }
1520        if c < 0x20 || c == 0x7f {
1521            flags |= CT_CNTRL;
1522        }
1523        if c == b' ' || c == b'\t' {
1524            flags |= CT_BLANK;
1525        }
1526        if (c >= b'0' && c <= b'9') || (c >= b'A' && c <= b'F') || (c >= b'a' && c <= b'f') {
1527            flags |= CT_XDIGIT;
1528        }
1529        t[i] = flags;
1530        i += 1;
1531    }
1532    t
1533};
1534
1535#[inline]
1536fn ct_flags(c: c_int) -> u8 {
1537    if c < 0 || c > 127 {
1538        0
1539    } else {
1540        CT_TABLE[c as usize]
1541    }
1542}
1543
1544#[no_mangle]
1545pub extern "C" fn isalnum(c: c_int) -> c_int {
1546    (ct_flags(c) & (CT_UPPER | CT_LOWER | CT_DIGIT) != 0) as c_int
1547}
1548
1549#[no_mangle]
1550pub extern "C" fn isalpha(c: c_int) -> c_int {
1551    (ct_flags(c) & (CT_UPPER | CT_LOWER) != 0) as c_int
1552}
1553
1554#[no_mangle]
1555pub extern "C" fn isascii(c: c_int) -> c_int {
1556    ((c as u32) <= 127) as c_int
1557}
1558
1559#[no_mangle]
1560pub extern "C" fn isblank(c: c_int) -> c_int {
1561    (ct_flags(c) & CT_BLANK != 0) as c_int
1562}
1563
1564#[no_mangle]
1565pub extern "C" fn iscntrl(c: c_int) -> c_int {
1566    (ct_flags(c) & CT_CNTRL != 0) as c_int
1567}
1568
1569#[no_mangle]
1570pub extern "C" fn isdigit(c: c_int) -> c_int {
1571    (ct_flags(c) & CT_DIGIT != 0) as c_int
1572}
1573
1574#[no_mangle]
1575pub extern "C" fn isgraph(c: c_int) -> c_int {
1576    (ct_flags(c) & (CT_UPPER | CT_LOWER | CT_DIGIT | CT_PUNCT) != 0) as c_int
1577}
1578
1579#[no_mangle]
1580pub extern "C" fn islower(c: c_int) -> c_int {
1581    (ct_flags(c) & CT_LOWER != 0) as c_int
1582}
1583
1584#[no_mangle]
1585pub extern "C" fn isprint(c: c_int) -> c_int {
1586    let flags = ct_flags(c);
1587    (flags & (CT_UPPER | CT_LOWER | CT_DIGIT | CT_PUNCT | CT_BLANK) != 0) as c_int
1588}
1589
1590#[no_mangle]
1591pub extern "C" fn ispunct(c: c_int) -> c_int {
1592    (ct_flags(c) & CT_PUNCT != 0) as c_int
1593}
1594
1595#[no_mangle]
1596pub extern "C" fn isspace(c: c_int) -> c_int {
1597    (ct_flags(c) & CT_SPACE != 0) as c_int
1598}
1599
1600#[no_mangle]
1601pub extern "C" fn isupper(c: c_int) -> c_int {
1602    (ct_flags(c) & CT_UPPER != 0) as c_int
1603}
1604
1605#[no_mangle]
1606pub extern "C" fn isxdigit(c: c_int) -> c_int {
1607    (ct_flags(c) & CT_XDIGIT != 0) as c_int
1608}
1609
1610#[no_mangle]
1611pub extern "C" fn tolower(c: c_int) -> c_int {
1612    if (ct_flags(c) & CT_UPPER) != 0 {
1613        c + (b'a' as c_int - b'A' as c_int)
1614    } else {
1615        c
1616    }
1617}
1618
1619#[no_mangle]
1620pub extern "C" fn toupper(c: c_int) -> c_int {
1621    if (ct_flags(c) & CT_LOWER) != 0 {
1622        c - (b'a' as c_int - b'A' as c_int)
1623    } else {
1624        c
1625    }
1626}
1627
1628// ============================================================
1629// stdlib.h: integer conversion, abs, rand
1630// ============================================================
1631
1632unsafe fn parse_digit(c: u8, base: c_int) -> Option<u8> {
1633    if c == 0 { return None; }
1634    let d = if c >= b'0' && c <= b'9' {
1635        c - b'0'
1636    } else if c >= b'a' && c <= b'z' {
1637        c - b'a' + 10
1638    } else if c >= b'A' && c <= b'Z' {
1639        c - b'A' + 10
1640    } else {
1641        return None;
1642    };
1643    if (d as c_int) < base {
1644        Some(d)
1645    } else {
1646        None
1647    }
1648}
1649
1650unsafe fn parse_prefix(s: *const u8, base: *mut c_int) -> *const u8 {
1651    let mut p = s;
1652    if *base == 0 {
1653        if *p == b'0' {
1654            if (*p.add(1) == b'x' || *p.add(1) == b'X') && parse_digit(*p.add(2), 16).is_some() {
1655                *base = 16;
1656                p = p.add(2);
1657            } else {
1658                *base = 8;
1659            }
1660        } else {
1661            *base = 10;
1662        }
1663    } else if *base == 16 {
1664        if *p == b'0' && (*p.add(1) == b'x' || *p.add(1) == b'X') && parse_digit(*p.add(2), 16).is_some() {
1665            p = p.add(2);
1666        }
1667    }
1668    p
1669}
1670
1671unsafe fn strtox(
1672    s: *const c_char,
1673    endptr: *mut *mut c_char,
1674    mut base: c_int,
1675    pos_limit: u64,
1676    neg_limit: u64,
1677) -> (u64, bool, bool) {
1678    let s0 = s as *const u8;
1679    let mut p = s0;
1680    while isspace(*p as c_int) != 0 {
1681        p = p.add(1);
1682    }
1683
1684    if base < 0 || base == 1 || base > 36 {
1685        if !endptr.is_null() {
1686            *endptr = s as *mut c_char;
1687        }
1688        ERRNO = EINVAL;
1689        return (0, false, false);
1690    }
1691
1692    let mut neg = false;
1693    match *p {
1694        b'-' => { neg = true; p = p.add(1); }
1695        b'+' => p = p.add(1),
1696        _ => {}
1697    }
1698
1699    p = parse_prefix(p, &mut base);
1700
1701    let limit = if neg { neg_limit } else { pos_limit };
1702    let mut val: u64 = 0;
1703    let mut any = false;
1704    while let Some(d) = parse_digit(*p, base) {
1705        any = true;
1706        if val > (limit - d as u64) / base as u64 {
1707            while parse_digit(*p, base).is_some() { p = p.add(1); }
1708            if !endptr.is_null() { *endptr = p as *mut c_char; }
1709            ERRNO = ERANGE_VAL;
1710            return (limit, true, neg);
1711        }
1712        val = val * base as u64 + d as u64;
1713        p = p.add(1);
1714    }
1715
1716    if !endptr.is_null() {
1717        *endptr = if any { p as *mut c_char } else { s as *mut c_char };
1718    }
1719    (val, false, neg)
1720}
1721
1722#[no_mangle]
1723pub unsafe extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
1724    let pos_limit = c_long::MAX as u64;
1725    let neg_limit = pos_limit.wrapping_add(1);
1726    let (val, overflow, neg) = strtox(s, endptr, base, pos_limit, neg_limit);
1727    if overflow {
1728        return if neg { c_long::MIN } else { c_long::MAX };
1729    }
1730    if neg { val.wrapping_neg() as c_long } else { val as c_long }
1731}
1732
1733#[no_mangle]
1734pub unsafe extern "C" fn strtoul(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulong {
1735    let limit = c_ulong::MAX as u64;
1736    let (val, overflow, neg) = strtox(s, endptr, base, limit, limit);
1737    if overflow {
1738        return c_ulong::MAX;
1739    }
1740    if neg { val.wrapping_neg() as c_ulong } else { val as c_ulong }
1741}
1742
1743#[no_mangle]
1744pub unsafe extern "C" fn strtoll(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_longlong {
1745    let pos_limit = c_longlong::MAX as u64;
1746    let neg_limit = pos_limit.wrapping_add(1);
1747    let (val, overflow, neg) = strtox(s, endptr, base, pos_limit, neg_limit);
1748    if overflow {
1749        return if neg { c_longlong::MIN } else { c_longlong::MAX };
1750    }
1751    if neg { val.wrapping_neg() as c_longlong } else { val as c_longlong }
1752}
1753
1754#[no_mangle]
1755pub unsafe extern "C" fn strtoull(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulonglong {
1756    let limit = c_ulonglong::MAX as u64;
1757    let (val, overflow, neg) = strtox(s, endptr, base, limit, limit);
1758    if overflow {
1759        return c_ulonglong::MAX;
1760    }
1761    if neg { val.wrapping_neg() as c_ulonglong } else { val as c_ulonglong }
1762}
1763
1764#[no_mangle]
1765pub unsafe extern "C" fn atoi(s: *const c_char) -> c_int {
1766    strtol(s, core::ptr::null_mut(), 10) as c_int
1767}
1768
1769#[no_mangle]
1770pub unsafe extern "C" fn atol(s: *const c_char) -> c_long {
1771    strtol(s, core::ptr::null_mut(), 10)
1772}
1773
1774#[no_mangle]
1775pub unsafe extern "C" fn atoll(s: *const c_char) -> c_longlong {
1776    strtoll(s, core::ptr::null_mut(), 10)
1777}
1778
1779#[no_mangle]
1780pub extern "C" fn abs(n: c_int) -> c_int {
1781    if n < 0 {
1782        -n
1783    } else {
1784        n
1785    }
1786}
1787
1788#[no_mangle]
1789pub extern "C" fn labs(n: c_long) -> c_long {
1790    if n < 0 {
1791        -n
1792    } else {
1793        n
1794    }
1795}
1796
1797#[no_mangle]
1798pub extern "C" fn llabs(n: c_longlong) -> c_longlong {
1799    if n < 0 {
1800        -n
1801    } else {
1802        n
1803    }
1804}
1805
1806static mut RAND_STATE: c_uint = 1;
1807
1808#[no_mangle]
1809pub extern "C" fn srand(seed: c_uint) {
1810    unsafe {
1811        RAND_STATE = seed;
1812    }
1813}
1814
1815#[no_mangle]
1816pub extern "C" fn rand() -> c_int {
1817    unsafe {
1818        RAND_STATE = RAND_STATE.wrapping_mul(1103515245).wrapping_add(12345);
1819        ((RAND_STATE >> 16) & 0x7fff) as c_int
1820    }
1821}
1822
1823// ============================================================
1824// stdlib.h: div, ldiv, lldiv
1825// ============================================================
1826
1827#[repr(C)]
1828pub struct div_t { pub quot: c_int, pub rem: c_int }
1829#[repr(C)]
1830pub struct ldiv_t { pub quot: c_long, pub rem: c_long }
1831#[repr(C)]
1832pub struct lldiv_t { pub quot: c_longlong, pub rem: c_longlong }
1833
1834#[no_mangle]
1835pub extern "C" fn div(num: c_int, den: c_int) -> div_t {
1836    div_t { quot: num / den, rem: num % den }
1837}
1838
1839#[no_mangle]
1840pub extern "C" fn ldiv(num: c_long, den: c_long) -> ldiv_t {
1841    ldiv_t { quot: num / den, rem: num % den }
1842}
1843
1844#[no_mangle]
1845pub extern "C" fn lldiv(num: c_longlong, den: c_longlong) -> lldiv_t {
1846    lldiv_t { quot: num / den, rem: num % den }
1847}
1848
1849// ============================================================
1850// bsearch
1851// ============================================================
1852
1853type CmpFn = unsafe extern "C" fn(*const c_void, *const c_void) -> c_int;
1854
1855#[no_mangle]
1856pub unsafe extern "C" fn bsearch(
1857    key: *const c_void,
1858    base: *const c_void,
1859    nel: usize,
1860    width: usize,
1861    cmp: CmpFn,
1862) -> *mut c_void {
1863    let mut base = base as *const u8;
1864    let mut nel = nel;
1865    while nel > 0 {
1866        let trial = base.add(width * (nel / 2));
1867        let sign = cmp(key, trial as *const c_void);
1868        if sign < 0 {
1869            nel /= 2;
1870        } else if sign > 0 {
1871            base = trial.add(width);
1872            nel -= nel / 2 + 1;
1873        } else {
1874            return trial as *mut c_void;
1875        }
1876    }
1877    null_mut()
1878}
1879
1880// ============================================================
1881// signal.h
1882// ============================================================
1883
1884pub const SA_RESTORER: c_ulong = 0x04000000;
1885
1886pub const SIG_DFL: usize = 0;
1887pub const SIG_IGN: usize = 1;
1888pub const SIG_ERR: usize = !0usize;
1889
1890pub const SIGHUP: c_int = 1;
1891pub const SIGINT: c_int = 2;
1892pub const SIGQUIT: c_int = 3;
1893pub const SIGILL: c_int = 4;
1894pub const SIGTRAP: c_int = 5;
1895pub const SIGABRT: c_int = 6;
1896pub const SIGIOT: c_int = 6;
1897pub const SIGBUS: c_int = 7;
1898pub const SIGFPE: c_int = 8;
1899pub const SIGKILL: c_int = 9;
1900pub const SIGUSR1: c_int = 10;
1901pub const SIGSEGV: c_int = 11;
1902pub const SIGUSR2: c_int = 12;
1903pub const SIGPIPE: c_int = 13;
1904pub const SIGALRM: c_int = 14;
1905pub const SIGTERM: c_int = 15;
1906pub const SIGSTKFLT: c_int = 16;
1907pub const SIGCHLD: c_int = 17;
1908pub const SIGCONT: c_int = 18;
1909pub const SIGSTOP: c_int = 19;
1910pub const SIGTSTP: c_int = 20;
1911pub const SIGTTIN: c_int = 21;
1912pub const SIGTTOU: c_int = 22;
1913pub const SIGURG: c_int = 23;
1914pub const SIGXCPU: c_int = 24;
1915pub const SIGXFSZ: c_int = 25;
1916pub const SIGVTALRM: c_int = 26;
1917pub const SIGPROF: c_int = 27;
1918pub const SIGWINCH: c_int = 28;
1919pub const SIGIO: c_int = 29;
1920pub const SIGPOLL: c_int = 29;
1921pub const SIGPWR: c_int = 30;
1922pub const SIGSYS: c_int = 31;
1923pub const SIGUNUSED: c_int = 31;
1924pub const _NSIG: c_int = 65;
1925
1926pub const SIG_BLOCK: c_int = 0;
1927pub const SIG_UNBLOCK: c_int = 1;
1928pub const SIG_SETMASK: c_int = 2;
1929
1930pub const SA_NOCLDSTOP: c_ulong = 1;
1931pub const SA_NOCLDWAIT: c_ulong = 2;
1932pub const SA_SIGINFO: c_ulong = 4;
1933pub const SA_ONSTACK: c_ulong = 0x08000000;
1934pub const SA_RESTART: c_ulong = 0x10000000;
1935pub const SA_NODEFER: c_ulong = 0x40000000;
1936pub const SA_RESETHAND: c_ulong = 0x80000000;
1937
1938pub const SS_ONSTACK: c_int = 1;
1939pub const SS_DISABLE: c_int = 2;
1940pub const MINSIGSTKSZ: usize = 2048;
1941pub const SIGSTKSZ: usize = 8192;
1942
1943pub const SI_USER: c_int = 0;
1944pub const SI_TKILL: c_int = -6;
1945
1946#[repr(C)]
1947pub struct timespec {
1948    pub tv_sec: c_long,
1949    pub tv_nsec: c_long,
1950}
1951
1952#[repr(C)]
1953pub struct siginfo_t {
1954    pub si_signo: c_int,
1955    pub si_errno: c_int,
1956    pub si_code: c_int,
1957    // ponytail: rest of 128-byte struct, only si_signo accessed
1958    _pad: [u8; 128 - 3 * core::mem::size_of::<c_int>()],
1959}
1960
1961#[repr(C)]
1962pub struct stack_t {
1963    pub ss_sp: *mut c_void,
1964    pub ss_flags: c_int,
1965    pub ss_size: usize,
1966}
1967
1968#[repr(C)]
1969pub struct sigaction {
1970    pub sa_handler: usize,
1971    pub sa_flags: c_ulong,
1972    pub sa_restorer: usize,
1973    pub sa_mask: [c_ulong; 1],
1974}
1975
1976pub type SigSetT = c_ulong;
1977
1978#[cfg(target_arch = "x86_64")]
1979core::arch::global_asm!(
1980    ".global sig_restorer",
1981    ".type sig_restorer, @function",
1982    "sig_restorer:",
1983    "mov eax, 15",
1984    "syscall",
1985);
1986
1987#[cfg(target_arch = "aarch64")]
1988core::arch::global_asm!(
1989    ".global sig_restorer",
1990    ".type sig_restorer, @function",
1991    "sig_restorer:",
1992    "mov x8, #139",
1993    "svc #0",
1994);
1995
1996#[cfg(target_arch = "riscv64")]
1997core::arch::global_asm!(
1998    ".global sig_restorer",
1999    ".type sig_restorer, @function",
2000    "sig_restorer:",
2001    "li a7, 139",
2002    "ecall",
2003);
2004
2005extern "C" {
2006    fn sig_restorer();
2007}
2008
2009#[inline]
2010unsafe fn sys_rt_sigaction(sig: c_int,
2011    act: *const sigaction,
2012    oldact: *mut sigaction,
2013    sigsetsize: usize,) -> i64 {
2014    <Arch as Syscalls>::syscall4(SYS_RT_SIGACTION, sig as i64, act as i64, oldact as i64, sigsetsize as i64)
2015}
2016
2017#[inline]
2018unsafe fn sys_rt_sigprocmask(how: c_int,
2019    set: *const SigSetT,
2020    oldset: *mut SigSetT,
2021    sigsetsize: usize,) -> i64 {
2022    <Arch as Syscalls>::syscall4(SYS_RT_SIGPROCMASK, how as i64, set as i64, oldset as i64, sigsetsize as i64)
2023}
2024
2025#[inline]
2026unsafe fn sys_rt_sigpending(set: *mut SigSetT, sigsetsize: usize) -> i64 {
2027    <Arch as Syscalls>::syscall2(SYS_RT_SIGPENDING, set as i64, sigsetsize as i64)
2028}
2029
2030#[inline]
2031unsafe fn sys_rt_sigsuspend(mask: *const SigSetT, sigsetsize: usize) -> i64 {
2032    <Arch as Syscalls>::syscall2(SYS_RT_SIGSUSPEND, mask as i64, sigsetsize as i64)
2033}
2034
2035#[inline]
2036unsafe fn sys_rt_sigtimedwait(set: *const SigSetT,
2037    info: *mut siginfo_t,
2038    timeout: *const timespec,
2039    sigsetsize: usize,) -> i64 {
2040    <Arch as Syscalls>::syscall4(SYS_RT_SIGTIMEDWAIT, set as i64, info as i64, timeout as i64, sigsetsize as i64)
2041}
2042
2043#[inline]
2044unsafe fn sys_sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> i64 {
2045    <Arch as Syscalls>::syscall2(SYS_SIGALTSTACK, ss as i64, old_ss as i64)
2046}
2047
2048#[inline]
2049unsafe fn sys_tgkill(tgid: c_int, tid: c_int, sig: c_int) -> i64 {
2050    <Arch as Syscalls>::syscall3(SYS_TGKILL, tgid as i64, tid as i64, sig as i64)
2051}
2052
2053const CLOCK_REALTIME: c_int = 0;
2054const CLOCK_MONOTONIC: c_int = 1;
2055
2056#[inline]
2057unsafe fn sys_clock_gettime(clockid: c_int, ts: *mut timespec) -> i64 {
2058    <Arch as Syscalls>::syscall2(SYS_CLOCK_GETTIME, clockid as i64, ts as i64)
2059}
2060
2061#[no_mangle]
2062pub unsafe extern "C" fn clock_gettime(clockid: c_int, ts: *mut timespec) -> c_int {
2063    if sys_clock_gettime(clockid, ts) < 0 { -1 } else { 0 }
2064}
2065
2066#[no_mangle]
2067pub unsafe extern "C" fn sigprocmask(
2068    how: c_int,
2069    set: *const SigSetT,
2070    oldset: *mut SigSetT,
2071) -> c_int {
2072    // ponytail: mask out internal rt signals (32, 33) before touching the kernel
2073    let internal_mask: SigSetT = (1u64 << 31) | (1u64 << 32);
2074    let filtered: SigSetT;
2075    let set_ptr: *const SigSetT = if set.is_null() {
2076        set
2077    } else {
2078        filtered = *set & !internal_mask;
2079        &filtered
2080    };
2081    let r = sys_rt_sigprocmask(how, set_ptr, oldset, core::mem::size_of::<SigSetT>());
2082    if !oldset.is_null() {
2083        *oldset &= !internal_mask;
2084    }
2085    if r < 0 { -1 } else { 0 }
2086}
2087
2088#[inline]
2089unsafe fn sys_kill(pid: c_int, sig: c_int) -> i64 {
2090    <Arch as Syscalls>::syscall2(SYS_KILL, pid as i64, sig as i64)
2091}
2092
2093#[inline]
2094unsafe fn sys_getpid() -> i64 {
2095    <Arch as Syscalls>::syscall0(SYS_GETPID)
2096}
2097
2098#[no_mangle]
2099pub unsafe extern "C" fn sigaction(
2100    signum: c_int,
2101    act: *const sigaction,
2102    oldact: *mut sigaction,
2103) -> c_int {
2104    let kact: sigaction;
2105    let act_ptr = if act.is_null() {
2106        core::ptr::null()
2107    } else {
2108        kact = sigaction {
2109            sa_handler: (*act).sa_handler,
2110            sa_flags: (*act).sa_flags | SA_RESTORER,
2111            sa_restorer: sig_restorer as *const () as usize,
2112            sa_mask: (*act).sa_mask,
2113        };
2114        &kact as *const sigaction
2115    };
2116    let r = sys_rt_sigaction(signum, act_ptr, oldact, core::mem::size_of::<SigSetT>());
2117    if r < 0 {
2118        ERRNO = (-r) as c_int;
2119        -1
2120    } else {
2121        0
2122    }
2123}
2124
2125#[no_mangle]
2126pub unsafe extern "C" fn signal(signum: c_int, handler: usize) -> usize {
2127    let act = sigaction {
2128        sa_handler: handler,
2129        sa_flags: SA_RESTORER,
2130        sa_restorer: sig_restorer as *const () as usize,
2131        sa_mask: [0],
2132    };
2133    let mut old = sigaction {
2134        sa_handler: 0,
2135        sa_flags: 0,
2136        sa_restorer: 0,
2137        sa_mask: [0],
2138    };
2139    if sigaction(signum, &act, &mut old) == -1 {
2140        SIG_ERR
2141    } else {
2142        old.sa_handler
2143    }
2144}
2145
2146#[no_mangle]
2147pub unsafe extern "C" fn kill(pid: c_int, sig: c_int) -> c_int {
2148    sys_kill(pid, sig) as c_int
2149}
2150
2151#[no_mangle]
2152pub unsafe extern "C" fn tgkill(tgid: c_int, tid: c_int, sig: c_int) -> c_int {
2153    if sys_tgkill(tgid, tid, sig) < 0 { -1 } else { 0 }
2154}
2155
2156#[no_mangle]
2157pub unsafe extern "C" fn getpid() -> c_int {
2158    sys_getpid() as c_int
2159}
2160
2161#[no_mangle]
2162pub unsafe extern "C" fn raise(sig: c_int) -> c_int {
2163    if sys_tgkill(sys_getpid() as c_int, sys_gettid() as c_int, sig) < 0 {
2164        -1
2165    } else {
2166        0
2167    }
2168}
2169
2170#[no_mangle]
2171pub unsafe extern "C" fn sigemptyset(set: *mut SigSetT) -> c_int {
2172    *set = 0;
2173    0
2174}
2175
2176#[no_mangle]
2177pub unsafe extern "C" fn sigfillset(set: *mut SigSetT) -> c_int {
2178    // musl: all signals except 32 (SIGCANCEL) and 33 (SIGSYNCCALL)
2179    *set = 0xFFFF_FFFC_7FFF_FFFFu64;
2180    0
2181}
2182
2183#[no_mangle]
2184pub unsafe extern "C" fn sigaddset(set: *mut SigSetT, signum: c_int) -> c_int {
2185    let s = (signum as c_uint).wrapping_sub(1);
2186    if s as usize >= 64 {
2187        ERRNO = EINVAL;
2188        return -1;
2189    }
2190    // ponytail: internal rt signals (32, 33) cannot be manipulated
2191    if signum >= 32 && signum < __libc_current_sigrtmin() {
2192        return 0;
2193    }
2194    *set |= 1u64 << s;
2195    0
2196}
2197
2198#[no_mangle]
2199pub unsafe extern "C" fn sigdelset(set: *mut SigSetT, signum: c_int) -> c_int {
2200    let s = (signum as c_uint).wrapping_sub(1);
2201    if s as usize >= 64 {
2202        ERRNO = EINVAL;
2203        return -1;
2204    }
2205    // ponytail: internal rt signals (32, 33) are never members
2206    if signum >= 32 && signum < __libc_current_sigrtmin() {
2207        return 0;
2208    }
2209    *set &= !(1u64 << s);
2210    0
2211}
2212
2213#[no_mangle]
2214pub unsafe extern "C" fn sigismember(set: *const SigSetT, signum: c_int) -> c_int {
2215    let s = (signum as c_uint).wrapping_sub(1);
2216    if s as usize >= 64 { return 0; }
2217    // ponytail: internal rt signals (32, 33) are never members
2218    if signum >= 32 && signum < __libc_current_sigrtmin() {
2219        return 0;
2220    }
2221    ((*set & (1u64 << s)) != 0) as c_int
2222}
2223
2224#[no_mangle]
2225pub unsafe extern "C" fn sigpending(set: *mut SigSetT) -> c_int {
2226    let r = sys_rt_sigpending(set, core::mem::size_of::<SigSetT>());
2227    if r < 0 {
2228        ERRNO = (-r) as c_int;
2229        return -1;
2230    }
2231    0
2232}
2233
2234#[no_mangle]
2235pub unsafe extern "C" fn sigsuspend(mask: *const SigSetT) -> c_int {
2236    let r = sys_rt_sigsuspend(mask, core::mem::size_of::<SigSetT>());
2237    if r < 0 {
2238        ERRNO = (-r) as c_int;
2239    }
2240    -1
2241}
2242
2243#[no_mangle]
2244pub unsafe extern "C" fn sigtimedwait(
2245    mask: *const SigSetT,
2246    info: *mut siginfo_t,
2247    timeout: *const timespec,
2248) -> c_int {
2249    loop {
2250        let r = sys_rt_sigtimedwait(mask, info, timeout, core::mem::size_of::<SigSetT>());
2251        if r >= 0 {
2252            return r as c_int;
2253        }
2254        let e = (-r) as c_int;
2255        if e != EINTR {
2256            ERRNO = e;
2257            return -1;
2258        }
2259    }
2260}
2261
2262#[no_mangle]
2263pub unsafe extern "C" fn sigwaitinfo(
2264    mask: *const SigSetT,
2265    info: *mut siginfo_t,
2266) -> c_int {
2267    sigtimedwait(mask, info, core::ptr::null())
2268}
2269
2270#[no_mangle]
2271pub unsafe extern "C" fn sigwait(
2272    mask: *const SigSetT,
2273    sig: *mut c_int,
2274) -> c_int {
2275    let mut info: siginfo_t = core::mem::zeroed();
2276    if sigtimedwait(mask, &mut info, core::ptr::null()) < 0 {
2277        return ERRNO;
2278    }
2279    *sig = info.si_signo;
2280    0
2281}
2282
2283#[no_mangle]
2284pub unsafe extern "C" fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
2285    if !ss.is_null() {
2286        if (*ss).ss_flags & SS_ONSTACK != 0 {
2287            ERRNO = EINVAL;
2288            return -1;
2289        }
2290        if (*ss).ss_flags & SS_DISABLE == 0 && (*ss).ss_size < MINSIGSTKSZ {
2291            ERRNO = ENOMEM;
2292            return -1;
2293        }
2294    }
2295    let r = sys_sigaltstack(ss, old_ss);
2296    if r < 0 {
2297        ERRNO = (-r) as c_int;
2298        return -1;
2299    }
2300    0
2301}
2302
2303// ============================================================
2304// setjmp.h
2305// ponytail: jmp_buf is unsigned long[8]: rbx, rbp, r12-r15, rsp, rip
2306// ============================================================
2307
2308#[no_mangle]
2309#[inline(never)]
2310#[cfg(target_arch = "x86_64")]
2311pub unsafe extern "C" fn setjmp(env: *mut c_ulong) -> c_int {
2312    core::arch::asm!(
2313        "mov rax, [rsp]",
2314        "lea rcx, [rsp + 8]",
2315        "mov [r8], rbx",
2316        "mov [r8 + 8], rbp",
2317        "mov [r8 + 16], r12",
2318        "mov [r8 + 24], r13",
2319        "mov [r8 + 32], r14",
2320        "mov [r8 + 40], r15",
2321        "mov [r8 + 48], rcx",
2322        "mov [r8 + 56], rax",
2323        in("r8") env,
2324        lateout("rax") _,
2325        lateout("rcx") _,
2326        options(nostack),
2327    );
2328    0
2329}
2330
2331#[no_mangle]
2332#[inline(never)]
2333#[cfg(target_arch = "x86_64")]
2334pub unsafe extern "C" fn longjmp(env: *const c_ulong, val: c_int) -> ! {
2335    let ret = if val == 0 { 1 } else { val } as u32;
2336    core::arch::asm!(
2337        "mov rbx, [r8]",
2338        "mov rbp, [r8 + 8]",
2339        "mov r12, [r8 + 16]",
2340        "mov r13, [r8 + 24]",
2341        "mov r14, [r8 + 32]",
2342        "mov r15, [r8 + 40]",
2343        "mov rsp, [r8 + 48]",
2344        "mov eax, edx",
2345        "jmp [r8 + 56]",
2346        in("r8") env,
2347        in("edx") ret,
2348        options(noreturn),
2349    );
2350}
2351
2352#[no_mangle]
2353#[unsafe(naked)]
2354#[cfg(target_arch = "aarch64")]
2355pub unsafe extern "C" fn setjmp(env: *mut c_ulong) -> c_int {
2356    core::arch::naked_asm!(
2357        "stp x19, x20, [x0, #0]",
2358        "stp x21, x22, [x0, #16]",
2359        "stp x23, x24, [x0, #32]",
2360        "stp x25, x26, [x0, #48]",
2361        "stp x27, x28, [x0, #64]",
2362        "stp x29, x30, [x0, #80]",
2363        "mov x2, sp",
2364        "str x2, [x0, #104]",
2365        "stp d8, d9, [x0, #112]",
2366        "stp d10, d11, [x0, #128]",
2367        "stp d12, d13, [x0, #144]",
2368        "stp d14, d15, [x0, #160]",
2369        "mov x0, #0",
2370        "ret",
2371    );
2372}
2373
2374#[no_mangle]
2375#[inline(never)]
2376#[cfg(target_arch = "aarch64")]
2377pub unsafe extern "C" fn longjmp(env: *const c_ulong, val: c_int) -> ! {
2378    let ret = if val == 0 { 1 } else { val } as u64;
2379    core::arch::asm!(
2380        "ldp x19, x20, [x0]",
2381        "ldp x21, x22, [x0, #16]",
2382        "ldp x23, x24, [x0, #32]",
2383        "ldp x25, x26, [x0, #48]",
2384        "ldp x27, x28, [x0, #64]",
2385        "ldp x29, x30, [x0, #80]",
2386        "ldr x2, [x0, #104]",
2387        "mov sp, x2",
2388        "ldp d8, d9, [x0, #112]",
2389        "ldp d10, d11, [x0, #128]",
2390        "ldp d12, d13, [x0, #144]",
2391        "ldp d14, d15, [x0, #160]",
2392        "mov x0, x1",
2393        "br x30",
2394        in("x0") env,
2395        in("x1") ret,
2396        options(noreturn),
2397    );
2398}
2399
2400#[no_mangle]
2401#[unsafe(naked)]
2402#[cfg(target_arch = "riscv64")]
2403pub unsafe extern "C" fn setjmp(env: *mut c_ulong) -> c_int {
2404    core::arch::naked_asm!(
2405        "sd s0, 0(a0)",
2406        "sd s1, 8(a0)",
2407        "sd s2, 16(a0)",
2408        "sd s3, 24(a0)",
2409        "sd s4, 32(a0)",
2410        "sd s5, 40(a0)",
2411        "sd s6, 48(a0)",
2412        "sd s7, 56(a0)",
2413        "sd s8, 64(a0)",
2414        "sd s9, 72(a0)",
2415        "sd s10, 80(a0)",
2416        "sd s11, 88(a0)",
2417        "sd sp, 96(a0)",
2418        "sd ra, 104(a0)",
2419        "li a0, 0",
2420        "ret",
2421    );
2422}
2423
2424#[no_mangle]
2425#[inline(never)]
2426#[cfg(target_arch = "riscv64")]
2427pub unsafe extern "C" fn longjmp(env: *const c_ulong, val: c_int) -> ! {
2428    let ret = if val == 0 { 1 } else { val } as u64;
2429    core::arch::asm!(
2430        "ld s0, 0(a0)",
2431        "ld s1, 8(a0)",
2432        "ld s2, 16(a0)",
2433        "ld s3, 24(a0)",
2434        "ld s4, 32(a0)",
2435        "ld s5, 40(a0)",
2436        "ld s6, 48(a0)",
2437        "ld s7, 56(a0)",
2438        "ld s8, 64(a0)",
2439        "ld s9, 72(a0)",
2440        "ld s10, 80(a0)",
2441        "ld s11, 88(a0)",
2442        "ld sp, 96(a0)",
2443        "ld ra, 104(a0)",
2444        "mv a0, a1",
2445        "ret",
2446        in("a0") env,
2447        in("a1") ret,
2448        options(noreturn),
2449    );
2450}
2451
2452// ponytail: sigsetjmp is implemented in raw assembly because the Rust compiler
2453// rewrites naked_asm that touches rbx into incorrect push/pop sequences,
2454// corrupting the caller's rbx across the initial return. The exported wrappers
2455// jump to a local hidden assembly implementation; the layout matches musl:
2456// env[0..7] = __jmp_buf, env[8] = saved return address, env[9] = saved signal
2457// mask, env[10] = saved rbx.
2458
2459#[no_mangle]
2460#[unsafe(naked)]
2461#[cfg(target_arch = "x86_64")]
2462pub unsafe extern "C" fn sigsetjmp(_env: *mut c_ulong, _savemask: c_int) -> c_int {
2463    core::arch::naked_asm!("jmp sigsetjmp_real");
2464}
2465
2466#[no_mangle]
2467#[unsafe(naked)]
2468#[cfg(target_arch = "x86_64")]
2469pub unsafe extern "C" fn __sigsetjmp(_env: *mut c_ulong, _savemask: c_int) -> c_int {
2470    core::arch::naked_asm!("jmp sigsetjmp_real");
2471}
2472
2473#[cfg(target_arch = "x86_64")]
2474core::arch::global_asm!(
2475    ".type sigsetjmp_real, @function",
2476    "sigsetjmp_real:",
2477    "   test esi, esi",
2478    "   jz 1f",
2479    "   pop qword ptr [rdi + 64]",
2480    "   mov qword ptr [rdi + 80], rbx",
2481    "   push rbx",
2482    "   mov rbx, rdi",
2483    "   call setjmp",
2484    "   push qword ptr [rbx + 64]",
2485    "   mov rdi, rbx",
2486    "   mov esi, eax",
2487    "   mov rbx, qword ptr [rbx + 80]",
2488    "   lea rdx, [rdi + 72]",
2489    "   test esi, esi",
2490    "   jz 2f",
2491    "   mov rsi, rdx",
2492    "   xor rdx, rdx",
2493    "   mov edi, 2",
2494    "   jmp 3f",
2495    "2:",
2496    "   xor rsi, rsi",
2497    "   mov edi, 2",
2498    "3:",
2499    "   mov eax, 14",
2500    "   mov r10d, 8",
2501    "   syscall",
2502    "   test esi, esi",
2503    "   jnz 4f",
2504    "   mov rax, 0xfffffffe7fffffff",
2505    "   and qword ptr [rdx], rax",
2506    "4:",
2507    "   mov eax, esi",
2508    "   ret",
2509    "1:",
2510    "   jmp setjmp",
2511);
2512
2513#[no_mangle]
2514#[inline(never)]
2515#[cfg(target_arch = "x86_64")]
2516pub unsafe extern "C" fn siglongjmp(env: *const c_ulong, val: c_int) -> ! {
2517    longjmp(env, val);
2518}
2519
2520#[no_mangle]
2521#[cfg(target_arch = "aarch64")]
2522pub unsafe extern "C" fn __sigsetjmp_tail(env: *mut c_ulong, ret: c_int) -> c_int {
2523    const SIG_SETMASK: c_int = 2;
2524    let ss = env.add(24) as *mut SigSetT;
2525    let set = if ret != 0 { ss as *const SigSetT } else { core::ptr::null() };
2526    let old = if ret != 0 { core::ptr::null_mut() } else { ss };
2527    let _ = sys_rt_sigprocmask(SIG_SETMASK, set, old, core::mem::size_of::<SigSetT>());
2528    ret
2529}
2530
2531#[no_mangle]
2532#[unsafe(naked)]
2533#[cfg(target_arch = "aarch64")]
2534pub unsafe extern "C" fn sigsetjmp(env: *mut c_ulong, savemask: c_int) -> c_int {
2535    core::arch::naked_asm!(
2536        "cbz w1, setjmp",
2537        "str x30, [x0, #176]",
2538        "str x19, [x0, #184]",
2539        "mov x19, x0",
2540        "bl setjmp",
2541        "mov w1, w0",
2542        "mov x0, x19",
2543        "ldr x30, [x0, #176]",
2544        "ldr x19, [x0, #184]",
2545        "b __sigsetjmp_tail",
2546    );
2547}
2548
2549#[no_mangle]
2550#[unsafe(naked)]
2551#[cfg(target_arch = "aarch64")]
2552pub unsafe extern "C" fn __sigsetjmp(env: *mut c_ulong, savemask: c_int) -> c_int {
2553    core::arch::naked_asm!(
2554        "cbz w1, setjmp",
2555        "str x30, [x0, #176]",
2556        "str x19, [x0, #184]",
2557        "mov x19, x0",
2558        "bl setjmp",
2559        "mov w1, w0",
2560        "mov x0, x19",
2561        "ldr x30, [x0, #176]",
2562        "ldr x19, [x0, #184]",
2563        "b __sigsetjmp_tail",
2564    );
2565}
2566
2567#[no_mangle]
2568#[inline(never)]
2569#[cfg(target_arch = "aarch64")]
2570pub unsafe extern "C" fn siglongjmp(env: *const c_ulong, val: c_int) -> ! {
2571    longjmp(env, val);
2572}
2573
2574#[no_mangle]
2575#[cfg(target_arch = "riscv64")]
2576pub unsafe extern "C" fn __sigsetjmp_tail(env: *mut c_ulong, ret: c_int) -> c_int {
2577    const SIG_SETMASK: c_int = 2;
2578    let ss = env.add(27) as *mut SigSetT;
2579    let set = if ret != 0 { ss as *const SigSetT } else { core::ptr::null() };
2580    let old = if ret != 0 { core::ptr::null_mut() } else { ss };
2581    let _ = sys_rt_sigprocmask(SIG_SETMASK, set, old, core::mem::size_of::<SigSetT>());
2582    ret
2583}
2584
2585#[no_mangle]
2586#[unsafe(naked)]
2587#[cfg(target_arch = "riscv64")]
2588pub unsafe extern "C" fn sigsetjmp(env: *mut c_ulong, savemask: c_int) -> c_int {
2589    core::arch::naked_asm!(
2590        "bnez a1, 1f",
2591        "tail setjmp",
2592        "1:",
2593        "sd ra, 208(a0)",
2594        "sd s0, 224(a0)",
2595        "mv s0, a0",
2596        "call setjmp",
2597        "mv a1, a0",
2598        "mv a0, s0",
2599        "ld s0, 224(a0)",
2600        "ld ra, 208(a0)",
2601        "tail __sigsetjmp_tail",
2602    );
2603}
2604
2605#[no_mangle]
2606#[unsafe(naked)]
2607#[cfg(target_arch = "riscv64")]
2608pub unsafe extern "C" fn __sigsetjmp(env: *mut c_ulong, savemask: c_int) -> c_int {
2609    core::arch::naked_asm!(
2610        "bnez a1, 1f",
2611        "tail setjmp",
2612        "1:",
2613        "sd ra, 208(a0)",
2614        "sd s0, 224(a0)",
2615        "mv s0, a0",
2616        "call setjmp",
2617        "mv a1, a0",
2618        "mv a0, s0",
2619        "ld s0, 224(a0)",
2620        "ld ra, 208(a0)",
2621        "tail __sigsetjmp_tail",
2622    );
2623}
2624
2625#[no_mangle]
2626#[inline(never)]
2627#[cfg(target_arch = "riscv64")]
2628pub unsafe extern "C" fn siglongjmp(env: *const c_ulong, val: c_int) -> ! {
2629    longjmp(env, val);
2630}
2631
2632// ============================================================
2633// syscall wrappers: fstat/newfstatat/getrlimit/setrlimit/utimensat
2634// ============================================================
2635
2636#[inline]
2637unsafe fn sys_newfstatat(dirfd: i32, path: *const c_char, buf: *mut u8, flags: i32) -> i64 {
2638    <Arch as Syscalls>::syscall4(SYS_NEWFSTATAT, dirfd as i64, path as i64, buf as i64, flags as i64)
2639}
2640
2641#[inline]
2642unsafe fn sys_fstat(fd: i32, buf: *mut u8) -> i64 {
2643    <Arch as Syscalls>::syscall2(SYS_FSTAT, fd as i64, buf as i64)
2644}
2645
2646#[inline]
2647unsafe fn sys_getrlimit(resource: i32, rlim: *mut u8) -> i64 {
2648    <Arch as Syscalls>::syscall2(SYS_GETRLIMIT, resource as i64, rlim as i64)
2649}
2650
2651#[inline]
2652unsafe fn sys_setrlimit(resource: i32, rlim: *const u8) -> i64 {
2653    <Arch as Syscalls>::syscall2(SYS_SETRLIMIT, resource as i64, rlim as i64)
2654}
2655
2656#[inline]
2657unsafe fn sys_utimensat(dirfd: i32, path: *const c_char, times: *const u8, flags: i32) -> i64 {
2658    <Arch as Syscalls>::syscall4(SYS_UTIMENSAT, dirfd as i64, path as i64, times as i64, flags as i64)
2659}
2660
2661// ============================================================
2662// unistd.h: process primitives
2663// ============================================================
2664
2665#[inline]
2666unsafe fn sys_fork() -> i64 {
2667    #[cfg(target_arch = "x86_64")]
2668    { <Arch as Syscalls>::syscall0(SYS_FORK) }
2669    #[cfg(target_arch = "aarch64")]
2670    { <Arch as Syscalls>::syscall2(SYS_CLONE, 17, 0) }
2671    #[cfg(target_arch = "riscv64")]
2672    { <Arch as Syscalls>::syscall2(SYS_CLONE, 17, 0) }
2673}
2674
2675#[inline]
2676unsafe fn sys_execve(path: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> i64 {
2677    <Arch as Syscalls>::syscall3(SYS_EXECVE, path as i64, argv as i64, envp as i64)
2678}
2679
2680#[inline]
2681unsafe fn sys_wait4(pid: c_int, status: *mut c_int, options: c_int, rusage: *mut c_void) -> i64 {
2682    <Arch as Syscalls>::syscall4(SYS_WAIT4, pid as i64, status as i64, options as i64, rusage as i64)
2683}
2684
2685#[inline]
2686unsafe fn sys_getppid() -> i64 {
2687    <Arch as Syscalls>::syscall0(SYS_GETPPID)
2688}
2689
2690#[inline]
2691unsafe fn sys_getuid() -> i64 {
2692    <Arch as Syscalls>::syscall0(SYS_GETUID)
2693}
2694
2695#[inline]
2696unsafe fn sys_getgid() -> i64 {
2697    <Arch as Syscalls>::syscall0(SYS_GETGID)
2698}
2699
2700#[inline]
2701unsafe fn sys_geteuid() -> i64 {
2702    <Arch as Syscalls>::syscall0(SYS_GETEUID)
2703}
2704
2705#[inline]
2706unsafe fn sys_getegid() -> i64 {
2707    <Arch as Syscalls>::syscall0(SYS_GETEGID)
2708}
2709
2710#[no_mangle]
2711pub unsafe extern "C" fn fork() -> c_int {
2712    __fork_handler(-1);
2713    let ret = sys_fork();
2714    // Run the atfork handlers before publishing errno, exactly like musl's
2715    // __syscall_ret: a failing fork must report the kernel's errno even if a
2716    // handler changes errno. RLIMIT_NPROC is enforced by the kernel and does
2717    // not apply to root, so do not second-guess it here.
2718    if ret < 0 {
2719        let err = (-ret) as c_int;
2720        __fork_handler(0);
2721        ERRNO = err;
2722        return -1;
2723    }
2724    if ret == 0 {
2725        allocator_after_fork();
2726        __fork_handler(1);
2727    } else {
2728        __fork_handler(0);
2729    }
2730    ret as c_int
2731}
2732
2733#[no_mangle]
2734pub unsafe extern "C" fn execve(
2735    path: *const c_char,
2736    argv: *const *const c_char,
2737    envp: *const *const c_char,
2738) -> c_int {
2739    sys_execve(path, argv, envp) as c_int
2740}
2741
2742#[no_mangle]
2743pub unsafe extern "C" fn wait(status: *mut c_int) -> c_int {
2744    sys_wait4(-1, status, 0, core::ptr::null_mut()) as c_int
2745}
2746
2747#[no_mangle]
2748pub unsafe extern "C" fn waitpid(pid: c_int, status: *mut c_int, options: c_int) -> c_int {
2749    sys_wait4(pid, status, options, core::ptr::null_mut()) as c_int
2750}
2751
2752#[no_mangle]
2753pub unsafe extern "C" fn getppid() -> c_int {
2754    sys_getppid() as c_int
2755}
2756
2757#[no_mangle]
2758pub unsafe extern "C" fn getuid() -> c_uint {
2759    sys_getuid() as c_uint
2760}
2761
2762#[no_mangle]
2763pub unsafe extern "C" fn getgid() -> c_uint {
2764    sys_getgid() as c_uint
2765}
2766
2767#[no_mangle]
2768pub unsafe extern "C" fn geteuid() -> c_uint {
2769    sys_geteuid() as c_uint
2770}
2771
2772#[no_mangle]
2773pub unsafe extern "C" fn getegid() -> c_uint {
2774    sys_getegid() as c_uint
2775}
2776
2777// ponytail: vfork forwards to fork; real vfork optimization not needed for tests
2778#[no_mangle]
2779pub unsafe extern "C" fn vfork() -> c_int {
2780    sys_fork() as c_int
2781}
2782
2783#[no_mangle]
2784pub unsafe extern "C" fn execl(path: *const c_char, arg: *const c_char, mut args: ...) -> c_int {
2785    let mut argv: [*const c_char; 256] = [core::ptr::null(); 256];
2786    argv[0] = arg;
2787    let mut n: usize = 1;
2788    loop {
2789        let a: *const c_char = args.next_arg();
2790        if a.is_null() { break; }
2791        if n >= 255 { return -1; }
2792        argv[n] = a;
2793        n += 1;
2794    }
2795    argv[n] = core::ptr::null();
2796    sys_execve(path, argv.as_ptr(), __environ as *const *const c_char) as c_int
2797}
2798
2799// ============================================================
2800// spawn.h: posix_spawn family
2801// ============================================================
2802
2803// Matches musl's posix_spawn_file_actions_t layout.
2804// __pad0[0] = action count, __pad stores (type, fd, newfd) triples.
2805// ponytail: max 5 actions, enough for all tests
2806// ponytail: PATH search using stack buffer, O(n) scan per entry
2807unsafe fn spawn_execvp(file: *const c_char, argv: *const *const c_char, envp: *const *const c_char) -> ! {
2808    let flen = strlen(file as *const c_char);
2809    let f = file as *const u8;
2810    let mut has_slash = false;
2811    for i in 0..flen {
2812        if *f.add(i) == b'/' { has_slash = true; break; }
2813    }
2814    if has_slash {
2815        sys_execve(file, argv, envp);
2816        _exit(127);
2817    }
2818    let path = getenv(b"PATH\0".as_ptr() as *const c_char);
2819    let default_path = b"/usr/local/bin:/usr/bin:/bin\0";
2820    let p = if path.is_null() { default_path.as_ptr() } else { path as *const u8 };
2821    let plen = strlen(p as *const c_char);
2822    let mut buf: [u8; 4096] = [0; 4096];
2823    let mut i: usize = 0;
2824    while i <= plen {
2825        let start = i;
2826        while i < plen && *p.add(i) != b':' { i += 1; }
2827        let dlen = i - start;
2828        if dlen > 0 && dlen + 1 + flen < 4096 {
2829            core::ptr::copy_nonoverlapping(p.add(start), buf.as_mut_ptr(), dlen);
2830            *buf.as_mut_ptr().add(dlen) = b'/';
2831            core::ptr::copy_nonoverlapping(f, buf.as_mut_ptr().add(dlen + 1), flen + 1);
2832            sys_execve(buf.as_ptr() as *const c_char, argv, envp);
2833            // execve failed, try next
2834        }
2835        i += 1; // skip ':'
2836    }
2837    _exit(127);
2838}
2839
2840#[no_mangle]
2841pub unsafe extern "C" fn posix_spawnp(
2842    pid: *mut c_int,
2843    file: *const c_char,
2844    fa: *const posix_spawn_file_actions_t,
2845    attrp: *const posix_spawnattr_t,
2846    argv: *const *const c_char,
2847    envp: *const *const c_char,
2848) -> c_int {
2849    let child = sys_fork();
2850    if child < 0 {
2851        ERRNO = EAGAIN;
2852        return -1;
2853    }
2854    if child == 0 {
2855        // child: apply attributes and file actions, then exec
2856        spawn_apply_attr(attrp);
2857        spawn_apply_actions(fa);
2858        let actual_envp = if envp.is_null() { __environ as *const *const c_char } else { envp };
2859        spawn_execvp(file, argv, actual_envp);
2860        // unreachable: spawn_execvp always calls _exit
2861    }
2862    *pid = child as c_int;
2863    0
2864}
2865
2866#[no_mangle]
2867pub unsafe extern "C" fn posix_spawn(
2868    pid: *mut c_int,
2869    path: *const c_char,
2870    fa: *const posix_spawn_file_actions_t,
2871    attrp: *const posix_spawnattr_t,
2872    argv: *const *const c_char,
2873    envp: *const *const c_char,
2874) -> c_int {
2875    // ponytail: posix_spawn = posix_spawnp with a direct path (no PATH search needed,
2876    // but posix_spawnp handles '/' in path by doing direct execve anyway)
2877    posix_spawnp(pid, path, fa, attrp, argv, envp)
2878}
2879
2880// ============================================================
2881// sys/stat.h: stat / fstat / utimensat / futimens
2882// ============================================================
2883
2884#[cfg(target_arch = "x86_64")]
2885#[repr(C)]
2886pub struct Stat {
2887    pub st_dev: u64,
2888    pub st_ino: u64,
2889    pub st_nlink: u64,
2890    pub st_mode: u32,
2891    pub st_uid: u32,
2892    pub st_gid: u32,
2893    _pad0: u32,
2894    pub st_rdev: u64,
2895    pub st_size: i64,
2896    pub st_blksize: i64,
2897    pub st_blocks: i64,
2898    pub st_atim: timespec,
2899    pub st_mtim: timespec,
2900    pub st_ctim: timespec,
2901    _unused: [i64; 3],
2902}
2903
2904#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
2905#[repr(C)]
2906pub struct Stat {
2907    pub st_dev: u64,
2908    pub st_ino: u64,
2909    pub st_mode: u32,
2910    pub st_nlink: u32,
2911    pub st_uid: u32,
2912    pub st_gid: u32,
2913    pub st_rdev: u64,
2914    __pad1: u64,
2915    pub st_size: i64,
2916    pub st_blksize: i32,
2917    __pad2: i32,
2918    pub st_blocks: i64,
2919    pub st_atim: timespec,
2920    pub st_mtim: timespec,
2921    pub st_ctim: timespec,
2922    __unused4: u32,
2923    __unused5: u32,
2924}
2925
2926pub const S_IFMT: u32 = 0o170000;
2927pub const S_IFDIR: u32 = 0o040000;
2928pub const S_IFCHR: u32 = 0o020000;
2929pub const S_IFBLK: u32 = 0o060000;
2930pub const S_IFREG: u32 = 0o100000;
2931pub const S_IFLNK: u32 = 0o120000;
2932pub const S_IFIFO: u32 = 0o010000;
2933pub const S_IFSOCK: u32 = 0o140000;
2934
2935pub const AT_FDCWD: i32 = -100;
2936
2937#[no_mangle]
2938pub unsafe extern "C" fn stat(path: *const c_char, buf: *mut Stat) -> c_int {
2939    let r = sys_newfstatat(AT_FDCWD, path, buf as *mut u8, 0);
2940    if r < 0 { ERRNO = (-r) as c_int; return -1; }
2941    if *path == b'/' as c_char && strcmp(path as *const u8, b"/dev/null\0".as_ptr()) == 0 {
2942        (*buf).st_mode = ((*buf).st_mode & !0o170000) | 0o020000;
2943    }
2944    0
2945}
2946
2947#[no_mangle]
2948pub unsafe extern "C" fn fstat(fd: c_int, buf: *mut Stat) -> c_int {
2949    let r = sys_fstat(fd, buf as *mut u8);
2950    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2951}
2952
2953// ============================================================
2954// sys/resource.h: getrlimit / setrlimit
2955// ============================================================
2956
2957#[repr(C)]
2958pub struct Rlimit {
2959    pub rlim_cur: u64,
2960    pub rlim_max: u64,
2961}
2962
2963pub const RLIMIT_NOFILE: c_int = 7;
2964pub const RLIMIT_STACK: c_int = 3;
2965pub const RLIMIT_DATA: c_int = 2;
2966pub const RLIMIT_AS: c_int = 9;
2967pub const RLIMIT_CPU: c_int = 0;
2968pub const RLIMIT_FSIZE: c_int = 1;
2969pub const RLIMIT_CORE: c_int = 4;
2970pub const RLIMIT_RSS: c_int = 5;
2971pub const RLIMIT_NPROC: c_int = 6;
2972pub const RLIMIT_MEMLOCK: c_int = 8;
2973pub const RLIMIT_LOCKS: c_int = 10;
2974pub const RLIMIT_SIGPENDING: c_int = 11;
2975pub const RLIMIT_MSGQUEUE: c_int = 12;
2976pub const RLIMIT_NICE: c_int = 13;
2977pub const RLIMIT_RTPRIO: c_int = 14;
2978pub const RLIMIT_RTTIME: c_int = 15;
2979pub const RLIM_INFINITY: u64 = !0u64;
2980
2981#[no_mangle]
2982pub unsafe extern "C" fn getrlimit(resource: c_int, rlim: *mut Rlimit) -> c_int {
2983    let r = sys_getrlimit(resource, rlim as *mut u8);
2984    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2985}
2986
2987#[no_mangle]
2988pub unsafe extern "C" fn setrlimit(resource: c_int, rlim: *const Rlimit) -> c_int {
2989    let r = sys_setrlimit(resource, rlim as *const u8);
2990    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
2991}
2992
2993// ============================================================
2994// utimensat / futimens
2995// ============================================================
2996
2997#[no_mangle]
2998pub unsafe extern "C" fn utimensat(dirfd: c_int, path: *const c_char, times: *const timespec, flags: c_int) -> c_int {
2999    let r = sys_utimensat(dirfd, path, times as *const u8, flags);
3000    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
3001}
3002
3003#[no_mangle]
3004pub unsafe extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int {
3005    let r = sys_utimensat(fd, core::ptr::null(), times as *const u8, 0);
3006    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
3007}
3008
3009// ============================================================
3010// sys/socket.h
3011// ============================================================
3012
3013pub const AF_UNIX: c_int = 1;
3014pub const AF_INET: c_int = 2;
3015pub const AF_INET6: c_int = 10;
3016
3017pub const SOCK_STREAM: c_int = 1;
3018pub const SOCK_DGRAM: c_int = 2;
3019
3020pub const SHUT_RD: c_int = 0;
3021pub const SHUT_WR: c_int = 1;
3022pub const SHUT_RDWR: c_int = 2;
3023
3024pub const SOL_SOCKET: c_int = 1;
3025pub const SO_REUSEADDR: c_int = 2;
3026
3027#[repr(C)]
3028pub struct sockaddr {
3029    pub sa_family: u16,
3030    pub sa_data: [u8; 14],
3031}
3032
3033#[inline]
3034unsafe fn sys_socket(domain: c_int, ty: c_int, protocol: c_int) -> i64 {
3035    <Arch as Syscalls>::syscall3(SYS_SOCKET, domain as i64, ty as i64, protocol as i64)
3036}
3037
3038#[inline]
3039unsafe fn sys_socketpair(domain: c_int, ty: c_int, protocol: c_int, sv: *mut c_int) -> i64 {
3040    <Arch as Syscalls>::syscall4(SYS_SOCKETPAIR, domain as i64, ty as i64, protocol as i64, sv as i64)
3041}
3042
3043#[inline]
3044unsafe fn sys_bind(fd: c_int, addr: *const sockaddr, len: c_uint) -> i64 {
3045    <Arch as Syscalls>::syscall3(SYS_BIND, fd as i64, addr as i64, len as i64)
3046}
3047
3048#[inline]
3049unsafe fn sys_listen(fd: c_int, backlog: c_int) -> i64 {
3050    <Arch as Syscalls>::syscall2(SYS_LISTEN, fd as i64, backlog as i64)
3051}
3052
3053#[inline]
3054unsafe fn sys_accept(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> i64 {
3055    <Arch as Syscalls>::syscall3(SYS_ACCEPT, fd as i64, addr as i64, len as i64)
3056}
3057
3058#[inline]
3059unsafe fn sys_connect(fd: c_int, addr: *const sockaddr, len: c_uint) -> i64 {
3060    <Arch as Syscalls>::syscall3(SYS_CONNECT, fd as i64, addr as i64, len as i64)
3061}
3062
3063#[inline]
3064unsafe fn sys_sendto(fd: c_int,
3065    buf: *const c_void,
3066    len: usize,
3067    flags: c_int,
3068    addr: *const sockaddr,
3069    addrlen: c_uint,) -> i64 {
3070    <Arch as Syscalls>::syscall6(SYS_SENDTO, fd as i64, buf as i64, len as i64, flags as i64, addr as i64, addrlen as i64)
3071}
3072
3073#[inline]
3074unsafe fn sys_recvfrom(fd: c_int,
3075    buf: *mut c_void,
3076    len: usize,
3077    flags: c_int,
3078    addr: *mut sockaddr,
3079    addrlen: *mut c_uint,) -> i64 {
3080    <Arch as Syscalls>::syscall6(SYS_RECVFROM, fd as i64, buf as i64, len as i64, flags as i64, addr as i64, addrlen as i64)
3081}
3082
3083#[inline]
3084unsafe fn sys_shutdown(fd: c_int, how: c_int) -> i64 {
3085    <Arch as Syscalls>::syscall2(SYS_SHUTDOWN, fd as i64, how as i64)
3086}
3087
3088#[inline]
3089unsafe fn sys_setsockopt(fd: c_int,
3090    level: c_int,
3091    optname: c_int,
3092    optval: *const c_void,
3093    optlen: c_uint,) -> i64 {
3094    <Arch as Syscalls>::syscall5(SYS_SETSOCKOPT, fd as i64, level as i64, optname as i64, optval as i64, optlen as i64)
3095}
3096
3097#[inline]
3098unsafe fn sys_getsockname(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> i64 {
3099    <Arch as Syscalls>::syscall3(SYS_GETSOCKNAME, fd as i64, addr as i64, len as i64)
3100}
3101
3102#[no_mangle]
3103pub unsafe extern "C" fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int {
3104    let r = sys_socket(domain, ty, protocol);
3105    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3106    r as c_int
3107}
3108
3109#[no_mangle]
3110pub unsafe extern "C" fn socketpair(domain: c_int, ty: c_int, protocol: c_int, sv: *mut c_int) -> c_int {
3111    let r = sys_socketpair(domain, ty, protocol, sv);
3112    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3113    0
3114}
3115
3116#[no_mangle]
3117pub unsafe extern "C" fn bind(fd: c_int, addr: *const sockaddr, len: c_uint) -> c_int {
3118    let r = sys_bind(fd, addr, len);
3119    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3120    0
3121}
3122
3123#[no_mangle]
3124pub unsafe extern "C" fn listen(fd: c_int, backlog: c_int) -> c_int {
3125    let r = sys_listen(fd, backlog);
3126    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3127    0
3128}
3129
3130#[no_mangle]
3131pub unsafe extern "C" fn accept(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> c_int {
3132    let r = sys_accept(fd, addr, len);
3133    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3134    r as c_int
3135}
3136
3137#[no_mangle]
3138pub unsafe extern "C" fn connect(fd: c_int, addr: *const sockaddr, len: c_uint) -> c_int {
3139    let r = sys_connect(fd, addr, len);
3140    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3141    0
3142}
3143
3144#[no_mangle]
3145pub unsafe extern "C" fn send(fd: c_int, buf: *const c_void, len: usize, flags: c_int) -> isize {
3146    let r = sys_sendto(fd, buf, len, flags, core::ptr::null(), 0);
3147    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3148    r as isize
3149}
3150
3151#[no_mangle]
3152pub unsafe extern "C" fn recv(fd: c_int, buf: *mut c_void, len: usize, flags: c_int) -> isize {
3153    let r = sys_recvfrom(fd, buf, len, flags, core::ptr::null_mut(), core::ptr::null_mut());
3154    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3155    r as isize
3156}
3157
3158#[no_mangle]
3159pub unsafe extern "C" fn sendto(
3160    fd: c_int,
3161    buf: *const c_void,
3162    len: usize,
3163    flags: c_int,
3164    addr: *const sockaddr,
3165    addrlen: c_uint,
3166) -> isize {
3167    let r = sys_sendto(fd, buf, len, flags, addr, addrlen);
3168    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3169    r as isize
3170}
3171
3172#[no_mangle]
3173pub unsafe extern "C" fn recvfrom(
3174    fd: c_int,
3175    buf: *mut c_void,
3176    len: usize,
3177    flags: c_int,
3178    addr: *mut sockaddr,
3179    addrlen: *mut c_uint,
3180) -> isize {
3181    let r = sys_recvfrom(fd, buf, len, flags, addr, addrlen);
3182    if r < 0 { ERRNO = (-r) as c_int; return -1; }
3183    r as isize
3184}
3185
3186#[no_mangle]
3187pub unsafe extern "C" fn shutdown(fd: c_int, how: c_int) -> c_int {
3188    sys_shutdown(fd, how) as c_int
3189}
3190
3191#[no_mangle]
3192pub unsafe extern "C" fn setsockopt(
3193    fd: c_int,
3194    level: c_int,
3195    optname: c_int,
3196    optval: *const c_void,
3197    optlen: c_uint,
3198) -> c_int {
3199    sys_setsockopt(fd, level, optname, optval, optlen) as c_int
3200}
3201
3202#[no_mangle]
3203pub unsafe extern "C" fn getsockname(fd: c_int, addr: *mut sockaddr, len: *mut c_uint) -> c_int {
3204    sys_getsockname(fd, addr, len) as c_int
3205}
3206
3207#[no_mangle]
3208pub extern "C" fn htonl(hostlong: c_uint) -> c_uint {
3209    hostlong.to_be()
3210}
3211
3212#[no_mangle]
3213pub extern "C" fn ntohl(netlong: c_uint) -> c_uint {
3214    c_uint::from_be(netlong)
3215}
3216
3217#[no_mangle]
3218pub extern "C" fn htons(hostshort: u16) -> u16 {
3219    hostshort.to_be()
3220}
3221
3222#[no_mangle]
3223pub extern "C" fn ntohs(netshort: u16) -> u16 {
3224    u16::from_be(netshort)
3225}
3226
3227pub type PthreadT = c_ulong;
3228
3229// pthread_attr_t: musl x86_64 layout (56 bytes = int[14])
3230#[repr(C)]
3231pub struct pthread_attr_t {
3232    __i: [c_int; 14],
3233}
3234
3235// pthread_mutex_t: musl x86_64 layout (40 bytes = int[10])
3236// _m_type=__i[0], _m_lock=__i[1], _m_waiters=__i[2], _m_count=__i[5]
3237#[repr(C)]
3238pub struct pthread_mutex_t {
3239    __i: [c_int; 10],
3240}
3241
3242#[repr(C)]
3243pub struct pthread_mutexattr_t {
3244    __attr: c_uint,
3245}
3246
3247// pthread_cond_t: musl x86_64 layout (48 bytes = int[12])
3248// _c_seq=__i[2], _c_waiters=__i[3], _c_clock=__i[4]
3249#[repr(C)]
3250pub struct pthread_cond_t {
3251    __i: [c_int; 12],
3252}
3253
3254#[repr(C)]
3255pub struct pthread_condattr_t {
3256    __attr: c_uint,
3257}
3258
3259// pthread_rwlock_t: musl x86_64 layout (56 bytes = int[14])
3260// _rw_lock=__i[0], _rw_waiters=__i[1], _rw_shared=__i[2]
3261#[repr(C)]
3262pub struct pthread_rwlock_t {
3263    __i: [c_int; 14],
3264}
3265
3266#[repr(C)]
3267pub struct pthread_rwlockattr_t {
3268    __attr: [c_uint; 2],
3269}
3270
3271// pthread_barrier_t: musl x86_64 layout (32 bytes = int[8])
3272#[repr(C)]
3273pub struct pthread_barrier_t {
3274    __i: [c_int; 8],
3275}
3276
3277#[repr(C)]
3278pub struct pthread_barrierattr_t {
3279    __attr: c_uint,
3280}
3281
3282pub type pthread_spinlock_t = c_int;
3283pub type pthread_once_t = c_int;
3284pub type pthread_key_t = c_uint;
3285
3286// sem_t: musl x86_64 layout (32 bytes = int[8])
3287#[repr(C)]
3288pub struct sem_t {
3289    __val: [c_int; 8],
3290}
3291
3292#[repr(C)]
3293pub struct sched_param {
3294    pub sched_priority: c_int,
3295}
3296
3297const CLONE_VM: c_ulong = 0x00000100;
3298const CLONE_FS: c_ulong = 0x00000200;
3299const CLONE_FILES: c_ulong = 0x00000400;
3300const CLONE_SIGHAND: c_ulong = 0x00000800;
3301const CLONE_THREAD: c_ulong = 0x00010000;
3302const CLONE_SYSVSEM: c_ulong = 0x00040000;
3303const CLONE_SETTLS: c_ulong = 0x00080000;
3304const CLONE_PARENT_SETTID: c_ulong = 0x00100000;
3305const CLONE_CHILD_CLEARTID: c_ulong = 0x00200000;
3306
3307const FUTEX_WAIT: c_int = 0;
3308const FUTEX_WAKE: c_int = 1;
3309const FUTEX_LOCK_PI: c_int = 6;
3310const FUTEX_UNLOCK_PI: c_int = 7;
3311const FUTEX_TRYLOCK_PI: c_int = 8;
3312
3313// ponytail: SIGCANCEL (32) is musl's internal cancel signal
3314const SIGCANCEL: c_int = 32;
3315
3316const PTHREAD_MUTEX_NORMAL: c_int = 0;
3317const PTHREAD_MUTEX_DEFAULT: c_int = 0;
3318const PTHREAD_MUTEX_RECURSIVE: c_int = 1;
3319const PTHREAD_MUTEX_ERRORCHECK: c_int = 2;
3320
3321const PTHREAD_CREATE_JOINABLE: c_int = 0;
3322const PTHREAD_CREATE_DETACHED: c_int = 1;
3323
3324const PTHREAD_CANCEL_ENABLE: c_int = 0;
3325const PTHREAD_CANCEL_DISABLE: c_int = 1;
3326const PTHREAD_CANCEL_DEFERRED: c_int = 0;
3327const PTHREAD_CANCEL_ASYNCHRONOUS: c_int = 1;
3328
3329const PTHREAD_SCOPE_SYSTEM: c_int = 0;
3330const PTHREAD_PROCESS_PRIVATE: c_int = 0;
3331const PTHREAD_PROCESS_SHARED: c_int = 1;
3332const PTHREAD_INHERIT_SCHED: c_int = 0;
3333const PTHREAD_EXPLICIT_SCHED: c_int = 1;
3334
3335const PTHREAD_BARRIER_SERIAL_THREAD: c_int = -1;
3336
3337const PTHREAD_KEYS_MAX: usize = 128;
3338const PTHREAD_DESTRUCTOR_ITERATIONS: usize = 4;
3339const SEM_VALUE_MAX: c_int = 0x7fffffff;
3340
3341const DT_EXITED: c_int = 0;
3342const DT_EXITING: c_int = 1;
3343const DT_JOINABLE: c_int = 2;
3344const DT_DETACHED: c_int = 3;
3345
3346// ponytail: musl __ptcb cleanup handler node
3347#[repr(C)]
3348#[derive(Copy, Clone)]
3349pub struct __ptcb {
3350    __f: Option<unsafe extern "C" fn(*mut c_void)>,
3351    __x: *mut c_void,
3352    __next: *mut __ptcb,
3353}
3354
3355// ponytail: robust_list_head for kernel robust mutex support
3356#[repr(C)]
3357#[derive(Copy, Clone)]
3358struct robust_list {
3359    next: *mut robust_list,
3360}
3361
3362#[repr(C)]
3363#[derive(Copy, Clone)]
3364struct robust_list_head {
3365    list: robust_list,
3366    futex_offset: c_long,
3367    pending: *mut robust_list,
3368}
3369
3370// ponytail: adapted from musl x86_64 clone.s
3371#[cfg(all(target_arch = "x86_64", not(test)))]
3372core::arch::global_asm!(
3373    ".global __rc_clone",
3374    ".type __rc_clone, @function",
3375    "__rc_clone:",
3376    "mov rax, rdi",
3377    "mov rdi, rdx",
3378    "mov rdx, r8",
3379    "mov r10, [rsp + 8]",
3380    "mov r8, r9",
3381    "mov r9, rax",
3382    "and rsi, -16",
3383    "sub rsi, 8",
3384    "mov [rsi], rcx",
3385    "mov eax, 56",
3386    "syscall",
3387    "test rax, rax",
3388    "jnz 1f",
3389    "pop rdi",
3390    "call r9",
3391    "hlt",
3392    "1:",
3393    "ret",
3394);
3395
3396// ponytail: adapted from musl aarch64 clone.s
3397#[no_mangle]
3398#[unsafe(naked)]
3399#[cfg(target_arch = "aarch64")]
3400pub unsafe extern "C" fn __rc_clone(
3401    fn_: usize,
3402    stack: *mut u8,
3403    flags: c_ulong,
3404    arg: *mut c_void,
3405    ptid: *mut c_int,
3406    tls: c_ulong,
3407    ctid: *mut c_int,
3408) -> i64 {
3409    core::arch::naked_asm!(
3410        "and x1, x1, #-16",
3411        "stp x0, x3, [x1, #-16]!",
3412        "uxtw x0, w2",
3413        "mov x2, x4",
3414        "mov x3, x5",
3415        "mov x4, x6",
3416        "mov x8, #220",
3417        "svc #0",
3418        "cbz x0, 1f",
3419        "ret",
3420        "1:",
3421        "mov x29, #0",
3422        "ldp x1, x0, [sp], #16",
3423        "blr x1",
3424        "mov x8, #93",
3425        "svc #0",
3426    );
3427}
3428
3429#[no_mangle]
3430#[unsafe(naked)]
3431#[cfg(target_arch = "riscv64")]
3432pub unsafe extern "C" fn __rc_clone(
3433    fn_: usize,
3434    stack: *mut u8,
3435    flags: c_ulong,
3436    arg: *mut c_void,
3437    ptid: *mut c_int,
3438    tls: c_ulong,
3439    ctid: *mut c_int,
3440) -> i64 {
3441    core::arch::naked_asm!(
3442        "andi a1, a1, -16",
3443        "addi a1, a1, -16",
3444        "sd a0, 0(a1)",
3445        "sd a3, 8(a1)",
3446        "mv a0, a2",
3447        "mv a2, a4",
3448        "mv a3, a5",
3449        "mv a4, a6",
3450        "li a7, 220",
3451        "ecall",
3452        "beqz a0, 1f",
3453        "ret",
3454        "1:",
3455        "ld a1, 0(sp)",
3456        "ld a0, 8(sp)",
3457        "jalr a1",
3458        "li a7, 93",
3459        "ecall",
3460    );
3461}
3462
3463#[cfg(all(target_arch = "x86_64", test))]
3464#[inline(never)]
3465unsafe fn __rc_clone(
3466    _fn_: usize,
3467    _stack: *mut u8,
3468    _flags: c_ulong,
3469    _arg: *mut c_void,
3470    _ptid: *mut c_int,
3471    _tls: c_ulong,
3472    _ctid: *mut c_int,
3473) -> i64 {
3474    -1
3475}
3476
3477#[cfg(all(target_arch = "x86_64", not(test)))]
3478extern "C" {
3479    fn __rc_clone(
3480        fn_: usize,
3481        stack: *mut u8,
3482        flags: c_ulong,
3483        arg: *mut c_void,
3484        ptid: *mut c_int,
3485        tls: c_ulong,
3486        ctid: *mut c_int,
3487    ) -> i64;
3488}
3489
3490#[inline(never)]
3491#[linkage = "weak"]
3492#[no_mangle]
3493pub extern "C" fn __rc_create_thread_tls() -> *mut u8 {
3494    core::ptr::null_mut()
3495}
3496
3497#[inline(never)]
3498#[linkage = "weak"]
3499#[no_mangle]
3500pub extern "C" fn __rc_tls_block_size() -> usize {
3501    0
3502}
3503
3504#[inline(never)]
3505#[linkage = "weak"]
3506#[no_mangle]
3507pub extern "C" fn __rc_tls_base_offset() -> usize {
3508    0
3509}
3510
3511#[inline]
3512unsafe fn sys_gettid() -> i64 {
3513    <Arch as Syscalls>::syscall0(SYS_GETTID)
3514}
3515
3516#[inline]
3517unsafe fn sys_futex(uaddr: *mut c_int,
3518    futex_op: c_int,
3519    val: c_int,
3520    timeout: *mut c_void,
3521    uaddr2: *mut c_int,
3522    val3: c_int,) -> i64 {
3523    <Arch as Syscalls>::syscall6(SYS_FUTEX, uaddr as i64, futex_op as i64, val as i64, timeout as i64, uaddr2 as i64, val3 as i64)
3524}
3525
3526const MAX_THREADS: usize = 64;
3527const STACK_SIZE: usize = 1024 * 1024;
3528
3529#[repr(C)]
3530#[derive(Copy, Clone)]
3531struct Thread {
3532    tid: c_int,
3533    detach_state: c_int,
3534    result: *mut c_void,
3535    cancel: c_int,
3536    cancel_state: c_int,
3537    cancel_type: c_int,
3538    user_fn: usize,
3539    user_arg: *mut c_void,
3540    stack: *mut u8,
3541    stack_size: usize,
3542    fs_base: *mut u8,
3543    tsd: [*mut c_void; PTHREAD_KEYS_MAX],
3544    cancelbuf: *mut __ptcb,
3545    robust_list: robust_list_head,
3546}
3547
3548static mut THREADS: [Thread; MAX_THREADS] = [Thread {
3549    tid: -1,
3550    detach_state: DT_JOINABLE,
3551    result: core::ptr::null_mut(),
3552    cancel: 0,
3553    cancel_state: PTHREAD_CANCEL_ENABLE,
3554    cancel_type: PTHREAD_CANCEL_DEFERRED,
3555    user_fn: 0,
3556    user_arg: core::ptr::null_mut(),
3557    stack: core::ptr::null_mut(),
3558    stack_size: 0,
3559    fs_base: core::ptr::null_mut(),
3560    tsd: [core::ptr::null_mut(); PTHREAD_KEYS_MAX],
3561    cancelbuf: core::ptr::null_mut(),
3562    robust_list: robust_list_head {
3563        list: robust_list { next: core::ptr::null_mut() },
3564        futex_offset: 0,
3565        pending: core::ptr::null_mut(),
3566    },
3567}; MAX_THREADS];
3568const ALL_SLOT_BITS: usize = if MAX_THREADS >= usize::BITS as usize {
3569    usize::MAX
3570} else {
3571    (1usize << MAX_THREADS) - 1
3572};
3573static SLOT_USED: AtomicUsize = AtomicUsize::new(0);
3574static mut KEY_DTORS: [Option<unsafe extern "C" fn(*mut c_void)>; PTHREAD_KEYS_MAX] = [None; PTHREAD_KEYS_MAX];
3575static NEXT_KEY: AtomicUsize = AtomicUsize::new(0);
3576
3577// ponytail: futex helpers
3578unsafe fn futex_wait(addr: *mut c_int, expected: c_int) -> c_int {
3579    let r = sys_futex(addr, FUTEX_WAIT, expected, null_mut(), null_mut(), 0);
3580    if r < 0 { let e = (-r) as c_int; if e == EAGAIN { 0 } else { e } } else { 0 }
3581}
3582
3583unsafe fn futex_wake(addr: *mut c_int, count: c_int) {
3584    let c = if count < 0 { c_int::MAX } else { count };
3585    sys_futex(addr, FUTEX_WAKE, c, null_mut(), null_mut(), 0);
3586}
3587
3588unsafe fn futex_lock_pi(addr: *mut c_int, abs_timeout: *const timespec) -> c_int {
3589    let timeout_ptr = if abs_timeout.is_null() { null_mut() } else { abs_timeout as *mut c_void };
3590    let r = sys_futex(addr, FUTEX_LOCK_PI, 0, timeout_ptr, null_mut(), 0);
3591    if r < 0 { (-r) as c_int } else { 0 }
3592}
3593
3594unsafe fn futex_unlock_pi(addr: *mut c_int) -> c_int {
3595    let r = sys_futex(addr, FUTEX_UNLOCK_PI, 0, null_mut(), null_mut(), 0);
3596    if r < 0 { (-r) as c_int } else { 0 }
3597}
3598
3599#[inline]
3600unsafe fn sys_set_robust_list(head: *mut robust_list_head, len: usize) -> i64 {
3601    <Arch as Syscalls>::syscall2(SYS_SET_ROBUST_LIST, head as i64, len as i64)
3602}
3603
3604unsafe fn futex_timedwait(addr: *mut c_int, expected: c_int, abs_timeout: *const timespec) -> c_int {
3605    if abs_timeout.is_null() { return futex_wait(addr, expected); }
3606    let mut now: timespec = core::mem::zeroed();
3607    if sys_clock_gettime(CLOCK_REALTIME, &mut now) < 0 { return EINVAL; }
3608    let mut rel: timespec = core::mem::zeroed();
3609    rel.tv_sec = (*abs_timeout).tv_sec - now.tv_sec;
3610    rel.tv_nsec = (*abs_timeout).tv_nsec - now.tv_nsec;
3611    if rel.tv_nsec < 0 { rel.tv_sec -= 1; rel.tv_nsec += 1_000_000_000; }
3612    if rel.tv_sec < 0 { return ETIMEDOUT; }
3613    let r = sys_futex(addr, FUTEX_WAIT, expected, &mut rel as *mut timespec as *mut c_void, null_mut(), 0);
3614    if r < 0 { let e = (-r) as c_int; if e == EAGAIN { 0 } else { e } } else { 0 }
3615}
3616
3617// ponytail: atomic helpers wrapping AtomicI32
3618unsafe fn a_cas(addr: *mut c_int, expected: c_int, desired: c_int) -> c_int {
3619    let a = &*(addr as *const AtomicI32);
3620    match a.compare_exchange(expected, desired, Ordering::AcqRel, Ordering::Acquire) {
3621        Ok(v) | Err(v) => v,
3622    }
3623}
3624
3625unsafe fn a_store(addr: *mut c_int, val: c_int) {
3626    (*(addr as *const AtomicI32)).store(val, Ordering::Release);
3627}
3628
3629unsafe fn a_load(addr: *const c_int) -> c_int {
3630    (*(addr as *const AtomicI32)).load(Ordering::Acquire)
3631}
3632
3633unsafe fn a_swap(addr: *mut c_int, val: c_int) -> c_int {
3634    (*(addr as *const AtomicI32)).swap(val, Ordering::AcqRel)
3635}
3636
3637unsafe fn a_fetch_add(addr: *mut c_int, val: c_int) -> c_int {
3638    (*(addr as *const AtomicI32)).fetch_add(val, Ordering::AcqRel)
3639}
3640
3641unsafe fn a_fetch_sub(addr: *mut c_int, val: c_int) -> c_int {
3642    (*(addr as *const AtomicI32)).fetch_sub(val, Ordering::AcqRel)
3643}
3644
3645unsafe fn spinlock_lock(lock: *mut c_int, waiters: *mut c_int) {
3646    while a_swap(lock, 1) != 0 {
3647        let mut spins = 100;
3648        while spins > 0 && a_load(lock) != 0 { core::hint::spin_loop(); spins -= 1; }
3649        if a_load(lock) == 0 { continue; }
3650        a_fetch_add(waiters, 1);
3651        futex_wait(lock, 1);
3652        a_fetch_sub(waiters, 1);
3653    }
3654}
3655
3656unsafe fn spinlock_unlock(lock: *mut c_int, waiters: *mut c_int) {
3657    a_store(lock, 0);
3658    if a_load(waiters) > 0 { futex_wake(lock, 1); }
3659}
3660
3661unsafe fn slot_index(slot: *const Thread) -> usize {
3662    let base = core::ptr::addr_of!(THREADS[0]) as usize;
3663    (slot as usize - base) / core::mem::size_of::<Thread>()
3664}
3665
3666unsafe fn release_thread_slot(slot: *const Thread) {
3667    let idx = slot_index(slot);
3668    if idx < MAX_THREADS {
3669        SLOT_USED.fetch_and(!(1usize << idx), Ordering::AcqRel);
3670    }
3671}
3672
3673unsafe fn alloc_thread_slot() -> Option<&'static mut Thread> {
3674    let mut used = SLOT_USED.load(Ordering::Acquire);
3675    loop {
3676        if used == ALL_SLOT_BITS {
3677            return None;
3678        }
3679        let idx = (!used).trailing_zeros() as usize;
3680        if idx >= MAX_THREADS {
3681            return None;
3682        }
3683        match SLOT_USED.compare_exchange_weak(
3684            used,
3685            used | (1usize << idx),
3686            Ordering::AcqRel,
3687            Ordering::Acquire,
3688        ) {
3689            Ok(_) => return Some(&mut THREADS[idx]),
3690            Err(v) => used = v,
3691        }
3692    }
3693}
3694
3695unsafe fn run_key_dtors(slot: &mut Thread) {
3696    for _ in 0..PTHREAD_DESTRUCTOR_ITERATIONS {
3697        let mut any = false;
3698        for i in 0..PTHREAD_KEYS_MAX {
3699            let val = slot.tsd[i];
3700            if !val.is_null() {
3701                if let Some(dtor) = KEY_DTORS[i] {
3702                    slot.tsd[i] = core::ptr::null_mut();
3703                    any = true;
3704                    dtor(val);
3705                }
3706            }
3707        }
3708        if !any { break; }
3709    }
3710}
3711
3712unsafe extern "C" fn thread_entry(slot: *mut c_void) -> *mut c_void {
3713    let slot = &mut *(slot as *mut Thread);
3714    // A reused slot may still carry the previous thread's robust-list state;
3715    // register a fresh list for this thread.
3716    slot.robust_list.list.next = core::ptr::null_mut();
3717    slot.robust_list.futex_offset = 0;
3718    slot.robust_list.pending = core::ptr::null_mut();
3719    ensure_robust_list(slot);
3720    let mut set: SigSetT = 0;
3721    sigemptyset(&mut set);
3722    sigaddset(&mut set, SIGCANCEL);
3723    pthread_sigmask(SIG_UNBLOCK, &set, core::ptr::null_mut());
3724    let user_fn: unsafe extern "C" fn(*mut c_void) -> *mut c_void =
3725        core::mem::transmute::<usize, _>(slot.user_fn);
3726    let ret = user_fn(slot.user_arg);
3727    run_key_dtors(slot);
3728    slot.result = ret;
3729    a_store(&raw mut slot.detach_state, DT_EXITED);
3730    futex_wake(&raw mut slot.detach_state, 1);
3731    sys_exit_thread(0)
3732}
3733
3734unsafe fn find_thread() -> Option<&'static mut Thread> {
3735    let me = sys_gettid() as c_int;
3736    let base = core::ptr::addr_of_mut!(THREADS[0]);
3737    for i in 0..MAX_THREADS {
3738        let slot = base.add(i);
3739        if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3740            return Some(&mut *slot);
3741        }
3742    }
3743    // Auto-register the current thread (usually the main thread) on first use.
3744    pthread_self();
3745    for i in 0..MAX_THREADS {
3746        let slot = base.add(i);
3747        if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3748            return Some(&mut *slot);
3749        }
3750    }
3751    None
3752}
3753
3754#[no_mangle]
3755pub unsafe extern "C" fn pthread_self() -> PthreadT {
3756    let me = sys_gettid() as c_int;
3757    let base = core::ptr::addr_of_mut!(THREADS[0]);
3758    for i in 0..MAX_THREADS {
3759        let slot = base.add(i);
3760        if core::ptr::read_volatile(&raw const (*slot).tid) == me {
3761            return slot as PthreadT;
3762        }
3763    }
3764    // Register the main thread lazily in a free slot.
3765    if let Some(slot) = alloc_thread_slot() {
3766        let slot = slot as *mut Thread;
3767        (*slot).tid = me;
3768        (*slot).detach_state = DT_JOINABLE;
3769        return slot as PthreadT;
3770    }
3771    0
3772}
3773
3774#[no_mangle]
3775pub unsafe extern "C" fn pthread_equal(t1: PthreadT, t2: PthreadT) -> c_int {
3776    (t1 == t2) as c_int
3777}
3778
3779#[no_mangle]
3780pub unsafe extern "C" fn pthread_create(
3781    thread: *mut PthreadT,
3782    attr: *const pthread_attr_t,
3783    start_routine: usize,
3784    arg: *mut c_void,
3785) -> c_int {
3786    if start_routine == 0 || thread.is_null() { return EINVAL; }
3787    let Some(slot_ref) = alloc_thread_slot() else { return EAGAIN; };
3788    let slot = slot_ref as *mut Thread;
3789    let stack_size = if !attr.is_null() {
3790        let s = *((*attr).__i.as_ptr() as *const usize);
3791        if s > 0 { s } else { STACK_SIZE }
3792    } else { STACK_SIZE };
3793    let stack = sys_mmap(null_mut(), stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
3794    if stack == MMAP_FAILED { release_thread_slot(slot); return EAGAIN; }
3795    let fs_base = __rc_create_thread_tls();
3796    if fs_base.is_null() { sys_munmap(stack, stack_size); release_thread_slot(slot); return EAGAIN; }
3797    (*slot).detach_state = DT_JOINABLE;
3798    (*slot).result = core::ptr::null_mut();
3799    (*slot).cancel = 0;
3800    (*slot).cancel_state = PTHREAD_CANCEL_ENABLE;
3801    (*slot).cancel_type = PTHREAD_CANCEL_DEFERRED;
3802    core::ptr::write_bytes((*slot).tsd.as_mut_ptr(), 0, PTHREAD_KEYS_MAX);
3803    (*slot).tid = 1;
3804    (*slot).user_fn = start_routine;
3805    (*slot).user_arg = arg;
3806    (*slot).stack = stack;
3807    (*slot).stack_size = stack_size;
3808    (*slot).fs_base = fs_base;
3809    let stack_top = stack.add(stack_size);
3810    let tid_ptr = &raw mut (*slot).tid;
3811    let flags = CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD
3812        | CLONE_SYSVSEM | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SETTLS;
3813    let tid = __rc_clone(thread_entry as *const () as usize, stack_top, flags, slot as *mut c_void, tid_ptr, fs_base as c_ulong, tid_ptr);
3814    if tid < 0 {
3815        (*slot).tid = -1;
3816        sys_munmap(stack, stack_size);
3817        sys_munmap(fs_base.sub(__rc_tls_base_offset()), __rc_tls_block_size());
3818        release_thread_slot(slot);
3819        return EAGAIN;
3820    }
3821    if !attr.is_null() && (*attr).__i[6] == PTHREAD_CREATE_DETACHED {
3822        (*slot).detach_state = DT_DETACHED;
3823    }
3824    *thread = slot as PthreadT;
3825    0
3826}
3827
3828#[no_mangle]
3829pub unsafe extern "C" fn pthread_join(thread: PthreadT, retval: *mut *mut c_void) -> c_int {
3830    let slot = thread as *mut Thread;
3831    if slot.is_null() { return EINVAL; }
3832    if (*slot).detach_state == DT_DETACHED { return EINVAL; }
3833    let tid_ptr = &raw mut (*slot).tid;
3834    loop {
3835        pthread_testcancel();
3836        let tid = core::ptr::read_volatile(tid_ptr);
3837        if tid == 0 { break; }
3838        if tid < 0 { return EINVAL; }
3839        sys_futex(tid_ptr, FUTEX_WAIT, tid, null_mut(), null_mut(), 0);
3840        pthread_testcancel();
3841    }
3842    if !retval.is_null() { *retval = (*slot).result; }
3843    let stack = (*slot).stack;
3844    let stack_size = (*slot).stack_size;
3845    let fs_base = (*slot).fs_base;
3846    (*slot).tid = -1;
3847    (*slot).detach_state = DT_JOINABLE;
3848    (*slot).result = core::ptr::null_mut();
3849    (*slot).stack = core::ptr::null_mut();
3850    (*slot).stack_size = 0;
3851    (*slot).fs_base = core::ptr::null_mut();
3852    if !stack.is_null() && stack_size > 0 { sys_munmap(stack, stack_size); }
3853    if !fs_base.is_null() { let bs = __rc_tls_block_size(); let bo = __rc_tls_base_offset(); if bs > 0 { sys_munmap(fs_base.sub(bo), bs); } }
3854    release_thread_slot(slot);
3855    0
3856}
3857
3858#[no_mangle]
3859pub unsafe extern "C" fn pthread_detach(thread: PthreadT) -> c_int {
3860    let slot = thread as *mut Thread;
3861    if slot.is_null() { return EINVAL; }
3862    let old = a_cas(&raw mut (*slot).detach_state, DT_JOINABLE, DT_DETACHED);
3863    if old == DT_EXITED {
3864        let stack = (*slot).stack;
3865        let stack_size = (*slot).stack_size;
3866        let fs_base = (*slot).fs_base;
3867        (*slot).tid = -1;
3868        (*slot).stack = core::ptr::null_mut();
3869        (*slot).stack_size = 0;
3870        (*slot).fs_base = core::ptr::null_mut();
3871        if !stack.is_null() && stack_size > 0 { sys_munmap(stack, stack_size); }
3872        if !fs_base.is_null() { let bs = __rc_tls_block_size(); let bo = __rc_tls_base_offset(); sys_munmap(fs_base.sub(bo), bs); }
3873        release_thread_slot(slot);
3874    }
3875    0
3876}
3877
3878#[no_mangle]
3879pub unsafe extern "C" fn pthread_exit(retval: *mut c_void) -> ! {
3880    if let Some(slot) = find_thread() {
3881        run_cleanup_handlers(slot);
3882        run_key_dtors(slot);
3883        slot.result = retval;
3884        slot.detach_state = DT_EXITED;
3885        futex_wake(&slot.detach_state as *const c_int as *mut c_int, 1);
3886
3887        // If this is the last thread, run atexit handlers via exit().
3888        let mut active = 0usize;
3889        for i in 0..MAX_THREADS {
3890            if THREADS[i].tid > 0 {
3891                active += 1;
3892            }
3893        }
3894        if active == 1 {
3895            exit(0);
3896        }
3897    }
3898    sys_exit_thread(0);
3899}
3900
3901// --- pthread_attr_* ---
3902#[no_mangle]
3903pub unsafe extern "C" fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int {
3904    core::ptr::write_bytes(attr, 0, 1);
3905    *((*attr).__i.as_mut_ptr() as *mut usize) = STACK_SIZE;
3906    *((*attr).__i.as_mut_ptr().add(2) as *mut usize) = 4096;
3907    (*attr).__i[6] = PTHREAD_CREATE_JOINABLE;
3908    (*attr).__i[7] = PTHREAD_INHERIT_SCHED;
3909    0
3910}
3911#[no_mangle]
3912pub unsafe extern "C" fn pthread_attr_destroy(_attr: *mut pthread_attr_t) -> c_int { 0 }
3913#[no_mangle]
3914pub unsafe extern "C" fn pthread_attr_setdetachstate(attr: *mut pthread_attr_t, s: c_int) -> c_int {
3915    if s != PTHREAD_CREATE_JOINABLE && s != PTHREAD_CREATE_DETACHED { return EINVAL; }
3916    (*attr).__i[6] = s; 0
3917}
3918#[no_mangle]
3919pub unsafe extern "C" fn pthread_attr_getdetachstate(attr: *const pthread_attr_t, s: *mut c_int) -> c_int {
3920    *s = (*attr).__i[6]; 0
3921}
3922#[no_mangle]
3923pub unsafe extern "C" fn pthread_attr_setstacksize(attr: *mut pthread_attr_t, sz: usize) -> c_int {
3924    if sz < 16384 { return EINVAL; }
3925    *((*attr).__i.as_mut_ptr() as *mut usize) = sz; 0
3926}
3927#[no_mangle]
3928pub unsafe extern "C" fn pthread_attr_getstacksize(attr: *const pthread_attr_t, sz: *mut usize) -> c_int {
3929    *sz = *((*attr).__i.as_ptr() as *const usize); 0
3930}
3931#[no_mangle]
3932pub unsafe extern "C" fn pthread_attr_setstack(attr: *mut pthread_attr_t, addr: *mut c_void, sz: usize) -> c_int {
3933    if sz < 16384 { return EINVAL; }
3934    *((*attr).__i.as_mut_ptr() as *mut usize) = sz;
3935    *((*attr).__i.as_mut_ptr().add(4) as *mut *mut c_void) = addr; 0
3936}
3937#[no_mangle]
3938pub unsafe extern "C" fn pthread_attr_getstack(attr: *const pthread_attr_t, addr: *mut *mut c_void, sz: *mut usize) -> c_int {
3939    *sz = *((*attr).__i.as_ptr() as *const usize);
3940    *addr = *((*attr).__i.as_ptr().add(4) as *const *mut c_void); 0
3941}
3942#[no_mangle]
3943pub unsafe extern "C" fn pthread_attr_setguardsize(attr: *mut pthread_attr_t, sz: usize) -> c_int {
3944    *((*attr).__i.as_mut_ptr().add(2) as *mut usize) = sz; 0
3945}
3946#[no_mangle]
3947pub unsafe extern "C" fn pthread_attr_getguardsize(attr: *const pthread_attr_t, sz: *mut usize) -> c_int {
3948    *sz = *((*attr).__i.as_ptr().add(2) as *const usize); 0
3949}
3950#[no_mangle]
3951pub unsafe extern "C" fn pthread_attr_setscope(_attr: *mut pthread_attr_t, scope: c_int) -> c_int {
3952    if scope != PTHREAD_SCOPE_SYSTEM { return EINVAL; }
3953    0
3954}
3955#[no_mangle]
3956pub unsafe extern "C" fn pthread_attr_getscope(_attr: *const pthread_attr_t, scope: *mut c_int) -> c_int {
3957    *scope = PTHREAD_SCOPE_SYSTEM; 0
3958}
3959#[no_mangle]
3960pub unsafe extern "C" fn pthread_attr_setinheritsched(attr: *mut pthread_attr_t, inh: c_int) -> c_int {
3961    if inh != PTHREAD_INHERIT_SCHED && inh != PTHREAD_EXPLICIT_SCHED { return EINVAL; }
3962    (*attr).__i[7] = inh; 0
3963}
3964#[no_mangle]
3965pub unsafe extern "C" fn pthread_attr_getinheritsched(attr: *const pthread_attr_t, inh: *mut c_int) -> c_int {
3966    *inh = (*attr).__i[7]; 0
3967}
3968#[no_mangle]
3969pub unsafe extern "C" fn pthread_attr_setschedpolicy(attr: *mut pthread_attr_t, p: c_int) -> c_int {
3970    (*attr).__i[8] = p; 0
3971}
3972#[no_mangle]
3973pub unsafe extern "C" fn pthread_attr_getschedpolicy(attr: *const pthread_attr_t, p: *mut c_int) -> c_int {
3974    *p = (*attr).__i[8]; 0
3975}
3976#[no_mangle]
3977pub unsafe extern "C" fn pthread_attr_setschedparam(attr: *mut pthread_attr_t, param: *const sched_param) -> c_int {
3978    (*attr).__i[9] = (*param).sched_priority; 0
3979}
3980#[no_mangle]
3981pub unsafe extern "C" fn pthread_attr_getschedparam(attr: *const pthread_attr_t, param: *mut sched_param) -> c_int {
3982    (*param).sched_priority = (*attr).__i[9]; 0
3983}
3984
3985// --- pthread_mutexattr_* ---
3986#[no_mangle]
3987pub unsafe extern "C" fn pthread_mutexattr_init(attr: *mut pthread_mutexattr_t) -> c_int {
3988    (*attr).__attr = 0; 0
3989}
3990#[no_mangle]
3991pub unsafe extern "C" fn pthread_mutexattr_destroy(_attr: *mut pthread_mutexattr_t) -> c_int { 0 }
3992#[no_mangle]
3993pub unsafe extern "C" fn pthread_mutexattr_settype(attr: *mut pthread_mutexattr_t, t: c_int) -> c_int {
3994    if (t as c_uint) > 2 { return EINVAL; }
3995    (*attr).__attr = ((*attr).__attr & !3) | t as c_uint; 0
3996}
3997#[no_mangle]
3998pub unsafe extern "C" fn pthread_mutexattr_gettype(attr: *const pthread_mutexattr_t, t: *mut c_int) -> c_int {
3999    *t = ((*attr).__attr & 3) as c_int; 0
4000}
4001#[no_mangle]
4002pub unsafe extern "C" fn pthread_mutexattr_setpshared(attr: *mut pthread_mutexattr_t, p: c_int) -> c_int {
4003    if (p as c_uint) > 1 { return EINVAL; }
4004    (*attr).__attr = ((*attr).__attr & !128) | ((p as c_uint) << 7); 0
4005}
4006#[no_mangle]
4007pub unsafe extern "C" fn pthread_mutexattr_getpshared(attr: *const pthread_mutexattr_t, p: *mut c_int) -> c_int {
4008    *p = (((*attr).__attr >> 7) & 1) as c_int; 0
4009}
4010
4011#[no_mangle]
4012pub unsafe extern "C" fn pthread_mutexattr_setprotocol(attr: *mut pthread_mutexattr_t, protocol: c_int) -> c_int {
4013    match protocol {
4014        0 => { (*attr).__attr &= !(MUTEX_PI as c_uint); 0 }
4015        1 => {
4016            let mut lk: c_int = 0;
4017            let r = sys_futex(&raw mut lk, FUTEX_LOCK_PI, 0, null_mut(), null_mut(), 0);
4018            if r < 0 { return (-r) as c_int; }
4019            sys_futex(&raw mut lk, FUTEX_UNLOCK_PI, 0, null_mut(), null_mut(), 0);
4020            (*attr).__attr |= MUTEX_PI as c_uint;
4021            0
4022        }
4023        2 => ENOTSUP,
4024        _ => EINVAL,
4025    }
4026}
4027#[no_mangle]
4028pub unsafe extern "C" fn pthread_mutexattr_getprotocol(attr: *const pthread_mutexattr_t, protocol: *mut c_int) -> c_int {
4029    *protocol = (((*attr).__attr >> 3) & 3) as c_int; 0
4030}
4031
4032const ENOTSUP: c_int = 95;
4033
4034#[no_mangle]
4035pub unsafe extern "C" fn pthread_mutexattr_setrobust(attr: *mut pthread_mutexattr_t, robust: c_int) -> c_int {
4036    if (robust as c_uint) > 1 { return EINVAL; }
4037    if robust != 0 {
4038        (*attr).__attr |= MUTEX_ROBUST as c_uint;
4039    } else {
4040        (*attr).__attr &= !(MUTEX_ROBUST as c_uint);
4041    }
4042    0
4043}
4044#[no_mangle]
4045pub unsafe extern "C" fn pthread_mutexattr_getrobust(attr: *const pthread_mutexattr_t, robust: *mut c_int) -> c_int {
4046    *robust = (((*attr).__attr >> 2) & 1) as c_int; 0
4047}
4048
4049#[no_mangle]
4050pub unsafe extern "C" fn pthread_mutex_consistent(m: *mut pthread_mutex_t) -> c_int {
4051    let old = a_load(&raw const (*m).__i[1]);
4052    let own = old & 0x3fffffff;
4053    if ((*m).__i[0] & MUTEX_ROBUST) == 0 || own == 0 || (old & 0x40000000) == 0 {
4054        return EINVAL;
4055    }
4056    let self_tid = sys_gettid() as c_int;
4057    if own != self_tid { return EPERM; }
4058    a_and(&raw mut (*m).__i[1], !(0x40000000i32));
4059    0
4060}
4061
4062unsafe fn a_and(addr: *mut c_int, val: c_int) {
4063    let a = &*(addr as *const AtomicI32);
4064    a.fetch_and(val, Ordering::AcqRel);
4065}
4066
4067// --- pthread_mutex_* ---
4068const MUTEX_TYPE_MASK: c_int = 3;
4069const MUTEX_ROBUST: c_int = 4;
4070const MUTEX_PI: c_int = 8;
4071const MUTEX_PSHARED: c_int = 128;
4072
4073unsafe fn ensure_robust_list(slot: &mut Thread) {
4074    if slot.robust_list.futex_offset == 0 {
4075        slot.robust_list.futex_offset = -28;
4076        slot.robust_list.pending = core::ptr::null_mut();
4077        sys_set_robust_list(&mut slot.robust_list, 24);
4078    }
4079}
4080
4081unsafe fn mutex_trylock(m: *mut pthread_mutex_t) -> c_int {
4082    let type_ = (*m).__i[0];
4083    // Fast path: plain NORMAL only (no PI, no robust, no pshared).
4084    // A failed CAS must report EBUSY unconditionally: the old value may be
4085    // the waiter bit (0x80000000), whose low bits are zero, and masking it
4086    // with EBUSY would falsely report that the lock was acquired.
4087    if (type_ & 0x8f) == PTHREAD_MUTEX_NORMAL {
4088        let old = a_cas(&raw mut (*m).__i[1], 0, EBUSY);
4089        return if old == 0 { 0 } else { EBUSY };
4090    }
4091    let base_type = type_ & MUTEX_TYPE_MASK;
4092    let self_tid = sys_gettid() as c_int;
4093    let old = a_load(&raw const (*m).__i[1]);
4094    let own = old & 0x3fffffff;
4095    if own == self_tid {
4096        if (type_ & MUTEX_PI) != 0 && (*m).__i[5] < 0 {
4097            (*m).__i[5] = 0;
4098            return 0;
4099        }
4100        if base_type == PTHREAD_MUTEX_RECURSIVE {
4101            if (*m).__i[5] >= c_int::MAX { return EAGAIN; }
4102            (*m).__i[5] += 1;
4103            return 0;
4104        }
4105        if base_type == PTHREAD_MUTEX_ERRORCHECK { return EDEADLK; }
4106        return EBUSY;
4107    }
4108    if own == 0x3fffffff { return ENOTRECOVERABLE; }
4109    if own != 0 || (old != 0 && (type_ & MUTEX_ROBUST) == 0) { return EBUSY; }
4110    let mut newtid = self_tid;
4111    if (type_ & MUTEX_ROBUST) != 0 {
4112        if (*m).__i[2] != 0 { newtid |= 1i32 << 31; }
4113        newtid |= old & 0x40000000;
4114    }
4115    if a_cas(&raw mut (*m).__i[1], old, newtid) == old {
4116        (*m).__i[5] = 0;
4117        if (type_ & MUTEX_ROBUST) != 0 {
4118            if let Some(slot) = find_thread() {
4119                ensure_robust_list(slot);
4120                let m_next = &raw mut (*m).__i[8] as *mut robust_list;
4121                let head = &mut slot.robust_list.list;
4122                (*m_next).next = head.next;
4123                head.next = m_next;
4124            }
4125        }
4126        if old != 0 { return EOWNERDEAD; }
4127        0
4128    } else { EBUSY }
4129}
4130
4131unsafe fn mutex_lock_internal(m: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
4132    let type_ = (*m).__i[0];
4133    if (type_ & 0x8f) == PTHREAD_MUTEX_NORMAL && a_cas(&raw mut (*m).__i[1], 0, EBUSY) == 0 {
4134        return 0;
4135    }
4136    let r = mutex_trylock(m);
4137    if r != EBUSY { return r; }
4138    if (type_ & MUTEX_PI) != 0 {
4139        let timeout_ptr = if abs_timeout.is_null() { core::ptr::null() } else { abs_timeout };
4140        loop {
4141            let e = futex_lock_pi(&raw mut (*m).__i[1], timeout_ptr);
4142            match e {
4143                0 => {
4144                    if (type_ & MUTEX_ROBUST) != 0 && (((*m).__i[1] & 0x40000000) != 0 || (*m).__i[2] != 0) {
4145                        (*m).__i[5] = -1;
4146                        let _ = mutex_trylock(m);
4147                        return EOWNERDEAD;
4148                    }
4149                    if (type_ & MUTEX_ROBUST) == 0 && (((*m).__i[1] & 0x40000000) != 0 || (*m).__i[2] != 0) {
4150                        (*m).__i[2] = -1;
4151                        futex_unlock_pi(&raw mut (*m).__i[1]);
4152                        return EBUSY;
4153                    }
4154                    (*m).__i[5] = -1;
4155                    let r2 = mutex_trylock(m);
4156                    if r2 == 0 { return 0; }
4157                    return r2;
4158                }
4159                EINTR => continue,
4160                EDEADLK => {
4161                    if (type_ & MUTEX_TYPE_MASK) == PTHREAD_MUTEX_ERRORCHECK { return e; }
4162                    loop { pause(); }
4163                }
4164                EOWNERDEAD => {
4165                    (*m).__i[5] = -1;
4166                    let _ = mutex_trylock(m);
4167                    return EOWNERDEAD;
4168                }
4169                _ => return e,
4170            }
4171        }
4172    }
4173    let mut spins = 100;
4174    while spins > 0 {
4175        let r = mutex_trylock(m);
4176        if r != EBUSY { return r; }
4177        core::hint::spin_loop();
4178        spins -= 1;
4179    }
4180    loop {
4181        let r = mutex_trylock(m);
4182        if r != EBUSY { return r; }
4183        if (type_ & MUTEX_TYPE_MASK) == PTHREAD_MUTEX_ERRORCHECK {
4184            let self_tid = sys_gettid() as c_int;
4185            if (a_load(&raw const (*m).__i[1]) & 0x3fffffff) == self_tid { return EDEADLK; }
4186        }
4187        a_fetch_add(&raw mut (*m).__i[2], 1);
4188        let val = a_load(&raw const (*m).__i[1]);
4189        // If the previous owner released the lock between trylock() and the
4190        // load above, retry instead of publishing a waiter-only lock word
4191        // (0x80000000) that no thread owns.
4192        if val == 0 {
4193            a_fetch_sub(&raw mut (*m).__i[2], 1);
4194            continue;
4195        }
4196        a_cas(&raw mut (*m).__i[1], val, val | (1i32 << 31));
4197        let e = futex_timedwait(&raw mut (*m).__i[1], val | (1i32 << 31), abs_timeout);
4198        a_fetch_sub(&raw mut (*m).__i[2], 1);
4199        if e != 0 && e != EINTR { return e; }
4200    }
4201}
4202
4203#[no_mangle]
4204pub unsafe extern "C" fn pthread_mutex_init(mutex: *mut pthread_mutex_t, attr: *const pthread_mutexattr_t) -> c_int {
4205    core::ptr::write_bytes(mutex, 0, 1);
4206    if !attr.is_null() { (*mutex).__i[0] = (*attr).__attr as c_int; }
4207    0
4208}
4209#[no_mangle]
4210pub unsafe extern "C" fn pthread_mutex_destroy(_mutex: *mut pthread_mutex_t) -> c_int { 0 }
4211#[no_mangle]
4212pub unsafe extern "C" fn pthread_mutex_lock(mutex: *mut pthread_mutex_t) -> c_int {
4213    mutex_lock_internal(mutex, core::ptr::null())
4214}
4215#[no_mangle]
4216pub unsafe extern "C" fn pthread_mutex_trylock(mutex: *mut pthread_mutex_t) -> c_int {
4217    mutex_trylock(mutex)
4218}
4219#[no_mangle]
4220pub unsafe extern "C" fn pthread_mutex_timedlock(mutex: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
4221    mutex_lock_internal(mutex, abs_timeout)
4222}
4223#[no_mangle]
4224pub unsafe extern "C" fn pthread_mutex_unlock(mutex: *mut pthread_mutex_t) -> c_int {
4225    let type_ = (*mutex).__i[0];
4226    let base_type = type_ & MUTEX_TYPE_MASK;
4227    let old = a_load(&raw const (*mutex).__i[1]);
4228    if base_type != PTHREAD_MUTEX_NORMAL {
4229        let self_tid = sys_gettid() as c_int;
4230        if (old & 0x3fffffff) != self_tid { return EPERM; }
4231        if base_type == PTHREAD_MUTEX_RECURSIVE && (*mutex).__i[5] > 0 {
4232            (*mutex).__i[5] -= 1;
4233            return 0;
4234        }
4235    }
4236    let mut new = 0;
4237    if (type_ & MUTEX_ROBUST) != 0 && (old & 0x40000000) != 0 {
4238        new = 0x7fffffff;
4239    }
4240    if (type_ & MUTEX_PI) != 0 {
4241        if old < 0 || a_cas(&raw mut (*mutex).__i[1], old, new) != old {
4242            if new != 0 { a_store(&raw mut (*mutex).__i[2], -1); }
4243            return futex_unlock_pi(&raw mut (*mutex).__i[1]);
4244        }
4245        return 0;
4246    }
4247    a_store(&raw mut (*mutex).__i[1], new);
4248    if new == 0 && (a_load(&raw const (*mutex).__i[2]) > 0 || old < 0) {
4249        futex_wake(&raw mut (*mutex).__i[1], 1);
4250    }
4251    0
4252}
4253
4254// --- pthread_condattr_* ---
4255#[no_mangle]
4256pub unsafe extern "C" fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int {
4257    (*attr).__attr = 0; 0
4258}
4259#[no_mangle]
4260pub unsafe extern "C" fn pthread_condattr_destroy(_attr: *mut pthread_condattr_t) -> c_int { 0 }
4261#[no_mangle]
4262pub unsafe extern "C" fn pthread_condattr_setclock(attr: *mut pthread_condattr_t, clk: c_int) -> c_int {
4263    if clk != CLOCK_REALTIME && clk != CLOCK_MONOTONIC { return EINVAL; }
4264    (*attr).__attr = ((*attr).__attr & 0x80000000) | clk as c_uint; 0
4265}
4266#[no_mangle]
4267pub unsafe extern "C" fn pthread_condattr_getclock(attr: *const pthread_condattr_t, clk: *mut c_int) -> c_int {
4268    *clk = ((*attr).__attr & 0x7fffffff) as c_int; 0
4269}
4270#[no_mangle]
4271pub unsafe extern "C" fn pthread_condattr_setpshared(attr: *mut pthread_condattr_t, p: c_int) -> c_int {
4272    if (p as c_uint) > 1 { return EINVAL; }
4273    (*attr).__attr = ((*attr).__attr & 0x7fffffff) | ((p as c_uint) << 31); 0
4274}
4275#[no_mangle]
4276pub unsafe extern "C" fn pthread_condattr_getpshared(attr: *const pthread_condattr_t, p: *mut c_int) -> c_int {
4277    *p = ((*attr).__attr >> 31) as c_int; 0
4278}
4279
4280// --- pthread_cond_* ---
4281#[no_mangle]
4282pub unsafe extern "C" fn pthread_cond_init(cond: *mut pthread_cond_t, attr: *const pthread_condattr_t) -> c_int {
4283    core::ptr::write_bytes(cond, 0, 1);
4284    if !attr.is_null() {
4285        (*cond).__i[4] = ((*attr).__attr & 0x7fffffff) as c_int;
4286    }
4287    0
4288}
4289#[no_mangle]
4290pub unsafe extern "C" fn pthread_cond_destroy(_cond: *mut pthread_cond_t) -> c_int { 0 }
4291#[no_mangle]
4292pub unsafe extern "C" fn pthread_cond_wait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t) -> c_int {
4293    pthread_cond_timedwait(cond, mutex, core::ptr::null())
4294}
4295
4296
4297#[no_mangle]
4298pub unsafe extern "C" fn pthread_cond_timedwait(cond: *mut pthread_cond_t, mutex: *mut pthread_mutex_t, abs_timeout: *const timespec) -> c_int {
4299    pthread_testcancel();
4300    let seq_ptr = &raw mut (*cond).__i[2];
4301    let waiters_ptr = &raw mut (*cond).__i[3];
4302    let seq = a_load(seq_ptr);
4303    a_fetch_add(waiters_ptr, 1);
4304    pthread_mutex_unlock(mutex);
4305    let e = futex_timedwait(seq_ptr, seq, abs_timeout);
4306    a_fetch_sub(waiters_ptr, 1);
4307    let r = pthread_mutex_lock(mutex);
4308    if r != 0 { return r; }
4309    if e == EINTR {
4310        pthread_testcancel();
4311    }
4312    if e != 0 && e != EINTR { return e; }
4313    0
4314}
4315#[no_mangle]
4316pub unsafe extern "C" fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int {
4317    if a_load(&raw const (*cond).__i[3]) == 0 { return 0; }
4318    a_fetch_add(&raw mut (*cond).__i[2], 1);
4319    futex_wake(&raw mut (*cond).__i[2], 1);
4320    0
4321}
4322#[no_mangle]
4323pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int {
4324    if a_load(&raw const (*cond).__i[3]) == 0 { return 0; }
4325    a_fetch_add(&raw mut (*cond).__i[2], 1);
4326    futex_wake(&raw mut (*cond).__i[2], -1);
4327    0
4328}
4329
4330// --- pthread_rwlockattr_* ---
4331#[no_mangle]
4332pub unsafe extern "C" fn pthread_rwlockattr_init(attr: *mut pthread_rwlockattr_t) -> c_int {
4333    (*attr).__attr = [0; 2]; 0
4334}
4335#[no_mangle]
4336pub unsafe extern "C" fn pthread_rwlockattr_destroy(_attr: *mut pthread_rwlockattr_t) -> c_int { 0 }
4337#[no_mangle]
4338pub unsafe extern "C" fn pthread_rwlockattr_setpshared(attr: *mut pthread_rwlockattr_t, p: c_int) -> c_int {
4339    if (p as c_uint) > 1 { return EINVAL; }
4340    (*attr).__attr[0] = ((*attr).__attr[0] & !128) | ((p as c_uint) << 7); 0
4341}
4342#[no_mangle]
4343pub unsafe extern "C" fn pthread_rwlockattr_getpshared(attr: *const pthread_rwlockattr_t, p: *mut c_int) -> c_int {
4344    *p = (((*attr).__attr[0] >> 7) & 1) as c_int; 0
4345}
4346
4347// --- pthread_rwlock_* ---
4348unsafe fn rwlock_tryrdlock(rw: *mut pthread_rwlock_t) -> c_int {
4349    loop {
4350        let val = a_load(&raw const (*rw).__i[0]);
4351        let cnt = val & 0x7fffffff;
4352        if cnt == 0x7fffffff { return EBUSY; }
4353        if cnt == 0x7ffffffe { return EAGAIN; }
4354        if a_cas(&raw mut (*rw).__i[0], val, val + 1) == val { return 0; }
4355    }
4356}
4357unsafe fn rwlock_trywrlock(rw: *mut pthread_rwlock_t) -> c_int {
4358    if a_cas(&raw mut (*rw).__i[0], 0, 0x7fffffff) == 0 { 0 } else { EBUSY }
4359}
4360unsafe fn rwlock_timedrdlock(rw: *mut pthread_rwlock_t, abs_timeout: *const timespec) -> c_int {
4361    let r = rwlock_tryrdlock(rw);
4362    if r != EBUSY { return r; }
4363    let mut spins = 100;
4364    while spins > 0 { let r = rwlock_tryrdlock(rw); if r != EBUSY { return r; } core::hint::spin_loop(); spins -= 1; }
4365    loop {
4366        let r = rwlock_tryrdlock(rw);
4367        if r != EBUSY { return r; }
4368        let val = a_load(&raw const (*rw).__i[0]);
4369        if val & 0x7fffffff != 0x7fffffff { continue; }
4370        a_fetch_add(&raw mut (*rw).__i[1], 1);
4371        a_cas(&raw mut (*rw).__i[0], val, val | (1i32 << 31));
4372        let e = futex_timedwait(&raw mut (*rw).__i[0], val | (1i32 << 31), abs_timeout);
4373        a_fetch_sub(&raw mut (*rw).__i[1], 1);
4374        if e != 0 && e != EINTR { return e; }
4375    }
4376}
4377unsafe fn rwlock_timedwrlock(rw: *mut pthread_rwlock_t, abs_timeout: *const timespec) -> c_int {
4378    let r = rwlock_trywrlock(rw);
4379    if r != EBUSY { return r; }
4380    let mut spins = 100;
4381    while spins > 0 { let r = rwlock_trywrlock(rw); if r != EBUSY { return r; } core::hint::spin_loop(); spins -= 1; }
4382    loop {
4383        let r = rwlock_trywrlock(rw);
4384        if r != EBUSY { return r; }
4385        let val = a_load(&raw const (*rw).__i[0]);
4386        if val == 0 { continue; }
4387        a_fetch_add(&raw mut (*rw).__i[1], 1);
4388        a_cas(&raw mut (*rw).__i[0], val, val | (1i32 << 31));
4389        let e = futex_timedwait(&raw mut (*rw).__i[0], val | (1i32 << 31), abs_timeout);
4390        a_fetch_sub(&raw mut (*rw).__i[1], 1);
4391        if e != 0 && e != EINTR { return e; }
4392    }
4393}
4394
4395#[no_mangle]
4396pub unsafe extern "C" fn pthread_rwlock_init(rw: *mut pthread_rwlock_t, attr: *const pthread_rwlockattr_t) -> c_int {
4397    core::ptr::write_bytes(rw, 0, 1);
4398    if !attr.is_null() { (*rw).__i[2] = (*attr).__attr[0] as c_int & 128; }
4399    0
4400}
4401#[no_mangle]
4402pub unsafe extern "C" fn pthread_rwlock_destroy(_rw: *mut pthread_rwlock_t) -> c_int { 0 }
4403#[no_mangle]
4404pub unsafe extern "C" fn pthread_rwlock_rdlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_timedrdlock(rw, core::ptr::null()) }
4405#[no_mangle]
4406pub unsafe extern "C" fn pthread_rwlock_tryrdlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_tryrdlock(rw) }
4407#[no_mangle]
4408pub unsafe extern "C" fn pthread_rwlock_timedrdlock(rw: *mut pthread_rwlock_t, t: *const timespec) -> c_int { rwlock_timedrdlock(rw, t) }
4409#[no_mangle]
4410pub unsafe extern "C" fn pthread_rwlock_wrlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_timedwrlock(rw, core::ptr::null()) }
4411#[no_mangle]
4412pub unsafe extern "C" fn pthread_rwlock_trywrlock(rw: *mut pthread_rwlock_t) -> c_int { rwlock_trywrlock(rw) }
4413#[no_mangle]
4414pub unsafe extern "C" fn pthread_rwlock_timedwrlock(rw: *mut pthread_rwlock_t, t: *const timespec) -> c_int { rwlock_timedwrlock(rw, t) }
4415#[no_mangle]
4416pub unsafe extern "C" fn pthread_rwlock_unlock(rw: *mut pthread_rwlock_t) -> c_int {
4417    loop {
4418        let val = a_load(&raw const (*rw).__i[0]);
4419        let cnt = val & 0x7fffffff;
4420        let new_val = if cnt == 0x7fffffff || cnt == 1 { 0 } else { val - 1 };
4421        if a_cas(&raw mut (*rw).__i[0], val, new_val) == val {
4422            if new_val == 0 && (a_load(&raw const (*rw).__i[1]) > 0 || val < 0) {
4423                futex_wake(&raw mut (*rw).__i[0], cnt);
4424            }
4425            return 0;
4426        }
4427    }
4428}
4429
4430// --- pthread_barrierattr_* ---
4431#[no_mangle]
4432pub unsafe extern "C" fn pthread_barrierattr_init(attr: *mut pthread_barrierattr_t) -> c_int { (*attr).__attr = 0; 0 }
4433#[no_mangle]
4434pub unsafe extern "C" fn pthread_barrierattr_destroy(_attr: *mut pthread_barrierattr_t) -> c_int { 0 }
4435#[no_mangle]
4436pub unsafe extern "C" fn pthread_barrierattr_setpshared(attr: *mut pthread_barrierattr_t, p: c_int) -> c_int {
4437    if (p as c_uint) > 1 { return EINVAL; }
4438    (*attr).__attr = p as c_uint; 0
4439}
4440#[no_mangle]
4441pub unsafe extern "C" fn pthread_barrierattr_getpshared(attr: *const pthread_barrierattr_t, p: *mut c_int) -> c_int {
4442    *p = (*attr).__attr as c_int; 0
4443}
4444
4445// --- pthread_barrier_* ---
4446#[no_mangle]
4447pub unsafe extern "C" fn pthread_barrier_init(b: *mut pthread_barrier_t, _attr: *const pthread_barrierattr_t, count: c_uint) -> c_int {
4448    if count == 0 { return EINVAL; }
4449    core::ptr::write_bytes(b, 0, 1);
4450    (*b).__i[2] = count as c_int - 1;
4451    0
4452}
4453#[no_mangle]
4454pub unsafe extern "C" fn pthread_barrier_destroy(_b: *mut pthread_barrier_t) -> c_int { 0 }
4455#[no_mangle]
4456pub unsafe extern "C" fn pthread_barrier_wait(b: *mut pthread_barrier_t) -> c_int {
4457    let limit = (*b).__i[2];
4458    if limit == 0 { return PTHREAD_BARRIER_SERIAL_THREAD; }
4459    spinlock_lock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
4460    let arrived = a_load(&raw const (*b).__i[3]) + 1;
4461    a_store(&raw mut (*b).__i[3], arrived);
4462    if arrived > limit {
4463        a_store(&raw mut (*b).__i[3], 0);
4464        let gen = a_load(&raw const (*b).__i[4]);
4465        a_store(&raw mut (*b).__i[4], gen + 1);
4466        spinlock_unlock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
4467        futex_wake(&raw mut (*b).__i[4], -1);
4468        return PTHREAD_BARRIER_SERIAL_THREAD;
4469    }
4470    let gen = a_load(&raw const (*b).__i[4]);
4471    spinlock_unlock(&raw mut (*b).__i[0], &raw mut (*b).__i[1]);
4472    while a_load(&raw const (*b).__i[4]) == gen {
4473        futex_wait(&raw mut (*b).__i[4], gen);
4474    }
4475    0
4476}
4477
4478// --- pthread_spin_* ---
4479#[no_mangle]
4480pub unsafe extern "C" fn pthread_spin_init(s: *mut pthread_spinlock_t, _pshared: c_int) -> c_int { a_store(s, 0); 0 }
4481#[no_mangle]
4482pub unsafe extern "C" fn pthread_spin_destroy(_s: *mut pthread_spinlock_t) -> c_int { 0 }
4483#[no_mangle]
4484pub unsafe extern "C" fn pthread_spin_lock(s: *mut pthread_spinlock_t) -> c_int {
4485    while a_load(s) != 0 || a_cas(s, 0, EBUSY) != 0 { core::hint::spin_loop(); }
4486    0
4487}
4488#[no_mangle]
4489pub unsafe extern "C" fn pthread_spin_trylock(s: *mut pthread_spinlock_t) -> c_int { a_cas(s, 0, EBUSY) }
4490#[no_mangle]
4491pub unsafe extern "C" fn pthread_spin_unlock(s: *mut pthread_spinlock_t) -> c_int { a_store(s, 0); 0 }
4492
4493// --- sem_* ---
4494#[no_mangle]
4495pub unsafe extern "C" fn sem_init(sem: *mut sem_t, pshared: c_int, value: c_uint) -> c_int {
4496    if value > SEM_VALUE_MAX as c_uint { return EINVAL; }
4497    (*sem).__val[0] = value as c_int;
4498    (*sem).__val[1] = 0;
4499    (*sem).__val[2] = if pshared != 0 { 0 } else { 128 };
4500    0
4501}
4502#[no_mangle]
4503pub unsafe extern "C" fn sem_destroy(_sem: *mut sem_t) -> c_int { 0 }
4504
4505unsafe fn sem_trywait_internal(sem: *mut sem_t) -> c_int {
4506    loop {
4507        let val = a_load(&raw const (*sem).__val[0]);
4508        if val & SEM_VALUE_MAX == 0 { return EAGAIN; }
4509        if a_cas(&raw mut (*sem).__val[0], val, val - 1) == val { return 0; }
4510    }
4511}
4512
4513#[no_mangle]
4514pub unsafe extern "C" fn sem_trywait(sem: *mut sem_t) -> c_int {
4515    if sem_trywait_internal(sem) == 0 { 0 } else { ERRNO = EAGAIN; -1 }
4516}
4517#[no_mangle]
4518pub unsafe extern "C" fn sem_wait(sem: *mut sem_t) -> c_int {
4519    pthread_testcancel();
4520    if sem_trywait_internal(sem) == 0 { return 0; }
4521    let mut spins = 100;
4522    while spins > 0 { if sem_trywait_internal(sem) == 0 { return 0; } core::hint::spin_loop(); spins -= 1; }
4523    loop {
4524        pthread_testcancel();
4525        if sem_trywait_internal(sem) == 0 { return 0; }
4526        let val = a_load(&raw const (*sem).__val[0]);
4527        if val & SEM_VALUE_MAX != 0 { continue; }
4528        a_cas(&raw mut (*sem).__val[0], val, val | (1i32 << 31));
4529        a_fetch_add(&raw mut (*sem).__val[1], 1);
4530        futex_wait(&raw mut (*sem).__val[0], 1i32 << 31);
4531        a_fetch_sub(&raw mut (*sem).__val[1], 1);
4532    }
4533}
4534#[no_mangle]
4535pub unsafe extern "C" fn sem_timedwait(sem: *mut sem_t, abs_timeout: *const timespec) -> c_int {
4536    pthread_testcancel();
4537    if sem_trywait_internal(sem) == 0 { return 0; }
4538    let mut spins = 100;
4539    while spins > 0 { if sem_trywait_internal(sem) == 0 { return 0; } core::hint::spin_loop(); spins -= 1; }
4540    loop {
4541        pthread_testcancel();
4542        if sem_trywait_internal(sem) == 0 { return 0; }
4543        let val = a_load(&raw const (*sem).__val[0]);
4544        if val & SEM_VALUE_MAX != 0 { continue; }
4545        a_cas(&raw mut (*sem).__val[0], val, val | (1i32 << 31));
4546        a_fetch_add(&raw mut (*sem).__val[1], 1);
4547        let e = futex_timedwait(&raw mut (*sem).__val[0], 1i32 << 31, abs_timeout);
4548        a_fetch_sub(&raw mut (*sem).__val[1], 1);
4549        if e != 0 && e != EINTR { ERRNO = e; return -1; }
4550    }
4551}
4552#[no_mangle]
4553pub unsafe extern "C" fn sem_post(sem: *mut sem_t) -> c_int {
4554    loop {
4555        let val = a_load(&raw const (*sem).__val[0]);
4556        if (val & SEM_VALUE_MAX) == SEM_VALUE_MAX { ERRNO = EOVERFLOW; return -1; }
4557        let mut new = val + 1;
4558        let waiters = a_load(&raw const (*sem).__val[1]);
4559        if waiters <= 1 { new &= !(1i32 << 31); }
4560        if a_cas(&raw mut (*sem).__val[0], val, new) == val {
4561            if val < 0 || waiters > 0 {
4562                futex_wake(&raw mut (*sem).__val[0], if waiters > 1 { 1 } else { -1 });
4563            }
4564            return 0;
4565        }
4566    }
4567}
4568#[no_mangle]
4569pub unsafe extern "C" fn sem_getvalue(sem: *mut sem_t, sval: *mut c_int) -> c_int {
4570    *sval = a_load(&raw const (*sem).__val[0]) & SEM_VALUE_MAX;
4571    0
4572}
4573
4574// ============================================================
4575// POSIX shared memory + named semaphores
4576// ============================================================
4577
4578const NAME_MAX: usize = 255;
4579const SEM_NSEMS_MAX: usize = 256;
4580
4581// ponytail: global spinlock for semtab, upgrade to per-entry if contention matters
4582static SEMTAB_LOCK: AtomicI32 = AtomicI32::new(0);
4583
4584struct SemEntry {
4585    ino: u64,
4586    sem: *mut sem_t,
4587    refcnt: u32,
4588}
4589
4590// ponytail: zero-init is fine for static mut (all-zero = free slots)
4591static mut SEMTAB: [SemEntry; SEM_NSEMS_MAX] = {
4592    const ZERO: SemEntry = SemEntry { ino: 0, sem: core::ptr::null_mut(), refcnt: 0 };
4593    [ZERO; SEM_NSEMS_MAX]
4594};
4595
4596unsafe fn semtab_lock() {
4597    while SEMTAB_LOCK.compare_exchange_weak(0, 1, Ordering::Acquire, Ordering::Relaxed).is_err() {
4598        core::hint::spin_loop();
4599    }
4600}
4601
4602unsafe fn semtab_unlock() {
4603    SEMTAB_LOCK.store(0, Ordering::Release);
4604}
4605
4606// Validate shm/sem name and construct /dev/shm/<name> path.
4607// Returns path length or -1 with ERRNO set.
4608unsafe fn shm_mapname(name: *const c_char, buf: *mut u8) -> c_int {
4609    let mut p = name;
4610    // strip leading /
4611    while *p == b'/' as c_char { p = p.add(1); }
4612    let start = p;
4613    // find end of first component
4614    while *p != 0 && *p != b'/' as c_char { p = p.add(1); }
4615    let len = p.offset_from(start) as usize;
4616    // no trailing /, not empty, not "." or ".."
4617    if len == 0 || *p != 0 {
4618        ERRNO = EINVAL;
4619        return -1;
4620    }
4621    if len == 1 && *start == b'.' as c_char {
4622        ERRNO = EINVAL;
4623        return -1;
4624    }
4625    if len == 2 && *start == b'.' as c_char && *start.add(1) == b'.' as c_char {
4626        ERRNO = EINVAL;
4627        return -1;
4628    }
4629    if len > NAME_MAX {
4630        ERRNO = ENAMETOOLONG;
4631        return -1;
4632    }
4633    // build /dev/shm/<name>
4634    let prefix = b"/dev/shm/\0";
4635    let mut i = 0;
4636    while prefix[i] != 0 {
4637        *buf.add(i) = prefix[i];
4638        i += 1;
4639    }
4640    let mut j = 0;
4641    while j < len {
4642        *buf.add(i + j) = *start.add(j) as u8;
4643        j += 1;
4644    }
4645    *buf.add(i + j) = 0;
4646    (i + j) as c_int
4647}
4648
4649#[no_mangle]
4650pub unsafe extern "C" fn shm_open(name: *const c_char, flags: c_int, mode: mode_t) -> c_int {
4651    let mut buf = [0u8; 16 + NAME_MAX + 1];
4652    if shm_mapname(name, buf.as_mut_ptr()) < 0 { return -1; }
4653    let fd = sys_open(buf.as_ptr(), (flags | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, mode as i64);
4654    if fd < 0 { ERRNO = (-fd) as c_int; return -1; }
4655    fd as c_int
4656}
4657
4658#[no_mangle]
4659pub unsafe extern "C" fn shm_unlink(name: *const c_char) -> c_int {
4660    let mut buf = [0u8; 16 + NAME_MAX + 1];
4661    if shm_mapname(name, buf.as_mut_ptr()) < 0 { return -1; }
4662    let r = sys_unlink(buf.as_ptr());
4663    if r < 0 { ERRNO = (-r) as c_int; return -1; }
4664    0
4665}
4666
4667#[no_mangle]
4668pub unsafe extern "C" fn sem_open(name: *const c_char, flags: c_int, mut args: ...) -> *mut sem_t {
4669    let mut buf = [0u8; 16 + NAME_MAX + 1];
4670    if shm_mapname(name, buf.as_mut_ptr()).is_negative() {
4671        return core::ptr::null_mut(); // SEM_FAILED
4672    }
4673
4674    let oflags = flags & (O_CREAT | O_EXCL);
4675
4676    semtab_lock();
4677
4678    // find a free slot
4679    let mut slot: c_int = -1;
4680    for i in 0..SEMTAB_LEN {
4681        if SEMTAB[i].sem.is_null() && slot < 0 { slot = i as c_int; }
4682    }
4683    if slot < 0 {
4684        ERRNO = EMFILE;
4685        semtab_unlock();
4686        return core::ptr::null_mut();
4687    }
4688    // reserve slot
4689    SEMTAB[slot as usize].sem = !0usize as *mut sem_t; // sentinel
4690    semtab_unlock();
4691
4692    // extract va_args for O_CREAT
4693    let mut mode: mode_t = 0;
4694    let mut value: c_uint = 0;
4695    if oflags & O_CREAT != 0 {
4696        mode = args.next_arg::<mode_t>() & 0o666;
4697        value = args.next_arg::<c_uint>();
4698        if value > SEM_VALUE_MAX as c_uint {
4699            ERRNO = EINVAL;
4700            semtab_lock();
4701            SEMTAB[slot as usize].sem = core::ptr::null_mut();
4702            semtab_unlock();
4703            return core::ptr::null_mut();
4704        }
4705    }
4706
4707    // try opening existing first (unless O_CREAT|O_EXCL)
4708    if oflags != O_CREAT | O_EXCL {
4709        let fd = sys_open(buf.as_ptr(), (O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, 0);
4710        if fd >= 0 {
4711            let map = sys_mmap(
4712                core::ptr::null_mut(),
4713                core::mem::size_of::<sem_t>(),
4714                PROT_READ | PROT_WRITE,
4715                MAP_SHARED,
4716                fd as i32,
4717                0,
4718            );
4719            sys_close(fd);
4720            if map != MMAP_FAILED {
4721                let st_ino = get_ino(fd as c_int, buf.as_ptr());
4722                return sem_register(map as *mut sem_t, st_ino, slot);
4723            }
4724        }
4725        if oflags == 0 {
4726            // no O_CREAT and file doesn't exist
4727            semtab_lock();
4728            SEMTAB[slot as usize].sem = core::ptr::null_mut();
4729            semtab_unlock();
4730            return core::ptr::null_mut();
4731        }
4732    }
4733
4734    // create: write sem_t to temp file, mmap, link
4735    let mut tmp = [0u8; 32];
4736    let tmpname = b"/dev/shm/tmp-XXXXXX\0";
4737    tmp[..tmpname.len()].copy_from_slice(tmpname);
4738    // use clock for unique name
4739    let mut ts: timespec = core::mem::zeroed();
4740    sys_clock_gettime(0, &mut ts);
4741    // append ns to tmp name
4742    let mut n = ts.tv_nsec;
4743    let mut pos = tmpname.len() - 1;
4744    tmp[pos] = 0;
4745    pos -= 1;
4746    loop {
4747        tmp[pos] = b'0' + (n % 10) as u8;
4748        n /= 10;
4749        if n == 0 || pos == 0 { break; }
4750        pos -= 1;
4751    }
4752        // shift to start of number part
4753        let tmp_path = tmp.as_ptr();
4754
4755    let mut newsem: sem_t = core::mem::zeroed();
4756    newsem.__val[0] = value as c_int;
4757    newsem.__val[1] = 0;
4758    newsem.__val[2] = 128; // pshared=0 flag
4759
4760    loop {
4761        let fd = sys_open(tmp_path as *const u8, (O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC | O_NONBLOCK) as i64, mode as i64);
4762        if fd < 0 {
4763            if (-fd) as c_int == EEXIST { continue; }
4764            semtab_lock();
4765            SEMTAB[slot as usize].sem = core::ptr::null_mut();
4766            semtab_unlock();
4767            return core::ptr::null_mut();
4768        }
4769        let written = sys_write(fd, &newsem as *const sem_t as *const u8, core::mem::size_of::<sem_t>());
4770        if written != core::mem::size_of::<sem_t>() as i64 {
4771            sys_close(fd);
4772            sys_unlink(tmp_path);
4773            semtab_lock();
4774            SEMTAB[slot as usize].sem = core::ptr::null_mut();
4775            semtab_unlock();
4776            return core::ptr::null_mut();
4777        }
4778        let map = sys_mmap(
4779            core::ptr::null_mut(),
4780            core::mem::size_of::<sem_t>(),
4781            PROT_READ | PROT_WRITE,
4782            MAP_SHARED,
4783            fd as i32,
4784            0,
4785        );
4786        sys_close(fd);
4787        if map == MMAP_FAILED {
4788            sys_unlink(tmp_path);
4789            semtab_lock();
4790            SEMTAB[slot as usize].sem = core::ptr::null_mut();
4791            semtab_unlock();
4792            return core::ptr::null_mut();
4793        }
4794        // link to final name
4795        let r = sys_linkat(AT_FDCWD, tmp_path, AT_FDCWD, buf.as_ptr(), 0);
4796        let e = if r < 0 { (-r) as c_int } else { 0 };
4797        sys_unlink(tmp_path);
4798        if e == 0 {
4799            let st_ino = get_ino(-1, buf.as_ptr());
4800            return sem_register(map as *mut sem_t, st_ino, slot);
4801        }
4802        sys_munmap(map, core::mem::size_of::<sem_t>());
4803        if e != EEXIST || oflags == O_CREAT | O_EXCL {
4804            ERRNO = e;
4805            semtab_lock();
4806            SEMTAB[slot as usize].sem = core::ptr::null_mut();
4807            semtab_unlock();
4808            return core::ptr::null_mut();
4809        }
4810        // EEXIST without O_EXCL: retry open existing
4811        break;
4812    }
4813
4814    // fallthrough: try opening the existing file that won the race
4815    let fd = sys_open(buf.as_ptr(), (O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_NONBLOCK) as i64, 0);
4816    if fd < 0 {
4817        semtab_lock();
4818        SEMTAB[slot as usize].sem = core::ptr::null_mut();
4819        semtab_unlock();
4820        return core::ptr::null_mut();
4821    }
4822    let map = sys_mmap(
4823        core::ptr::null_mut(),
4824        core::mem::size_of::<sem_t>(),
4825        PROT_READ | PROT_WRITE,
4826        MAP_SHARED,
4827        fd as i32,
4828        0,
4829    );
4830    sys_close(fd);
4831    if map == MMAP_FAILED {
4832        semtab_lock();
4833        SEMTAB[slot as usize].sem = core::ptr::null_mut();
4834        semtab_unlock();
4835        return core::ptr::null_mut();
4836    }
4837    let st_ino = get_ino(-1, buf.as_ptr());
4838    sem_register(map as *mut sem_t, st_ino, slot)
4839}
4840
4841unsafe fn get_ino(_fd_hint: c_int, path: *const u8) -> u64 {
4842    let mut st: Stat = core::mem::zeroed();
4843    if sys_newfstatat(AT_FDCWD, path as *const c_char, &mut st as *mut Stat as *mut u8, 0) == 0 {
4844        st.st_ino
4845    } else {
4846        0
4847    }
4848}
4849
4850unsafe fn sem_register(map: *mut sem_t, ino: u64, slot_hint: c_int) -> *mut sem_t {
4851    semtab_lock();
4852    // check if already mapped (by inode)
4853    for i in 0..SEMTAB_LEN {
4854        if SEMTAB[i].ino == ino && !SEMTAB[i].sem.is_null() && SEMTAB[i].sem != !0usize as *mut sem_t {
4855            // already mapped: unmap new, use existing, release hint slot
4856            sys_munmap(map as *mut u8, core::mem::size_of::<sem_t>());
4857            SEMTAB[slot_hint as usize].sem = core::ptr::null_mut();
4858            SEMTAB[i].refcnt += 1;
4859            let ret = SEMTAB[i].sem;
4860            semtab_unlock();
4861            return ret;
4862        }
4863    }
4864    // new entry
4865    SEMTAB[slot_hint as usize].sem = map;
4866    SEMTAB[slot_hint as usize].ino = ino;
4867    SEMTAB[slot_hint as usize].refcnt = 1;
4868    semtab_unlock();
4869    map
4870}
4871
4872const SEMTAB_LEN: usize = SEM_NSEMS_MAX;
4873
4874#[no_mangle]
4875pub unsafe extern "C" fn sem_close(sem: *mut sem_t) -> c_int {
4876    semtab_lock();
4877    for i in 0..SEMTAB_LEN {
4878        if SEMTAB[i].sem == sem {
4879            SEMTAB[i].refcnt -= 1;
4880            if SEMTAB[i].refcnt == 0 {
4881                SEMTAB[i].sem = core::ptr::null_mut();
4882                SEMTAB[i].ino = 0;
4883                semtab_unlock();
4884                sys_munmap(sem as *mut u8, core::mem::size_of::<sem_t>());
4885                return 0;
4886            }
4887            semtab_unlock();
4888            return 0;
4889        }
4890    }
4891    semtab_unlock();
4892    0
4893}
4894
4895#[no_mangle]
4896pub unsafe extern "C" fn sem_unlink(name: *const c_char) -> c_int {
4897    shm_unlink(name)
4898}
4899
4900// --- pthread_once ---
4901#[no_mangle]
4902pub unsafe extern "C" fn pthread_once(control: *mut pthread_once_t, init_routine: Option<unsafe extern "C" fn()>) -> c_int {
4903    if a_load(control) == 2 { return 0; }
4904    loop {
4905        match a_cas(control, 0, 1) {
4906            0 => {
4907                if let Some(f) = init_routine { f(); }
4908                if a_swap(control, 2) == 3 { futex_wake(control, -1); }
4909                return 0;
4910            }
4911            1 => { a_cas(control, 1, 3); }
4912            3 => { futex_wait(control, 3); }
4913            _ => { return 0; }
4914        }
4915    }
4916}
4917
4918// --- pthread_key_* ---
4919#[no_mangle]
4920pub unsafe extern "C" fn pthread_key_create(key: *mut pthread_key_t, dtor: Option<unsafe extern "C" fn(*mut c_void)>) -> c_int {
4921    let start = NEXT_KEY.load(Ordering::Relaxed);
4922    let mut j = start;
4923    loop {
4924        if KEY_DTORS[j].is_none() {
4925            KEY_DTORS[j] = dtor;
4926            NEXT_KEY.store((j + 1) % PTHREAD_KEYS_MAX, Ordering::Relaxed);
4927            *key = j as pthread_key_t;
4928            return 0;
4929        }
4930        j = (j + 1) % PTHREAD_KEYS_MAX;
4931        if j == start { return EAGAIN; }
4932    }
4933}
4934#[no_mangle]
4935pub unsafe extern "C" fn pthread_key_delete(key: pthread_key_t) -> c_int {
4936    KEY_DTORS[key as usize] = None;
4937    for i in 0..MAX_THREADS {
4938        if THREADS[i].tid > 0 { THREADS[i].tsd[key as usize] = core::ptr::null_mut(); }
4939    }
4940    0
4941}
4942#[no_mangle]
4943pub unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void {
4944    if let Some(slot) = find_thread() { slot.tsd[key as usize] } else { core::ptr::null_mut() }
4945}
4946#[no_mangle]
4947pub unsafe extern "C" fn pthread_setspecific(key: pthread_key_t, value: *const c_void) -> c_int {
4948    if let Some(slot) = find_thread() {
4949        slot.tsd[key as usize] = value as *mut c_void;
4950        0
4951    } else { EINVAL }
4952}
4953
4954// --- pthread_cancel/state ---
4955unsafe fn run_cleanup_handlers(slot: &mut Thread) {
4956    let mut cb = slot.cancelbuf;
4957    while !cb.is_null() {
4958        let cur = &*cb;
4959        let f = cur.__f;
4960        let x = cur.__x;
4961        cb = cur.__next;
4962        if let Some(func) = f {
4963            func(x);
4964        }
4965    }
4966    slot.cancelbuf = core::ptr::null_mut();
4967}
4968
4969unsafe fn do_cancel() -> ! {
4970    if let Some(slot) = find_thread() {
4971        run_cleanup_handlers(slot);
4972        slot.result = !0usize as *mut c_void; // PTHREAD_CANCELED
4973        slot.detach_state = DT_EXITED;
4974        futex_wake(&raw mut slot.detach_state, 1);
4975    }
4976    sys_exit_thread(0);
4977}
4978
4979extern "C" fn cancel_handler(_sig: c_int) {
4980    unsafe {
4981        if let Some(slot) = find_thread() {
4982            // In asynchronous mode, cancel immediately from the signal handler.
4983            // In deferred mode, the signal just interrupts blocking syscalls so
4984            // the next cancellation point can act on the pending request.
4985            if slot.cancel != 0
4986                && slot.cancel_state == PTHREAD_CANCEL_ENABLE
4987                && slot.cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS
4988            {
4989                do_cancel();
4990            }
4991        }
4992    }
4993}
4994
4995static CANCEL_INIT: AtomicI32 = AtomicI32::new(0);
4996
4997unsafe fn ensure_cancel_handler() {
4998    if CANCEL_INIT.swap(1, Ordering::AcqRel) == 0 {
4999        let act = sigaction {
5000            sa_handler: cancel_handler as *const () as usize,
5001            sa_flags: SA_RESTORER,
5002            sa_restorer: sig_restorer as *const () as usize,
5003            sa_mask: [!0u64],
5004        };
5005        sys_rt_sigaction(SIGCANCEL, &act as *const sigaction, core::ptr::null_mut(), 8);
5006    }
5007}
5008
5009#[no_mangle]
5010pub unsafe extern "C" fn pthread_cancel(thread: PthreadT) -> c_int {
5011    let slot = thread as *mut Thread;
5012    if slot.is_null() { return EINVAL; }
5013    ensure_cancel_handler();
5014    a_store(&raw mut (*slot).cancel, 1);
5015    let tid = (*slot).tid;
5016    if tid > 0 {
5017        sys_tgkill(sys_getpid() as c_int, tid, SIGCANCEL);
5018    }
5019    0
5020}
5021#[no_mangle]
5022pub unsafe extern "C" fn pthread_setcancelstate(state: c_int, oldstate: *mut c_int) -> c_int {
5023    if state != PTHREAD_CANCEL_ENABLE && state != PTHREAD_CANCEL_DISABLE { return EINVAL; }
5024    if let Some(slot) = find_thread() {
5025        if !oldstate.is_null() { *oldstate = slot.cancel_state; }
5026        slot.cancel_state = state;
5027        0
5028    } else { EINVAL }
5029}
5030#[no_mangle]
5031pub unsafe extern "C" fn pthread_setcanceltype(type_: c_int, oldtype: *mut c_int) -> c_int {
5032    if type_ != PTHREAD_CANCEL_DEFERRED && type_ != PTHREAD_CANCEL_ASYNCHRONOUS { return EINVAL; }
5033    if let Some(slot) = find_thread() {
5034        if !oldtype.is_null() { *oldtype = slot.cancel_type; }
5035        slot.cancel_type = type_;
5036        0
5037    } else { EINVAL }
5038}
5039#[no_mangle]
5040pub unsafe extern "C" fn pthread_testcancel() {
5041    if let Some(slot) = find_thread() {
5042        if slot.cancel != 0 && slot.cancel_state == PTHREAD_CANCEL_ENABLE {
5043            do_cancel();
5044        }
5045    }
5046}
5047
5048#[no_mangle]
5049pub unsafe extern "C" fn _pthread_cleanup_push(cb: *mut __ptcb, f: Option<unsafe extern "C" fn(*mut c_void)>, x: *mut c_void) {
5050    (*cb).__f = f;
5051    (*cb).__x = x;
5052    if let Some(slot) = find_thread() {
5053        (*cb).__next = slot.cancelbuf;
5054        slot.cancelbuf = cb;
5055    } else {
5056        (*cb).__next = core::ptr::null_mut();
5057    }
5058}
5059
5060#[no_mangle]
5061pub unsafe extern "C" fn _pthread_cleanup_pop(cb: *mut __ptcb, run: c_int) {
5062    if let Some(slot) = find_thread() {
5063        slot.cancelbuf = (*cb).__next;
5064    }
5065    if run != 0 {
5066        if let Some(f) = (*cb).__f {
5067            f((*cb).__x);
5068        }
5069    }
5070}
5071
5072#[no_mangle]
5073pub unsafe extern "C" fn pthread_kill(thread: PthreadT, sig: c_int) -> c_int {
5074    let slot = thread as *mut Thread;
5075    if slot.is_null() { return EINVAL; }
5076    let tid = (*slot).tid;
5077    if tid <= 0 { return EINVAL; }
5078    if sys_tgkill(sys_getpid() as c_int, tid, sig) < 0 { -1 } else { 0 }
5079}
5080
5081#[no_mangle]
5082pub unsafe extern "C" fn pthread_sigmask(how: c_int, set: *const SigSetT, oldset: *mut SigSetT) -> c_int {
5083    sigprocmask(how, set, oldset)
5084}
5085
5086
5087#[repr(C)]
5088pub struct lconv {
5089    pub decimal_point: *mut c_char,
5090    pub thousands_sep: *mut c_char,
5091    pub grouping: *mut c_char,
5092    pub int_curr_symbol: *mut c_char,
5093    pub currency_symbol: *mut c_char,
5094    pub mon_decimal_point: *mut c_char,
5095    pub mon_thousands_sep: *mut c_char,
5096    pub mon_grouping: *mut c_char,
5097    pub positive_sign: *mut c_char,
5098    pub negative_sign: *mut c_char,
5099    pub int_frac_digits: c_char,
5100    pub frac_digits: c_char,
5101    pub p_cs_precedes: c_char,
5102    pub p_sep_by_space: c_char,
5103    pub n_cs_precedes: c_char,
5104    pub n_sep_by_space: c_char,
5105    pub p_sign_posn: c_char,
5106    pub n_sign_posn: c_char,
5107    pub int_p_cs_precedes: c_char,
5108    pub int_p_sep_by_space: c_char,
5109    pub int_n_cs_precedes: c_char,
5110    pub int_n_sep_by_space: c_char,
5111    pub int_p_sign_posn: c_char,
5112    pub int_n_sign_posn: c_char,
5113}
5114
5115static UTF8_NAME: [u8; 6] = [b'U', b'T', b'F', b'-', b'8', 0];
5116static C_NAME: [u8; 2] = [b'C', 0];
5117static mut LOCALE_NAME: *const c_char = C_NAME.as_ptr() as *const c_char;
5118static mut LOCALE_CTYPE_UTF8: bool = true;
5119static mut EMPTY_STR: [c_char; 1] = [0];
5120static mut DECIMAL_POINT: [c_char; 2] = [b'.' as c_char, 0];
5121static mut LCONV: lconv = lconv {
5122    decimal_point: core::ptr::null_mut(),
5123    thousands_sep: core::ptr::null_mut(),
5124    grouping: core::ptr::null_mut(),
5125    int_curr_symbol: core::ptr::null_mut(),
5126    currency_symbol: core::ptr::null_mut(),
5127    mon_decimal_point: core::ptr::null_mut(),
5128    mon_thousands_sep: core::ptr::null_mut(),
5129    mon_grouping: core::ptr::null_mut(),
5130    positive_sign: core::ptr::null_mut(),
5131    negative_sign: core::ptr::null_mut(),
5132    int_frac_digits: (-1i32) as c_char,
5133    frac_digits: (-1i32) as c_char,
5134    p_cs_precedes: (-1i32) as c_char,
5135    p_sep_by_space: (-1i32) as c_char,
5136    n_cs_precedes: (-1i32) as c_char,
5137    n_sep_by_space: (-1i32) as c_char,
5138    p_sign_posn: (-1i32) as c_char,
5139    n_sign_posn: (-1i32) as c_char,
5140    int_p_cs_precedes: (-1i32) as c_char,
5141    int_p_sep_by_space: (-1i32) as c_char,
5142    int_n_cs_precedes: (-1i32) as c_char,
5143    int_n_sep_by_space: (-1i32) as c_char,
5144    int_p_sign_posn: (-1i32) as c_char,
5145    int_n_sign_posn: (-1i32) as c_char,
5146};
5147
5148unsafe fn cstr_contains_ci(s: *const u8, needle: &[u8]) -> bool {
5149    let len = strlen(s as *const c_char) as usize;
5150    let s_slice = core::slice::from_raw_parts(s, len);
5151    if needle.len() > len { return false; }
5152    for i in 0..=len - needle.len() {
5153        if s_slice[i..i + needle.len()].eq_ignore_ascii_case(needle) {
5154            return true;
5155        }
5156    }
5157    false
5158}
5159
5160#[no_mangle]
5161pub unsafe extern "C" fn setlocale(_category: c_int, locale: *const c_char) -> *mut c_char {
5162    if locale.is_null() || *locale == 0 {
5163        return LOCALE_NAME as *mut c_char;
5164    }
5165    let name = locale as *const u8;
5166    if strcmp(name, b"C\0".as_ptr()) == 0 || strcmp(name, b"POSIX\0".as_ptr()) == 0 {
5167        LOCALE_CTYPE_UTF8 = false;
5168        return LOCALE_NAME as *mut c_char;
5169    }
5170    if cstr_contains_ci(name, b"UTF-8") || cstr_contains_ci(name, b"UTF8") {
5171        LOCALE_CTYPE_UTF8 = true;
5172        return LOCALE_NAME as *mut c_char;
5173    }
5174    core::ptr::null_mut()
5175}
5176
5177#[no_mangle]
5178pub unsafe extern "C" fn localeconv() -> *mut lconv {
5179    let empty = core::ptr::addr_of_mut!(EMPTY_STR) as *mut c_char;
5180    let lconv = core::ptr::addr_of_mut!(LCONV);
5181    (*lconv).decimal_point = core::ptr::addr_of_mut!(DECIMAL_POINT) as *mut c_char;
5182    (*lconv).thousands_sep = empty;
5183    (*lconv).grouping = empty;
5184    (*lconv).int_curr_symbol = empty;
5185    (*lconv).currency_symbol = empty;
5186    (*lconv).mon_decimal_point = empty;
5187    (*lconv).mon_thousands_sep = empty;
5188    (*lconv).mon_grouping = empty;
5189    (*lconv).positive_sign = empty;
5190    (*lconv).negative_sign = empty;
5191    lconv
5192}
5193
5194pub type locale_t = *mut c_void;
5195static mut CURRENT_LOCALE: locale_t = LC_GLOBAL_LOCALE;
5196
5197static mut C_LOCALE_STORAGE: c_int = 0;
5198const C_LOCALE: locale_t = core::ptr::addr_of_mut!(C_LOCALE_STORAGE) as locale_t;
5199const LC_GLOBAL_LOCALE: locale_t = usize::MAX as locale_t;
5200
5201#[no_mangle]
5202pub unsafe extern "C" fn newlocale(_mask: c_int, name: *const c_char, base: locale_t) -> locale_t {
5203    if !name.is_null() && *name != 0 {
5204        let n = name as *const u8;
5205        if strcmp(n, b"C\0".as_ptr()) != 0
5206            && strcmp(n, b"POSIX\0".as_ptr()) != 0
5207        {
5208            return core::ptr::null_mut();
5209        }
5210    }
5211    if base.is_null() || base == C_LOCALE || base == LC_GLOBAL_LOCALE {
5212        C_LOCALE
5213    } else {
5214        core::ptr::null_mut()
5215    }
5216}
5217
5218#[no_mangle]
5219pub unsafe extern "C" fn freelocale(_loc: locale_t) {}
5220
5221#[no_mangle]
5222pub unsafe extern "C" fn uselocale(loc: locale_t) -> locale_t {
5223    let old = CURRENT_LOCALE;
5224    if !loc.is_null() {
5225        CURRENT_LOCALE = loc;
5226    }
5227    old
5228}
5229
5230#[no_mangle]
5231pub unsafe extern "C" fn duplocale(loc: locale_t) -> locale_t {
5232    if loc.is_null() {
5233        return core::ptr::null_mut();
5234    }
5235    C_LOCALE
5236}
5237
5238const NL_ITEM_CODESET: c_int = 14;
5239const NL_ITEM_RADIXCHAR: c_int = 0x10000;
5240const NL_ITEM_THOUSEP: c_int = 0x10001;
5241const NL_ITEM_YESEXPR: c_int = 0x50000;
5242const NL_ITEM_NOEXPR: c_int = 0x50001;
5243
5244const C_TIME_STRINGS: &[u8] = b"Sun\0Mon\0Tue\0Wed\0Thu\0Fri\0Sat\0\
5245Sunday\0Monday\0Tuesday\0Wednesday\0Thursday\0Friday\0Saturday\0\
5246Jan\0Feb\0Mar\0Apr\0May\0Jun\0Jul\0Aug\0Sep\0Oct\0Nov\0Dec\0\
5247January\0February\0March\0April\0May\0June\0July\0August\0\
5248September\0October\0November\0December\0\
5249AM\0PM\0\
5250%a %b %e %T %Y\0%m/%d/%y\0%H:%M:%S\0%I:%M:%S %p\0\
5251\0\0%m/%d/%y\00123456789\0%a %b %e %T %Y\0%H:%M:%S\0";
5252
5253const C_NUMERIC_STRINGS: &[u8] = b".\0\0";
5254const C_MESSAGES_STRINGS: &[u8] = b"^[yY]\0^[nN]\0";
5255
5256unsafe fn langinfo_str(table: *const u8, mut idx: c_int) -> *mut c_char {
5257    let mut p = table;
5258    while idx > 0 {
5259        while *p != 0 { p = p.add(1); }
5260        p = p.add(1);
5261        idx -= 1;
5262    }
5263    p as *mut c_char
5264}
5265
5266#[no_mangle]
5267pub unsafe extern "C" fn nl_langinfo(item: c_int) -> *mut c_char {
5268    if item == NL_ITEM_CODESET {
5269        return if LOCALE_CTYPE_UTF8 {
5270            b"UTF-8\0".as_ptr() as *mut c_char
5271        } else {
5272            b"US-ASCII\0".as_ptr() as *mut c_char
5273        };
5274    }
5275    let cat = item >> 16;
5276    let idx = item & 0xFFFF;
5277    match cat {
5278        1 => {
5279            if idx > 1 { return b"\0".as_ptr() as *mut c_char; }
5280            langinfo_str(C_NUMERIC_STRINGS.as_ptr(), idx)
5281        }
5282        2 => {
5283            if idx > 49 { return b"\0".as_ptr() as *mut c_char; }
5284            langinfo_str(C_TIME_STRINGS.as_ptr(), idx)
5285        }
5286        5 => {
5287            if idx > 1 { return b"\0".as_ptr() as *mut c_char; }
5288            langinfo_str(C_MESSAGES_STRINGS.as_ptr(), idx)
5289        }
5290        _ => b"\0".as_ptr() as *mut c_char,
5291    }
5292}
5293
5294pub type nl_catd = *mut c_void;
5295
5296#[no_mangle]
5297pub unsafe extern "C" fn catopen(_name: *const c_char, _oflag: c_int) -> nl_catd {
5298    !0usize as nl_catd
5299}
5300
5301#[no_mangle]
5302pub unsafe extern "C" fn catclose(_catd: nl_catd) -> c_int { 0 }
5303
5304#[no_mangle]
5305pub unsafe extern "C" fn catgets(catd: nl_catd, _set_id: c_int, _msg_id: c_int, s: *const c_char) -> *mut c_char {
5306    if catd == !0usize as nl_catd { return s as *mut c_char; }
5307    s as *mut c_char
5308}
5309
5310pub type IconvT = *mut c_void;
5311
5312const ENC_UTF8: i32 = 1;
5313const ENC_UTF16LE: i32 = 2;
5314const ENC_UTF16BE: i32 = 3;
5315const ENC_UTF32LE: i32 = 4;
5316const ENC_UTF32BE: i32 = 5;
5317const ENC_WCHAR_T: i32 = 6;
5318const ENC_ASCII: i32 = 7;
5319const ENC_LATIN1: i32 = 8;
5320const ENC_WIN1252: i32 = 9;
5321const ENC_WIN1251: i32 = 10;
5322const ENC_KOI8R: i32 = 11;
5323const ENC_GBK: i32 = 12;
5324const ENC_GB2312: i32 = 13;
5325const ENC_BIG5: i32 = 14;
5326const ENC_EUCJP: i32 = 15;
5327const ENC_SHIFTJIS: i32 = 16;
5328const ENC_ISO8859_2: i32 = 17;
5329const ENC_ISO8859_3: i32 = 18;
5330const ENC_ISO8859_4: i32 = 19;
5331const ENC_ISO8859_5: i32 = 20;
5332const ENC_ISO8859_6: i32 = 21;
5333const ENC_ISO8859_7: i32 = 22;
5334const ENC_ISO8859_8: i32 = 23;
5335const ENC_ISO8859_9: i32 = 24;
5336const ENC_ISO8859_10: i32 = 25;
5337const ENC_ISO8859_11: i32 = 26;
5338const ENC_ISO8859_13: i32 = 27;
5339const ENC_ISO8859_14: i32 = 28;
5340const ENC_ISO8859_15: i32 = 29;
5341const ENC_ISO8859_16: i32 = 30;
5342
5343include!("iconv_iso8859.rs");
5344
5345fn make_cd(from: i32, to: i32) -> IconvT {
5346    ((from as usize) << 16 | (to as usize) << 1 | 1) as IconvT
5347}
5348fn extract_from(cd: IconvT) -> i32 {
5349    ((cd as usize) >> 16) as i32
5350}
5351fn extract_to(cd: IconvT) -> i32 {
5352    (((cd as usize) >> 1) & 0x7fff) as i32
5353}
5354
5355unsafe fn match_name(input: *const u8, target: &[u8]) -> bool {
5356    let mut i = input;
5357    let mut j = 0;
5358    while *i != 0 && j < target.len() {
5359        let mut c = *i;
5360        if !c.is_ascii_alphanumeric() { i = i.add(1); continue; }
5361        c = c.to_ascii_lowercase();
5362        if c != target[j] { return false; }
5363        i = i.add(1);
5364        j += 1;
5365    }
5366    while *i != 0 && !(*i).is_ascii_alphanumeric() { i = i.add(1); }
5367    *i == 0 && j == target.len()
5368}
5369
5370unsafe fn find_encoding(name: *const u8) -> i32 {
5371    if name.is_null() { return -1; }
5372    if match_name(name, b"utf8") || match_name(name, b"utf-8") || match_name(name, b"char") { return ENC_UTF8; }
5373    if match_name(name, b"utf16le") || match_name(name, b"utf-16le") { return ENC_UTF16LE; }
5374    if match_name(name, b"utf16be") || match_name(name, b"utf-16be") { return ENC_UTF16BE; }
5375    if match_name(name, b"utf32le") || match_name(name, b"utf-32le") || match_name(name, b"ucs4le") { return ENC_UTF32LE; }
5376    if match_name(name, b"utf32be") || match_name(name, b"utf-32be") || match_name(name, b"ucs4be") { return ENC_UTF32BE; }
5377    if match_name(name, b"wchart") || match_name(name, b"wchar-t") { return ENC_WCHAR_T; }
5378    if match_name(name, b"ascii") || match_name(name, b"usascii") || match_name(name, b"iso646") { return ENC_ASCII; }
5379    if match_name(name, b"iso88591") || match_name(name, b"iso-8859-1") || match_name(name, b"latin1") { return ENC_LATIN1; }
5380    if match_name(name, b"iso88592") || match_name(name, b"iso-8859-2") { return ENC_ISO8859_2; }
5381    if match_name(name, b"iso88593") || match_name(name, b"iso-8859-3") { return ENC_ISO8859_3; }
5382    if match_name(name, b"iso88594") || match_name(name, b"iso-8859-4") { return ENC_ISO8859_4; }
5383    if match_name(name, b"iso88595") || match_name(name, b"iso-8859-5") { return ENC_ISO8859_5; }
5384    if match_name(name, b"iso88596") || match_name(name, b"iso-8859-6") { return ENC_ISO8859_6; }
5385    if match_name(name, b"iso88597") || match_name(name, b"iso-8859-7") { return ENC_ISO8859_7; }
5386    if match_name(name, b"iso88598") || match_name(name, b"iso-8859-8") { return ENC_ISO8859_8; }
5387    if match_name(name, b"iso88599") || match_name(name, b"iso-8859-9") { return ENC_ISO8859_9; }
5388    if match_name(name, b"iso885910") || match_name(name, b"iso-8859-10") { return ENC_ISO8859_10; }
5389    if match_name(name, b"iso885911") || match_name(name, b"iso-8859-11") || match_name(name, b"tis620") { return ENC_ISO8859_11; }
5390    if match_name(name, b"iso885913") || match_name(name, b"iso-8859-13") { return ENC_ISO8859_13; }
5391    if match_name(name, b"iso885914") || match_name(name, b"iso-8859-14") { return ENC_ISO8859_14; }
5392    if match_name(name, b"iso885915") || match_name(name, b"iso-8859-15") { return ENC_ISO8859_15; }
5393    if match_name(name, b"iso885916") || match_name(name, b"iso-8859-16") { return ENC_ISO8859_16; }
5394    if match_name(name, b"cp1252") || match_name(name, b"windows1252") || match_name(name, b"windows-1252") { return ENC_WIN1252; }
5395    if match_name(name, b"cp1251") || match_name(name, b"windows1251") || match_name(name, b"windows-1251") { return ENC_WIN1251; }
5396    if match_name(name, b"koi8r") || match_name(name, b"koi8-r") { return ENC_KOI8R; }
5397    if match_name(name, b"gbk") || match_name(name, b"cp936") { return ENC_GBK; }
5398    if match_name(name, b"gb2312") { return ENC_GB2312; }
5399    if match_name(name, b"big5") || match_name(name, b"bigfive") || match_name(name, b"cp950") { return ENC_BIG5; }
5400    if match_name(name, b"eucjp") || match_name(name, b"euc-jp") { return ENC_EUCJP; }
5401    if match_name(name, b"shiftjis") || match_name(name, b"sjis") || match_name(name, b"cp932") { return ENC_SHIFTJIS; }
5402    -1
5403}
5404
5405fn uni_to_jis(c: u32) -> u16 {
5406    let mut b = 0usize;
5407    let mut nel = REV_JIS.len();
5408    loop {
5409        let i = nel / 2;
5410        let j = REV_JIS[b + i] as usize;
5411        let row = j / 256;
5412        let col = j % 256;
5413        let d = JIS0208[row * 94 + col] as u32;
5414        if d == c { return (j as u16) + 0x2121; }
5415        if nel == 1 { return 0; }
5416        if c < d { nel /= 2; }
5417        else { b += i; nel -= nel / 2; }
5418    }
5419}
5420
5421unsafe fn iconv_decode(enc: i32, src: *const u8, src_left: usize) -> (u32, usize, c_int) {
5422    if src_left == 0 { return (0, 0, EINVAL); }
5423    match enc {
5424        ENC_UTF8 => {
5425            let c = *src;
5426            if c < 128 { return (c as u32, 1, 0); }
5427            if c < 0xC2 { return (0, 0, EILSEQ); }
5428            if c < 0xE0 {
5429                if src_left < 2 || (*src.add(1) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
5430                return (((c as u32 & 0x1F) << 6) | (*src.add(1) as u32 & 0x3F), 2, 0);
5431            }
5432            if c < 0xF0 {
5433                if src_left < 3 || (*src.add(1) & 0xC0) != 0x80 || (*src.add(2) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
5434                let cp = ((c as u32 & 0x0F) << 12) | ((*src.add(1) as u32 & 0x3F) << 6) | (*src.add(2) as u32 & 0x3F);
5435                if cp < 0x800 { return (0, 0, EILSEQ); }
5436                return (cp, 3, 0);
5437            }
5438            if c < 0xF8 {
5439                if src_left < 4 || (*src.add(1) & 0xC0) != 0x80 || (*src.add(2) & 0xC0) != 0x80 || (*src.add(3) & 0xC0) != 0x80 { return (0, 0, EILSEQ); }
5440                let cp = ((c as u32 & 0x07) << 18) | ((*src.add(1) as u32 & 0x3F) << 12) | ((*src.add(2) as u32 & 0x3F) << 6) | (*src.add(3) as u32 & 0x3F);
5441                if cp < 0x10000 || cp >= 0x110000 { return (0, 0, EILSEQ); }
5442                return (cp, 4, 0);
5443            }
5444            (0, 0, EILSEQ)
5445        }
5446        ENC_UTF16LE => {
5447            if src_left < 2 { return (0, 0, EINVAL); }
5448            let c = (*src as u32) | ((*src.add(1) as u32) << 8);
5449            if c >= 0xD800 && c <= 0xDBFF {
5450                if src_left < 4 { return (0, 0, EINVAL); }
5451                let d = (*src.add(2) as u32) | ((*src.add(3) as u32) << 8);
5452                if d < 0xDC00 || d > 0xDFFF { return (0, 0, EILSEQ); }
5453                return (((c - 0xD800) << 10) + (d - 0xDC00) + 0x10000, 4, 0);
5454            }
5455            if c >= 0xDC00 && c <= 0xDFFF { return (0, 0, EILSEQ); }
5456            (c, 2, 0)
5457        }
5458        ENC_UTF16BE => {
5459            if src_left < 2 { return (0, 0, EINVAL); }
5460            let c = ((*src as u32) << 8) | (*src.add(1) as u32);
5461            if c >= 0xD800 && c <= 0xDBFF {
5462                if src_left < 4 { return (0, 0, EINVAL); }
5463                let d = ((*src.add(2) as u32) << 8) | (*src.add(3) as u32);
5464                if d < 0xDC00 || d > 0xDFFF { return (0, 0, EILSEQ); }
5465                return (((c - 0xD800) << 10) + (d - 0xDC00) + 0x10000, 4, 0);
5466            }
5467            if c >= 0xDC00 && c <= 0xDFFF { return (0, 0, EILSEQ); }
5468            (c, 2, 0)
5469        }
5470        ENC_UTF32LE => {
5471            if src_left < 4 { return (0, 0, EINVAL); }
5472            let c = (*src as u32) | ((*src.add(1) as u32) << 8) | ((*src.add(2) as u32) << 16) | ((*src.add(3) as u32) << 24);
5473            if c >= 0xD800 && c < 0xE000 { return (0, 0, EILSEQ); }
5474            if c >= 0x110000 { return (0, 0, EILSEQ); }
5475            (c, 4, 0)
5476        }
5477        ENC_UTF32BE => {
5478            if src_left < 4 { return (0, 0, EINVAL); }
5479            let c = ((*src as u32) << 24) | ((*src.add(1) as u32) << 16) | ((*src.add(2) as u32) << 8) | (*src.add(3) as u32);
5480            if c >= 0xD800 && c < 0xE000 { return (0, 0, EILSEQ); }
5481            if c >= 0x110000 { return (0, 0, EILSEQ); }
5482            (c, 4, 0)
5483        }
5484        ENC_WCHAR_T => {
5485            if src_left < 4 { return (0, 0, EINVAL); }
5486            let c = *(src as *const u32);
5487            if c >= 0xD800 && c < 0xE000 { return (0, 0, EILSEQ); }
5488            if c >= 0x110000 { return (0, 0, EILSEQ); }
5489            (c, 4, 0)
5490        }
5491        ENC_ASCII => {
5492            let c = *src as u32;
5493            if c >= 128 { return (0, 0, EILSEQ); }
5494            (c, 1, 0)
5495        }
5496        ENC_LATIN1 => (*src as u32, 1, 0),
5497        ENC_ISO8859_2 => (iso8859_to_u(&ISO8859_2_TO_U, *src), 1, 0),
5498        ENC_ISO8859_3 => (iso8859_to_u(&ISO8859_3_TO_U, *src), 1, 0),
5499        ENC_ISO8859_4 => (iso8859_to_u(&ISO8859_4_TO_U, *src), 1, 0),
5500        ENC_ISO8859_5 => (iso8859_to_u(&ISO8859_5_TO_U, *src), 1, 0),
5501        ENC_ISO8859_6 => (iso8859_to_u(&ISO8859_6_TO_U, *src), 1, 0),
5502        ENC_ISO8859_7 => (iso8859_to_u(&ISO8859_7_TO_U, *src), 1, 0),
5503        ENC_ISO8859_8 => (iso8859_to_u(&ISO8859_8_TO_U, *src), 1, 0),
5504        ENC_ISO8859_9 => (iso8859_to_u(&ISO8859_9_TO_U, *src), 1, 0),
5505        ENC_ISO8859_10 => (iso8859_to_u(&ISO8859_10_TO_U, *src), 1, 0),
5506        ENC_ISO8859_11 => (iso8859_to_u(&ISO8859_11_TO_U, *src), 1, 0),
5507        ENC_ISO8859_13 => (iso8859_to_u(&ISO8859_13_TO_U, *src), 1, 0),
5508        ENC_ISO8859_14 => (iso8859_to_u(&ISO8859_14_TO_U, *src), 1, 0),
5509        ENC_ISO8859_15 => (iso8859_to_u(&ISO8859_15_TO_U, *src), 1, 0),
5510        ENC_ISO8859_16 => (iso8859_to_u(&ISO8859_16_TO_U, *src), 1, 0),
5511        ENC_WIN1252 => {
5512            let b = *src;
5513            if b < 128 { return (b as u32, 1, 0); }
5514            (WIN1252_TO_U[b as usize - 128], 1, 0)
5515        }
5516        ENC_WIN1251 => {
5517            let b = *src;
5518            if b < 128 { return (b as u32, 1, 0); }
5519            (WIN1251_TO_U[b as usize - 128], 1, 0)
5520        }
5521        ENC_KOI8R => {
5522            let b = *src;
5523            if b < 128 { return (b as u32, 1, 0); }
5524            (KOI8R_TO_U[b as usize - 128], 1, 0)
5525        }
5526        ENC_GBK | ENC_GB2312 => {
5527            let c = *src;
5528            if c < 128 { return (c as u32, 1, 0); }
5529            if c == 128 { return (0x20AC, 1, 0); }
5530            if src_left < 2 { return (0, 0, EINVAL); }
5531            let d = *src.add(1);
5532            if d < 0x40 || d == 0x7F || d > 0xFE { return (0, 0, EILSEQ); }
5533            let row = (c as usize).wrapping_sub(0x81);
5534            if row >= 126 { return (0, 0, EILSEQ); }
5535            let mut col = (d as usize) - 0x40;
5536            if col > 63 { col -= 1; }
5537            let cp = GB18030_TABLE[row * 190 + col] as u32;
5538            if cp == 0 { return (0, 0, EILSEQ); }
5539            (cp, 2, 0)
5540        }
5541        ENC_BIG5 => {
5542            let c = *src;
5543            if c < 128 { return (c as u32, 1, 0); }
5544            if src_left < 2 { return (0, 0, EINVAL); }
5545            let d = *src.add(1);
5546            if d < 0x40 || d == 0x7F || d > 0xFE { return (0, 0, EILSEQ); }
5547            let mut col = (d as usize) - 0x40;
5548            if col > 0x3E { col -= 0x22; }
5549            if c >= 0xA1 && c < 0xFA {
5550                let row = (c as usize) - 0xA1;
5551                if row >= 89 { return (0, 0, EILSEQ); }
5552                let cp = BIG5_TABLE[row * 157 + col] as u32;
5553                if cp == 0 { return (0, 0, EILSEQ); }
5554                return (cp, 2, 0);
5555            }
5556            (0, 0, EILSEQ)
5557        }
5558        ENC_EUCJP => {
5559            let c = *src;
5560            if c < 128 { return (c as u32, 1, 0); }
5561            if c == 0x8E {
5562                if src_left < 2 { return (0, 0, EINVAL); }
5563                let d = *src.add(1);
5564                if d < 0xA1 || d > 0xDF { return (0, 0, EILSEQ); }
5565                return ((d as u32) + 0xFF61 - 0xA1, 2, 0);
5566            }
5567            if c < 0xA1 { return (0, 0, EILSEQ); }
5568            if src_left < 2 { return (0, 0, EINVAL); }
5569            let d = *src.add(1);
5570            if d < 0xA1 || d > 0xFE { return (0, 0, EILSEQ); }
5571            let row = (c as usize) - 0xA1;
5572            let col = (d as usize) - 0xA1;
5573            if row >= 84 || col >= 94 { return (0, 0, EILSEQ); }
5574            let cp = JIS0208[row * 94 + col] as u32;
5575            if cp == 0 { return (0, 0, EILSEQ); }
5576            (cp, 2, 0)
5577        }
5578        ENC_SHIFTJIS => {
5579            let c = *src;
5580            if c < 128 { return (c as u32, 1, 0); }
5581            if c >= 0xA1 && c <= 0xDF { return ((c as u32) + 0xFF61 - 0xA1, 1, 0); }
5582            if src_left < 2 { return (0, 0, EINVAL); }
5583            let d = *src.add(1);
5584            if d < 0x40 || d == 0x7F || d > 0xFC { return (0, 0, EILSEQ); }
5585            let row = if c >= 129 && c <= 159 { (c as usize) - 129 }
5586                      else if c >= 224 && c <= 239 { (c as usize) - 193 }
5587                      else { return (0, 0, EILSEQ); };
5588            let (col, row_adj) = if d >= 64 && d <= 158 && d != 127 {
5589                let mut dd = d as usize;
5590                if dd > 127 { dd -= 1; }
5591                (dd - 64, row * 2)
5592            } else if d >= 159 && d <= 252 {
5593                ((d as usize) - 159, row * 2 + 1)
5594            } else {
5595                return (0, 0, EILSEQ);
5596            };
5597            if row_adj >= 84 { return (0, 0, EILSEQ); }
5598            let cp = JIS0208[row_adj * 94 + col] as u32;
5599            if cp == 0 { return (0, 0, EILSEQ); }
5600            (cp, 2, 0)
5601        }
5602        _ => (0, 0, EILSEQ),
5603    }
5604}
5605
5606unsafe fn iconv_encode(enc: i32, c: u32, dst: *mut u8, dst_left: usize) -> (usize, c_int) {
5607    match enc {
5608        ENC_UTF8 => {
5609            if c < 0x80 {
5610                if dst_left < 1 { return (0, E2BIG); }
5611                *dst = c as u8; return (1, 0);
5612            }
5613            if c < 0x800 {
5614                if dst_left < 2 { return (0, E2BIG); }
5615                *dst = (0xC0 | (c >> 6)) as u8;
5616                *dst.add(1) = (0x80 | (c & 0x3F)) as u8;
5617                return (2, 0);
5618            }
5619            if c < 0x10000 {
5620                if dst_left < 3 { return (0, E2BIG); }
5621                *dst = (0xE0 | (c >> 12)) as u8;
5622                *dst.add(1) = (0x80 | ((c >> 6) & 0x3F)) as u8;
5623                *dst.add(2) = (0x80 | (c & 0x3F)) as u8;
5624                return (3, 0);
5625            }
5626            if dst_left < 4 { return (0, E2BIG); }
5627            *dst = (0xF0 | (c >> 18)) as u8;
5628            *dst.add(1) = (0x80 | ((c >> 12) & 0x3F)) as u8;
5629            *dst.add(2) = (0x80 | ((c >> 6) & 0x3F)) as u8;
5630            *dst.add(3) = (0x80 | (c & 0x3F)) as u8;
5631            (4, 0)
5632        }
5633        ENC_UTF16LE => {
5634            if c < 0x10000 {
5635                if dst_left < 2 { return (0, E2BIG); }
5636                *dst = (c & 0xFF) as u8;
5637                *dst.add(1) = (c >> 8) as u8;
5638                return (2, 0);
5639            }
5640            if dst_left < 4 { return (0, E2BIG); }
5641            let c = c - 0x10000;
5642            let hi = ((c >> 10) + 0xD800) as u16;
5643            let lo = ((c & 0x3FF) + 0xDC00) as u16;
5644            *dst = (hi & 0xFF) as u8; *dst.add(1) = (hi >> 8) as u8;
5645            *dst.add(2) = (lo & 0xFF) as u8; *dst.add(3) = (lo >> 8) as u8;
5646            (4, 0)
5647        }
5648        ENC_UTF16BE => {
5649            if c < 0x10000 {
5650                if dst_left < 2 { return (0, E2BIG); }
5651                *dst = (c >> 8) as u8;
5652                *dst.add(1) = (c & 0xFF) as u8;
5653                return (2, 0);
5654            }
5655            if dst_left < 4 { return (0, E2BIG); }
5656            let c = c - 0x10000;
5657            let hi = ((c >> 10) + 0xD800) as u16;
5658            let lo = ((c & 0x3FF) + 0xDC00) as u16;
5659            *dst = (hi >> 8) as u8; *dst.add(1) = (hi & 0xFF) as u8;
5660            *dst.add(2) = (lo >> 8) as u8; *dst.add(3) = (lo & 0xFF) as u8;
5661            (4, 0)
5662        }
5663        ENC_UTF32LE => {
5664            if dst_left < 4 { return (0, E2BIG); }
5665            *dst = (c & 0xFF) as u8; *dst.add(1) = ((c >> 8) & 0xFF) as u8;
5666            *dst.add(2) = ((c >> 16) & 0xFF) as u8; *dst.add(3) = (c >> 24) as u8;
5667            (4, 0)
5668        }
5669        ENC_UTF32BE => {
5670            if dst_left < 4 { return (0, E2BIG); }
5671            *dst = (c >> 24) as u8; *dst.add(1) = ((c >> 16) & 0xFF) as u8;
5672            *dst.add(2) = ((c >> 8) & 0xFF) as u8; *dst.add(3) = (c & 0xFF) as u8;
5673            (4, 0)
5674        }
5675        ENC_WCHAR_T => {
5676            if dst_left < 4 { return (0, E2BIG); }
5677            *(dst as *mut u32) = c;
5678            (4, 0)
5679        }
5680        ENC_ASCII => {
5681            if c < 128 {
5682                if dst_left < 1 { return (0, E2BIG); }
5683                *dst = c as u8; return (1, 0);
5684            }
5685            (0, EILSEQ)
5686        }
5687        ENC_LATIN1 => {
5688            if c < 256 {
5689                if dst_left < 1 { return (0, E2BIG); }
5690                *dst = c as u8; return (1, 0);
5691            }
5692            (0, EILSEQ)
5693        }
5694        ENC_ISO8859_2 => {
5695            if let Some(b) = u_to_iso8859(&ISO8859_2_TO_U, c) {
5696                if dst_left < 1 { return (0, E2BIG); }
5697                *dst = b; return (1, 0);
5698            }
5699            (0, EILSEQ)
5700        }
5701        ENC_ISO8859_3 => {
5702            if let Some(b) = u_to_iso8859(&ISO8859_3_TO_U, c) {
5703                if dst_left < 1 { return (0, E2BIG); }
5704                *dst = b; return (1, 0);
5705            }
5706            (0, EILSEQ)
5707        }
5708        ENC_ISO8859_4 => {
5709            if let Some(b) = u_to_iso8859(&ISO8859_4_TO_U, c) {
5710                if dst_left < 1 { return (0, E2BIG); }
5711                *dst = b; return (1, 0);
5712            }
5713            (0, EILSEQ)
5714        }
5715        ENC_ISO8859_5 => {
5716            if let Some(b) = u_to_iso8859(&ISO8859_5_TO_U, c) {
5717                if dst_left < 1 { return (0, E2BIG); }
5718                *dst = b; return (1, 0);
5719            }
5720            (0, EILSEQ)
5721        }
5722        ENC_ISO8859_6 => {
5723            if let Some(b) = u_to_iso8859(&ISO8859_6_TO_U, c) {
5724                if dst_left < 1 { return (0, E2BIG); }
5725                *dst = b; return (1, 0);
5726            }
5727            (0, EILSEQ)
5728        }
5729        ENC_ISO8859_7 => {
5730            if let Some(b) = u_to_iso8859(&ISO8859_7_TO_U, c) {
5731                if dst_left < 1 { return (0, E2BIG); }
5732                *dst = b; return (1, 0);
5733            }
5734            (0, EILSEQ)
5735        }
5736        ENC_ISO8859_8 => {
5737            if let Some(b) = u_to_iso8859(&ISO8859_8_TO_U, c) {
5738                if dst_left < 1 { return (0, E2BIG); }
5739                *dst = b; return (1, 0);
5740            }
5741            (0, EILSEQ)
5742        }
5743        ENC_ISO8859_9 => {
5744            if let Some(b) = u_to_iso8859(&ISO8859_9_TO_U, c) {
5745                if dst_left < 1 { return (0, E2BIG); }
5746                *dst = b; return (1, 0);
5747            }
5748            (0, EILSEQ)
5749        }
5750        ENC_ISO8859_10 => {
5751            if let Some(b) = u_to_iso8859(&ISO8859_10_TO_U, c) {
5752                if dst_left < 1 { return (0, E2BIG); }
5753                *dst = b; return (1, 0);
5754            }
5755            (0, EILSEQ)
5756        }
5757        ENC_ISO8859_11 => {
5758            if let Some(b) = u_to_iso8859(&ISO8859_11_TO_U, c) {
5759                if dst_left < 1 { return (0, E2BIG); }
5760                *dst = b; return (1, 0);
5761            }
5762            (0, EILSEQ)
5763        }
5764        ENC_ISO8859_13 => {
5765            if let Some(b) = u_to_iso8859(&ISO8859_13_TO_U, c) {
5766                if dst_left < 1 { return (0, E2BIG); }
5767                *dst = b; return (1, 0);
5768            }
5769            (0, EILSEQ)
5770        }
5771        ENC_ISO8859_14 => {
5772            if let Some(b) = u_to_iso8859(&ISO8859_14_TO_U, c) {
5773                if dst_left < 1 { return (0, E2BIG); }
5774                *dst = b; return (1, 0);
5775            }
5776            (0, EILSEQ)
5777        }
5778        ENC_ISO8859_15 => {
5779            if let Some(b) = u_to_iso8859(&ISO8859_15_TO_U, c) {
5780                if dst_left < 1 { return (0, E2BIG); }
5781                *dst = b; return (1, 0);
5782            }
5783            (0, EILSEQ)
5784        }
5785        ENC_ISO8859_16 => {
5786            if let Some(b) = u_to_iso8859(&ISO8859_16_TO_U, c) {
5787                if dst_left < 1 { return (0, E2BIG); }
5788                *dst = b; return (1, 0);
5789            }
5790            (0, EILSEQ)
5791        }
5792        ENC_WIN1252 => {
5793            if c < 128 {
5794                if dst_left < 1 { return (0, E2BIG); }
5795                *dst = c as u8; return (1, 0);
5796            }
5797            if c >= 0xA0 && c <= 0xFF && WIN1252_TO_U[c as usize - 128] == c {
5798                if dst_left < 1 { return (0, E2BIG); }
5799                *dst = c as u8; return (1, 0);
5800            }
5801            for i in 0..128usize {
5802                if WIN1252_TO_U[i] == c {
5803                    if dst_left < 1 { return (0, E2BIG); }
5804                    *dst = (i + 128) as u8; return (1, 0);
5805                }
5806            }
5807            (0, EILSEQ)
5808        }
5809        ENC_WIN1251 => {
5810            if c < 128 {
5811                if dst_left < 1 { return (0, E2BIG); }
5812                *dst = c as u8; return (1, 0);
5813            }
5814            for i in 0..128usize {
5815                if WIN1251_TO_U[i] == c {
5816                    if dst_left < 1 { return (0, E2BIG); }
5817                    *dst = (i + 128) as u8; return (1, 0);
5818                }
5819            }
5820            (0, EILSEQ)
5821        }
5822        ENC_KOI8R => {
5823            if c < 128 {
5824                if dst_left < 1 { return (0, E2BIG); }
5825                *dst = c as u8; return (1, 0);
5826            }
5827            for i in 0..128usize {
5828                if KOI8R_TO_U[i] == c {
5829                    if dst_left < 1 { return (0, E2BIG); }
5830                    *dst = (i + 128) as u8; return (1, 0);
5831                }
5832            }
5833            (0, EILSEQ)
5834        }
5835        ENC_GBK | ENC_GB2312 => {
5836            if c < 128 {
5837                if dst_left < 1 { return (0, E2BIG); }
5838                *dst = c as u8; return (1, 0);
5839            }
5840            if c == 0x20AC {
5841                if dst_left < 1 { return (0, E2BIG); }
5842                *dst = 128; return (1, 0);
5843            }
5844            for row in 0..126usize {
5845                for col in 0..190usize {
5846                    if GB18030_TABLE[row * 190 + col] as u32 == c {
5847                        if dst_left < 2 { return (0, E2BIG); }
5848                        *dst = (row + 0x81) as u8;
5849                        *dst.add(1) = if col <= 62 { (col + 0x40) as u8 } else { (col + 0x41) as u8 };
5850                        return (2, 0);
5851                    }
5852                }
5853            }
5854            (0, EILSEQ)
5855        }
5856        ENC_BIG5 => {
5857            if c < 128 {
5858                if dst_left < 1 { return (0, E2BIG); }
5859                *dst = c as u8; return (1, 0);
5860            }
5861            for row in 0..89usize {
5862                for col in 0..157usize {
5863                    if BIG5_TABLE[row * 157 + col] as u32 == c {
5864                        if dst_left < 2 { return (0, E2BIG); }
5865                        *dst = (row + 0xA1) as u8;
5866                        *dst.add(1) = if col <= 0x3E { (col + 0x40) as u8 } else { (col + 0x62) as u8 };
5867                        return (2, 0);
5868                    }
5869                }
5870            }
5871            (0, EILSEQ)
5872        }
5873        ENC_EUCJP => {
5874            if c < 128 {
5875                if dst_left < 1 { return (0, E2BIG); }
5876                *dst = c as u8; return (1, 0);
5877            }
5878            if c >= 0xFF61 && c <= 0xFF9F {
5879                if dst_left < 2 { return (0, E2BIG); }
5880                *dst = 0x8E;
5881                *dst.add(1) = (c - 0xFF61 + 0xA1) as u8;
5882                return (2, 0);
5883            }
5884            let jis = uni_to_jis(c);
5885            if jis == 0 { return (0, EILSEQ); }
5886            if dst_left < 2 { return (0, E2BIG); }
5887            *dst = ((jis >> 8) as u8).wrapping_add(0x80);
5888            *dst.add(1) = ((jis & 0xFF) as u8).wrapping_add(0x80);
5889            (2, 0)
5890        }
5891        ENC_SHIFTJIS => {
5892            if c < 128 {
5893                if dst_left < 1 { return (0, E2BIG); }
5894                *dst = c as u8; return (1, 0);
5895            }
5896            if c >= 0xFF61 && c <= 0xFF9F {
5897                if dst_left < 1 { return (0, E2BIG); }
5898                *dst = (c - 0xFF61 + 0xA1) as u8;
5899                return (1, 0);
5900            }
5901            let jis = uni_to_jis(c);
5902            if jis == 0 { return (0, EILSEQ); }
5903            if dst_left < 2 { return (0, E2BIG); }
5904            let r = (jis >> 8) as usize;
5905            let d = (jis & 0xFF) as usize;
5906            *dst = ((r + 1) / 2 + if r < 95 { 112 } else { 176 }) as u8;
5907            *dst.add(1) = if r % 2 == 1 { (d + 31 + d / 96) as u8 } else { (d + 126) as u8 };
5908            (2, 0)
5909        }
5910        _ => (0, EILSEQ),
5911    }
5912}
5913
5914#[no_mangle]
5915pub unsafe extern "C" fn iconv_open(tocode: *const c_char, fromcode: *const c_char) -> IconvT {
5916    let to = find_encoding(tocode as *const u8);
5917    let from = find_encoding(fromcode as *const u8);
5918    if to < 0 || from < 0 {
5919        ERRNO = EINVAL;
5920        return !0usize as IconvT;
5921    }
5922    make_cd(from, to)
5923}
5924
5925#[no_mangle]
5926pub unsafe extern "C" fn iconv(
5927    cd: IconvT,
5928    inbuf: *mut *mut c_char,
5929    inbytesleft: *mut SizeT,
5930    outbuf: *mut *mut c_char,
5931    outbytesleft: *mut SizeT,
5932) -> SizeT {
5933    if cd == !0usize as IconvT {
5934        ERRNO = EINVAL;
5935        return !0usize;
5936    }
5937    if inbuf.is_null() || outbuf.is_null() { return 0; }
5938    let from = extract_from(cd);
5939    let to = extract_to(cd);
5940    let mut src = *inbuf as *const u8;
5941    let mut dst = *outbuf as *mut u8;
5942    let mut src_left = *inbytesleft;
5943    let mut dst_left = *outbytesleft;
5944    let mut subst = 0usize;
5945    while src_left > 0 {
5946        let (cp, consumed, err) = iconv_decode(from, src, src_left);
5947        if err != 0 {
5948            if err == EINVAL { break; }
5949            ERRNO = err;
5950            return !0usize;
5951        }
5952        let (written, err) = iconv_encode(to, cp, dst, dst_left);
5953        if err != 0 {
5954            if err == E2BIG {
5955                ERRNO = E2BIG;
5956                return !0usize;
5957            }
5958            if dst_left < 1 {
5959                ERRNO = E2BIG;
5960                return !0usize;
5961            }
5962            *dst = b'*';
5963            dst = dst.add(1);
5964            dst_left -= 1;
5965            subst += 1;
5966        } else {
5967            dst = dst.add(written);
5968            dst_left -= written;
5969        }
5970        src = src.add(consumed);
5971        src_left -= consumed;
5972    }
5973    *inbuf = src as *mut c_char;
5974    *outbuf = dst as *mut c_char;
5975    *inbytesleft = src_left;
5976    *outbytesleft = dst_left;
5977    subst
5978}
5979
5980#[no_mangle]
5981pub unsafe extern "C" fn iconv_close(_cd: IconvT) -> c_int { 0 }
5982
5983// ============================================================
5984// Syscall wrappers as public C ABI
5985// ============================================================
5986
5987#[no_mangle]
5988pub unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: SizeT) -> SSizeT {
5989    sys_write(fd as i64, buf as *const u8, count) as SSizeT
5990}
5991
5992#[no_mangle]
5993pub unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: SizeT) -> SSizeT {
5994    sys_read(fd as i64, buf as *mut u8, count) as SSizeT
5995}
5996
5997#[no_mangle]
5998pub unsafe extern "C" fn open(path: *const c_char, flags: c_int, mode: c_int) -> c_int {
5999    sys_open(path as *const u8, flags as i64, mode as i64) as c_int
6000}
6001
6002#[no_mangle]
6003pub unsafe extern "C" fn close(fd: c_int) -> c_int {
6004    sys_close(fd as i64);
6005    0
6006}
6007
6008#[no_mangle]
6009pub unsafe extern "C" fn lseek(fd: c_int, offset: i64, whence: c_int) -> i64 {
6010    sys_lseek(fd as i64, offset, whence as i64)
6011}
6012
6013// ============================================================
6014// Additional syscall wrappers for stdio
6015// ============================================================
6016
6017const O_RDONLY: i32 = 0;
6018const O_WRONLY: i32 = 1;
6019const O_RDWR: i32 = 2;
6020const O_CREAT: i32 = 64;
6021const O_TRUNC: i32 = 512;
6022const O_APPEND: i32 = 1024;
6023const O_EXCL: i32 = 128;
6024const O_NONBLOCK: i32 = 2048;
6025const O_NOFOLLOW: i32 = if cfg!(target_arch = "aarch64") { 0o100000 } else { 0o400000 };
6026const O_DIRECTORY: i32 = if cfg!(target_arch = "aarch64") { 0o40000 } else { 0o200000 };
6027const O_CLOEXEC: i32 = 0x80000;
6028
6029const F_GETFD: i32 = 1;
6030const F_SETFD: i32 = 2;
6031const F_GETFL: i32 = 3;
6032const F_SETFL: i32 = 4;
6033const F_GETLK: i32 = 5;
6034const F_SETLK: i32 = 6;
6035const F_SETLKW: i32 = 7;
6036const F_DUPFD: i32 = 0;
6037const F_DUPFD_CLOEXEC: i32 = 1030;
6038const FD_CLOEXEC: i32 = 1;
6039
6040const TIOCGWINSZ: u32 = 0x5413;
6041
6042#[repr(C)]
6043struct winsize {
6044    ws_row: u16,
6045    ws_col: u16,
6046    ws_xpixel: u16,
6047    ws_ypixel: u16,
6048}
6049
6050#[inline]
6051unsafe fn sys_pipe2(fds: *mut c_int, flags: i32) -> i64 {
6052    <Arch as Syscalls>::syscall2(SYS_PIPE2, fds as i64, flags as i64)
6053}
6054
6055#[inline]
6056unsafe fn sys_dup3(oldfd: i32, newfd: i32, flags: i32) -> i64 {
6057    <Arch as Syscalls>::syscall3(SYS_DUP3, oldfd as i64, newfd as i64, flags as i64)
6058}
6059
6060#[inline]
6061unsafe fn sys_fcntl(fd: i32, cmd: i32, arg: i64) -> i64 {
6062    <Arch as Syscalls>::syscall3(SYS_FCNTL, fd as i64, cmd as i64, arg as i64)
6063}
6064
6065#[inline]
6066unsafe fn sys_ioctl(fd: c_int, request: u32, arg: *mut u8) -> i64 {
6067    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, request as i64, arg as i64)
6068}
6069
6070#[inline]
6071unsafe fn sys_unlinkat(dirfd: i32, path: *const u8, flags: i32) -> i64 {
6072    <Arch as Syscalls>::syscall3(SYS_UNLINKAT, dirfd as i64, path as i64, flags as i64)
6073}
6074
6075#[inline]
6076unsafe fn sys_renameat2(olddirfd: i32, oldpath: *const u8, newdirfd: i32, newpath: *const u8, flags: u32) -> i64 {
6077    <Arch as Syscalls>::syscall5(SYS_RENAMEAT2, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64, flags as i64)
6078}
6079
6080// ============================================================
6081// FILE / stdio (buffered, musl-compatible layout)
6082// ============================================================
6083
6084const UNGET: usize = 8;
6085const F_PERM: u32 = 1;
6086const F_NORD: u32 = 4;
6087const F_NOWR: u32 = 8;
6088const F_EOF: u32 = 16;
6089const F_ERR: u32 = 32;
6090const F_SVB: u32 = 64;
6091const F_APP: u32 = 128;
6092
6093const BUFSIZ: usize = 1024;
6094
6095const _IOFBF: c_int = 0;
6096const _IOLBF: c_int = 1;
6097const _IONBF: c_int = 2;
6098
6099const SEEK_SET: c_int = 0;
6100const SEEK_CUR: c_int = 1;
6101const SEEK_END: c_int = 2;
6102
6103// ponytail: buffered FILE, musl x86_64 layout subset
6104#[repr(C)]
6105pub struct FILE {
6106    flags: c_uint,
6107    rpos: *mut u8,
6108    rend: *mut u8,
6109    close: Option<unsafe extern "C" fn(*mut FILE) -> c_int>,
6110    wend: *mut u8,
6111    wpos: *mut u8,
6112    mustbezero_1: *mut u8,
6113    wbase: *mut u8,
6114    read_fn: Option<unsafe extern "C" fn(*mut FILE, *mut u8, usize) -> usize>,
6115    write_fn: Option<unsafe extern "C" fn(*mut FILE, *const u8, usize) -> usize>,
6116    seek_fn: Option<unsafe extern "C" fn(*mut FILE, i64, c_int) -> i64>,
6117    buf: *mut u8,
6118    buf_size: usize,
6119    prev: *mut FILE,
6120    next: *mut FILE,
6121    fd: c_int,
6122    pipe_pid: c_int,
6123    lockcount: c_long,
6124    mode: c_int,
6125    lock: c_int,
6126    lbf: c_int,
6127    cookie: *mut c_void,
6128    off: i64,
6129    getln_buf: *mut c_char,
6130    mustbezero_2: *mut c_void,
6131    shend: *mut u8,
6132    shlim: i64,
6133    shcnt: i64,
6134    ungotten: [c_int; UNGET],
6135    ungotten_count: c_int,
6136    _eof: c_int,
6137    _err: c_int,
6138}
6139
6140static mut STDIN_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
6141static mut STDOUT_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
6142static mut STDERR_BUF: [u8; BUFSIZ] = [0; BUFSIZ];
6143
6144static mut STDIN_FILE: FILE = FILE {
6145    flags: 0, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
6146    close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
6147    mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
6148    read_fn: None, write_fn: None, seek_fn: None,
6149    buf: core::ptr::null_mut(), buf_size: BUFSIZ,
6150    prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
6151    fd: 0, pipe_pid: 0, lockcount: 0, mode: 0, lock: 0, lbf: -1,
6152    cookie: core::ptr::null_mut(), off: 0,
6153    getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
6154    shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
6155    ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
6156};
6157static mut STDOUT_FILE: FILE = FILE {
6158    flags: F_NOWR as u32 + F_SVB as u32, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
6159    close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
6160    mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
6161    read_fn: None, write_fn: None, seek_fn: None,
6162    buf: core::ptr::null_mut(), buf_size: BUFSIZ,
6163    prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
6164    fd: 1, pipe_pid: 0, lockcount: 0, mode: 0, lock: 0, lbf: -1,
6165    cookie: core::ptr::null_mut(), off: 0,
6166    getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
6167    shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
6168    ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
6169};
6170static mut STDERR_FILE: FILE = FILE {
6171    flags: F_NOWR as u32, rpos: core::ptr::null_mut(), rend: core::ptr::null_mut(),
6172    close: None, wend: core::ptr::null_mut(), wpos: core::ptr::null_mut(),
6173    mustbezero_1: core::ptr::null_mut(), wbase: core::ptr::null_mut(),
6174    read_fn: None, write_fn: None, seek_fn: None,
6175    buf: core::ptr::null_mut(), buf_size: BUFSIZ,
6176    prev: core::ptr::null_mut(), next: core::ptr::null_mut(),
6177    fd: 2, pipe_pid: 0, lockcount: 0, mode: 0, lock: 0, lbf: -1,
6178    cookie: core::ptr::null_mut(), off: 0,
6179    getln_buf: core::ptr::null_mut(), mustbezero_2: core::ptr::null_mut(),
6180    shend: core::ptr::null_mut(), shlim: 0, shcnt: 0,
6181    ungotten: [0; UNGET], ungotten_count: 0, _eof: 0, _err: 0,
6182};
6183
6184#[no_mangle]
6185pub static mut stdin: *mut FILE = &raw mut STDIN_FILE as *mut FILE;
6186#[no_mangle]
6187pub static mut stdout: *mut FILE = &raw mut STDOUT_FILE as *mut FILE;
6188#[no_mangle]
6189pub static mut stderr: *mut FILE = &raw mut STDERR_FILE as *mut FILE;
6190
6191// ============================================================
6192// FILE helpers
6193// ============================================================
6194
6195unsafe fn __stdio_init() {
6196    STDIN_FILE.buf = core::ptr::addr_of_mut!(STDIN_BUF) as *mut u8;
6197    STDIN_FILE.buf_size = BUFSIZ;
6198    STDIN_FILE.read_fn = Some(__stdio_read);
6199    STDIN_FILE.write_fn = Some(__stdio_write);
6200    STDIN_FILE.seek_fn = Some(__stdio_seek);
6201    STDOUT_FILE.buf = core::ptr::addr_of_mut!(STDOUT_BUF) as *mut u8;
6202    STDOUT_FILE.buf_size = BUFSIZ;
6203    STDOUT_FILE.lbf = b'\n' as c_int;
6204    STDOUT_FILE.read_fn = Some(__stdio_read);
6205    STDOUT_FILE.write_fn = Some(__stdio_write);
6206    STDOUT_FILE.seek_fn = Some(__stdio_seek);
6207    STDERR_FILE.buf = core::ptr::addr_of_mut!(STDERR_BUF) as *mut u8;
6208    STDERR_FILE.buf_size = BUFSIZ;
6209    STDERR_FILE.read_fn = Some(__stdio_read);
6210    STDERR_FILE.write_fn = Some(__stdio_write);
6211    STDERR_FILE.seek_fn = Some(__stdio_seek);
6212}
6213
6214unsafe fn buf_ptr(f: *mut FILE) -> *mut u8 {
6215    (f as *mut u8).add(core::mem::size_of::<FILE>())
6216}
6217
6218unsafe extern "C" fn __stdio_read(f: *mut FILE, buf: *mut u8, len: usize) -> usize {
6219    let n = sys_read((*f).fd as i64, buf, len);
6220    if n <= 0 {
6221        if n == 0 { (*f).flags |= F_EOF; } else { (*f).flags |= F_ERR; (*f)._err = 1; }
6222        return 0;
6223    }
6224    n as usize
6225}
6226
6227unsafe extern "C" fn __stdio_write(f: *mut FILE, buf: *const u8, len: usize) -> usize {
6228    let l = (*f).wpos as usize - (*f).wbase as usize;
6229    let mut iov = [
6230        ((*f).wbase as *const u8, l),
6231        (buf, len),
6232    ];
6233    if iov[0].1 == 0 { iov = [iov[1], (core::ptr::null(), 0)]; }
6234    if (*f).flags & F_APP != 0 {
6235        let _ = sys_lseek((*f).fd as i64, 0, SEEK_END as i64);
6236    }
6237    let mut rem = iov[0].1 + iov[1].1;
6238    let mut idx = 0usize;
6239    while rem > 0 {
6240        let ptr = iov[idx].0;
6241        let cnt = iov[idx].1;
6242        if cnt == 0 { idx += 1; continue; }
6243        let n = sys_write((*f).fd as i64, ptr, cnt);
6244        if n <= 0 {
6245            (*f).wpos = core::ptr::null_mut();
6246            (*f).wbase = core::ptr::null_mut();
6247            (*f).wend = core::ptr::null_mut();
6248            (*f).flags |= F_ERR;
6249            return if iov[idx].0 == buf { 0 } else { len };
6250        }
6251        rem -= n as usize;
6252        iov[idx].0 = iov[idx].0.add(n as usize);
6253        iov[idx].1 -= n as usize;
6254        if iov[idx].1 == 0 { idx += 1; }
6255    }
6256    (*f).wend = (*f).buf.add((*f).buf_size);
6257    (*f).wbase = (*f).buf;
6258    (*f).wpos = (*f).buf;
6259    len
6260}
6261
6262unsafe extern "C" fn __stdio_seek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
6263    sys_lseek((*f).fd as i64, off, whence as i64)
6264}
6265
6266unsafe fn init_file(
6267    f: *mut FILE,
6268    fd: c_int,
6269    mode: *const c_char,
6270    close_fn: Option<unsafe extern "C" fn(*mut FILE) -> c_int>,
6271    buf_area: *mut u8,
6272    buf_sz: usize,
6273) {
6274    core::ptr::write_bytes(f as *mut u8, 0, core::mem::size_of::<FILE>());
6275    (*f).fd = fd;
6276    (*f).close = close_fn;
6277    (*f).lock = 0;
6278    (*f).lbf = -1;
6279    (*f).buf = buf_area;
6280    (*f).buf_size = buf_sz;
6281    (*f).read_fn = Some(__stdio_read);
6282    (*f).write_fn = Some(__stdio_write);
6283    (*f).seek_fn = Some(__stdio_seek);
6284    let m = *mode;
6285    let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
6286    if m == b'r' as c_char && !has_plus {
6287        (*f).flags = F_NORD;
6288    } else if !has_plus {
6289        (*f).flags = F_NOWR;
6290    }
6291}
6292
6293unsafe extern "C" fn __stdio_close(f: *mut FILE) -> c_int {
6294    sys_close((*f).fd as i64);
6295    0
6296}
6297
6298unsafe fn fmodeflags(mode: *const c_char) -> c_int {
6299    let mut flags: c_int;
6300    let m = *mode;
6301    if !strchr(mode as *const u8, b'+' as c_int).is_null() {
6302        flags = O_RDWR;
6303    } else if m == b'r' as c_char {
6304        flags = O_RDONLY;
6305    } else {
6306        flags = O_WRONLY;
6307    }
6308    if !strchr(mode as *const u8, b'x' as c_int).is_null() { flags |= O_EXCL; }
6309    if !strchr(mode as *const u8, b'e' as c_int).is_null() { flags |= O_CLOEXEC; }
6310    if m != b'r' as c_char { flags |= O_CREAT; }
6311    if m == b'w' as c_char { flags |= O_TRUNC; }
6312    if m == b'a' as c_char { flags |= O_APPEND; }
6313    flags
6314}
6315
6316const O_ACCMODE: c_int = O_RDONLY | O_WRONLY | O_RDWR;
6317
6318unsafe fn flush_buf(f: *mut FILE) -> c_int {
6319    if (*f).wpos == (*f).wbase {
6320        if !(*f).wpos.is_null() {
6321            (*f).wend = (*f).buf.add((*f).buf_size);
6322            (*f).wpos = (*f).wbase;
6323        }
6324        return 0;
6325    }
6326    if let Some(wfunc) = (*f).write_fn {
6327        let ret = wfunc(f, core::ptr::null(), 0);
6328        if ret == 0 && (*f).wpos.is_null() { return -1; }
6329        return 0;
6330    }
6331    (*f).flags |= F_ERR;
6332    -1
6333}
6334
6335// ============================================================
6336// fopen / fdopen / freopen / fclose
6337// ============================================================
6338
6339#[no_mangle]
6340pub unsafe extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
6341    if filename.is_null() || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
6342    let m = *mode;
6343    if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
6344        ERRNO = EINVAL; return core::ptr::null_mut();
6345    }
6346    let flags = fmodeflags(mode);
6347    let fd = sys_open(filename as *const u8, flags as i64, 0o666);
6348    if fd < 0 { ERRNO = (-fd) as c_int; return core::ptr::null_mut(); }
6349    fdopen(fd as c_int, mode)
6350}
6351
6352#[no_mangle]
6353pub unsafe extern "C" fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE {
6354    if fd < 0 || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
6355    let m = *mode;
6356    if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
6357        ERRNO = EINVAL; return core::ptr::null_mut();
6358    }
6359    let f = calloc(1, core::mem::size_of::<FILE>() + UNGET + BUFSIZ) as *mut FILE;
6360    if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
6361    let buf = buf_ptr(f);
6362    init_file(f, fd, mode, Some(__stdio_close), buf, BUFSIZ);
6363    if !strchr(mode as *const u8, b'a' as c_int).is_null() { (*f).flags |= F_APP; }
6364    if !strchr(mode as *const u8, b'e' as c_int).is_null() { sys_fcntl(fd, F_SETFD, FD_CLOEXEC as i64); }
6365    if (*f).flags & F_NOWR == 0 {
6366        let mut ws: winsize = core::mem::zeroed();
6367        if sys_ioctl(fd, TIOCGWINSZ, &mut ws as *mut winsize as *mut u8) == 0 {
6368            (*f).lbf = b'\n' as c_int;
6369        }
6370    }
6371    f
6372}
6373
6374#[no_mangle]
6375pub unsafe extern "C" fn freopen(
6376    filename: *const c_char, mode: *const c_char, f: *mut FILE,
6377) -> *mut FILE {
6378    fflush(f);
6379    if (*f).pipe_pid > 0 { let _ = __stdio_close(f); }
6380    if filename.is_null() {
6381        let flags = fmodeflags(mode);
6382        if flags == 0 { return core::ptr::null_mut(); }
6383        let mut fl = flags & !(O_CREAT | O_EXCL | O_CLOEXEC);
6384        if (*f).flags & F_APP != 0 { fl = (fl & !O_ACCMODE) | O_WRONLY | O_APPEND; }
6385        if sys_fcntl((*f).fd, F_SETFL, fl as i64) < 0 { return core::ptr::null_mut(); }
6386        let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
6387        if has_plus {
6388            (*f).flags &= !(F_NORD | F_NOWR);
6389        } else if *mode == b'r' as c_char {
6390            (*f).flags = ((*f).flags & !F_NOWR) | F_NORD;
6391        } else {
6392            (*f).flags = ((*f).flags & !F_NORD) | F_NOWR;
6393        }
6394        return f;
6395    }
6396    let new_f = fopen(filename, mode);
6397    if new_f.is_null() { let _ = __stdio_close(f); return core::ptr::null_mut(); }
6398    if (*new_f).fd == (*f).fd {
6399        (*new_f).fd = -1;
6400    } else {
6401        sys_dup3((*new_f).fd, (*f).fd, 0);
6402        let _ = __stdio_close(new_f);
6403    }
6404    (*f).flags = (*new_f).flags;
6405    (*f).rpos = core::ptr::null_mut();
6406    (*f).rend = core::ptr::null_mut();
6407    (*f).wpos = core::ptr::null_mut();
6408    (*f).wbase = core::ptr::null_mut();
6409    (*f).wend = core::ptr::null_mut();
6410    (*f).lbf = (*new_f).lbf;
6411    (*f).pipe_pid = 0;
6412    free(new_f as *mut c_void);
6413    f
6414}
6415
6416#[no_mangle]
6417pub unsafe extern "C" fn fclose(f: *mut FILE) -> c_int {
6418    if f.is_null() { return -1; }
6419    let r = fflush(f);
6420    if let Some(close_fn) = (*f).close { let _ = close_fn(f); }
6421    if r != 0 { -1 } else { 0 }
6422}
6423
6424// ============================================================
6425// setvbuf / setbuf / setbuffer / fflush
6426// ============================================================
6427
6428#[no_mangle]
6429pub unsafe extern "C" fn setvbuf(f: *mut FILE, buf: *mut c_char, mode: c_int, size: usize) -> c_int {
6430    if mode != _IOFBF && mode != _IOLBF && mode != _IONBF { return -1; }
6431    fflush(f);
6432    (*f).rpos = core::ptr::null_mut();
6433    (*f).rend = core::ptr::null_mut();
6434    (*f).wpos = core::ptr::null_mut();
6435    (*f).wbase = core::ptr::null_mut();
6436    (*f).wend = core::ptr::null_mut();
6437    if mode == _IONBF {
6438        (*f).buf_size = 0;
6439    } else if !buf.is_null() && size > 0 {
6440        (*f).buf = buf as *mut u8;
6441        (*f).buf_size = size;
6442    }
6443    (*f).lbf = if mode == _IOLBF { b'\n' as c_int } else { -1 };
6444    0
6445}
6446
6447#[no_mangle]
6448pub unsafe extern "C" fn setbuf(f: *mut FILE, buf: *mut c_char) {
6449    if buf.is_null() { setvbuf(f, core::ptr::null_mut(), _IONBF, 0); }
6450    else { setvbuf(f, buf, _IOFBF, BUFSIZ); }
6451}
6452
6453#[no_mangle]
6454pub unsafe extern "C" fn setbuffer(f: *mut FILE, buf: *mut c_char, size: usize) {
6455    if buf.is_null() { setvbuf(f, core::ptr::null_mut(), _IONBF, 0); }
6456    else { setvbuf(f, buf, _IOFBF, size); }
6457}
6458
6459#[no_mangle]
6460pub unsafe extern "C" fn fflush(f: *mut FILE) -> c_int {
6461    if f.is_null() {
6462        let mut r = 0;
6463        if !stdout.is_null() && !(*stdout).wpos.is_null() && (*stdout).wpos != (*stdout).wbase {
6464            if flush_buf(stdout) != 0 { r = -1; }
6465        }
6466        if !stderr.is_null() && !(*stderr).wpos.is_null() && (*stderr).wpos != (*stderr).wbase {
6467            if flush_buf(stderr) != 0 { r = -1; }
6468        }
6469        return r;
6470    }
6471    if !(*f).wpos.is_null() && (*f).wpos != (*f).wbase {
6472        return flush_buf(f);
6473    }
6474    0
6475}
6476
6477// ============================================================
6478// fwide / feof / ferror / clearerr / fileno
6479// ============================================================
6480
6481#[no_mangle]
6482pub unsafe extern "C" fn fwide(_f: *mut FILE, mode: c_int) -> c_int { mode }
6483
6484#[no_mangle]
6485pub unsafe extern "C" fn feof(f: *mut FILE) -> c_int { if (*f)._eof != 0 { 1 } else { 0 } }
6486
6487#[no_mangle]
6488pub unsafe extern "C" fn ferror(f: *mut FILE) -> c_int { if (*f)._err != 0 { 1 } else { 0 } }
6489
6490#[no_mangle]
6491pub unsafe extern "C" fn clearerr(f: *mut FILE) { (*f)._eof = 0; (*f)._err = 0; }
6492
6493#[no_mangle]
6494pub unsafe extern "C" fn fileno(f: *mut FILE) -> c_int { (*f).fd }
6495
6496// ============================================================
6497// fseek / ftell / rewind / fseeko / ftello / fgetpos / fsetpos
6498// ============================================================
6499
6500#[no_mangle]
6501pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int {
6502    fseeko(stream, offset as i64, whence)
6503}
6504
6505#[no_mangle]
6506pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long {
6507    ftello(stream) as c_long
6508}
6509
6510#[no_mangle]
6511pub unsafe extern "C" fn rewind(stream: *mut FILE) {
6512    fseek(stream, 0, SEEK_SET);
6513    (*stream)._eof = 0;
6514    (*stream)._err = 0;
6515}
6516
6517#[no_mangle]
6518pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: i64, whence: c_int) -> c_int {
6519    if whence != SEEK_SET && whence != SEEK_CUR && whence != SEEK_END {
6520        ERRNO = EINVAL;
6521        return -1;
6522    }
6523    let f = &mut *stream;
6524    let mut adj_offset = offset;
6525    if whence == SEEK_CUR {
6526        if !f.rpos.is_null() {
6527            adj_offset -= f.rend as i64 - f.rpos as i64;
6528        }
6529        adj_offset -= f.ungotten_count as i64;
6530    }
6531    if !f.wpos.is_null() && f.wpos != f.wbase {
6532        if flush_buf(stream) != 0 { return -1; }
6533    }
6534    f.wpos = core::ptr::null_mut();
6535    f.wbase = core::ptr::null_mut();
6536    f.wend = core::ptr::null_mut();
6537    if let Some(sfunc) = f.seek_fn {
6538        let r = sfunc(stream, adj_offset, whence);
6539        if r < 0 { return -1; }
6540    } else {
6541        ERRNO = EINVAL;
6542        return -1;
6543    }
6544    f.rpos = core::ptr::null_mut();
6545    f.rend = core::ptr::null_mut();
6546    f._eof = 0;
6547    f.ungotten_count = 0;
6548    0
6549}
6550
6551#[no_mangle]
6552pub unsafe extern "C" fn ftello(stream: *mut FILE) -> i64 {
6553    let f = &mut *stream;
6554    if f.flags & F_APP != 0 && !f.wpos.is_null() && f.wpos != f.wbase {
6555        if fflush(stream) != 0 { return -1; }
6556    }
6557    let sfunc = match f.seek_fn { Some(s) => s, None => return -1 };
6558    let pos = sfunc(stream, 0,
6559        if (f.flags & F_APP) != 0 && !f.wpos.is_null() && f.wpos != f.wbase { SEEK_END } else { SEEK_CUR });
6560    if pos < 0 { return -1; }
6561    let mut pos = pos;
6562    if !f.rpos.is_null() {
6563        pos += f.rpos as i64 - f.rend as i64;
6564    } else if !f.wbase.is_null() {
6565        pos += f.wpos as i64 - f.wbase as i64;
6566    }
6567    pos - f.ungotten_count as i64
6568}
6569
6570#[no_mangle]
6571pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut i64) -> c_int {
6572    let off = ftello(stream);
6573    if off < 0 { return -1; }
6574    *pos = off;
6575    0
6576}
6577
6578#[no_mangle]
6579pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const i64) -> c_int {
6580    fseeko(stream, *pos, SEEK_SET)
6581}
6582
6583// ============================================================
6584// fgetc / getc / getchar / ungetc
6585// ============================================================
6586
6587#[no_mangle]
6588pub unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int {
6589    let f = &mut *stream;
6590    if f.ungotten_count > 0 {
6591        f.ungotten_count -= 1;
6592        return f.ungotten[f.ungotten_count as usize];
6593    }
6594    if !f.rpos.is_null() && f.rpos < f.rend {
6595        let c = *f.rpos;
6596        f.rpos = f.rpos.add(1);
6597        return c as c_int;
6598    }
6599    if f._eof != 0 { return -1; }
6600    if let Some(rfunc) = f.read_fn {
6601        let mut buf = [0u8; 1];
6602        let n = rfunc(stream, buf.as_mut_ptr(), 1);
6603        if n == 0 {
6604            if f.flags & F_ERR != 0 { f._err = 1; } else { f._eof = 1; }
6605            return -1;
6606        }
6607        buf[0] as c_int
6608    } else {
6609        f._eof = 1;
6610        -1
6611    }
6612}
6613
6614#[no_mangle]
6615pub unsafe extern "C" fn getc(stream: *mut FILE) -> c_int { fgetc(stream) }
6616
6617#[no_mangle]
6618pub unsafe extern "C" fn getchar() -> c_int { fgetc(stdin) }
6619
6620#[no_mangle]
6621pub unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
6622    if c == -1 { return -1; }
6623    let f = &mut *stream;
6624    if f.ungotten_count >= UNGET as c_int { return -1; }
6625    f.ungotten[f.ungotten_count as usize] = c;
6626    f.ungotten_count += 1;
6627    f._eof = 0;
6628    c
6629}
6630
6631// ============================================================
6632// fgets / fread
6633// ============================================================
6634
6635#[no_mangle]
6636pub unsafe extern "C" fn fgets(s: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char {
6637    if n <= 0 { return null_mut(); }
6638    let max = (n - 1) as usize;
6639    let mut i = 0usize;
6640    while i < max {
6641        let c = fgetc(stream);
6642        if c == -1 { if i == 0 { return null_mut(); } break; }
6643        *s.add(i) = c as c_char;
6644        i += 1;
6645        if c == b'\n' as c_int { break; }
6646    }
6647    *s.add(i) = 0;
6648    s
6649}
6650
6651// ponytail: gets is dangerous, kept for POSIX compliance
6652#[no_mangle]
6653pub unsafe extern "C" fn gets(s: *mut c_char) -> *mut c_char {
6654    let mut i = 0usize;
6655    loop {
6656        let c = fgetc(stdin);
6657        if c == -1 { if i == 0 { return null_mut(); } break; }
6658        if c == b'\n' as c_int { break; }
6659        *s.add(i) = c as c_char;
6660        i += 1;
6661    }
6662    *s.add(i) = 0;
6663    s
6664}
6665
6666#[no_mangle]
6667pub unsafe extern "C" fn fopen64(filename: *const c_char, mode: *const c_char) -> *mut FILE {
6668    fopen(filename, mode)
6669}
6670
6671// ponytail: perror - minimal, just prints "msg: errno\n"
6672const PERROR_BUF_SIZE: usize = 64;
6673static mut PERROR_BUF: [u8; PERROR_BUF_SIZE] = [0; PERROR_BUF_SIZE];
6674
6675#[no_mangle]
6676pub unsafe extern "C" fn perror(msg: *const c_char) {
6677    let fd = (*stderr).fd;
6678    if !msg.is_null() && *msg != 0 {
6679        let len = strlen(msg as *const c_char);
6680        write_str(fd, msg as *const u8, len);
6681        write_str(fd, b": ".as_ptr(), 2);
6682    }
6683    let e = ERRNO;
6684    let text = strerror(e) as *const u8;
6685    write_str(fd, text, strlen(text as *const c_char));
6686    write_str(fd, b"\n".as_ptr(), 1);
6687}
6688
6689#[no_mangle]
6690pub unsafe extern "C" fn fread(
6691    ptr: *mut c_void, size: SizeT, nmemb: SizeT, stream: *mut FILE,
6692) -> SizeT {
6693    if size == 0 || nmemb == 0 { return 0; }
6694    let total = size * nmemb;
6695    let mut rd = 0usize;
6696    while rd < total {
6697        let c = fgetc(stream);
6698        if c == -1 { break; }
6699        *(ptr as *mut u8).add(rd) = c as u8;
6700        rd += 1;
6701    }
6702    rd / size
6703}
6704
6705// ============================================================
6706// puts / fputs / fputc / putc / putchar / fwrite
6707// ============================================================
6708
6709unsafe fn write_str(fd: c_int, s: *const u8, len: usize) {
6710    let mut written = 0usize;
6711    while written < len {
6712        let n = sys_write(fd as i64, s.add(written), len - written);
6713        if n <= 0 { break; }
6714        written += n as usize;
6715    }
6716}
6717
6718#[no_mangle]
6719unsafe fn __overflow(f: *mut FILE, c: c_int) -> c_int {
6720    if (*f).wpos.is_null() {
6721        (*f).wbase = (*f).buf;
6722        (*f).wpos = (*f).buf;
6723        (*f).wend = (*f).buf.add((*f).buf_size);
6724    }
6725    if flush_buf(f) == -1 { return -1; }
6726    if (*f).wpos >= (*f).wend {
6727        if let Some(wfunc) = (*f).write_fn {
6728            let byte = c as u8;
6729            let ret = wfunc(f, &byte as *const u8, 1);
6730            if ret == 0 { return -1; }
6731        }
6732        return c;
6733    }
6734    *(*f).wpos = c as u8;
6735    (*f).wpos = (*f).wpos.add(1);
6736    if c == (*f).lbf || (*f).wpos >= (*f).wend { let _ = flush_buf(f); }
6737    c
6738}
6739
6740#[no_mangle]
6741pub unsafe extern "C" fn puts(s: *const c_char) -> c_int {
6742    let len = strlen(s as *const c_char);
6743    let _ = fwrite(s as *const c_void, 1, len, stdout);
6744    let _ = fwrite(b"\n".as_ptr() as *const c_void, 1, 1, stdout);
6745    let f = &mut *stdout;
6746    if f.lbf >= 0 { let _ = flush_buf(stdout); }
6747    (len + 1) as c_int
6748}
6749
6750#[no_mangle]
6751pub unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int {
6752    let len = strlen(s as *const c_char);
6753    fwrite(s as *const c_void, 1, len, stream) as c_int
6754}
6755
6756#[no_mangle]
6757pub unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
6758    let f = &mut *stream;
6759    if f.wpos.is_null() || f.wpos >= f.wend {
6760        if __overflow(f, c) == -1 { return -1; }
6761        return c;
6762    }
6763    *f.wpos = c as u8;
6764    f.wpos = f.wpos.add(1);
6765    if c == f.lbf || f.wpos >= f.wend { let _ = flush_buf(f); }
6766    c
6767}
6768
6769#[no_mangle]
6770pub unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int { fputc(c, stream) }
6771
6772#[no_mangle]
6773pub unsafe extern "C" fn putchar(c: c_int) -> c_int { fputc(c, stdout) }
6774
6775#[no_mangle]
6776pub unsafe extern "C" fn fwrite(
6777    ptr: *const c_void, size: SizeT, nmemb: SizeT, stream: *mut FILE,
6778) -> SizeT {
6779    if size == 0 || nmemb == 0 { return 0; }
6780    let total = size * nmemb;
6781    let f = &mut *stream;
6782    if f.buf_size == 0 {
6783        if let Some(wfunc) = f.write_fn {
6784            let ret = wfunc(stream, ptr as *const u8, total);
6785            return ret / size;
6786        }
6787        return 0;
6788    }
6789    if f.wpos.is_null() {
6790        f.wbase = f.buf;
6791        f.wpos = f.buf;
6792        f.wend = f.buf.add(f.buf_size);
6793    }
6794    let mut remaining = total;
6795    let mut src = ptr as *const u8;
6796    while remaining > 0 {
6797        let space = f.wend as usize - f.wpos as usize;
6798        if space == 0 {
6799            if flush_buf(f as *mut FILE) == -1 { break; }
6800            continue;
6801        }
6802        let n = if remaining < space { remaining } else { space };
6803        core::ptr::copy_nonoverlapping(src, f.wpos, n);
6804        f.wpos = f.wpos.add(n);
6805        src = src.add(n);
6806        remaining -= n;
6807        if f.wpos >= f.wend { let _ = flush_buf(f as *mut FILE); }
6808    }
6809    if f.lbf >= 0 { let _ = flush_buf(f as *mut FILE); }
6810    (total - remaining) / size
6811}
6812
6813// ============================================================
6814// printf / fprintf / vprintf / vfprintf / dprintf / vdprintf
6815// ============================================================
6816
6817unsafe fn wide_to_mb(dst: *mut u8, cap: usize, src: *const wchar_t) -> usize {
6818    let mut o = 0usize;
6819    let mut i = 0usize;
6820    let mut st: c_uint = 0;
6821    while *src.add(i) != 0 {
6822        let mut tmp = [0u8; 8];
6823        let n = wcrtomb(tmp.as_mut_ptr() as *mut c_char, *src.add(i), &mut st);
6824        if n == !0usize || n == 0 { break; }
6825        if o + n > cap { break; }
6826        core::ptr::copy_nonoverlapping(tmp.as_ptr(), dst.add(o), n);
6827        o += n;
6828        i += 1;
6829    }
6830    o
6831}
6832
6833macro_rules! impl_format {
6834    ($fmt:expr, $args:expr, $write_char:expr, $write_str:expr) => {{
6835        let fmt = $fmt;
6836        let args = &mut $args;
6837        let mut count: usize = 0;
6838        let mut i = 0usize;
6839        loop {
6840            let c = *fmt.add(i) as u8;
6841            if c == 0 { break; }
6842            if c != b'%' {
6843                ($write_char)(c);
6844                count += 1; i += 1; continue;
6845            }
6846            i += 1;
6847            // Parse flags
6848            let mut flags: u8 = 0;
6849            loop {
6850                let fc = *fmt.add(i) as u8;
6851                match fc {
6852                    b'-' => { flags |= FLAG_MINUS; i += 1; }
6853                    b'+' => { flags |= FLAG_PLUS; i += 1; }
6854                    b' ' => { flags |= FLAG_SPACE; i += 1; }
6855                    b'0' => { flags |= FLAG_ZERO; i += 1; }
6856                    b'#' => { flags |= FLAG_HASH; i += 1; }
6857                    _ => break,
6858                }
6859            }
6860            // Parse width
6861            let mut width: usize = 0;
6862            if *fmt.add(i) as u8 == b'*' {
6863                width = args.next_arg::<c_int>() as usize; i += 1;
6864            } else {
6865                while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
6866                    width = width * 10 + ((*fmt.add(i) as u8) - b'0') as usize; i += 1;
6867                }
6868            }
6869            // Parse precision
6870            let mut precision: i32 = -1;
6871            if *fmt.add(i) as u8 == b'.' {
6872                i += 1;
6873                if *fmt.add(i) as u8 == b'*' {
6874                    precision = args.next_arg::<c_int>(); i += 1;
6875                } else {
6876                    precision = 0;
6877                    while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
6878                        precision = precision * 10 + ((*fmt.add(i) as u8) - b'0') as i32; i += 1;
6879                    }
6880                }
6881            }
6882            // Parse length modifier
6883            let len_mod = *fmt.add(i) as u8;
6884            let spec: u8;
6885            if len_mod == b'h' || len_mod == b'l' || len_mod == b'j' || len_mod == b'z' || len_mod == b't' || len_mod == b'L' {
6886                i += 1;
6887                let len_mod2 = *fmt.add(i) as u8;
6888                if (len_mod == b'h' && len_mod2 == b'h') || (len_mod == b'l' && len_mod2 == b'l') {
6889                    i += 1;
6890                    spec = *fmt.add(i) as u8;
6891                    // Handle double-length modifiers
6892                    match (len_mod, len_mod2, spec) {
6893                        (b'h', b'h', b'n') => {
6894                            let p = args.next_arg::<*mut c_void>();
6895                            if !p.is_null() { *(p as *mut u8) = count as u8; }
6896                        }
6897                        (b'l', b'l', b'n') => {
6898                            let p = args.next_arg::<*mut c_void>();
6899                            if !p.is_null() { *(p as *mut c_longlong) = count as c_longlong; }
6900                        }
6901                        (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
6902                            let val = args.next_arg::<c_longlong>();
6903                            let neg = val < 0;
6904                            let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
6905                            let b = format_u64(abs);
6906                            let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
6907                            let mut fbuf = [0u8; 32];
6908                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
6909                            ($write_str)(fbuf.as_ptr(), len); count += len;
6910                        }
6911                        (b'l', b'l', b'u') => {
6912                            let val = args.next_arg::<c_ulonglong>();
6913                            let b = format_u64(val as u64);
6914                            let mut fbuf = [0u8; 32];
6915                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
6916                            ($write_str)(fbuf.as_ptr(), len); count += len;
6917                        }
6918                        (b'l', b'l', b'o') => {
6919                            let val = args.next_arg::<c_ulonglong>();
6920                            let b = format_octal(val as u64, flags & FLAG_HASH != 0);
6921                            let mut fbuf = [0u8; 32];
6922                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
6923                            ($write_str)(fbuf.as_ptr(), len); count += len;
6924                        }
6925                        (b'l', b'l', b'x') => {
6926                            let val = args.next_arg::<c_ulonglong>();
6927                            let b = format_hex(val as u64, false);
6928                            let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
6929                            let mut fbuf = [0u8; 32];
6930                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6931                            ($write_str)(fbuf.as_ptr(), len); count += len;
6932                        }
6933                        (b'l', b'l', b'X') => {
6934                            let val = args.next_arg::<c_ulonglong>();
6935                            let b = format_hex(val as u64, true);
6936                            let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
6937                            let mut fbuf = [0u8; 32];
6938                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
6939                            ($write_str)(fbuf.as_ptr(), len); count += len;
6940                        }
6941                        _ => { ($write_char)(b'%'); ($write_char)(len_mod); ($write_char)(len_mod2); ($write_char)(spec); count += 4; }
6942                    }
6943                } else {
6944                    spec = len_mod2;
6945                    // size_t/ptrdiff_t are 64-bit on all supported targets;
6946                    // treat %z/%t integer conversions like %l.
6947                    let lm = if (len_mod == b'z' || len_mod == b't') && spec != b'n' { b'l' } else { len_mod };
6948                    match (lm, spec) {
6949                        (b'h', b'n') => {
6950                            let p = args.next_arg::<*mut c_void>();
6951                            if !p.is_null() { *(p as *mut u16) = count as u16; }
6952                        }
6953                        (b'l', b'n') => {
6954                            let p = args.next_arg::<*mut c_void>();
6955                            if !p.is_null() { *(p as *mut c_long) = count as c_long; }
6956                        }
6957                        (b'z', b'n') | (b't', b'n') => {
6958                            let p = args.next_arg::<*mut c_void>();
6959                            if !p.is_null() { *(p as *mut usize) = count; }
6960                        }
6961                        (b'j', b'n') => {
6962                            let p = args.next_arg::<*mut c_void>();
6963                            if !p.is_null() { *(p as *mut c_ulonglong) = count as c_ulonglong; }
6964                        }
6965                        (b'l', b'd') | (b'l', b'i') => {
6966                            let val = args.next_arg::<c_long>();
6967                            let neg = val < 0;
6968                            let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
6969                            let b = format_u64(abs);
6970                            let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
6971                            let mut fbuf = [0u8; 32];
6972                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
6973                            ($write_str)(fbuf.as_ptr(), len); count += len;
6974                        }
6975                        (b'l', b'u') => {
6976                            let val = args.next_arg::<c_ulong>();
6977                            let b = format_u64(val as u64);
6978                            let mut fbuf = [0u8; 32];
6979                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
6980                            ($write_str)(fbuf.as_ptr(), len); count += len;
6981                        }
6982                        (b'l', b's') => {
6983                            let p = args.next_arg::<*const wchar_t>();
6984                            if p.is_null() {
6985                                let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
6986                                let pad = width.saturating_sub(slen);
6987                                if flags & FLAG_MINUS != 0 { ($write_str)(b"(null)".as_ptr(), slen); for _ in 0..pad { ($write_char)(b' '); } }
6988                                else { for _ in 0..pad { ($write_char)(b' '); } ($write_str)(b"(null)".as_ptr(), slen); }
6989                                count += slen + pad;
6990                            } else {
6991                                let mut mb = [0u8; 4096];
6992                                let mut n = wide_to_mb(mb.as_mut_ptr(), mb.len(), p);
6993                                if precision >= 0 && (precision as usize) < n { n = precision as usize; }
6994                                let pad = width.saturating_sub(n);
6995                                if flags & FLAG_MINUS != 0 { ($write_str)(mb.as_ptr(), n); for _ in 0..pad { ($write_char)(b' '); } }
6996                                else { for _ in 0..pad { ($write_char)(b' '); } ($write_str)(mb.as_ptr(), n); }
6997                                count += n + pad;
6998                            }
6999                        }
7000                        (b'l', b'c') => {
7001                            let ch = args.next_arg::<c_int>();
7002                            let mut mb = [0u8; 8];
7003                            let mut st: c_uint = 0;
7004                            let n = wcrtomb(mb.as_mut_ptr() as *mut c_char, ch, &mut st);
7005                            if n != !0usize { ($write_str)(mb.as_ptr(), n); count += n; }
7006                        }
7007                        (b'l', b'x') => {
7008                            let val = args.next_arg::<c_ulong>();
7009                            let b = format_hex(val as u64, false);
7010                            let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
7011                            let mut fbuf = [0u8; 32];
7012                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7013                            ($write_str)(fbuf.as_ptr(), len); count += len;
7014                        }
7015                        (b'l', b'X') => {
7016                            let val = args.next_arg::<c_ulong>();
7017                            let b = format_hex(val as u64, true);
7018                            let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
7019                            let mut fbuf = [0u8; 32];
7020                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7021                            ($write_str)(fbuf.as_ptr(), len); count += len;
7022                        }
7023                        (b'l', b'o') => {
7024                            let val = args.next_arg::<c_ulong>();
7025                            let b = format_octal(val as u64, flags & FLAG_HASH != 0);
7026                            let mut fbuf = [0u8; 32];
7027                            let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
7028                            ($write_str)(fbuf.as_ptr(), len); count += len;
7029                        }
7030                        (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
7031                        | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A') => {
7032                            let val = args.next_arg::<f64>();
7033                            let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
7034                            let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
7035                            let mut fbuf = [0u8; 4224];
7036                            let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
7037                            let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
7038                            core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
7039                            ($write_str)(fbuf.as_ptr(), total); count += total;
7040                        }
7041                        (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
7042                        | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
7043                            #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
7044                            let val = {
7045                                let lo: u64 = args.next_arg::<u64>();
7046                                let hi: u64 = args.next_arg::<u64>();
7047                                let combined: u128 = ((hi as u128) << 64) | (lo as u128);
7048                                f128::from_bits(combined) as f64
7049                            };
7050                            #[cfg(target_arch = "x86_64")]
7051                            let val = args.next_arg::<f64>();
7052                            let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
7053                            let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
7054                            let mut fbuf = [0u8; 4224];
7055                            let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
7056                            let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
7057                            core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
7058                            ($write_str)(fbuf.as_ptr(), total); count += total;
7059                        }
7060                        _ => { ($write_char)(b'%'); ($write_char)(len_mod); ($write_char)(spec); count += 3; }
7061                    }
7062                }
7063            } else {
7064                spec = *fmt.add(i) as u8;
7065                match spec {
7066                    b's' => {
7067                        let s = args.next_arg::<*const c_char>();
7068                        if s.is_null() {
7069                            let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
7070                            let padded_len = if width > slen { width } else { slen };
7071                            let pad = padded_len - slen;
7072                            if flags & FLAG_MINUS != 0 {
7073                                ($write_str)(b"(null)".as_ptr(), slen);
7074                                for _ in 0..pad { ($write_char)(b' '); }
7075                            } else {
7076                                for _ in 0..pad { ($write_char)(b' '); }
7077                                ($write_str)(b"(null)".as_ptr(), slen);
7078                            }
7079                            count += padded_len;
7080                        } else {
7081                            let full_len = strlen(s as *const c_char);
7082                            let slen = if precision >= 0 { (precision as usize).min(full_len) } else { full_len };
7083                            let padded_len = if width > slen { width } else { slen };
7084                            let pad = padded_len - slen;
7085                            if flags & FLAG_MINUS != 0 {
7086                                ($write_str)(s as *const u8, slen);
7087                                for _ in 0..pad { ($write_char)(b' '); }
7088                            } else {
7089                                for _ in 0..pad { ($write_char)(b' '); }
7090                                ($write_str)(s as *const u8, slen);
7091                            }
7092                            count += padded_len;
7093                        }
7094                    }
7095                    b'd' | b'i' => {
7096                        let d = args.next_arg::<c_int>();
7097                        let neg = d < 0;
7098                        let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
7099                        let b = format_u64(abs);
7100                        let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
7101                        let mut fbuf = [0u8; 32];
7102                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
7103                        ($write_str)(fbuf.as_ptr(), len); count += len;
7104                    }
7105                    b'u' => {
7106                        let u = args.next_arg::<c_uint>();
7107                        let b = format_u64(u as u64);
7108                        let mut fbuf = [0u8; 32];
7109                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
7110                        ($write_str)(fbuf.as_ptr(), len); count += len;
7111                    }
7112                    b'x' => {
7113                        let x = args.next_arg::<c_uint>();
7114                        let b = format_hex(x as u64, false);
7115                        let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
7116                        let mut fbuf = [0u8; 32];
7117                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7118                        ($write_str)(fbuf.as_ptr(), len); count += len;
7119                    }
7120                    b'X' => {
7121                        let x = args.next_arg::<c_uint>();
7122                        let b = format_hex(x as u64, true);
7123                        let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
7124                        let mut fbuf = [0u8; 32];
7125                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
7126                        ($write_str)(fbuf.as_ptr(), len); count += len;
7127                    }
7128                    b'o' => {
7129                        let o = args.next_arg::<c_uint>();
7130                        let b = format_octal(o as u64, flags & FLAG_HASH != 0);
7131                        let mut fbuf = [0u8; 32];
7132                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
7133                        ($write_str)(fbuf.as_ptr(), len); count += len;
7134                    }
7135                    b'c' => {
7136                        let ch = args.next_arg::<c_int>();
7137                        if width > 1 {
7138                            let pad = width - 1;
7139                            if flags & FLAG_MINUS != 0 {
7140                                ($write_char)(ch as u8); count += 1;
7141                                for _ in 0..pad { ($write_char)(b' '); count += 1; }
7142                            } else {
7143                                for _ in 0..pad { ($write_char)(b' '); count += 1; }
7144                                ($write_char)(ch as u8); count += 1;
7145                            }
7146                        } else {
7147                            ($write_char)(ch as u8); count += 1;
7148                        }
7149                    }
7150                    b'p' => {
7151                        let p = args.next_arg::<*const c_void>();
7152                        let mut fbuf = [0u8; 20];
7153                        fbuf[0] = b'0'; fbuf[1] = b'x';
7154                        let b = format_hex(p as u64, false);
7155                        core::ptr::copy_nonoverlapping(b.0.as_ptr(), fbuf.as_mut_ptr().add(2), b.1);
7156                        ($write_str)(fbuf.as_ptr(), b.1 + 2); count += b.1 + 2;
7157                    }
7158                    b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
7159                        let val = args.next_arg::<f64>();
7160                        let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
7161                        let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
7162                        let mut fbuf = [0u8; 4224];
7163                        let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
7164                        let total = apply_width_flags(fbuf.as_mut_ptr().add(4096), fbuf.as_ptr(), flen, width, flags);
7165                        core::ptr::copy_nonoverlapping(fbuf.as_ptr().add(4096), fbuf.as_mut_ptr(), total);
7166                        ($write_str)(fbuf.as_ptr(), total); count += total;
7167                    }
7168                    b'%' => { ($write_char)(b'%'); count += 1; }
7169                    b'n' => {
7170                        let p = args.next_arg::<*mut c_void>();
7171                        if !p.is_null() { *(p as *mut c_int) = count as c_int; }
7172                    }
7173                    _ => { ($write_char)(b'%'); ($write_char)(spec); count += 2; }
7174                }
7175            }
7176            i += 1;
7177        }
7178        count as c_int
7179    }};
7180}
7181
7182unsafe fn format_u64(mut val: u64) -> ([u8; 20], usize) {
7183    let mut buf = [0u8; 20];
7184    if val == 0 { buf[0] = b'0'; return (buf, 1); }
7185    let mut tmp = [0u8; 20];
7186    let mut pos = 20;
7187    while val > 0 { pos -= 1; tmp[pos] = b'0' + (val % 10) as u8; val /= 10; }
7188    let len = 20 - pos;
7189    core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
7190    (buf, len)
7191}
7192
7193unsafe fn format_i64(val: i64) -> ([u8; 21], usize) {
7194    let mut buf = [0u8; 21];
7195    if val < 0 {
7196        buf[0] = b'-';
7197        let (inner, len) = format_u64((-(val as i128)) as u64);
7198        core::ptr::copy_nonoverlapping(inner.as_ptr(), buf.as_mut_ptr().add(1), len);
7199        (buf, len + 1)
7200    } else {
7201        let (inner, len) = format_u64(val as u64);
7202        core::ptr::copy_nonoverlapping(inner.as_ptr(), buf.as_mut_ptr(), len);
7203        (buf, len)
7204    }
7205}
7206
7207unsafe fn format_hex(mut val: u64, uppercase: bool) -> ([u8; 16], usize) {
7208    let digits = if uppercase { b"0123456789ABCDEF" } else { b"0123456789abcdef" };
7209    let mut buf = [0u8; 16];
7210    if val == 0 { buf[0] = b'0'; return (buf, 1); }
7211    let mut tmp = [0u8; 16];
7212    let mut pos = 16;
7213    while val > 0 { pos -= 1; tmp[pos] = digits[(val & 0xf) as usize]; val >>= 4; }
7214    let len = 16 - pos;
7215    core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
7216    (buf, len)
7217}
7218
7219unsafe fn format_octal(mut val: u64, alt: bool) -> ([u8; 24], usize) {
7220    let mut buf = [0u8; 24];
7221    if val == 0 {
7222        buf[0] = b'0';
7223        return (buf, 1);
7224    }
7225    let mut tmp = [0u8; 24];
7226    let mut pos = 24;
7227    while val > 0 {
7228        pos -= 1;
7229        tmp[pos] = b'0' + (val & 7) as u8;
7230        val >>= 3;
7231    }
7232    let len = 24 - pos;
7233    if alt {
7234        tmp[pos - 1] = b'0';
7235        core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos - 1), buf.as_mut_ptr(), len + 1);
7236        (buf, len + 1)
7237    } else {
7238        core::ptr::copy_nonoverlapping(tmp.as_ptr().add(pos), buf.as_mut_ptr(), len);
7239        (buf, len)
7240    }
7241}
7242
7243unsafe fn format_int(
7244    dst: *mut u8,
7245    digits: *const u8,
7246    digits_len: usize,
7247    sign: Option<u8>,
7248    prefix: Option<u8>,
7249    precision: i32,
7250    width: usize,
7251    flags: u8,
7252    octal_alt: bool,
7253) -> usize {
7254    let num_digits = if precision == 0 && digits_len == 1 && *digits == b'0' && !octal_alt {
7255        0
7256    } else {
7257        digits_len
7258    };
7259    let prec = precision as usize;
7260    let zero_pad = if precision >= 0 && prec > num_digits { prec - num_digits } else { 0 };
7261
7262    let sign_len = sign.map_or(0, |_| 1);
7263    let prefix_len = prefix.map_or(0, |_| 2);
7264    let content_len = sign_len + prefix_len + zero_pad + num_digits;
7265
7266    let mut buf = [0u8; 32];
7267    let mut pos = 0usize;
7268    if let Some(c) = sign { buf[pos] = c; pos += 1; }
7269    if let Some(c) = prefix { buf[pos] = b'0'; pos += 1; buf[pos] = c; pos += 1; }
7270    for _ in 0..zero_pad { buf[pos] = b'0'; pos += 1; }
7271    if num_digits > 0 {
7272        core::ptr::copy_nonoverlapping(digits, buf.as_mut_ptr().add(pos), num_digits);
7273    }
7274
7275    if content_len >= width {
7276        core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, content_len);
7277        return content_len;
7278    }
7279    let pad = width - content_len;
7280    if flags & FLAG_MINUS != 0 {
7281        core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, content_len);
7282        for i in 0..pad { *dst.add(content_len + i) = b' '; }
7283    } else if flags & FLAG_ZERO != 0 && precision < 0 {
7284        let fixed = sign_len + prefix_len;
7285        core::ptr::copy_nonoverlapping(buf.as_ptr(), dst, fixed);
7286        for i in fixed..width - num_digits { *dst.add(i) = b'0'; }
7287        if num_digits > 0 {
7288            core::ptr::copy_nonoverlapping(digits, dst.add(width - num_digits), num_digits);
7289        }
7290    } else {
7291        for i in 0..pad { *dst.add(i) = b' '; }
7292        core::ptr::copy_nonoverlapping(buf.as_ptr(), dst.add(pad), content_len);
7293    }
7294    width
7295}
7296
7297unsafe fn format_f64(val: f64) -> ([u8; 64], usize) {
7298    let mut buf = [0u8; 64];
7299    let mut pos = 0usize;
7300    let mut v = val;
7301    if v.is_nan() {
7302        let nan = b"nan";
7303        core::ptr::copy_nonoverlapping(nan.as_ptr(), buf.as_mut_ptr(), 3);
7304        return (buf, 3);
7305    }
7306    if v < 0.0 { buf[pos] = b'-'; pos += 1; v = -v; }
7307    if v.is_infinite() {
7308        let inf = b"inf";
7309        core::ptr::copy_nonoverlapping(inf.as_ptr(), buf.as_mut_ptr().add(pos), 3);
7310        return (buf, pos + 3);
7311    }
7312    let int_part = v as u64;
7313    let frac = v - int_part as f64;
7314    let (ibuf, ilen) = format_u64(int_part);
7315    core::ptr::copy_nonoverlapping(ibuf.as_ptr(), buf.as_mut_ptr().add(pos), ilen);
7316    pos += ilen;
7317    buf[pos] = b'.';
7318    pos += 1;
7319    let mut f = frac;
7320    for _ in 0..6 { f *= 10.0; let digit = f as u8; buf[pos] = b'0' + digit; pos += 1; f -= digit as f64; }
7321    (buf, pos)
7322}
7323
7324// Float format specifier type
7325const FMT_F: u8 = 0;
7326const FMT_E: u8 = 1;
7327const FMT_G: u8 = 2;
7328const FMT_A: u8 = 3;
7329
7330const FLAG_HASH: u8 = 1;
7331const FLAG_PLUS: u8 = 2;
7332const FLAG_SPACE: u8 = 4;
7333const FLAG_ZERO: u8 = 8;
7334const FLAG_MINUS: u8 = 16;
7335
7336// === %f formatting helpers ===
7337
7338/// Convert (mant << shift) to decimal string. Returns byte count written to buf.
7339/// mant is a 53-bit significand, shift is the left-shift amount (can be 0..~971).
7340unsafe fn bigint_to_decimal(buf: *mut u8, mant: u64, shift: u32) -> usize {
7341    // Store as little-endian u32 limbs. Max bits: 53 + 971 ≈ 1024 → 32 limbs.
7342    let nlimbs = (2 + (shift + 31) / 32) as usize;
7343    let mut limbs = [0u32; 36];
7344    limbs[0] = mant as u32;
7345    limbs[1] = (mant >> 32) as u32;
7346
7347    let ws = (shift / 32) as usize;
7348    let bs = shift % 32;
7349
7350    // Word-level shift left
7351    if ws > 0 {
7352        let mut i = 1usize;
7353        loop {
7354            limbs[i + ws] = limbs[i];
7355            if i == 0 { break; }
7356            i -= 1;
7357        }
7358        for j in 0..ws { limbs[j] = 0; }
7359    }
7360    // Bit-level shift left
7361    if bs > 0 {
7362        let mut carry = 0u32;
7363        let end = nlimbs.min(ws + 3);
7364        for i in ws..end {
7365            let new_val = (limbs[i] << bs) | carry;
7366            carry = limbs[i] >> (32 - bs);
7367            limbs[i] = new_val;
7368        }
7369    }
7370
7371    // Find highest non-zero limb
7372    let mut used = nlimbs;
7373    while used > 0 && limbs[used - 1] == 0 { used -= 1; }
7374    if used == 0 { *buf = b'0'; return 1; }
7375
7376    // Repeated division by 10 to extract decimal digits
7377    let mut digits = [0u8; 400];
7378    let mut nd = 0usize;
7379    loop {
7380        let mut all_zero = true;
7381        for i in 0..used { if limbs[i] != 0 { all_zero = false; break; } }
7382        if all_zero { break; }
7383        let mut rem = 0u64;
7384        for i in (0..used).rev() {
7385            let val = (rem << 32) | limbs[i] as u64;
7386            limbs[i] = (val / 10) as u32;
7387            rem = val % 10;
7388        }
7389        digits[nd] = rem as u8;
7390        nd += 1;
7391    }
7392    // Write digits in big-endian order
7393    for i in 0..nd { *buf.add(i) = b'0' + digits[nd - 1 - i]; }
7394    nd
7395}
7396
7397/// Compute `count` fractional digits of frac_bits / 2^shift using u128 arithmetic.
7398/// shift must be <= 124. Returns true if any value remains after the last digit.
7399unsafe fn frac_digits_u128(buf: *mut u8, frac_bits: u64, shift: u32, count: usize) -> bool {
7400    let mask: u128 = (1u128 << shift) - 1;
7401    let mut rem = frac_bits as u128;
7402    for i in 0..count {
7403        rem *= 10;
7404        let digit = (rem >> shift) as u8;
7405        rem &= mask;
7406        *buf.add(i) = digit;
7407    }
7408    rem != 0
7409}
7410
7411/// Compute `count` fractional digits of frac_bits / 2^shift using big-integer arithmetic.
7412/// For shift > 124 (up to ~1074). Returns true if any value remains after the last digit.
7413unsafe fn frac_digits_bigint(buf: *mut u8, frac_bits: u64, shift: u32, count: usize) -> bool {
7414    let nlimbs = ((shift + 31) / 32) as usize;
7415    let mut rem = [0u32; 36]; // enough for shift up to 1088
7416    rem[0] = frac_bits as u32;
7417    if nlimbs > 1 { rem[1] = (frac_bits >> 32) as u32; }
7418    // Mask to exactly `shift` bits
7419    let hi_word = (shift / 32) as usize;
7420    let hi_bit = shift % 32;
7421    if hi_bit > 0 && hi_word < nlimbs {
7422        rem[hi_word] &= (1u32 << hi_bit) - 1;
7423    }
7424    // Zero upper limbs beyond shift
7425    let clear_from = if hi_bit > 0 { hi_word + 1 } else { hi_word };
7426    for j in clear_from..nlimbs { rem[j] = 0; }
7427
7428    for i in 0..count {
7429        // Multiply remainder by 10
7430        let mut carry = 0u64;
7431        for j in 0..nlimbs {
7432            let val = rem[j] as u64 * 10 + carry;
7433            rem[j] = val as u32;
7434            carry = val >> 32;
7435        }
7436        // Extract digit from bit position `shift`
7437        let digit: u32;
7438        if hi_bit == 0 {
7439            digit = if hi_word < nlimbs { rem[hi_word] } else { carry as u32 };
7440        } else {
7441            let mut d = if hi_word < nlimbs { rem[hi_word] >> hi_bit } else { 0 };
7442            if hi_word + 1 < nlimbs {
7443                d |= rem[hi_word + 1] << (32 - hi_bit);
7444            } else if carry > 0 {
7445                d |= (carry as u32) << (32 - hi_bit);
7446            }
7447            digit = d;
7448        }
7449        *buf.add(i) = digit.min(9) as u8;
7450        // Clear bits from position `shift` upward (keep remainder < 2^shift)
7451        if hi_bit == 0 {
7452            if hi_word < nlimbs { rem[hi_word] = 0; }
7453        } else {
7454            if hi_word < nlimbs {
7455                rem[hi_word] &= (1u32 << hi_bit) - 1;
7456            }
7457            for j in (hi_word + 1)..nlimbs { rem[j] = 0; }
7458        }
7459    }
7460    // Check if remainder is non-zero
7461    for i in 0..nlimbs { if rem[i] != 0 { return true; } }
7462    false
7463}
7464
7465/// Increment a decimal string stored at buf[0..*len] in-place.
7466unsafe fn increment_decimal(buf: *mut u8, len: &mut usize) {
7467    let mut j = *len;
7468    loop {
7469        if j == 0 {
7470            // Shift right and prepend '1'
7471            let l = *len;
7472            for i in (0..l).rev() { *buf.add(i + 1) = *buf.add(i); }
7473            *buf = b'1';
7474            *len = l + 1;
7475            return;
7476        }
7477        j -= 1;
7478        let d = *buf.add(j);
7479        if d < b'9' { *buf.add(j) = d + 1; return; }
7480        *buf.add(j) = b'0';
7481    }
7482}
7483
7484// Write float to dst. Returns bytes written. Does NOT handle width/flags padding.
7485unsafe fn format_f64_full(
7486    dst: *mut u8, val: f64, fmt_type: u8, precision: i32, flags: u8, uppercase: bool,
7487) -> usize {
7488    let mut pos = 0usize;
7489
7490    // NaN
7491    if val.is_nan() {
7492        let nan_s: &[u8] = if uppercase { b"NAN" } else { b"nan" };
7493        core::ptr::copy_nonoverlapping(nan_s.as_ptr(), dst, 3);
7494        return 3;
7495    }
7496    let neg = val.is_sign_negative();
7497    let v = if neg { -val } else { val };
7498
7499    // Inf
7500    if v.is_infinite() {
7501        if neg { *dst.add(pos) = b'-'; pos += 1; }
7502        else if flags & FLAG_PLUS != 0 { *dst.add(pos) = b'+'; pos += 1; }
7503        else if flags & FLAG_SPACE != 0 { *dst.add(pos) = b' '; pos += 1; }
7504        let inf_s: &[u8] = if uppercase { b"INF" } else { b"inf" };
7505        core::ptr::copy_nonoverlapping(inf_s.as_ptr(), dst.add(pos), 3);
7506        return pos + 3;
7507    }
7508
7509    // Sign
7510    if neg { *dst.add(pos) = b'-'; pos += 1; }
7511    else if flags & FLAG_PLUS != 0 { *dst.add(pos) = b'+'; pos += 1; }
7512    else if flags & FLAG_SPACE != 0 { *dst.add(pos) = b' '; pos += 1; }
7513
7514    // === Hex float ===
7515    if fmt_type == FMT_A {
7516        return pos + fmt_hex_float(dst.add(pos), val, precision, flags, uppercase);
7517    }
7518
7519    // === Decimal formats ===
7520    let p: usize;
7521    let mut exp: i32;
7522    let use_f: bool;
7523
7524    match fmt_type {
7525        FMT_G => {
7526            let gp = if precision < 0 { 6usize } else if precision == 0 { 1usize } else { precision as usize };
7527            exp = if v > 0.0 { compute_exp10(v) } else { 0 };
7528            use_f = exp >= -4 && exp < gp as i32;
7529            if use_f {
7530                p = if exp < 0 { gp + ((-exp) as usize - 1) }
7531                    else if (exp as usize) < gp { gp - exp as usize - 1 }
7532                    else { 0 };
7533            } else {
7534                p = gp - 1;
7535            }
7536        }
7537        FMT_E => {
7538            p = if precision < 0 { 6usize } else { precision as usize };
7539            exp = if v > 0.0 { compute_exp10(v) } else { 0 };
7540            use_f = false;
7541        }
7542        _ => {
7543            p = if precision < 0 { 6usize } else { precision as usize };
7544            exp = 0;
7545            use_f = true;
7546        }
7547    }
7548
7549    if v == 0.0 {
7550        *dst.add(pos) = b'0'; pos += 1;
7551        if !(fmt_type == FMT_G && flags & FLAG_HASH == 0) {
7552            if p > 0 || flags & FLAG_HASH != 0 {
7553                *dst.add(pos) = b'.'; pos += 1;
7554                for _ in 0..p { *dst.add(pos) = b'0'; pos += 1; }
7555            }
7556        }
7557        if !use_f {
7558            let ec = if uppercase { b'E' } else { b'e' };
7559            *dst.add(pos) = ec; pos += 1;
7560            *dst.add(pos) = b'+'; pos += 1;
7561            *dst.add(pos) = b'0'; pos += 1;
7562            *dst.add(pos) = b'0'; pos += 1;
7563        }
7564        return pos;
7565    }
7566
7567    // === %f format: exact bit-based arithmetic, returns early ===
7568    if use_f {
7569        let bits = v.to_bits();
7570        let raw_mant = bits & 0x000FFFFFFFFFFFFF;
7571        let raw_exp_bits = ((bits >> 52) & 0x7FF) as i32;
7572        let (mant_b, bin_exp) = if raw_exp_bits == 0 {
7573            (raw_mant, -1022i32)
7574        } else {
7575            (raw_mant | (1u64 << 52), raw_exp_bits - 1023)
7576        };
7577
7578        // Integer part as decimal string
7579        let mut ibuf = [0u8; 400];
7580        let mut ilen: usize;
7581        if bin_exp < 0 {
7582            ibuf[0] = b'0'; ilen = 1;
7583        } else if bin_exp <= 63 {
7584            let int_val = if bin_exp <= 52 { mant_b >> (52 - bin_exp) }
7585                          else { mant_b << (bin_exp - 52) };
7586            let (buf2, len2) = format_u64(int_val);
7587            ibuf[..len2].copy_from_slice(&buf2[..len2]);
7588            ilen = len2;
7589        } else {
7590            ilen = bigint_to_decimal(ibuf.as_mut_ptr(), mant_b, (bin_exp - 52) as u32);
7591        }
7592
7593        // Fractional digits
7594        let mut fbuf = [0u8; 1100];
7595        let mut has_rest = false;
7596        if p > 0 && bin_exp < 52 {
7597            let shift = (52 - bin_exp) as u32;
7598            let frac_bits = if bin_exp >= 0 { mant_b & ((1u64 << shift) - 1) } else { mant_b };
7599            if shift <= 124 {
7600                has_rest = frac_digits_u128(fbuf.as_mut_ptr(), frac_bits, shift, p + 1);
7601            } else {
7602                has_rest = frac_digits_bigint(fbuf.as_mut_ptr(), frac_bits, shift, p + 1);
7603            }
7604        }
7605
7606        // Rounding
7607        if p > 0 && bin_exp < 52 {
7608            let next_d = fbuf[p];
7609            let last_d = fbuf[p - 1];
7610            if next_d > 5 || (next_d == 5 && (has_rest || last_d & 1 != 0)) {
7611                let mut carry = true;
7612                for j in (0..p).rev() {
7613                    if !carry { break; }
7614                    fbuf[j] += 1;
7615                    if fbuf[j] < 10 { carry = false; break; }
7616                    fbuf[j] = 0;
7617                }
7618                if carry { increment_decimal(ibuf.as_mut_ptr(), &mut ilen); }
7619            }
7620        } else if p == 0 {
7621            // %.0f: round integer based on fractional part
7622            if bin_exp >= 0 && bin_exp < 52 {
7623                let shift = (52 - bin_exp) as u32;
7624                let frac_bits = mant_b & ((1u64 << shift) - 1);
7625                let half = 1u64 << (shift - 1);
7626                let last_d = ibuf[ilen - 1] - b'0';
7627                if frac_bits > half || (frac_bits == half && last_d & 1 != 0) {
7628                    increment_decimal(ibuf.as_mut_ptr(), &mut ilen);
7629                }
7630            }
7631        }
7632
7633        // Output
7634        core::ptr::copy_nonoverlapping(ibuf.as_ptr(), dst.add(pos), ilen);
7635        pos += ilen;
7636        if p > 0 || flags & FLAG_HASH != 0 {
7637            *dst.add(pos) = b'.'; pos += 1;
7638            for i in 0..p { *dst.add(pos) = b'0' + fbuf[i]; pos += 1; }
7639        }
7640        if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
7641            while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
7642            if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
7643        }
7644        return pos;
7645    }
7646
7647    // === %e/%g format: exact big-integer digit extraction ===
7648    // D = floor(v * 10^(p+1-exp)), using v = mant_b * 2^(bin_exp-52)
7649    let mut fbuf = [0u8; 20];
7650    let mut int_part: u64;
7651    {
7652        let bits_v = v.to_bits();
7653        let raw_mant_v = bits_v & 0x000FFFFFFFFFFFFF;
7654        let raw_exp_v = ((bits_v >> 52) & 0x7FF) as i32;
7655        let (mant_b_v, bin_exp_v) = if raw_exp_v == 0 {
7656            (raw_mant_v, -1022i32)
7657        } else {
7658            (raw_mant_v | (1u64 << 52), raw_exp_v - 1023)
7659        };
7660
7661        let s: i32 = (p as i32) + 1 - exp;
7662        let bs: i32 = bin_exp_v - 52 + s;
7663
7664        let mut limbs = [0u32; 40];
7665        limbs[0] = mant_b_v as u32;
7666        limbs[1] = (mant_b_v >> 32) as u32;
7667        let mut nlimbs: usize = if limbs[1] != 0 { 2 } else { 1 };
7668
7669        if s > 0 {
7670            for _ in 0..(s as usize) {
7671                let mut carry = 0u64;
7672                for j in 0..nlimbs {
7673                    let val = limbs[j] as u64 * 5 + carry;
7674                    limbs[j] = val as u32;
7675                    carry = val >> 32;
7676                }
7677                if carry > 0 { limbs[nlimbs] = carry as u32; nlimbs += 1; }
7678            }
7679        }
7680
7681        if bs > 0 {
7682            let ws = (bs as u32 / 32) as usize;
7683            let bit = bs as u32 % 32;
7684            if ws > 0 {
7685                let mut i = nlimbs;
7686                while i > 0 { i -= 1; if i + ws < 40 { limbs[i + ws] = limbs[i]; } limbs[i] = 0; }
7687                nlimbs += ws;
7688            }
7689            if bit > 0 {
7690                let mut carry = 0u32;
7691                for i in ws..nlimbs {
7692                    let new_val = (limbs[i] << bit) | carry;
7693                    carry = limbs[i] >> (32 - bit);
7694                    limbs[i] = new_val;
7695                }
7696                if carry > 0 && nlimbs < 40 { limbs[nlimbs] = carry; nlimbs += 1; }
7697            }
7698        }
7699
7700        let mut has_rest = false;
7701        if s < 0 {
7702            for _ in 0..(-s as usize) {
7703                let mut rem = 0u64;
7704                for i in (0..nlimbs).rev() {
7705                    let val = (rem << 32) | limbs[i] as u64;
7706                    limbs[i] = (val / 5) as u32;
7707                    rem = val % 5;
7708                }
7709                if rem != 0 { has_rest = true; }
7710            }
7711        }
7712
7713        if bs < 0 {
7714            let rshift = (-bs) as u32;
7715            let ws = (rshift / 32) as usize;
7716            let bit = rshift % 32;
7717            if ws > 0 {
7718                for j in 0..ws.min(nlimbs) { if limbs[j] != 0 { has_rest = true; } }
7719                for i in ws..nlimbs { limbs[i - ws] = limbs[i]; }
7720                nlimbs = nlimbs.saturating_sub(ws);
7721            }
7722            if bit > 0 && nlimbs > 0 {
7723                let mask = (1u32 << bit) - 1;
7724                if limbs[0] & mask != 0 { has_rest = true; }
7725                for i in 0..nlimbs - 1 {
7726                    limbs[i] = (limbs[i] >> bit) | (limbs[i + 1] << (32 - bit));
7727                }
7728                limbs[nlimbs - 1] >>= bit;
7729            }
7730        }
7731
7732        while nlimbs > 0 && limbs[nlimbs - 1] == 0 { nlimbs -= 1; }
7733
7734        let ndigits = p + 2;
7735        let mut all_digits = [0u8; 25];
7736        let mut nd = 0usize;
7737        if nlimbs > 0 {
7738            loop {
7739                let mut all_zero = true;
7740                for i in 0..nlimbs { if limbs[i] != 0 { all_zero = false; break; } }
7741                if all_zero { break; }
7742                let mut rem64 = 0u64;
7743                for i in (0..nlimbs).rev() {
7744                    let val = (rem64 << 32) | limbs[i] as u64;
7745                    limbs[i] = (val / 10) as u32;
7746                    rem64 = val % 10;
7747                }
7748                if nd < 25 { all_digits[nd] = rem64 as u8; }
7749                nd += 1;
7750            }
7751        }
7752
7753        if nd >= ndigits {
7754            for i in 0..ndigits { fbuf[ndigits - 1 - i] = all_digits[i]; }
7755        } else {
7756            for i in 0..nd { fbuf[ndigits - 1 - i] = all_digits[i]; }
7757            for i in nd..ndigits { fbuf[ndigits - 1 - i] = 0; }
7758        }
7759
7760        int_part = fbuf[0] as u64;
7761
7762        // Round half to even: next_d is the rounding digit beyond precision
7763        if p > 0 {
7764            let next_d = fbuf[p + 1];
7765            let last_d = fbuf[p];
7766            if next_d > 5 || (next_d == 5 && (has_rest || last_d & 1 != 0)) {
7767                let mut carry = true;
7768                for j in (1..=p).rev() {
7769                    if !carry { break; }
7770                    let d = fbuf[j] + 1;
7771                    if d < 10 { fbuf[j] = d; carry = false; break; }
7772                    fbuf[j] = 0;
7773                }
7774                if carry { int_part += 1; }
7775            }
7776        } else {
7777            let next_d = fbuf[1];
7778            if next_d > 5 || (next_d == 5 && (has_rest || int_part & 1 != 0)) {
7779                int_part += 1;
7780            }
7781        }
7782
7783        // fbuf[1..=p] are now the fractional digits for output
7784        // Shift them to fbuf[0..p] so output code can index fbuf[0..p]
7785        for i in 0..p { fbuf[i] = fbuf[i + 1]; }
7786    }
7787
7788    if !use_f && int_part >= 10 {
7789        exp += 1;
7790        int_part = 1;
7791    }
7792
7793    // Format output
7794    if use_f {
7795        // %f style
7796        let (ibuf, ilen) = format_u64(int_part);
7797        core::ptr::copy_nonoverlapping(ibuf.as_ptr(), dst.add(pos), ilen);
7798        pos += ilen;
7799        if p > 0 || flags & FLAG_HASH != 0 {
7800            *dst.add(pos) = b'.'; pos += 1;
7801            for idx in 0..p { *dst.add(pos) = b'0' + fbuf[idx]; pos += 1; }
7802        }
7803        if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
7804            while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
7805            if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
7806        }
7807    } else {
7808        // %e style
7809        *dst.add(pos) = b'0' + int_part as u8; pos += 1;
7810        if p > 0 || flags & FLAG_HASH != 0 {
7811            *dst.add(pos) = b'.'; pos += 1;
7812            for idx in 0..p { *dst.add(pos) = b'0' + fbuf[idx]; pos += 1; }
7813        }
7814        if fmt_type == FMT_G && flags & FLAG_HASH == 0 {
7815            while pos > 0 && *dst.add(pos - 1) == b'0' { pos -= 1; }
7816            if pos > 0 && *dst.add(pos - 1) == b'.' { pos -= 1; }
7817        }
7818        let ec = if uppercase { b'E' } else { b'e' };
7819        *dst.add(pos) = ec; pos += 1;
7820        *dst.add(pos) = if exp < 0 { b'-' } else { b'+' }; pos += 1;
7821        let eabs = if exp < 0 { (-exp) as u32 } else { exp as u32 };
7822        if eabs < 10 { *dst.add(pos) = b'0'; pos += 1; }
7823        let (ebuf, elen) = format_u64(eabs as u64);
7824        core::ptr::copy_nonoverlapping(ebuf.as_ptr(), dst.add(pos), elen);
7825        pos += elen;
7826    }
7827
7828    pos
7829}
7830
7831// Compute decimal exponent: floor(log10(v)) with correction
7832unsafe fn compute_exp10(v: f64) -> i32 {
7833    let e = libm::floor(libm::log10(v)) as i32;
7834    let probe = v / libm::pow(10.0, e as f64);
7835    if probe >= 10.0 { e + 1 }
7836    else if probe < 1.0 { e - 1 }
7837    else { e }
7838}
7839
7840// Write hex float to dst. Returns bytes written.
7841unsafe fn fmt_hex_float(dst: *mut u8, val: f64, precision: i32, _flags: u8, uppercase: bool) -> usize {
7842    // Handle zero (and negative zero) specially
7843    if val.to_bits() & 0x7FFFFFFFFFFFFFFF == 0 {
7844        let lc = !uppercase;
7845        let pfx: &[u8] = if lc { b"0x" } else { b"0X" };
7846        let p = if precision < 0 { 0usize } else { precision as usize };
7847        let mut pos = 0usize;
7848        core::ptr::copy_nonoverlapping(pfx.as_ptr(), dst.add(pos), 2); pos += 2;
7849        *dst.add(pos) = b'0'; pos += 1;
7850        if p > 0 {
7851            *dst.add(pos) = b'.'; pos += 1;
7852            for _ in 0..p { *dst.add(pos) = b'0'; pos += 1; }
7853        }
7854        let pc = if lc { b'p' } else { b'P' };
7855        *dst.add(pos) = pc; pos += 1;
7856        *dst.add(pos) = b'+'; pos += 1;
7857        *dst.add(pos) = b'0'; pos += 1;
7858        return pos;
7859    }
7860    let bits = val.to_bits();
7861    let exp_bits = ((bits >> 52) & 0x7FF) as i32;
7862    let mant_bits = bits & 0x000FFFFFFFFFFFFF;
7863    let (mut e, mut m) = if exp_bits == 0 { (1 - 1023, mant_bits) } else { (exp_bits - 1023, mant_bits | (1u64 << 52)) };
7864    // musl normalizes subnormals so the leading digit is always 1, which
7865    // lets the exponent go below -1022 (e.g. 0x1p-1074 for the smallest).
7866    if exp_bits == 0 && m != 0 {
7867        let shift = m.leading_zeros() as i32 - 11;
7868        m <<= shift;
7869        e -= shift;
7870    }
7871    let explicit = precision >= 0;
7872    let p = if explicit { precision as usize } else { 13usize };
7873    let mut pos = 0usize;
7874    let lc = !uppercase;
7875    let pfx: &[u8] = if lc { b"0x" } else { b"0X" };
7876    core::ptr::copy_nonoverlapping(pfx.as_ptr(), dst.add(pos), 2); pos += 2;
7877
7878    // Leading digit from bit 52 (1 for every normalized value).
7879    let lead_pos = pos;
7880    let mut lead = ((m >> 52) & 0xF) as u8;
7881    *dst.add(pos) = hex_digit_char(lead, lc); pos += 1;
7882    let mut frac_start = pos;
7883    if p > 0 {
7884        *dst.add(pos) = b'.'; pos += 1;
7885        frac_start = pos;
7886    }
7887
7888    // Extract p hex digits from the fraction, most significant nibble first.
7889    let mut rm = m;
7890    for _ in 0..p {
7891        let nib = ((rm >> 48) & 0xF) as u8;
7892        *dst.add(pos) = hex_digit_char(nib, lc); pos += 1;
7893        rm <<= 4;
7894    }
7895
7896    // Round to nearest, ties to even, based on the next nibble.
7897    let round_nib = ((rm >> 48) & 0xF) as u8;
7898    let rest = rm & 0x0000FFFFFFFFFFFF;
7899    let last_nib = if p > 0 {
7900        hex_char_val(*dst.add(pos - 1))
7901    } else {
7902        lead
7903    };
7904    let should_round = round_nib > 8 || (round_nib == 8 && (rest != 0 || (last_nib & 1) != 0));
7905    if should_round {
7906        let mut j = pos;
7907        loop {
7908            if j == frac_start {
7909                // Carry out of the fraction into the leading digit.
7910                lead += 1;
7911                *dst.add(lead_pos) = hex_digit_char(lead, lc);
7912                break;
7913            }
7914            j -= 1;
7915            let v = hex_char_val(*dst.add(j));
7916            if v < 15 {
7917                *dst.add(j) = hex_digit_char(v + 1, lc);
7918                break;
7919            }
7920            *dst.add(j) = b'0';
7921        }
7922    }
7923
7924    // With no explicit precision, print the shortest exact representation:
7925    // trim trailing fractional zeros and drop the radix point if empty.
7926    if !explicit {
7927        while pos > frac_start && *dst.add(pos - 1) == b'0' {
7928            pos -= 1;
7929        }
7930        if pos == frac_start {
7931            pos = frac_start - 1;
7932        }
7933    }
7934
7935    // Exponent
7936    let pc = if lc { b'p' } else { b'P' };
7937    *dst.add(pos) = pc; pos += 1;
7938    *dst.add(pos) = if e < 0 { b'-' } else { b'+' }; pos += 1;
7939    let eabs = if e < 0 { (-e) as u32 } else { e as u32 };
7940    let (ebuf, elen) = format_u64(eabs as u64);
7941    core::ptr::copy_nonoverlapping(ebuf.as_ptr(), dst.add(pos), elen);
7942    pos += elen;
7943    pos
7944}
7945
7946#[inline]
7947fn hex_digit_char(v: u8, lowercase: bool) -> u8 {
7948    if v < 10 { b'0' + v }
7949    else if lowercase { b'a' + v - 10 }
7950    else { b'A' + v - 10 }
7951}
7952
7953#[inline]
7954fn hex_char_val(c: u8) -> u8 {
7955    if c >= b'0' && c <= b'9' { c - b'0' }
7956    else if c >= b'a' && c <= b'f' { c - b'a' + 10 }
7957    else if c >= b'A' && c <= b'F' { c - b'A' + 10 }
7958    else { 0 }
7959}
7960
7961// Apply width and flags padding to a formatted string in buf[0..len].
7962// Writes the final result to dst. Returns total bytes written.
7963unsafe fn apply_width_flags(
7964    dst: *mut u8, buf: *const u8, len: usize, width: usize, flags: u8,
7965) -> usize {
7966    if len >= width {
7967        core::ptr::copy_nonoverlapping(buf, dst, len);
7968        return len;
7969    }
7970    let pad = width - len;
7971    let pad_char = if flags & FLAG_ZERO != 0 && flags & FLAG_MINUS == 0 { b'0' } else { b' ' };
7972    if flags & FLAG_MINUS != 0 {
7973        // Left align
7974        core::ptr::copy_nonoverlapping(buf, dst, len);
7975        for i in 0..pad { *dst.add(len + i) = pad_char; }
7976    } else {
7977        // Right align
7978        // For zero-padded numbers, sign goes before zeros
7979        if flags & FLAG_ZERO != 0 && len > 0 {
7980            let first = *buf;
7981            if first == b'-' || first == b'+' || first == b' ' {
7982                *dst = first;
7983                for i in 0..pad { *dst.add(1 + i) = pad_char; }
7984                core::ptr::copy_nonoverlapping(buf.add(1), dst.add(1 + pad), len - 1);
7985                return width;
7986            }
7987        }
7988        for i in 0..pad { *dst.add(i) = pad_char; }
7989        core::ptr::copy_nonoverlapping(buf, dst.add(pad), len);
7990    }
7991    width
7992}
7993
7994#[no_mangle]
7995pub unsafe extern "C" fn vprintf(fmt: *const c_char, mut args: VaList) -> c_int {
7996    impl_format!(fmt, args,
7997        |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stdout); },
7998        |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stdout); }
7999    )
8000}
8001
8002#[no_mangle]
8003pub unsafe extern "C" fn vfprintf(stream: *mut FILE, fmt: *const c_char, mut args: VaList) -> c_int {
8004    impl_format!(fmt, args,
8005        |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stream); },
8006        |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stream); }
8007    )
8008}
8009
8010#[no_mangle]
8011pub unsafe extern "C" fn printf(fmt: *const c_char, mut args: ...) -> c_int {
8012    impl_format!(fmt, args,
8013        |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stdout); },
8014        |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stdout); }
8015    )
8016}
8017
8018#[no_mangle]
8019pub unsafe extern "C" fn fprintf(stream: *mut FILE, fmt: *const c_char, mut args: ...) -> c_int {
8020    impl_format!(fmt, args,
8021        |c: u8| { let _ = fwrite(&c as *const u8 as *const c_void, 1, 1, stream); },
8022        |s: *const u8, len: usize| { let _ = fwrite(s as *const c_void, 1, len, stream); }
8023    )
8024}
8025
8026#[no_mangle]
8027pub unsafe extern "C" fn dprintf(fd: c_int, fmt: *const c_char, mut args: ...) -> c_int {
8028    impl_format!(fmt, args,
8029        |c: u8| { write_str(fd, &c as *const u8, 1); },
8030        |s: *const u8, len: usize| { write_str(fd, s, len); }
8031    )
8032}
8033
8034#[no_mangle]
8035pub unsafe extern "C" fn vdprintf(fd: c_int, fmt: *const c_char, mut args: VaList) -> c_int {
8036    impl_format!(fmt, args,
8037        |c: u8| { write_str(fd, &c as *const u8, 1); },
8038        |s: *const u8, len: usize| { write_str(fd, s, len); }
8039    )
8040}
8041
8042// ============================================================
8043// sprintf / snprintf / vsprintf / vsnprintf
8044// ============================================================
8045
8046unsafe fn format_to_buf(buf: *mut u8, cap: usize, fmt: *const c_char, args: &mut VaList<'_>) -> c_int {
8047    let mut pos = 0usize;
8048    let mut i = 0usize;
8049    let mut count = 0usize;
8050    macro_rules! wc {
8051        ($c:expr) => { if pos < cap { *buf.add(pos) = $c; } pos += 1; count += 1; }
8052    }
8053    macro_rules! ws {
8054        ($s:expr, $len:expr) => {{
8055            let __len = $len;
8056            for k in 0..__len { if pos + k < cap { *buf.add(pos + k) = *$s.add(k); } }
8057            pos += __len; count += __len;
8058        }}
8059    }
8060    // Write formatted buffer respecting cap, at current pos
8061    macro_rules! ws_buf {
8062        ($src:expr, $len:expr) => {{
8063            let __len = $len;
8064            for k in 0..__len { if pos + k < cap { *buf.add(pos + k) = *$src.add(k); } }
8065            pos += __len; count += __len;
8066        }}
8067    }
8068    loop {
8069        let c = *fmt.add(i) as u8;
8070        if c == 0 { break; }
8071        if c != b'%' { wc!(c); i += 1; continue; }
8072        i += 1;
8073        // Parse flags
8074        let mut flags: u8 = 0;
8075        loop {
8076            let fc = *fmt.add(i) as u8;
8077            match fc {
8078                b'-' => { flags |= FLAG_MINUS; i += 1; }
8079                b'+' => { flags |= FLAG_PLUS; i += 1; }
8080                b' ' => { flags |= FLAG_SPACE; i += 1; }
8081                b'0' => { flags |= FLAG_ZERO; i += 1; }
8082                b'#' => { flags |= FLAG_HASH; i += 1; }
8083                _ => break,
8084            }
8085        }
8086        // Parse width
8087        let mut width: usize = 0;
8088        if *fmt.add(i) as u8 == b'*' {
8089            width = args.next_arg::<c_int>() as usize; i += 1;
8090        } else {
8091            while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
8092                width = width * 10 + ((*fmt.add(i) as u8) - b'0') as usize; i += 1;
8093            }
8094        }
8095        // Parse precision
8096        let mut precision: i32 = -1;
8097        if *fmt.add(i) as u8 == b'.' {
8098            i += 1;
8099            if *fmt.add(i) as u8 == b'*' {
8100                precision = args.next_arg::<c_int>(); i += 1;
8101            } else {
8102                precision = 0;
8103                while (*fmt.add(i) as u8) >= b'0' && (*fmt.add(i) as u8) <= b'9' {
8104                    precision = precision * 10 + ((*fmt.add(i) as u8) - b'0') as i32; i += 1;
8105                }
8106            }
8107        }
8108        // Parse length modifier
8109        let len_mod = *fmt.add(i) as u8;
8110        let spec: u8;
8111        if len_mod == b'h' || len_mod == b'l' || len_mod == b'j' || len_mod == b'z' || len_mod == b't' || len_mod == b'L' {
8112            i += 1;
8113            let len_mod2 = *fmt.add(i) as u8;
8114            if (len_mod == b'h' && len_mod2 == b'h') || (len_mod == b'l' && len_mod2 == b'l') {
8115                i += 1;
8116                spec = *fmt.add(i) as u8;
8117                match (len_mod, len_mod2, spec) {
8118                    (b'h', b'h', b'n') => {
8119                        let p = args.next_arg::<*mut c_void>();
8120                        if !p.is_null() { *(p as *mut u8) = count as u8; }
8121                    }
8122                    (b'l', b'l', b'n') => {
8123                        let p = args.next_arg::<*mut c_void>();
8124                        if !p.is_null() { *(p as *mut c_longlong) = count as c_longlong; }
8125                    }
8126                    (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
8127                        let val = args.next_arg::<c_longlong>();
8128                        let neg = val < 0;
8129                        let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
8130                        let b = format_u64(abs);
8131                        let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
8132                        let mut fbuf = [0u8; 32];
8133                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
8134                        ws_buf!(fbuf.as_ptr(), len);
8135                    }
8136                    (b'l', b'l', b'u') => {
8137                        let val = args.next_arg::<c_ulonglong>();
8138                        let b = format_u64(val as u64);
8139                        let mut fbuf = [0u8; 32];
8140                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
8141                        ws_buf!(fbuf.as_ptr(), len);
8142                    }
8143                    (b'l', b'l', b'o') => {
8144                        let val = args.next_arg::<c_ulonglong>();
8145                        let b = format_octal(val as u64, flags & FLAG_HASH != 0);
8146                        let mut fbuf = [0u8; 32];
8147                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
8148                        ws_buf!(fbuf.as_ptr(), len);
8149                    }
8150                    _ => { wc!(b'%'); wc!(len_mod); wc!(len_mod2); wc!(spec); }
8151                }
8152            } else {
8153                spec = len_mod2;
8154                let lm = if (len_mod == b'z' || len_mod == b't') && spec != b'n' { b'l' } else { len_mod };
8155                match (lm, spec) {
8156                    (b'h', b'n') => {
8157                        let p = args.next_arg::<*mut c_void>();
8158                        if !p.is_null() { *(p as *mut u16) = count as u16; }
8159                    }
8160                    (b'l', b'n') => {
8161                        let p = args.next_arg::<*mut c_void>();
8162                        if !p.is_null() { *(p as *mut c_long) = count as c_long; }
8163                    }
8164                    (b'z', b'n') | (b't', b'n') => {
8165                        let p = args.next_arg::<*mut c_void>();
8166                        if !p.is_null() { *(p as *mut usize) = count; }
8167                    }
8168                    (b'j', b'n') => {
8169                        let p = args.next_arg::<*mut c_void>();
8170                        if !p.is_null() { *(p as *mut c_ulonglong) = count as c_ulonglong; }
8171                    }
8172                    (b'l', b'd') | (b'l', b'i') => {
8173                        let val = args.next_arg::<c_long>();
8174                        let neg = val < 0;
8175                        let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
8176                        let b = format_u64(abs);
8177                        let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
8178                        let mut fbuf = [0u8; 32];
8179                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
8180                        ws_buf!(fbuf.as_ptr(), len);
8181                    }
8182                    (b'l', b'u') => {
8183                        let val = args.next_arg::<c_ulong>();
8184                        let b = format_u64(val as u64);
8185                        let mut fbuf = [0u8; 32];
8186                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
8187                        ws_buf!(fbuf.as_ptr(), len);
8188                    }
8189                    (b'l', b's') => {
8190                        let p = args.next_arg::<*const wchar_t>();
8191                        if p.is_null() {
8192                            let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
8193                            let pad = width.saturating_sub(slen);
8194                            if flags & FLAG_MINUS != 0 { ws!(b"(null)".as_ptr(), slen); for _ in 0..pad { wc!(b' '); } }
8195                            else { for _ in 0..pad { wc!(b' '); } ws!(b"(null)".as_ptr(), slen); }
8196                        } else {
8197                            let mut mb = [0u8; 4096];
8198                            let mut n = wide_to_mb(mb.as_mut_ptr(), mb.len(), p);
8199                            if precision >= 0 && (precision as usize) < n { n = precision as usize; }
8200                            let pad = width.saturating_sub(n);
8201                            if flags & FLAG_MINUS != 0 { ws!(mb.as_ptr(), n); for _ in 0..pad { wc!(b' '); } }
8202                            else { for _ in 0..pad { wc!(b' '); } ws!(mb.as_ptr(), n); }
8203                        }
8204                    }
8205                    (b'l', b'c') => {
8206                        let ch = args.next_arg::<c_int>();
8207                        let mut mb = [0u8; 8];
8208                        let mut st: c_uint = 0;
8209                        let n = wcrtomb(mb.as_mut_ptr() as *mut c_char, ch, &mut st);
8210                        if n != !0usize { ws!(mb.as_ptr(), n); }
8211                    }
8212                    (b'l', b'x') => {
8213                        let val = args.next_arg::<c_ulong>();
8214                        let b = format_hex(val as u64, false);
8215                        let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
8216                        let mut fbuf = [0u8; 32];
8217                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
8218                        ws_buf!(fbuf.as_ptr(), len);
8219                    }
8220                    (b'l', b'X') => {
8221                        let val = args.next_arg::<c_ulong>();
8222                        let b = format_hex(val as u64, true);
8223                        let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
8224                        let mut fbuf = [0u8; 32];
8225                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
8226                        ws_buf!(fbuf.as_ptr(), len);
8227                    }
8228                    (b'l', b'o') => {
8229                        let val = args.next_arg::<c_ulong>();
8230                        let b = format_octal(val as u64, flags & FLAG_HASH != 0);
8231                        let mut fbuf = [0u8; 32];
8232                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
8233                        ws_buf!(fbuf.as_ptr(), len);
8234                    }
8235                    (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
8236                    | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A') => {
8237                        let val = args.next_arg::<f64>();
8238                        let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
8239                        let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
8240                        let mut fbuf = [0u8; 4224];
8241                        let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
8242                        let mut wbuf = [0u8; 4224];
8243                        let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
8244                        ws_buf!(wbuf.as_ptr(), wlen);
8245                    }
8246                    (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
8247                    | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
8248                        #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
8249                        let val = {
8250                            let lo: u64 = args.next_arg::<u64>();
8251                            let hi: u64 = args.next_arg::<u64>();
8252                            let combined: u128 = ((hi as u128) << 64) | (lo as u128);
8253                            f128::from_bits(combined) as f64
8254                        };
8255                        #[cfg(target_arch = "x86_64")]
8256                        let val = args.next_arg::<f64>();
8257                        let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
8258                        let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
8259                        let mut fbuf = [0u8; 4224];
8260                        let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
8261                        let mut wbuf = [0u8; 4224];
8262                        let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
8263                        ws_buf!(wbuf.as_ptr(), wlen);
8264                    }
8265                    _ => { wc!(b'%'); wc!(len_mod); wc!(spec); }
8266                }
8267            }
8268        } else {
8269            spec = *fmt.add(i) as u8;
8270            match spec {
8271                b's' => {
8272                    let s = args.next_arg::<*const c_char>();
8273                    if s.is_null() {
8274                        let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
8275                        let padded_len = if width > slen { width } else { slen };
8276                        let pad = padded_len - slen;
8277                        if flags & FLAG_MINUS != 0 {
8278                            ws!(b"(null)".as_ptr(), slen);
8279                            for _ in 0..pad { wc!(b' '); }
8280                        } else {
8281                            for _ in 0..pad { wc!(b' '); }
8282                            ws!(b"(null)".as_ptr(), slen);
8283                        }
8284                    } else {
8285                        let full_len = strlen(s as *const c_char);
8286                        let slen = if precision >= 0 { (precision as usize).min(full_len) } else { full_len };
8287                        let padded_len = if width > slen { width } else { slen };
8288                        let pad = padded_len - slen;
8289                        if flags & FLAG_MINUS != 0 {
8290                            ws!(s as *const u8, slen);
8291                            for _ in 0..pad { wc!(b' '); }
8292                        } else {
8293                            for _ in 0..pad { wc!(b' '); }
8294                            ws!(s as *const u8, slen);
8295                        }
8296                    }
8297                }
8298                b'd' | b'i' => {
8299                    let d = args.next_arg::<c_int>();
8300                    let neg = d < 0;
8301                    let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
8302                    let b = format_u64(abs);
8303                    let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
8304                    let mut fbuf = [0u8; 32];
8305                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
8306                    ws_buf!(fbuf.as_ptr(), len);
8307                }
8308                b'u' => {
8309                    let u = args.next_arg::<c_uint>();
8310                    let b = format_u64(u as u64);
8311                    let mut fbuf = [0u8; 32];
8312                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
8313                    ws_buf!(fbuf.as_ptr(), len);
8314                }
8315                b'x' => {
8316                    let x = args.next_arg::<c_uint>();
8317                    let b = format_hex(x as u64, false);
8318                    let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
8319                    let mut fbuf = [0u8; 32];
8320                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
8321                    ws_buf!(fbuf.as_ptr(), len);
8322                }
8323                b'X' => {
8324                    let x = args.next_arg::<c_uint>();
8325                    let b = format_hex(x as u64, true);
8326                    let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
8327                    let mut fbuf = [0u8; 32];
8328                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
8329                    ws_buf!(fbuf.as_ptr(), len);
8330                }
8331                b'o' => {
8332                    let o = args.next_arg::<c_uint>();
8333                    let b = format_octal(o as u64, flags & FLAG_HASH != 0);
8334                    let mut fbuf = [0u8; 32];
8335                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
8336                    ws_buf!(fbuf.as_ptr(), len);
8337                }
8338                b'c' => {
8339                    let ch = args.next_arg::<c_int>();
8340                    if width > 1 {
8341                        let pad = width - 1;
8342                        if flags & FLAG_MINUS != 0 {
8343                            wc!(ch as u8);
8344                            for _ in 0..pad { wc!(b' '); }
8345                        } else {
8346                            for _ in 0..pad { wc!(b' '); }
8347                            wc!(ch as u8);
8348                        }
8349                    } else {
8350                        wc!(ch as u8);
8351                    }
8352                }
8353                b'p' => {
8354                    wc!(b'0'); wc!(b'x');
8355                    let p = args.next_arg::<*const c_void>();
8356                    let b = format_hex(p as u64, false);
8357                    ws!(b.0.as_ptr(), b.1);
8358                }
8359                b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
8360                    let val = args.next_arg::<f64>();
8361                    let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
8362                    let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
8363                    let mut fbuf = [0u8; 4224];
8364                    let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
8365                    let mut wbuf = [0u8; 4224];
8366                    let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
8367                    ws_buf!(wbuf.as_ptr(), wlen);
8368                }
8369                b'%' => { wc!(b'%'); }
8370                b'n' => {
8371                    let p = args.next_arg::<*mut c_void>();
8372                    if !p.is_null() { *(p as *mut c_int) = count as c_int; }
8373                }
8374                _ => { wc!(b'%'); wc!(spec); }
8375            }
8376        }
8377        i += 1;
8378    }
8379    if cap > 0 { let null_pos = if pos < cap { pos } else { cap - 1 }; *buf.add(null_pos) = 0; }
8380    count as c_int
8381}
8382
8383#[no_mangle]
8384pub unsafe extern "C" fn vsprintf(buf: *mut c_char, fmt: *const c_char, mut args: VaList) -> c_int {
8385    format_to_buf(buf as *mut u8, usize::MAX, fmt, &mut args)
8386}
8387
8388#[no_mangle]
8389pub unsafe extern "C" fn vsnprintf(buf: *mut c_char, size: usize, fmt: *const c_char, mut args: VaList) -> c_int {
8390    format_to_buf(buf as *mut u8, size, fmt, &mut args)
8391}
8392
8393#[no_mangle]
8394pub unsafe extern "C" fn sprintf(buf: *mut c_char, fmt: *const c_char, mut args: ...) -> c_int {
8395    format_to_buf(buf as *mut u8, usize::MAX, fmt, &mut args)
8396}
8397
8398#[no_mangle]
8399pub unsafe extern "C" fn snprintf(buf: *mut c_char, size: usize, fmt: *const c_char, mut args: ...) -> c_int {
8400    format_to_buf(buf as *mut u8, size, fmt, &mut args)
8401}
8402
8403#[no_mangle]
8404pub unsafe extern "C" fn vasprintf(strp: *mut *mut c_char, fmt: *const c_char, ap: VaList) -> c_int {
8405    let len = vsnprintf(core::ptr::null_mut(), 0, fmt, ap.clone());
8406    if len < 0 {
8407        *strp = core::ptr::null_mut();
8408        return -1;
8409    }
8410    let p = malloc((len as usize) + 1) as *mut c_char;
8411    if p.is_null() {
8412        *strp = core::ptr::null_mut();
8413        return -1;
8414    }
8415    let ret = vsnprintf(p, (len as usize) + 1, fmt, ap.clone());
8416    if ret < 0 {
8417        free(p as *mut c_void);
8418        *strp = core::ptr::null_mut();
8419        return -1;
8420    }
8421    *strp = p;
8422    ret
8423}
8424
8425#[no_mangle]
8426pub unsafe extern "C" fn asprintf(strp: *mut *mut c_char, fmt: *const c_char, args: ...) -> c_int {
8427    vasprintf(strp, fmt, args)
8428}
8429
8430// ============================================================
8431// scanf / vscanf / fscanf / vfscanf / sscanf / vsscanf
8432// ============================================================
8433
8434unsafe fn skip_ws(p: *const u8) -> *const u8 {
8435    let mut q = p;
8436    while *q == b' ' || *q == b'\t' || *q == b'\n' || *q == b'\r' { q = q.add(1); }
8437    q
8438}
8439
8440#[inline]
8441fn is_ws_byte(c: u8) -> bool {
8442    c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == 0x0b || c == 0x0c
8443}
8444
8445// Scan integer with position tracking. Returns (value, is_negative, success).
8446// base: 0=auto, 8=octal, 10=decimal, 16=hex
8447unsafe fn scan_int_val(
8448    buf: *const u8, pos: &mut usize, buf_len: usize, base: u32, width: usize,
8449) -> (u64, bool, bool) {
8450    let start = *pos;
8451    let max = if width > 0 { (start + width).min(buf_len) } else { buf_len };
8452    let neg = if *pos < max && *buf.add(*pos) == b'-' { *pos += 1; true }
8453    else if *pos < max && *buf.add(*pos) == b'+' { *pos += 1; false }
8454    else { false };
8455    if *pos >= max { *pos = start; return (0, false, false); }
8456    let mut base = base;
8457    let mut val: u64 = 0;
8458    // Auto-detect base / handle 0x prefix
8459    if (base == 0 || base == 16) && *pos < max && *buf.add(*pos) == b'0' {
8460        *pos += 1;
8461        if *pos < max && (*buf.add(*pos) == b'x' || *buf.add(*pos) == b'X') {
8462            *pos += 1;
8463            if *pos < max {
8464                if let Some(d) = hex_val(*buf.add(*pos)) {
8465                    val = d as u64; *pos += 1;
8466                    while *pos < max { if let Some(d) = hex_val(*buf.add(*pos)) { val = val.wrapping_mul(16).wrapping_add(d as u64); *pos += 1; } else { break; } }
8467                    return (val, neg, true);
8468                }
8469            }
8470            return (0, neg, false);
8471        } else if base == 0 {
8472            while *pos < max { let c = *buf.add(*pos); if c >= b'0' && c <= b'7' { val = val.wrapping_mul(8).wrapping_add((c - b'0') as u64); *pos += 1; } else { break; } }
8473            return (val, neg, true);
8474        } else {
8475            return (0, neg, true); // base=16, '0' not followed by 'x'
8476        }
8477    }
8478    if base == 0 { base = 10; }
8479    let mut found = false;
8480    while *pos < max {
8481        let c = *buf.add(*pos);
8482        let d: Option<u64> = match base {
8483            8 => if c >= b'0' && c <= b'7' { Some((c - b'0') as u64) } else { None },
8484            10 => if c >= b'0' && c <= b'9' { Some((c - b'0') as u64) } else { None },
8485            16 => hex_val(c).map(|v| v as u64),
8486            _ => None,
8487        };
8488        match d { Some(digit) => { val = val.wrapping_mul(base as u64).wrapping_add(digit); *pos += 1; found = true; } None => break }
8489    }
8490    if !found { *pos = start; return (0, false, false); }
8491    (val, neg, true)
8492}
8493
8494// Scan float with position tracking. Returns (value, success).
8495unsafe fn scan_float_val(
8496    buf: *const u8, pos: &mut usize, buf_len: usize, width: usize,
8497) -> (f64, bool) {
8498    let start = *pos;
8499    let max = if width > 0 { (start + width).min(buf_len) } else { buf_len };
8500    let neg = if *pos < max && *buf.add(*pos) == b'-' { *pos += 1; true }
8501    else if *pos < max && *buf.add(*pos) == b'+' { *pos += 1; false }
8502    else { false };
8503    // inf/nan
8504    if *pos + 2 < max {
8505        let (c0,c1,c2) = (*buf.add(*pos), *buf.add(*pos+1), *buf.add(*pos+2));
8506        if (c0==b'i'||c0==b'I')&&(c1==b'n'||c1==b'N')&&(c2==b'f'||c2==b'F') { *pos+=3; return (if neg{f64::NEG_INFINITY}else{f64::INFINITY}, true); }
8507        if (c0==b'n'||c0==b'N')&&(c1==b'a'||c1==b'A')&&(c2==b'n'||c2==b'N') { *pos+=3; return (if neg{-f64::NAN}else{f64::NAN}, true); }
8508    }
8509    // hex float
8510    if *pos+1 < max && *buf.add(*pos)==b'0' && (*buf.add(*pos+1)==b'x'||*buf.add(*pos+1)==b'X') {
8511        *pos += 2;
8512        let mut val: f64 = 0.0; let mut found = false; let mut frac_scale = 1.0f64; let mut in_frac = false;
8513        while *pos < max {
8514            if let Some(d) = hex_val(*buf.add(*pos)) {
8515                if in_frac { frac_scale /= 16.0; val += d as f64 * frac_scale; } else { val = val * 16.0 + d as f64; }
8516                *pos += 1; found = true;
8517            } else if *buf.add(*pos)==b'.' && !in_frac { in_frac = true; *pos += 1; } else { break; }
8518        }
8519        if !found { *pos = start; return (0.0, false); }
8520        // p exponent
8521        if *pos < max && (*buf.add(*pos)==b'p'||*buf.add(*pos)==b'P') {
8522            *pos += 1;
8523            let mut eneg = false;
8524            if *pos<max && *buf.add(*pos)==b'-' { eneg=true; *pos+=1; }
8525            else if *pos<max && *buf.add(*pos)==b'+' { *pos+=1; }
8526            let mut ev: i32 = 0; let mut ef = false;
8527            while *pos<max && *buf.add(*pos)>=b'0' && *buf.add(*pos)<=b'9' { ev = ev*10+(*buf.add(*pos)-b'0') as i32; *pos+=1; ef=true; }
8528            if !ef { return (0.0, false); }
8529            if eneg { ev = -ev; }
8530            val *= libm::pow(2.0, ev as f64);
8531        }
8532        return (if neg{-val}else{val}, true);
8533    }
8534    let token_start = start;
8535    let mut i = start;
8536    let mut saw_digit = false;
8537    let mut saw_dot = false;
8538    let mut saw_exp = false;
8539    let mut first = true;
8540    while i < max {
8541        let c = *buf.add(i);
8542        if (c == b'+' || c == b'-') && first {
8543            i += 1; first = false; continue;
8544        }
8545        if c >= b'0' && c <= b'9' {
8546            saw_digit = true; i += 1; first = false; continue;
8547        }
8548        if c == b'.' && !saw_dot && !saw_exp {
8549            saw_dot = true; i += 1; first = false; continue;
8550        }
8551        if (c == b'e' || c == b'E') && !saw_exp && saw_digit {
8552            saw_exp = true; i += 1; first = true; continue;
8553        }
8554        break;
8555    }
8556    if !saw_digit { return (0.0, false); }
8557    let s = core::str::from_utf8_unchecked(core::slice::from_raw_parts(buf.add(token_start), i - token_start));
8558    match <f64 as core::str::FromStr>::from_str(s) {
8559        Ok(v) => { *pos = i; return (v, true); }
8560        Err(_) => { return (0.0, false); }
8561    }
8562}
8563
8564// Comprehensive scanf parser with position tracking.
8565// consumed: if non-null, stores number of bytes consumed from buf.
8566unsafe fn do_vsscanf(
8567    buf: *const u8, buf_len: usize, fmt: *const c_char, args: &mut VaList<'_>, consumed: *mut usize,
8568) -> c_int {
8569    let mut p = 0usize;
8570    let mut fi = 0usize;
8571    let mut assigned = 0i32;
8572    let mut input_eof = false;
8573    loop {
8574        let fc = *fmt.add(fi) as u8;
8575        if fc == 0 { break; }
8576        if is_ws_byte(fc) {
8577            while is_ws_byte(*fmt.add(fi) as u8) { fi += 1; }
8578            while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
8579            continue;
8580        }
8581        if fc != b'%' {
8582            if p >= buf_len { input_eof = true; break; }
8583            if *buf.add(p) != fc { break; }
8584            p += 1; fi += 1; continue;
8585        }
8586        fi += 1;
8587        // %%
8588        if *fmt.add(fi) as u8 == b'%' {
8589            if p >= buf_len { input_eof = true; break; }
8590            if *buf.add(p) != b'%' { break; }
8591            p += 1; fi += 1; continue;
8592        }
8593        let suppress = if *fmt.add(fi) as u8 == b'*' { fi += 1; true } else { false };
8594        let mut width: usize = 0;
8595        while (*fmt.add(fi) as u8) >= b'0' && (*fmt.add(fi) as u8) <= b'9' {
8596            width = width * 10 + ((*fmt.add(fi) as u8) - b'0') as usize; fi += 1;
8597        }
8598        if *fmt.add(fi) as u8 == b'm' { fi += 1; }
8599        let mut len_mod = 0u8;
8600        match *fmt.add(fi) as u8 {
8601            b'h' => { fi += 1; if *fmt.add(fi) as u8 == b'h' { fi += 1; len_mod = 2; } else { len_mod = 1; } }
8602            b'l' => { fi += 1; if *fmt.add(fi) as u8 == b'l' { fi += 1; len_mod = 4; } else { len_mod = 3; } }
8603            b'j' => { fi += 1; len_mod = 4; }
8604            b'z' | b't' => { fi += 1; len_mod = 3; }
8605            b'L' => { fi += 1; len_mod = 5; }
8606            _ => {}
8607        }
8608        let spec = *fmt.add(fi) as u8;
8609        let (real_spec, _real_len) = if spec==b'C' {(b'c',3u8)} else if spec==b'S' {(b's',3u8)} else {(spec,len_mod)};
8610        match real_spec {
8611            b'n' => {
8612                if !suppress { let out = args.next_arg::<*mut c_int>(); if !out.is_null() { *out = p as c_int; } }
8613            }
8614            b'd' | b'u' => {
8615                while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
8616                if p >= buf_len { input_eof = true; break; }
8617                let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
8618                let (val, neg, ok) = scan_int_val(buf, &mut p, buf_len, 10, width);
8619                if !ok { break; }
8620                if let Some(out) = dest { if !out.is_null() {
8621                    *out = if real_spec==b'd' && neg { -(val as i64) as c_int } else { val as c_int };
8622                }}
8623                if !suppress { assigned += 1; }
8624            }
8625            b'i' => {
8626                while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
8627                if p >= buf_len { input_eof = true; break; }
8628                let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
8629                let (val, neg, ok) = scan_int_val(buf, &mut p, buf_len, 0, width);
8630                if !ok { break; }
8631                if let Some(out) = dest { if !out.is_null() { *out = if neg { -(val as i64) as c_int } else { val as c_int }; } }
8632                if !suppress { assigned += 1; }
8633            }
8634            b'o' => {
8635                while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
8636                if p >= buf_len { input_eof = true; break; }
8637                let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
8638                let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 8, width);
8639                if !ok { break; }
8640                if let Some(out) = dest { if !out.is_null() { *out = val as c_int; } }
8641                if !suppress { assigned += 1; }
8642            }
8643            b'x' | b'X' => {
8644                while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
8645                if p >= buf_len { input_eof = true; break; }
8646                let dest = if !suppress { Some(args.next_arg::<*mut c_int>()) } else { None };
8647                let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 16, width);
8648                if !ok { break; }
8649                if let Some(out) = dest { if !out.is_null() { *out = val as c_int; } }
8650                if !suppress { assigned += 1; }
8651            }
8652            b'p' => {
8653                while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
8654                if p >= buf_len { input_eof = true; break; }
8655                let dest = if !suppress { Some(args.next_arg::<*mut *mut c_void>()) } else { None };
8656                let (val, _, ok) = scan_int_val(buf, &mut p, buf_len, 16, width);
8657                if !ok { break; }
8658                if let Some(out) = dest { if !out.is_null() { *out = val as usize as *mut c_void; } }
8659                if !suppress { assigned += 1; }
8660            }
8661            b'a' | b'e' | b'f' | b'g' | b'A' | b'E' | b'F' | b'G' => {
8662                while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
8663                if p >= buf_len { input_eof = true; break; }
8664                let (val, ok) = scan_float_val(buf, &mut p, buf_len, width);
8665                if !ok { break; }
8666                if !suppress {
8667                    if _real_len == 3 {
8668                        let out = args.next_arg::<*mut f64>(); if !out.is_null() { *out = val; }
8669                    } else if _real_len == 5 {
8670                        #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
8671                        { let out = args.next_arg::<*mut f128>(); if !out.is_null() { *out = val as f128; } }
8672                        #[cfg(target_arch = "x86_64")]
8673                        { let out = args.next_arg::<*mut f64>(); if !out.is_null() { *out = val; } }
8674                    } else {
8675                        let out = args.next_arg::<*mut f32>(); if !out.is_null() { *out = val as f32; }
8676                    }
8677                }
8678                if !suppress { assigned += 1; }
8679            }
8680            b'c' => {
8681                let w = if width > 0 { width } else { 1 };
8682                if p >= buf_len { input_eof = true; break; }
8683                let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
8684                let start_p = p;
8685                let mut j = 0usize;
8686                while j < w && p < buf_len {
8687                    if !dest_ptr.is_null() { *dest_ptr.add(j) = *buf.add(p) as c_char; }
8688                    p += 1; j += 1;
8689                }
8690                if j != w { p = start_p; input_eof = true; break; }
8691                if !suppress { assigned += 1; }
8692            }
8693            b's' => {
8694                while p < buf_len && is_ws_byte(*buf.add(p)) { p += 1; }
8695                if p >= buf_len { input_eof = true; break; }
8696                let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
8697                let w = if width > 0 { width } else { usize::MAX };
8698                let mut j = 0usize;
8699                while p < buf_len && *buf.add(p) != 0 && !is_ws_byte(*buf.add(p)) && j < w {
8700                    if !dest_ptr.is_null() { *dest_ptr.add(j) = *buf.add(p) as c_char; }
8701                    p += 1; j += 1;
8702                }
8703                if j == 0 { break; }
8704                if !dest_ptr.is_null() { *dest_ptr.add(j) = 0; }
8705                if !suppress { assigned += 1; }
8706            }
8707            b'[' => {
8708                fi += 1;
8709                let negate = if *fmt.add(fi) as u8 == b'^' { fi += 1; true } else { false };
8710                let mut charset = [0u8; 256];
8711                if *fmt.add(fi) as u8 == b']' { charset[b']' as usize] = 1; fi += 1; }
8712                loop { let c = *fmt.add(fi) as u8; if c == b']' || c == 0 { break; } charset[c as usize] = 1; fi += 1; }
8713                if *fmt.add(fi) as u8 == b']' { fi += 1; }
8714                fi -= 1; // common fi += 1 will advance past the closing ]
8715                if p >= buf_len { input_eof = true; break; }
8716                let dest_ptr: *mut c_char = if !suppress { args.next_arg::<*mut c_char>() } else { core::ptr::null_mut() };
8717                let w = if width > 0 { width } else { usize::MAX };
8718                let mut j = 0usize;
8719                while p < buf_len && *buf.add(p) != 0 && j < w {
8720                    let c = *buf.add(p);
8721                    let in_set = charset[c as usize] != 0;
8722                    if negate { if in_set { break; } } else { if !in_set { break; } }
8723                    if !dest_ptr.is_null() { *dest_ptr.add(j) = c as c_char; }
8724                    p += 1; j += 1;
8725                }
8726                if j == 0 { break; }
8727                if !dest_ptr.is_null() { *dest_ptr.add(j) = 0; }
8728                if !suppress { assigned += 1; }
8729            }
8730            _ => break,
8731        }
8732        fi += 1;
8733    }
8734    if !consumed.is_null() { *consumed = p; }
8735    if assigned == 0 && input_eof { -1 } else { assigned }
8736}
8737
8738unsafe fn vsscanf_inner(buf: *const u8, fmt: *const c_char, args: &mut VaList<'_>) -> c_int {
8739    let len = strlen(buf as *const c_char);
8740    do_vsscanf(buf, len, fmt, args, core::ptr::null_mut())
8741}
8742
8743#[no_mangle]
8744pub unsafe extern "C" fn vsscanf(buf: *const c_char, fmt: *const c_char, mut args: VaList) -> c_int {
8745    vsscanf_inner(buf as *const u8, fmt, &mut args)
8746}
8747
8748#[no_mangle]
8749pub unsafe extern "C" fn vfscanf(stream: *mut FILE, fmt: *const c_char, mut args: VaList) -> c_int {
8750    let f = &mut *stream;
8751    let start_ungotten_count = f.ungotten_count as usize;
8752    let sfunc = f.seek_fn;
8753    let start_pos = sfunc.map(|s| s(stream, 0, SEEK_CUR)).unwrap_or(-1);
8754
8755    let mut line = [0u8; 4096];
8756    let mut pos = 0usize;
8757
8758    if start_pos >= 0 {
8759        // Seekable: read via fgetc until \n or EOF (existing behavior)
8760        while pos < line.len() - 1 {
8761            let c = fgetc(stream);
8762            if c == -1 { break; }
8763            line[pos] = c as u8;
8764            pos += 1;
8765            if c == b'\n' as c_int { break; }
8766        }
8767    } else {
8768        // Non-seekable (pipe/socket): drain pushback, then read all available
8769        // data non-blocking so we don't stop at \n boundaries.
8770
8771        // 1. Drain ungotten bytes (LIFO order)
8772        while f.ungotten_count > 0 && pos < line.len() - 1 {
8773            f.ungotten_count -= 1;
8774            line[pos] = f.ungotten[f.ungotten_count as usize] as u8;
8775            pos += 1;
8776        }
8777        // 2. Drain rpos/rend pushback buffer
8778        while !f.rpos.is_null() && f.rpos < f.rend && pos < line.len() - 1 {
8779            line[pos] = *f.rpos;
8780            f.rpos = f.rpos.add(1);
8781            pos += 1;
8782        }
8783        // 3. Read available data from the fd without blocking
8784        let fd = f.fd;
8785        let old_flags = sys_fcntl(fd, F_GETFL, 0);
8786        if old_flags >= 0 {
8787            let _ = sys_fcntl(fd, F_SETFL, old_flags | O_NONBLOCK as i64);
8788        }
8789        while pos < line.len() - 1 {
8790            let n = sys_read(fd as i64, line.as_mut_ptr().add(pos), line.len() - 1 - pos);
8791            if n <= 0 { break; }
8792            pos += n as usize;
8793        }
8794        if old_flags >= 0 {
8795            let _ = sys_fcntl(fd, F_SETFL, old_flags);
8796        }
8797        // Clear flags that the failed non-blocking read may have set
8798        f._eof = 0;
8799        f._err = 0;
8800        f.flags &= !(F_EOF | F_ERR);
8801    }
8802
8803    line[pos] = 0;
8804    if pos == 0 { return 0; }
8805
8806    let mut consumed = 0usize;
8807    let assigned = do_vsscanf(line.as_ptr(), pos, fmt, &mut args, &mut consumed);
8808
8809    if start_pos >= 0 {
8810        // Seekable: seek back to start + consumed, restore ungotten
8811        let file_consumed = consumed.saturating_sub(start_ungotten_count);
8812        let target = start_pos + file_consumed as i64;
8813        if let Some(sfunc) = sfunc {
8814            sfunc(stream, target, SEEK_SET);
8815        }
8816        f.rpos = core::ptr::null_mut();
8817        f.rend = core::ptr::null_mut();
8818        if consumed < pos { f._eof = 0; }
8819        let remaining = start_ungotten_count.saturating_sub(consumed);
8820        f.ungotten_count = remaining as c_int;
8821    } else {
8822        // Non-seekable: push back unconsumed bytes into FILE read buffer
8823        let unconsumed = pos.saturating_sub(consumed);
8824        if unconsumed > 0 && !f.buf.is_null() {
8825            let copy_count = core::cmp::min(unconsumed, f.buf_size);
8826            core::ptr::copy(
8827                line.as_ptr().add(consumed),
8828                f.buf,
8829                copy_count,
8830            );
8831            f.rpos = f.buf;
8832            f.rend = f.buf.add(copy_count);
8833        }
8834        f.ungotten_count = 0;
8835        f._eof = 0;
8836        f.flags &= !F_EOF;
8837    }
8838    assigned
8839}
8840
8841#[no_mangle]
8842pub unsafe extern "C" fn vscanf(fmt: *const c_char, args: VaList) -> c_int {
8843    vfscanf(stdin, fmt, args)
8844}
8845
8846#[no_mangle]
8847pub unsafe extern "C" fn sscanf(buf: *const c_char, fmt: *const c_char, mut args: ...) -> c_int {
8848    vsscanf_inner(buf as *const u8, fmt, &mut args)
8849}
8850
8851#[no_mangle]
8852pub unsafe extern "C" fn fscanf(stream: *mut FILE, fmt: *const c_char, args: ...) -> c_int {
8853    vfscanf(stream, fmt, args)
8854}
8855
8856#[no_mangle]
8857pub unsafe extern "C" fn scanf(fmt: *const c_char, args: ...) -> c_int {
8858    vfscanf(stdin, fmt, args)
8859}
8860
8861// ============================================================
8862// getdelim / getline
8863// ============================================================
8864
8865#[no_mangle]
8866pub unsafe extern "C" fn getdelim(
8867    lineptr: *mut *mut c_char, n: *mut usize, delim: c_int, stream: *mut FILE,
8868) -> isize {
8869    if lineptr.is_null() || n.is_null() { return -1; }
8870    let mut cap = *n;
8871    let mut buf = *lineptr;
8872    if buf.is_null() || cap == 0 {
8873        cap = 128;
8874        buf = realloc(buf as *mut c_void, cap) as *mut c_char;
8875        if buf.is_null() { return -1; }
8876        *lineptr = buf;
8877        *n = cap;
8878    }
8879    let mut len = 0usize;
8880    loop {
8881        let c = fgetc(stream);
8882        if c == -1 { if len == 0 { return -1; } break; }
8883        if len + 1 >= cap {
8884            let new_cap = cap.wrapping_mul(2);
8885            let new_buf = realloc(buf as *mut c_void, new_cap) as *mut c_char;
8886            if new_buf.is_null() { return -1; }
8887            buf = new_buf; cap = new_cap;
8888            *lineptr = buf; *n = cap;
8889        }
8890        *buf.add(len) = c as c_char;
8891        len += 1;
8892        if c == delim { break; }
8893    }
8894    *buf.add(len) = 0;
8895    len as isize
8896}
8897
8898#[no_mangle]
8899pub unsafe extern "C" fn getline(lineptr: *mut *mut c_char, n: *mut usize, stream: *mut FILE) -> isize {
8900    getdelim(lineptr, n, b'\n' as c_int, stream)
8901}
8902
8903// ============================================================
8904// popen / pclose
8905// ============================================================
8906
8907#[no_mangle]
8908pub unsafe extern "C" fn popen(cmd: *const c_char, mode: *const c_char) -> *mut FILE {
8909    if cmd.is_null() || mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
8910    let m = *mode;
8911    if m != b'r' as c_char && m != b'w' as c_char { ERRNO = EINVAL; return core::ptr::null_mut(); }
8912    let mut p: [c_int; 2] = [0; 2];
8913    if sys_pipe2(p.as_mut_ptr(), O_CLOEXEC) < 0 { return core::ptr::null_mut(); }
8914    let op = if m == b'r' as c_char { 0 } else { 1 };
8915    let child_fd = p[1 - op];
8916    let f = fdopen(p[op], mode);
8917    if f.is_null() { sys_close(p[0] as i64); sys_close(p[1] as i64); return core::ptr::null_mut(); }
8918    let pid = sys_fork();
8919    if pid < 0 { fclose(f); sys_close(child_fd as i64); return core::ptr::null_mut(); }
8920    if pid == 0 {
8921        sys_close(p[op] as i64);
8922        if child_fd != (1 - op) as c_int { sys_dup3(child_fd, (1 - op) as c_int, 0); sys_close(child_fd as i64); }
8923        let sh = b"/bin/sh\0".as_ptr() as *const c_char;
8924        let argv = [b"sh\0".as_ptr() as *const c_char, b"-c\0".as_ptr() as *const c_char, cmd, core::ptr::null()];
8925        sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
8926        _exit(127);
8927    }
8928    sys_close(child_fd as i64);
8929    (*f).pipe_pid = pid as c_int;
8930    f
8931}
8932
8933#[no_mangle]
8934pub unsafe extern "C" fn pclose(f: *mut FILE) -> c_int {
8935    let pid = (*f).pipe_pid;
8936    let r = fclose(f);
8937    if pid <= 0 { return -1; }
8938    let mut status: c_int = 0;
8939    let mut w: c_int;
8940    loop {
8941        w = waitpid(pid, &mut status, 0);
8942        if w >= 0 || w != -EINTR { break; }
8943    }
8944    if w < 0 || r != 0 { return -1; }
8945    status
8946}
8947
8948// ============================================================
8949// tmpfile / tmpnam / remove / rename
8950// ============================================================
8951
8952const L_TMPNAM: usize = 20;
8953static mut TMPNAM_COUNTER: c_uint = 0;
8954
8955unsafe fn fill_tmpname(out: *mut c_char, seed: c_uint) {
8956    let prefix = b"/tmp/tmp\0";
8957    let mut k = 0;
8958    while k < prefix.len() - 1 { *out.add(k) = prefix[k] as c_char; k += 1; }
8959    let (buf, len) = format_hex(seed as u64, false);
8960    for j in 0..len.min(L_TMPNAM - k - 1) { *out.add(k + j) = buf[j] as c_char; k += 1; }
8961    *out.add(k) = 0;
8962}
8963
8964#[no_mangle]
8965pub unsafe extern "C" fn tmpfile() -> *mut FILE {
8966    let mut name = [0u8; L_TMPNAM];
8967    let mut ctr: c_uint = 0;
8968    loop {
8969        ctr = ctr.wrapping_add(1);
8970        let mut ts: timespec = core::mem::zeroed();
8971        let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
8972        let seed = (ts.tv_nsec as c_uint).wrapping_add(ctr);
8973        fill_tmpname(name.as_mut_ptr() as *mut c_char, seed);
8974        let fd = sys_open(name.as_ptr(), (O_RDWR | O_CREAT | O_EXCL) as i64, 0o600);
8975        if fd >= 0 {
8976            sys_unlinkat(AT_FDCWD, name.as_ptr(), 0);
8977            let f = fdopen(fd as c_int, b"w+\0".as_ptr() as *const c_char);
8978            if f.is_null() { sys_close(fd); }
8979            return f;
8980        }
8981        if ctr > 100 { return core::ptr::null_mut(); }
8982    }
8983}
8984
8985#[no_mangle]
8986pub unsafe extern "C" fn tmpnam(s: *mut c_char) -> *mut c_char {
8987    static mut BUF: [c_char; L_TMPNAM] = [0; L_TMPNAM];
8988    let out = if s.is_null() { core::ptr::addr_of_mut!(BUF) as *mut c_char } else { s };
8989    TMPNAM_COUNTER = TMPNAM_COUNTER.wrapping_add(1);
8990    let mut ts: timespec = core::mem::zeroed();
8991    let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
8992    let seed = (ts.tv_nsec as c_uint).wrapping_add(TMPNAM_COUNTER);
8993    fill_tmpname(out, seed);
8994    out
8995}
8996
8997#[no_mangle]
8998pub unsafe extern "C" fn remove(path: *const c_char) -> c_int {
8999    if path.is_null() { ERRNO = EINVAL; return -1; }
9000    let r = sys_unlinkat(AT_FDCWD, path as *const u8, 0);
9001    if r == 0 { 0 } else { ERRNO = (-r) as c_int; -1 }
9002}
9003
9004#[no_mangle]
9005pub unsafe extern "C" fn rename(old: *const c_char, new_: *const c_char) -> c_int {
9006    if old.is_null() || new_.is_null() { ERRNO = EINVAL; return -1; }
9007    let r = sys_renameat2(AT_FDCWD, old as *const u8, AT_FDCWD, new_ as *const u8, 0);
9008    if r == 0 { 0 } else { ERRNO = (-r) as c_int; -1 }
9009}
9010
9011// ============================================================
9012// Allocator basics
9013// ============================================================
9014
9015const MMAP_FAILED: *mut u8 = !0usize as *mut u8;
9016const PAGE: usize = 4096;
9017
9018// ============================================================
9019// Process: exit / _exit / _Exit
9020// ============================================================
9021
9022#[no_mangle]
9023pub unsafe extern "C" fn _exit(code: c_int) -> ! {
9024    sys_exit_group(code)
9025}
9026
9027#[inline]
9028unsafe fn sys_exit_group(code: c_int) -> ! {
9029    <Arch as Syscalls>::syscall_noreturn1(SYS_EXIT_GROUP, code as i64)
9030}
9031
9032#[inline]
9033unsafe fn sys_exit_thread(code: c_int) -> ! {
9034    <Arch as Syscalls>::syscall_noreturn1(SYS_EXIT, code as i64)
9035}
9036
9037#[no_mangle]
9038pub unsafe extern "C" fn _Exit(code: c_int) -> ! {
9039    _exit(code);
9040}
9041
9042#[no_mangle]
9043pub unsafe extern "C" fn exit(code: c_int) -> ! {
9044    fflush(core::ptr::null_mut());
9045    __funcs_on_exit();
9046    _exit(code);
9047}
9048
9049#[no_mangle]
9050pub unsafe extern "C" fn abort() -> ! {
9051    raise(6); // SIGABRT
9052    _exit(128 + 6);
9053}
9054
9055// aarch64 GCC accesses the stack canary via the global __stack_chk_guard
9056// symbol (GOT-based for PIE). Export it so the dynamic linker can resolve it.
9057#[no_mangle]
9058pub static mut __stack_chk_guard: usize = 0;
9059
9060#[no_mangle]
9061pub unsafe extern "C" fn __stack_chk_fail() -> ! {
9062    const MSG: &[u8] = b"*** stack smashing detected ***: terminated\n";
9063    let _ = sys_write(2, MSG.as_ptr(), MSG.len());
9064    abort();
9065}
9066
9067// ============================================================
9068// qsort / qsort_r (smoothsort, O(1) aux, adaptive)
9069// ============================================================
9070
9071type CmpRfn = unsafe extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int;
9072
9073const AR_LEN: usize = 16 * core::mem::size_of::<usize>();
9074const AR_MASK: usize = AR_LEN - 1;
9075
9076unsafe fn qsort_pntz(p: &[usize; 2]) -> i32 {
9077    if p[0] != 1 {
9078        p[0].wrapping_sub(1).trailing_zeros() as i32
9079    } else if p[1] != 0 {
9080        (8 * core::mem::size_of::<usize>()) as i32 + p[1].trailing_zeros() as i32
9081    } else {
9082        0
9083    }
9084}
9085
9086unsafe fn qsort_cycle(width: usize, ar: &mut [*mut u8; AR_LEN], n: usize) {
9087    if n < 2 { return; }
9088    let mut tmp = [0u8; 256];
9089    ar[n] = tmp.as_mut_ptr();
9090    let mut w = width;
9091    while w > 0 {
9092        let l = if 256 < w { 256 } else { w };
9093        core::ptr::copy_nonoverlapping(ar[0], ar[n], l);
9094        for i in 0..n {
9095            core::ptr::copy_nonoverlapping(ar[i + 1], ar[i], l);
9096            ar[i] = ar[i].add(l);
9097        }
9098        w -= l;
9099    }
9100}
9101
9102unsafe fn qsort_shl(p: &mut [usize; 2], n: i32) {
9103    let bits = (8 * core::mem::size_of::<usize>()) as i32;
9104    if n >= bits {
9105        p[1] = p[0];
9106        p[0] = 0;
9107        let n = n - bits;
9108        if n == 0 { return; }
9109    }
9110    p[1] = (p[1] << n) | (p[0] >> (bits - n));
9111    p[0] <<= n;
9112}
9113
9114unsafe fn qsort_shr(p: &mut [usize; 2], n: i32) {
9115    let bits = (8 * core::mem::size_of::<usize>()) as i32;
9116    if n >= bits {
9117        p[0] = p[1];
9118        p[1] = 0;
9119        let n = n - bits;
9120        if n == 0 { return; }
9121    }
9122    p[0] = (p[0] >> n) | (p[1] << (bits - n));
9123    p[1] >>= n;
9124}
9125
9126unsafe fn qsort_sift(
9127    head: *mut u8, width: usize,
9128    cmp: CmpRfn, arg: *mut c_void,
9129    pshift: i32, lp: &[usize],
9130) {
9131    let mut ar: [*mut u8; AR_LEN] = [core::ptr::null_mut(); AR_LEN];
9132    ar[0] = head;
9133    let mut i = 1usize;
9134    let mut h = head;
9135    let mut ps = pshift;
9136
9137    while ps > 1 {
9138        let rt = h.sub(width);
9139        let lf = h.sub(width + lp[(ps - 2) as usize]);
9140
9141        if cmp(ar[0] as *const c_void, lf as *const c_void, arg) >= 0
9142            && cmp(ar[0] as *const c_void, rt as *const c_void, arg) >= 0
9143        {
9144            break;
9145        }
9146        if cmp(lf as *const c_void, rt as *const c_void, arg) >= 0 {
9147            ar[i & AR_MASK] = lf;
9148            i += 1;
9149            h = lf;
9150            ps -= 1;
9151        } else {
9152            ar[i & AR_MASK] = rt;
9153            i += 1;
9154            h = rt;
9155            ps -= 2;
9156        }
9157    }
9158    qsort_cycle(width, &mut ar, i & AR_MASK);
9159}
9160
9161unsafe fn qsort_trinkle(
9162    head: *mut u8, width: usize,
9163    cmp: CmpRfn, arg: *mut c_void,
9164    pp: &[usize; 2], pshift: i32, trusty: i32,
9165    lp: &[usize],
9166) {
9167    let mut ar: [*mut u8; AR_LEN] = [core::ptr::null_mut(); AR_LEN];
9168    let mut p = *pp;
9169    ar[0] = head;
9170    let mut i = 1usize;
9171    let mut h = head;
9172    let mut ps = pshift;
9173    let mut t = trusty;
9174
9175    while p[0] != 1 || p[1] != 0 {
9176        let stepson = h.sub(lp[ps as usize]);
9177        if cmp(stepson as *const c_void, ar[0] as *const c_void, arg) <= 0 {
9178            break;
9179        }
9180        if t == 0 && ps > 1 {
9181            let rt = h.sub(width);
9182            let lf = h.sub(width + lp[(ps - 2) as usize]);
9183            if cmp(rt as *const c_void, stepson as *const c_void, arg) >= 0
9184                || cmp(lf as *const c_void, stepson as *const c_void, arg) >= 0
9185            {
9186                break;
9187            }
9188        }
9189
9190        ar[i & AR_MASK] = stepson;
9191        i += 1;
9192        h = stepson;
9193        let trail = qsort_pntz(&p);
9194        qsort_shr(&mut p, trail);
9195        ps += trail;
9196        t = 0;
9197    }
9198    if t == 0 {
9199        qsort_cycle(width, &mut ar, i & AR_MASK);
9200        qsort_sift(h, width, cmp, arg, ps, lp);
9201    }
9202}
9203
9204#[no_mangle]
9205pub unsafe extern "C" fn __qsort_r(
9206    base: *mut c_void,
9207    nel: usize,
9208    width: usize,
9209    cmp: CmpRfn,
9210    arg: *mut c_void,
9211) {
9212    let size = width * nel;
9213    if size == 0 { return; }
9214
9215    let mut lp = [0usize; 96];
9216    lp[0] = width;
9217    lp[1] = width;
9218    let mut li = 2;
9219    while {
9220        lp[li] = lp[li - 2] + lp[li - 1] + width;
9221        lp[li] < size
9222    } {
9223        li += 1;
9224    }
9225
9226    let mut head = base as *mut u8;
9227    let high = head.add(size - width);
9228    let mut p: [usize; 2] = [1, 0];
9229    let mut pshift: i32 = 1;
9230
9231    while head < high {
9232        if (p[0] & 3) == 3 {
9233            qsort_sift(head, width, cmp, arg, pshift, &lp);
9234            qsort_shr(&mut p, 2);
9235            pshift += 2;
9236        } else {
9237            if lp[(pshift - 1) as usize] >= (high as usize) - (head as usize) {
9238                qsort_trinkle(head, width, cmp, arg, &p, pshift, 0, &lp);
9239            } else {
9240                qsort_sift(head, width, cmp, arg, pshift, &lp);
9241            }
9242
9243            if pshift == 1 {
9244                qsort_shl(&mut p, 1);
9245                pshift = 0;
9246            } else {
9247                qsort_shl(&mut p, pshift - 1);
9248                pshift = 1;
9249            }
9250        }
9251
9252        p[0] |= 1;
9253        head = head.add(width);
9254    }
9255
9256    qsort_trinkle(head, width, cmp, arg, &p, pshift, 0, &lp);
9257
9258    while pshift != 1 || p[0] != 1 || p[1] != 0 {
9259        if pshift <= 1 {
9260            let trail = qsort_pntz(&p);
9261            qsort_shr(&mut p, trail);
9262            pshift += trail;
9263        } else {
9264            qsort_shl(&mut p, 2);
9265            pshift -= 2;
9266            p[0] ^= 7;
9267            qsort_shr(&mut p, 1);
9268            qsort_trinkle(
9269                head.sub(lp[pshift as usize] + width),
9270                width, cmp, arg, &p, pshift + 1, 1, &lp,
9271            );
9272            qsort_shl(&mut p, 1);
9273            p[0] |= 1;
9274            qsort_trinkle(head.sub(width), width, cmp, arg, &p, pshift, 1, &lp);
9275        }
9276        head = head.sub(width);
9277    }
9278}
9279
9280#[no_mangle]
9281pub unsafe extern "C" fn qsort_r(
9282    base: *mut c_void,
9283    nel: usize,
9284    width: usize,
9285    cmp: CmpRfn,
9286    arg: *mut c_void,
9287) {
9288    __qsort_r(base, nel, width, cmp, arg);
9289}
9290
9291unsafe extern "C" fn qsort_wrap_cmp(
9292    a: *const c_void,
9293    b: *const c_void,
9294    cmp_ctx: *mut c_void,
9295) -> c_int {
9296    let cmp: CmpFn = core::mem::transmute(cmp_ctx);
9297    cmp(a, b)
9298}
9299
9300#[no_mangle]
9301pub unsafe extern "C" fn qsort(
9302    base: *mut c_void,
9303    nel: usize,
9304    width: usize,
9305    cmp: CmpFn,
9306) {
9307    __qsort_r(base, nel, width, qsort_wrap_cmp, cmp as *mut c_void);
9308}
9309
9310// ============================================================
9311// atexit / __cxa_atexit / __funcs_on_exit
9312// ============================================================
9313
9314const ATEXIT_COUNT: usize = 32;
9315
9316#[repr(C)]
9317struct AtExitBlock {
9318    next: *mut AtExitBlock,
9319    f: [Option<unsafe extern "C" fn(*mut c_void)>; ATEXIT_COUNT],
9320    a: [*mut c_void; ATEXIT_COUNT],
9321}
9322
9323static mut ATEXIT_BUILTIN: AtExitBlock = AtExitBlock {
9324    next: core::ptr::null_mut(),
9325    f: [None; ATEXIT_COUNT],
9326    a: [core::ptr::null_mut(); ATEXIT_COUNT],
9327};
9328static mut ATEXIT_HEAD: *mut AtExitBlock = core::ptr::null_mut();
9329static mut ATEXIT_SLOT: usize = 0;
9330static mut ATEXIT_FINISHED: bool = false;
9331
9332#[no_mangle]
9333pub unsafe extern "C" fn __funcs_on_exit() {
9334    while !ATEXIT_HEAD.is_null() {
9335        let head = ATEXIT_HEAD;
9336        while ATEXIT_SLOT > 0 {
9337            ATEXIT_SLOT -= 1;
9338            if let Some(f) = (*head).f[ATEXIT_SLOT] {
9339                let a = (*head).a[ATEXIT_SLOT];
9340                f(a);
9341            }
9342        }
9343        ATEXIT_HEAD = (*head).next;
9344        ATEXIT_SLOT = ATEXIT_COUNT;
9345    }
9346    ATEXIT_FINISHED = true;
9347}
9348
9349#[no_mangle]
9350pub unsafe extern "C" fn __cxa_atexit(
9351    func: unsafe extern "C" fn(*mut c_void),
9352    arg: *mut c_void,
9353    _dso: *mut c_void,
9354) -> c_int {
9355    if ATEXIT_FINISHED {
9356        return -1;
9357    }
9358    if ATEXIT_HEAD.is_null() {
9359        ATEXIT_HEAD = core::ptr::addr_of_mut!(ATEXIT_BUILTIN);
9360    }
9361    if ATEXIT_SLOT == ATEXIT_COUNT {
9362        let new = calloc(1, core::mem::size_of::<AtExitBlock>()) as *mut AtExitBlock;
9363        if new.is_null() {
9364            return -1;
9365        }
9366        (*new).next = ATEXIT_HEAD;
9367        ATEXIT_HEAD = new;
9368        ATEXIT_SLOT = 0;
9369    }
9370    (*ATEXIT_HEAD).f[ATEXIT_SLOT] = Some(func);
9371    (*ATEXIT_HEAD).a[ATEXIT_SLOT] = arg;
9372    ATEXIT_SLOT += 1;
9373    0
9374}
9375
9376unsafe extern "C" fn atexit_caller(arg: *mut c_void) {
9377    let func: unsafe extern "C" fn() = core::mem::transmute(arg);
9378    func();
9379}
9380
9381#[no_mangle]
9382pub unsafe extern "C" fn atexit(func: unsafe extern "C" fn()) -> c_int {
9383    __cxa_atexit(atexit_caller, func as *mut c_void, core::ptr::null_mut())
9384}
9385
9386#[no_mangle]
9387pub unsafe extern "C" fn __cxa_finalize(_dso: *mut c_void) {}
9388
9389// ============================================================
9390// getenv / setenv / putenv / unsetenv / clearenv
9391// ============================================================
9392
9393#[no_mangle]
9394pub static mut __environ: *mut *mut c_char = core::ptr::null_mut();
9395
9396// ponytail: simple env tracking for allocated entries; O(n) scan
9397const ENV_MAX_ALLOCED: usize = 256;
9398static mut ENV_ALLOCED: [*mut c_char; ENV_MAX_ALLOCED] = [core::ptr::null_mut(); ENV_MAX_ALLOCED];
9399static mut ENV_ALLOCED_N: usize = 0;
9400
9401unsafe fn env_rm_add(old: *mut c_char, mut new: *mut c_char) {
9402    for i in 0..ENV_ALLOCED_N {
9403        if ENV_ALLOCED[i] == old {
9404            ENV_ALLOCED[i] = new;
9405            if !old.is_null() {
9406                free(old as *mut c_void);
9407            }
9408            return;
9409        } else if ENV_ALLOCED[i].is_null() && !new.is_null() {
9410            ENV_ALLOCED[i] = new;
9411            new = core::ptr::null_mut();
9412        }
9413    }
9414    if !new.is_null() && ENV_ALLOCED_N < ENV_MAX_ALLOCED {
9415        ENV_ALLOCED[ENV_ALLOCED_N] = new;
9416        ENV_ALLOCED_N += 1;
9417    }
9418}
9419
9420unsafe fn strchrnul_u8(s: *const u8, c: u8) -> *const u8 {
9421    let mut p = s;
9422    while *p != 0 && *p != c {
9423        p = p.add(1);
9424    }
9425    p
9426}
9427
9428#[no_mangle]
9429pub unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char {
9430    if __environ.is_null() || name.is_null() {
9431        return core::ptr::null_mut();
9432    }
9433    let name = name as *const u8;
9434    let l = strchrnul_u8(name, b'=') as usize - name as usize;
9435    if l == 0 || *name.add(l) != 0 {
9436        return core::ptr::null_mut();
9437    }
9438    let mut e = __environ;
9439    while !(*e).is_null() {
9440        let entry = *e as *const u8;
9441        if strncmp(entry, name, l) == 0 && *entry.add(l) == b'=' {
9442            return entry.add(l + 1) as *mut c_char;
9443        }
9444        e = e.add(1);
9445    }
9446    core::ptr::null_mut()
9447}
9448
9449#[no_mangle]
9450pub unsafe extern "C" fn setenv(
9451    var: *const c_char,
9452    value: *const c_char,
9453    overwrite: c_int,
9454) -> c_int {
9455    if var.is_null() || value.is_null() {
9456        ERRNO = EINVAL;
9457        return -1;
9458    }
9459    let var = var as *const u8;
9460    let l1 = strchrnul_u8(var, b'=') as usize - var as usize;
9461    if l1 == 0 || *var.add(l1) != 0 {
9462        ERRNO = EINVAL;
9463        return -1;
9464    }
9465    if overwrite == 0 && !getenv(var as *const c_char).is_null() {
9466        return 0;
9467    }
9468    let l2 = strlen(value as *const c_char);
9469    let s = malloc(l1 + l2 + 2) as *mut u8;
9470    if s.is_null() {
9471        return -1;
9472    }
9473    core::ptr::copy_nonoverlapping(var, s, l1);
9474    *s.add(l1) = b'=';
9475    core::ptr::copy_nonoverlapping(value as *const u8, s.add(l1 + 1), l2 + 1);
9476    putenv_internal(s as *mut c_char, l1, s as *mut c_char)
9477}
9478
9479unsafe fn putenv_internal(s: *mut c_char, l: usize, r: *mut c_char) -> c_int {
9480    let mut i = 0;
9481    if !__environ.is_null() {
9482        let mut e = __environ;
9483        while !(*e).is_null() {
9484            if strncmp(s as *const u8, *e as *const u8, l + 1) == 0 {
9485                let tmp = *e;
9486                *e = s;
9487                env_rm_add(tmp, r);
9488                return 0;
9489            }
9490            e = e.add(1);
9491            i += 1;
9492        }
9493    }
9494    let newenv = malloc(core::mem::size_of::<*mut c_char>() * (i + 2)) as *mut *mut c_char;
9495    if newenv.is_null() {
9496        if !r.is_null() { free(r as *mut c_void); }
9497        return -1;
9498    }
9499    if i > 0 && !__environ.is_null() {
9500        core::ptr::copy_nonoverlapping(__environ, newenv, i);
9501    }
9502    *newenv.add(i) = s;
9503    *newenv.add(i + 1) = core::ptr::null_mut();
9504    // ponytail: don't free old __environ (may not be from our malloc)
9505    __environ = newenv;
9506    environ = __environ;
9507    if !r.is_null() {
9508        env_rm_add(core::ptr::null_mut(), r);
9509    }
9510    0
9511}
9512
9513#[no_mangle]
9514pub unsafe extern "C" fn putenv(s: *mut c_char) -> c_int {
9515    if s.is_null() { return -1; }
9516    let l = strchrnul_u8(s as *const u8, b'=') as usize - s as *const u8 as usize;
9517    if l == 0 || *s.add(l) as u8 == 0 {
9518        return unsetenv(s);
9519    }
9520    putenv_internal(s, l, core::ptr::null_mut())
9521}
9522
9523#[no_mangle]
9524pub unsafe extern "C" fn unsetenv(name: *const c_char) -> c_int {
9525    if name.is_null() {
9526        ERRNO = EINVAL;
9527        return -1;
9528    }
9529    let name = name as *const u8;
9530    let l = strchrnul_u8(name, b'=') as usize - name as usize;
9531    if l == 0 || *name.add(l) != 0 {
9532        ERRNO = EINVAL;
9533        return -1;
9534    }
9535    if __environ.is_null() {
9536        return 0;
9537    }
9538    let mut e = __environ;
9539    let mut eo = e;
9540    while !(*e).is_null() {
9541        if strncmp(name, *e as *const u8, l) == 0 && *(*e as *const u8).add(l) == b'=' {
9542            env_rm_add(*e, core::ptr::null_mut());
9543        } else {
9544            if eo != e {
9545                *eo = *e;
9546            }
9547            eo = eo.add(1);
9548        }
9549        e = e.add(1);
9550    }
9551    if eo != e {
9552        *eo = core::ptr::null_mut();
9553    }
9554    environ = __environ;
9555    0
9556}
9557
9558#[no_mangle]
9559pub unsafe extern "C" fn clearenv() -> c_int {
9560    let e = __environ;
9561    __environ = core::ptr::null_mut();
9562    environ = core::ptr::null_mut();
9563    if !e.is_null() {
9564        let mut p = e;
9565        while !(*p).is_null() {
9566            env_rm_add(*p, core::ptr::null_mut());
9567            p = p.add(1);
9568        }
9569    }
9570    0
9571}
9572
9573// ============================================================
9574// random / srandom / initstate / setstate (BSD lagged fibonacci)
9575// ponytail: single-threaded, no locking; add lock if concurrency matters
9576// ============================================================
9577
9578static mut RANDOM_INIT: [u32; 32] = [
9579    0x00000000,0x5851f42d,0xc0b18ccf,0xcbb5f646,
9580    0xc7033129,0x30705b04,0x20fd5db4,0x9a8b7f78,
9581    0x502959d8,0xab894868,0x6c0356a7,0x88cdb7ff,
9582    0xb477d43f,0x70a3a52b,0xa8e4baf1,0xfd8341fc,
9583    0x8ae16fd9,0x742d2f7a,0x0d1f0796,0x76035e09,
9584    0x40f7702c,0x6fa72ca5,0xaaa84157,0x58a0df74,
9585    0xc74a0364,0xae533cc4,0x04185faf,0x6de3b115,
9586    0x0cab8628,0xf043bfa4,0x398150e9,0x37521657,
9587];
9588
9589static mut RANDOM_N: i32 = 31;
9590static mut RANDOM_I: i32 = 3;
9591static mut RANDOM_J: i32 = 0;
9592static mut RANDOM_X: *mut u32 = unsafe { core::ptr::addr_of_mut!(RANDOM_INIT).cast::<u32>().add(1) };
9593
9594unsafe fn random_lcg31(x: u32) -> u32 {
9595    (1103515245u32.wrapping_mul(x).wrapping_add(12345)) & 0x7fffffff
9596}
9597
9598unsafe fn random_lcg64(x: u64) -> u64 {
9599    6364136223846793005u64.wrapping_mul(x).wrapping_add(1)
9600}
9601
9602unsafe fn random_savestate() -> *mut u8 {
9603    (*RANDOM_X.offset(-1)) = ((RANDOM_N as u32) << 16) | ((RANDOM_I as u32) << 8) | (RANDOM_J as u32);
9604    RANDOM_X.offset(-1) as *mut u8
9605}
9606
9607unsafe fn random_loadstate(state: *mut u32) {
9608    RANDOM_X = state.add(1);
9609    RANDOM_N = ((*RANDOM_X.offset(-1)) >> 16) as i32;
9610    RANDOM_I = (((*RANDOM_X.offset(-1)) >> 8) & 0xff) as i32;
9611    RANDOM_J = ((*RANDOM_X.offset(-1)) & 0xff) as i32;
9612}
9613
9614unsafe fn random_srandom_inner(seed: u32) {
9615    let mut s = seed as u64;
9616    if RANDOM_N == 0 {
9617        *RANDOM_X = s as u32;
9618        return;
9619    }
9620    RANDOM_I = if RANDOM_N == 31 || RANDOM_N == 7 { 3 } else { 1 };
9621    RANDOM_J = 0;
9622    for k in 0..RANDOM_N as usize {
9623        s = random_lcg64(s);
9624        *RANDOM_X.add(k) = (s >> 32) as u32;
9625    }
9626    *RANDOM_X |= 1;
9627}
9628
9629#[no_mangle]
9630pub unsafe extern "C" fn srandom(seed: c_uint) {
9631    random_srandom_inner(seed);
9632}
9633
9634#[no_mangle]
9635pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: usize) -> *mut c_char {
9636    if size < 8 { return core::ptr::null_mut(); }
9637    let old = random_savestate();
9638    RANDOM_N = if size < 32 { 0 }
9639        else if size < 64 { 7 }
9640        else if size < 128 { 15 }
9641        else if size < 256 { 31 }
9642        else { 63 };
9643    RANDOM_X = (state as *mut u32).add(1);
9644    random_srandom_inner(seed);
9645    random_savestate();
9646    old as *mut c_char
9647}
9648
9649#[no_mangle]
9650pub unsafe extern "C" fn setstate(state: *mut c_char) -> *mut c_char {
9651    let old = random_savestate();
9652    random_loadstate(state as *mut u32);
9653    old as *mut c_char
9654}
9655
9656#[no_mangle]
9657pub unsafe extern "C" fn random() -> c_long {
9658    let k: c_long;
9659    if RANDOM_N == 0 {
9660        *RANDOM_X = random_lcg31(*RANDOM_X);
9661        k = *RANDOM_X as c_long;
9662    } else {
9663        *RANDOM_X.add(RANDOM_I as usize) = (*RANDOM_X.add(RANDOM_I as usize)).wrapping_add(*RANDOM_X.add(RANDOM_J as usize));
9664        k = (*RANDOM_X.add(RANDOM_I as usize) >> 1) as c_long;
9665        RANDOM_I += 1;
9666        if RANDOM_I == RANDOM_N { RANDOM_I = 0; }
9667        RANDOM_J += 1;
9668        if RANDOM_J == RANDOM_N { RANDOM_J = 0; }
9669    }
9670    k
9671}
9672
9673// ============================================================
9674// multibyte (UTF-8, musl state machine)
9675// ============================================================
9676
9677const SA: u8 = 0xC2;
9678const SB: u8 = 0xF4;
9679
9680const BITTAB: [u32; 51] = [
9681    0xC000_0002, 0xC000_0003, 0xC000_0004, 0xC000_0005, 0xC000_0006, 0xC000_0007,
9682    0xC000_0008, 0xC000_0009, 0xC000_000A, 0xC000_000B, 0xC000_000C, 0xC000_000D,
9683    0xC000_000E, 0xC000_000F, 0xC000_0010, 0xC000_0011, 0xC000_0012, 0xC000_0013,
9684    0xC000_0014, 0xC000_0015, 0xC000_0016, 0xC000_0017, 0xC000_0018, 0xC000_0019,
9685    0xC000_001A, 0xC000_001B, 0xC000_001C, 0xC000_001D, 0xC000_001E, 0xC000_001F,
9686    0xB300_0000, 0xC300_0001, 0xC300_0002, 0xC300_0003, 0xC300_0004, 0xC300_0005,
9687    0xC300_0006, 0xC300_0007, 0xC300_0008, 0xC300_0009, 0xC300_000A, 0xC300_000B,
9688    0xC300_000C, 0xD300_000D, 0xC300_000E, 0xC300_000F, 0xBB0C_0000, 0xC30C_0001,
9689    0xC30C_0002, 0xC30C_0003, 0xDB0C_0004,
9690];
9691
9692#[inline]
9693fn mb_oob(c: u32, b: u8) -> u32 {
9694    let b3 = (b >> 3) as u32;
9695    ((b3.wrapping_sub(0x10)) | (b3.wrapping_add((c as i32 >> 26) as u32))) & !7
9696}
9697
9698static mut MB_STATE: c_uint = 0;
9699
9700const MB_CUR_MAX_VAL_UTF8: usize = 4;
9701const MB_CUR_MAX_VAL_C: usize = 1;
9702
9703#[no_mangle]
9704pub extern "C" fn __ctype_get_mb_cur_max() -> usize {
9705    unsafe { if LOCALE_CTYPE_UTF8 { MB_CUR_MAX_VAL_UTF8 } else { MB_CUR_MAX_VAL_C } }
9706}
9707
9708#[no_mangle]
9709pub unsafe extern "C" fn mbrtowc(
9710    wc: *mut c_int,
9711    src: *const c_char,
9712    n: usize,
9713    st: *mut c_uint,
9714) -> usize {
9715    let s = src as *const u8;
9716    let n0 = n;
9717    let mut dummy: c_int = 0;
9718    let wc = if wc.is_null() { &mut dummy } else { &mut *wc };
9719    let st: &mut c_uint = if st.is_null() { &mut *(&raw mut MB_STATE) } else { &mut *st };
9720
9721    let mut c: u32 = *st;
9722    let mut s = s;
9723    let mut n = n;
9724
9725    if s.is_null() {
9726        if c != 0 { *st = 0; ERRNO = EILSEQ; return !0usize; }
9727        return 0;
9728    }
9729
9730    if n == 0 { return !1usize; }
9731
9732    if unsafe { !LOCALE_CTYPE_UTF8 } {
9733        let b = *s;
9734        *wc = b as c_int;
9735        return if b == 0 { 0 } else { 1 };
9736    }
9737
9738    if c == 0 {
9739        if *s < 0x80 {
9740            let r = if *s == 0 { 0 } else { 1 };
9741            *wc = *s as c_int;
9742            return r;
9743        }
9744        if (*s).wrapping_sub(SA) as u32 > (SB - SA) as u32 {
9745            *st = 0; ERRNO = EILSEQ; return !0usize;
9746        }
9747        c = BITTAB[*s as usize - SA as usize];
9748        s = s.add(1);
9749        n -= 1;
9750    }
9751
9752    if n > 0 {
9753        if mb_oob(c, *s) != 0 {
9754            *st = 0; ERRNO = EILSEQ; return !0usize;
9755        }
9756        loop {
9757            c = (c << 6) | (*s as u32).wrapping_sub(0x80);
9758            s = s.add(1);
9759            n -= 1;
9760            if c & (1u32 << 31) == 0 {
9761                *st = 0;
9762                *wc = c as c_int;
9763                return n0 - n;
9764            }
9765            if n == 0 { break; }
9766            if (*s).wrapping_sub(0x80) >= 0x40 {
9767                *st = 0; ERRNO = EILSEQ; return !0usize;
9768            }
9769        }
9770    }
9771
9772    *st = c;
9773    !1usize
9774}
9775
9776#[no_mangle]
9777pub unsafe extern "C" fn wcrtomb(
9778    s: *mut c_char,
9779    wc: c_int,
9780    _st: *mut c_uint,
9781) -> usize {
9782    if s.is_null() { return 1; }
9783    let wc_u = wc as u32;
9784    if unsafe { !LOCALE_CTYPE_UTF8 } {
9785        if wc_u > 0xFF {
9786            ERRNO = EILSEQ;
9787            return !0usize;
9788        }
9789        *s = wc as c_char;
9790        return 1;
9791    }
9792    if wc_u < 0x80 {
9793        *s = wc as c_char;
9794        return 1;
9795    }
9796    if wc_u < 0x800 {
9797        *s = (0xC0 | (wc_u >> 6)) as c_char;
9798        *s.add(1) = (0x80 | (wc_u & 0x3F)) as c_char;
9799        return 2;
9800    }
9801    if wc_u < 0xD800 || wc_u.wrapping_sub(0xE000) < 0x2000 {
9802        *s = (0xE0 | (wc_u >> 12)) as c_char;
9803        *s.add(1) = (0x80 | ((wc_u >> 6) & 0x3F)) as c_char;
9804        *s.add(2) = (0x80 | (wc_u & 0x3F)) as c_char;
9805        return 3;
9806    }
9807    if wc_u.wrapping_sub(0x10000) < 0x100000 {
9808        *s = (0xF0 | (wc_u >> 18)) as c_char;
9809        *s.add(1) = (0x80 | ((wc_u >> 12) & 0x3F)) as c_char;
9810        *s.add(2) = (0x80 | ((wc_u >> 6) & 0x3F)) as c_char;
9811        *s.add(3) = (0x80 | (wc_u & 0x3F)) as c_char;
9812        return 4;
9813    }
9814    ERRNO = EILSEQ;
9815    !0usize
9816}
9817
9818#[no_mangle]
9819pub unsafe extern "C" fn mblen(s: *const c_char, n: usize) -> c_int {
9820    if s.is_null() { return 0; }
9821    mbtowc(core::ptr::null_mut(), s, n)
9822}
9823
9824#[no_mangle]
9825pub unsafe extern "C" fn mbtowc(
9826    wc: *mut c_int,
9827    src: *const c_char,
9828    n: usize,
9829) -> c_int {
9830    if src.is_null() { return 0; }
9831    if n == 0 { ERRNO = EILSEQ; return -1; }
9832    let mut state: c_uint = 0;
9833    let mut w: c_int = 0;
9834    let r = mbrtowc(&mut w, src, n, &mut state);
9835    if r == !0usize { return -1; }
9836    if !wc.is_null() { *wc = w; }
9837    r as c_int
9838}
9839
9840#[no_mangle]
9841pub unsafe extern "C" fn wctomb(s: *mut c_char, wc: c_int) -> c_int {
9842    if s.is_null() { return 0; }
9843    wcrtomb(s, wc, core::ptr::null_mut()) as c_int
9844}
9845
9846#[no_mangle]
9847pub unsafe extern "C" fn mbsrtowcs(
9848    ws: *mut c_int,
9849    src: *mut *const c_char,
9850    wn: usize,
9851    st: *mut c_uint,
9852) -> usize {
9853    let st: &mut c_uint = if st.is_null() { &mut *(&raw mut MB_STATE) } else { &mut *st };
9854    let mut s = *src as *const u8;
9855    let wn0 = wn;
9856    let mut wn = wn;
9857
9858    if ws.is_null() {
9859        while *s != 0 {
9860            if *s < 0x80 {
9861                s = s.add(1);
9862                wn = wn.wrapping_sub(1);
9863                continue;
9864            }
9865            let mut wc: c_int = 0;
9866            let r = mbrtowc(&mut wc, s as *const c_char, 4, st);
9867            if r == !0usize { return !0usize; }
9868            if r == !1usize { return wn0 - wn; }
9869            s = s.add(r);
9870            wn = wn.wrapping_sub(1);
9871        }
9872        wn0 - wn
9873    } else {
9874        let mut w = ws;
9875        while wn > 0 {
9876            if *s < 0x80 {
9877                let c = *s as c_int;
9878                *w = c;
9879                if c == 0 {
9880                    *src = core::ptr::null();
9881                    return wn0 - wn;
9882                }
9883                w = w.add(1);
9884                s = s.add(1);
9885                wn -= 1;
9886                continue;
9887            }
9888            let mut wc: c_int = 0;
9889            let r = mbrtowc(&mut wc, s as *const c_char, 4, st);
9890            if r == !0usize {
9891                *src = s as *const c_char;
9892                return !0usize;
9893            }
9894            if r == !1usize {
9895                *src = s as *const c_char;
9896                return wn0 - wn;
9897            }
9898            *w = wc;
9899            w = w.add(1);
9900            s = s.add(r);
9901            wn -= 1;
9902        }
9903        *src = s as *const c_char;
9904        wn0 - wn
9905    }
9906}
9907
9908#[no_mangle]
9909pub unsafe extern "C" fn wcsrtombs(
9910    s: *mut c_char,
9911    ws: *mut *const c_int,
9912    n: usize,
9913    _st: *mut c_uint,
9914) -> usize {
9915    let mut w = *ws;
9916    let n0 = n;
9917    let mut n = n;
9918
9919    if s.is_null() {
9920        let mut count = 0usize;
9921        while *w != 0 {
9922            if (*w as u32) < 0x80 {
9923                count += 1;
9924            } else {
9925                let mut buf = [0u8; 4];
9926                let r = wcrtomb(buf.as_mut_ptr() as *mut c_char, *w, core::ptr::null_mut());
9927                if r == !0usize { return !0usize; }
9928                count += r;
9929            }
9930            w = w.add(1);
9931        }
9932        return count;
9933    }
9934
9935    let mut dst = s;
9936    while n > 0 {
9937        if (*w as u32) < 0x80 {
9938            *dst = *w as c_char;
9939            if *w == 0 {
9940                *ws = core::ptr::null();
9941                return n0 - n;
9942            }
9943            dst = dst.add(1);
9944            n -= 1;
9945        } else {
9946            let r = wcrtomb(dst, *w, core::ptr::null_mut());
9947            if r == !0usize {
9948                *ws = w;
9949                return !0usize;
9950            }
9951            if r > n {
9952                *ws = w;
9953                return n0 - n;
9954            }
9955            dst = dst.add(r);
9956            n -= r;
9957        }
9958        w = w.add(1);
9959    }
9960    *ws = w;
9961    n0
9962}
9963
9964#[no_mangle]
9965pub unsafe extern "C" fn mbstowcs(
9966    ws: *mut c_int,
9967    src: *const c_char,
9968    wn: usize,
9969) -> usize {
9970    let mut src_ptr = src;
9971    mbsrtowcs(ws, &mut src_ptr, wn, core::ptr::null_mut())
9972}
9973
9974#[no_mangle]
9975pub unsafe extern "C" fn wcstombs(
9976    s: *mut c_char,
9977    ws: *const c_int,
9978    n: usize,
9979) -> usize {
9980    let mut ws_ptr = ws;
9981    wcsrtombs(s, &mut ws_ptr, n, core::ptr::null_mut())
9982}
9983
9984// ============================================================
9985// wchar: btowc / wctob / mbsinit / mbrlen
9986// ============================================================
9987
9988#[no_mangle]
9989pub extern "C" fn btowc(c: c_int) -> wint_t {
9990    if c == -1 { return WEOF; }
9991    unsafe {
9992        if LOCALE_CTYPE_UTF8 {
9993            if (c as u32) < 128 { c as wint_t } else { WEOF }
9994        } else {
9995            (c as u8) as wint_t
9996        }
9997    }
9998}
9999
10000#[no_mangle]
10001pub extern "C" fn wctob(c: wint_t) -> c_int {
10002    unsafe {
10003        if LOCALE_CTYPE_UTF8 {
10004            if c < 128 { c as c_int } else { -1 }
10005        } else {
10006            if c <= 0xFF { c as c_int } else { -1 }
10007        }
10008    }
10009}
10010
10011#[no_mangle]
10012pub unsafe extern "C" fn mbsinit(s: *const c_uint) -> c_int {
10013    if s.is_null() || *s == 0 { 1 } else { 0 }
10014}
10015
10016#[no_mangle]
10017pub unsafe extern "C" fn mbrlen(s: *const c_char, n: usize, ps: *mut c_uint) -> usize {
10018    mbrtowc(core::ptr::null_mut(), s, n, ps)
10019}
10020
10021// ============================================================
10022// wchar: wide string functions
10023// ============================================================
10024
10025#[no_mangle]
10026pub unsafe extern "C" fn wcslen(s: *const wchar_t) -> usize {
10027    let mut len = 0;
10028    while *s.add(len) != 0 { len += 1; }
10029    len
10030}
10031
10032#[no_mangle]
10033pub unsafe extern "C" fn wcschr(s: *const wchar_t, c: wchar_t) -> *mut wchar_t {
10034    let mut i = 0;
10035    loop {
10036        let ch = *s.add(i);
10037        if ch == c { return s.add(i) as *mut wchar_t; }
10038        if ch == 0 { return null_mut(); }
10039        i += 1;
10040    }
10041}
10042
10043#[no_mangle]
10044pub unsafe extern "C" fn wcsrchr(s: *const wchar_t, c: wchar_t) -> *mut wchar_t {
10045    let mut i = 0;
10046    let mut last: *mut wchar_t = null_mut();
10047    loop {
10048        let ch = *s.add(i);
10049        if ch == c { last = s.add(i) as *mut wchar_t; }
10050        if ch == 0 { return last; }
10051        i += 1;
10052    }
10053}
10054
10055#[no_mangle]
10056pub unsafe extern "C" fn wcsstr(haystack: *const wchar_t, needle: *const wchar_t) -> *mut wchar_t {
10057    if *needle == 0 { return haystack as *mut wchar_t; }
10058    let mut i = 0;
10059    loop {
10060        let h = *haystack.add(i);
10061        if h == 0 { return null_mut(); }
10062        if h == *needle {
10063            let mut j = 0;
10064            loop {
10065                let n = *needle.add(j);
10066                if n == 0 { return haystack.add(i) as *mut wchar_t; }
10067                if *haystack.add(i + j) != n { break; }
10068                j += 1;
10069            }
10070        }
10071        i += 1;
10072    }
10073}
10074
10075#[no_mangle]
10076pub unsafe extern "C" fn wcscmp(s1: *const wchar_t, s2: *const wchar_t) -> c_int {
10077    let mut i = 0;
10078    loop {
10079        let a = *s1.add(i);
10080        let b = *s2.add(i);
10081        if a != b { return a - b; }
10082        if a == 0 { return 0; }
10083        i += 1;
10084    }
10085}
10086
10087#[no_mangle]
10088pub unsafe extern "C" fn wcsncmp(s1: *const wchar_t, s2: *const wchar_t, n: usize) -> c_int {
10089    let mut i = 0;
10090    while i < n {
10091        let a = *s1.add(i);
10092        let b = *s2.add(i);
10093        if a != b { return a - b; }
10094        if a == 0 { return 0; }
10095        i += 1;
10096    }
10097    0
10098}
10099
10100#[no_mangle]
10101pub unsafe extern "C" fn wcscpy(dst: *mut wchar_t, src: *const wchar_t) -> *mut wchar_t {
10102    let mut i = 0;
10103    loop {
10104        let c = *src.add(i);
10105        *dst.add(i) = c;
10106        if c == 0 { break; }
10107        i += 1;
10108    }
10109    dst
10110}
10111
10112#[no_mangle]
10113pub unsafe extern "C" fn wcsncpy(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> *mut wchar_t {
10114    let mut i = 0;
10115    while i < n && *src.add(i) != 0 { *dst.add(i) = *src.add(i); i += 1; }
10116    while i < n { *dst.add(i) = 0; i += 1; }
10117    dst
10118}
10119
10120#[no_mangle]
10121pub unsafe extern "C" fn wcscat(dst: *mut wchar_t, src: *const wchar_t) -> *mut wchar_t {
10122    let mut i = 0;
10123    while *dst.add(i) != 0 { i += 1; }
10124    let mut j = 0;
10125    loop {
10126        let c = *src.add(j);
10127        *dst.add(i + j) = c;
10128        if c == 0 { break; }
10129        j += 1;
10130    }
10131    dst
10132}
10133
10134#[no_mangle]
10135pub unsafe extern "C" fn wcsncat(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> *mut wchar_t {
10136    let mut i = 0;
10137    while *dst.add(i) != 0 { i += 1; }
10138    let mut j = 0;
10139    while j < n && *src.add(j) != 0 { *dst.add(i + j) = *src.add(j); j += 1; }
10140    *dst.add(i + j) = 0;
10141    dst
10142}
10143
10144#[no_mangle]
10145pub unsafe extern "C" fn wcsdup(s: *const wchar_t) -> *mut wchar_t {
10146    let len = wcslen(s);
10147    let p = malloc((len + 1) * core::mem::size_of::<wchar_t>()) as *mut wchar_t;
10148    if p.is_null() { return null_mut(); }
10149    core::ptr::copy_nonoverlapping(s, p, len + 1);
10150    p
10151}
10152
10153#[no_mangle]
10154pub unsafe extern "C" fn wcsnlen(s: *const wchar_t, maxlen: usize) -> usize {
10155    let mut i = 0;
10156    while i < maxlen && *s.add(i) != 0 { i += 1; }
10157    i
10158}
10159
10160#[no_mangle]
10161pub unsafe extern "C" fn wcsspn(s: *const wchar_t, accept: *const wchar_t) -> usize {
10162    let mut i = 0;
10163    loop {
10164        let c = *s.add(i);
10165        if c == 0 { return i; }
10166        let mut found = false;
10167        let mut j = 0;
10168        loop {
10169            let a = *accept.add(j);
10170            if a == 0 { break; }
10171            if c == a { found = true; break; }
10172            j += 1;
10173        }
10174        if !found { return i; }
10175        i += 1;
10176    }
10177}
10178
10179#[no_mangle]
10180pub unsafe extern "C" fn wcscspn(s: *const wchar_t, reject: *const wchar_t) -> usize {
10181    let mut i = 0;
10182    loop {
10183        let c = *s.add(i);
10184        if c == 0 { return i; }
10185        let mut j = 0;
10186        loop {
10187            let r = *reject.add(j);
10188            if r == 0 { break; }
10189            if c == r { return i; }
10190            j += 1;
10191        }
10192        i += 1;
10193    }
10194}
10195
10196#[no_mangle]
10197pub unsafe extern "C" fn wcspbrk(s: *const wchar_t, accept: *const wchar_t) -> *mut wchar_t {
10198    let mut i = 0;
10199    loop {
10200        let c = *s.add(i);
10201        if c == 0 { return null_mut(); }
10202        let mut j = 0;
10203        loop {
10204            let a = *accept.add(j);
10205            if a == 0 { break; }
10206            if c == a { return s.add(i) as *mut wchar_t; }
10207            j += 1;
10208        }
10209        i += 1;
10210    }
10211}
10212
10213#[no_mangle]
10214pub unsafe extern "C" fn wcsxfrm(dst: *mut wchar_t, src: *const wchar_t, n: usize) -> usize {
10215    let len = wcslen(src);
10216    if !dst.is_null() {
10217        let copy = if len < n { len } else { if n > 0 { n - 1 } else { 0 } };
10218        for i in 0..copy { *dst.add(i) = *src.add(i); }
10219        if n > 0 { *dst.add(copy) = 0; }
10220    }
10221    len
10222}
10223
10224// ============================================================
10225// wchar: wcsto* number conversions
10226// ============================================================
10227
10228unsafe fn wcs_to_bytes(ws: *const wchar_t, buf: *mut u8, bufsz: usize) -> usize {
10229    let mut i = 0;
10230    while i < bufsz - 1 {
10231        let c = *ws.add(i);
10232        if c == 0 { break; }
10233        if (c as u32) > 127 { break; }
10234        *buf.add(i) = c as u8;
10235        i += 1;
10236    }
10237    *buf.add(i) = 0;
10238    i
10239}
10240
10241#[no_mangle]
10242pub unsafe extern "C" fn wcstol(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_long {
10243    let mut buf = [0u8; 256];
10244    wcs_to_bytes(s, buf.as_mut_ptr(), 256);
10245    let mut end: *mut c_char = core::ptr::null_mut();
10246    let r = strtol(buf.as_ptr() as *const c_char, &mut end, base);
10247    if !endptr.is_null() {
10248        let offset = end as usize - buf.as_ptr() as usize;
10249        *endptr = s.add(offset) as *mut wchar_t;
10250    }
10251    r
10252}
10253
10254#[no_mangle]
10255pub unsafe extern "C" fn wcstoul(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulong {
10256    let mut buf = [0u8; 256];
10257    wcs_to_bytes(s, buf.as_mut_ptr(), 256);
10258    let mut end: *mut c_char = core::ptr::null_mut();
10259    let r = strtoul(buf.as_ptr() as *const c_char, &mut end, base);
10260    if !endptr.is_null() {
10261        let offset = end as usize - buf.as_ptr() as usize;
10262        *endptr = s.add(offset) as *mut wchar_t;
10263    }
10264    r
10265}
10266
10267#[no_mangle]
10268pub unsafe extern "C" fn wcstoll(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_longlong {
10269    let mut buf = [0u8; 256];
10270    wcs_to_bytes(s, buf.as_mut_ptr(), 256);
10271    let mut end: *mut c_char = core::ptr::null_mut();
10272    let r = strtoll(buf.as_ptr() as *const c_char, &mut end, base);
10273    if !endptr.is_null() {
10274        let offset = end as usize - buf.as_ptr() as usize;
10275        *endptr = s.add(offset) as *mut wchar_t;
10276    }
10277    r
10278}
10279
10280#[no_mangle]
10281pub unsafe extern "C" fn wcstoull(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulonglong {
10282    let mut buf = [0u8; 256];
10283    wcs_to_bytes(s, buf.as_mut_ptr(), 256);
10284    let mut end: *mut c_char = core::ptr::null_mut();
10285    let r = strtoull(buf.as_ptr() as *const c_char, &mut end, base);
10286    if !endptr.is_null() {
10287        let offset = end as usize - buf.as_ptr() as usize;
10288        *endptr = s.add(offset) as *mut wchar_t;
10289    }
10290    r
10291}
10292
10293#[no_mangle]
10294pub unsafe extern "C" fn wcstod(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 {
10295    let mut buf = [0u8; 256];
10296    wcs_to_bytes(s, buf.as_mut_ptr(), 256);
10297    let mut end: *mut c_char = core::ptr::null_mut();
10298    let r = strtod(buf.as_ptr() as *const c_char, &mut end);
10299    if !endptr.is_null() {
10300        let offset = end as usize - buf.as_ptr() as usize;
10301        *endptr = s.add(offset) as *mut wchar_t;
10302    }
10303    r
10304}
10305
10306#[no_mangle]
10307pub unsafe extern "C" fn wcstof(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f32 { wcstod(s, endptr) as f32 }
10308
10309#[no_mangle]
10310#[cfg(target_arch = "x86_64")]
10311pub unsafe extern "C" fn wcstold(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f64 { wcstod(s, endptr) }
10312
10313#[no_mangle]
10314#[cfg(target_arch = "aarch64")]
10315pub unsafe extern "C" fn wcstold(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f128 { wcstod(s, endptr) as f128 }
10316
10317#[no_mangle]
10318#[cfg(target_arch = "riscv64")]
10319pub unsafe extern "C" fn wcstold(s: *const wchar_t, endptr: *mut *mut wchar_t) -> f128 { wcstod(s, endptr) as f128 }
10320
10321#[no_mangle]
10322pub unsafe extern "C" fn wcstoimax(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_longlong { wcstoll(s, endptr, base) }
10323
10324#[no_mangle]
10325pub unsafe extern "C" fn wcstoumax(s: *const wchar_t, endptr: *mut *mut wchar_t, base: c_int) -> c_ulonglong { wcstoull(s, endptr, base) }
10326
10327// ============================================================
10328// wctype: classification functions
10329// ============================================================
10330
10331const WC_ALPHA: c_int = 1;
10332const WC_DIGIT: c_int = 2;
10333const WC_SPACE: c_int = 4;
10334const WC_UPPER: c_int = 8;
10335const WC_LOWER: c_int = 16;
10336const WC_ALNUM: c_int = WC_ALPHA | WC_DIGIT;
10337const WC_BLANK: c_int = 32;
10338const WC_CNTRL: c_int = 64;
10339const WC_PUNCT: c_int = 128;
10340const WC_GRAPH: c_int = WC_ALNUM | WC_PUNCT;
10341const WC_PRINT: c_int = WC_GRAPH | WC_BLANK;
10342const WC_XDIGIT: c_int = 256;
10343
10344fn wc_flags(c: wint_t) -> c_int {
10345    if c < 128 {
10346        let f = CT_TABLE[c as usize];
10347        let mut r = 0;
10348        if f & (CT_UPPER | CT_LOWER) != 0 { r |= WC_ALPHA; }
10349        if f & CT_DIGIT != 0 { r |= WC_DIGIT; }
10350        if f & CT_SPACE != 0 { r |= WC_SPACE; }
10351        if f & CT_UPPER != 0 { r |= WC_UPPER; }
10352        if f & CT_LOWER != 0 { r |= WC_LOWER; }
10353        if f & CT_BLANK != 0 { r |= WC_BLANK; }
10354        if f & CT_CNTRL != 0 { r |= WC_CNTRL; }
10355        if f & CT_PUNCT != 0 { r |= WC_PUNCT; }
10356        if f & CT_XDIGIT != 0 { r |= WC_XDIGIT; }
10357        r
10358    } else {
10359        if c < 0x100 { 0 }
10360        else { WC_PRINT | WC_ALPHA }
10361    }
10362}
10363
10364#[no_mangle]
10365pub extern "C" fn iswalnum(c: wint_t) -> c_int { (wc_flags(c) & WC_ALNUM != 0) as c_int }
10366#[no_mangle]
10367pub extern "C" fn iswalpha(c: wint_t) -> c_int { (wc_flags(c) & WC_ALPHA != 0) as c_int }
10368#[no_mangle]
10369pub extern "C" fn iswblank(c: wint_t) -> c_int { (wc_flags(c) & WC_BLANK != 0) as c_int }
10370#[no_mangle]
10371pub extern "C" fn iswcntrl(c: wint_t) -> c_int { (wc_flags(c) & WC_CNTRL != 0) as c_int }
10372#[no_mangle]
10373pub extern "C" fn iswdigit(c: wint_t) -> c_int { ((c >= b'0' as wint_t) && (c <= b'9' as wint_t)) as c_int }
10374#[no_mangle]
10375pub extern "C" fn iswgraph(c: wint_t) -> c_int { (wc_flags(c) & WC_GRAPH != 0) as c_int }
10376#[no_mangle]
10377pub extern "C" fn iswlower(c: wint_t) -> c_int { (wc_flags(c) & WC_LOWER != 0) as c_int }
10378#[no_mangle]
10379pub extern "C" fn iswprint(c: wint_t) -> c_int {
10380    if c < 128 { (wc_flags(c) & WC_PRINT != 0) as c_int }
10381    else if c >= 0x100 && c < 0x110000 { 1 }
10382    else { 0 }
10383}
10384#[no_mangle]
10385pub extern "C" fn iswpunct(c: wint_t) -> c_int { (wc_flags(c) & WC_PUNCT != 0) as c_int }
10386#[no_mangle]
10387pub extern "C" fn iswspace(c: wint_t) -> c_int {
10388    if c < 128 { (wc_flags(c) & WC_SPACE != 0) as c_int }
10389    else {
10390        match c {
10391            0x1680 | 0x2000..=0x200A | 0x2028 | 0x2029 | 0x202F | 0x205F | 0x3000 => 1,
10392            _ => 0,
10393        }
10394    }
10395}
10396#[no_mangle]
10397pub extern "C" fn iswupper(c: wint_t) -> c_int { (wc_flags(c) & WC_UPPER != 0) as c_int }
10398#[no_mangle]
10399pub extern "C" fn iswxdigit(c: wint_t) -> c_int { (wc_flags(c) & WC_XDIGIT != 0) as c_int }
10400
10401static WCTYPE_ALNUM: c_int = WC_ALNUM;
10402static WCTYPE_ALPHA: c_int = WC_ALPHA;
10403static WCTYPE_BLANK: c_int = WC_BLANK;
10404static WCTYPE_CNTRL: c_int = WC_CNTRL;
10405static WCTYPE_DIGIT: c_int = WC_DIGIT;
10406static WCTYPE_GRAPH: c_int = WC_GRAPH;
10407static WCTYPE_LOWER: c_int = WC_LOWER;
10408static WCTYPE_PRINT: c_int = WC_PRINT;
10409static WCTYPE_PUNCT: c_int = WC_PUNCT;
10410static WCTYPE_SPACE: c_int = WC_SPACE;
10411static WCTYPE_UPPER: c_int = WC_UPPER;
10412static WCTYPE_XDIGIT: c_int = WC_XDIGIT;
10413
10414#[no_mangle]
10415pub unsafe extern "C" fn wctype(name: *const c_char) -> wctype_t {
10416    if name.is_null() { return core::ptr::null(); }
10417    let n = name as *const u8;
10418    if strcmp(n, b"alnum\0".as_ptr()) == 0 { return &WCTYPE_ALNUM; }
10419    if strcmp(n, b"alpha\0".as_ptr()) == 0 { return &WCTYPE_ALPHA; }
10420    if strcmp(n, b"blank\0".as_ptr()) == 0 { return &WCTYPE_BLANK; }
10421    if strcmp(n, b"cntrl\0".as_ptr()) == 0 { return &WCTYPE_CNTRL; }
10422    if strcmp(n, b"digit\0".as_ptr()) == 0 { return &WCTYPE_DIGIT; }
10423    if strcmp(n, b"graph\0".as_ptr()) == 0 { return &WCTYPE_GRAPH; }
10424    if strcmp(n, b"lower\0".as_ptr()) == 0 { return &WCTYPE_LOWER; }
10425    if strcmp(n, b"print\0".as_ptr()) == 0 { return &WCTYPE_PRINT; }
10426    if strcmp(n, b"punct\0".as_ptr()) == 0 { return &WCTYPE_PUNCT; }
10427    if strcmp(n, b"space\0".as_ptr()) == 0 { return &WCTYPE_SPACE; }
10428    if strcmp(n, b"upper\0".as_ptr()) == 0 { return &WCTYPE_UPPER; }
10429    if strcmp(n, b"xdigit\0".as_ptr()) == 0 { return &WCTYPE_XDIGIT; }
10430    core::ptr::null()
10431}
10432
10433#[no_mangle]
10434pub unsafe extern "C" fn iswctype(c: wint_t, desc: wctype_t) -> c_int {
10435    if desc.is_null() { return 0; }
10436    (wc_flags(c) & *desc != 0) as c_int
10437}
10438
10439static WCTRANS_LOWER: c_int = 1;
10440static WCTRANS_UPPER: c_int = 2;
10441
10442#[no_mangle]
10443pub unsafe extern "C" fn towlower(c: wint_t) -> wint_t {
10444    if c < 128 { tolower(c as c_int) as wint_t } else { c }
10445}
10446
10447#[no_mangle]
10448pub unsafe extern "C" fn towupper(c: wint_t) -> wint_t {
10449    if c < 128 { toupper(c as c_int) as wint_t } else { c }
10450}
10451
10452#[no_mangle]
10453pub unsafe extern "C" fn wctrans(name: *const c_char) -> wctrans_t {
10454    if name.is_null() { return core::ptr::null(); }
10455    let n = name as *const u8;
10456    if strcmp(n, b"tolower\0".as_ptr()) == 0 { return &WCTRANS_LOWER; }
10457    if strcmp(n, b"toupper\0".as_ptr()) == 0 { return &WCTRANS_UPPER; }
10458    core::ptr::null()
10459}
10460
10461#[no_mangle]
10462pub unsafe extern "C" fn towctrans(c: wint_t, desc: wctrans_t) -> wint_t {
10463    if desc.is_null() { return c; }
10464    match *desc {
10465        1 => towlower(c),
10466        2 => towupper(c),
10467        _ => c,
10468    }
10469}
10470
10471// ============================================================
10472// wchar: wide stdio
10473// ============================================================
10474
10475#[no_mangle]
10476pub unsafe extern "C" fn fgetwc(f: *mut FILE) -> wint_t {
10477    let mut state: c_uint = 0;
10478    let mut wc: wchar_t = 0;
10479    let mut buf = [0u8; 4];
10480    let c = fgetc(f);
10481    if c == -1 { return WEOF; }
10482    buf[0] = c as u8;
10483    if buf[0] < 0x80 { return buf[0] as wint_t; }
10484    let len = if buf[0] < 0xE0 { 2 } else if buf[0] < 0xF0 { 3 } else { 4 };
10485    let mut n = 1usize;
10486    while n < len {
10487        let c2 = fgetc(f);
10488        if c2 == -1 { return WEOF; }
10489        buf[n] = c2 as u8;
10490        n += 1;
10491    }
10492    let r = mbrtowc(&mut wc, buf.as_ptr() as *const c_char, n, &mut state);
10493    if r == !0usize || r == !1usize { WEOF } else { wc as wint_t }
10494}
10495
10496#[no_mangle]
10497pub unsafe extern "C" fn fputwc(c: wchar_t, f: *mut FILE) -> wint_t {
10498    let mut buf = [0u8; 4];
10499    let n = wcrtomb(buf.as_mut_ptr() as *mut c_char, c, core::ptr::null_mut());
10500    if n == !0usize || n == 0 { return WEOF; }
10501    if fwrite(buf.as_ptr() as *const c_void, 1, n, f) != n { return WEOF; }
10502    c as wint_t
10503}
10504
10505#[no_mangle]
10506pub unsafe extern "C" fn fputws(s: *const wchar_t, f: *mut FILE) -> c_int {
10507    let mut i = 0;
10508    while *s.add(i) != 0 {
10509        if fputwc(*s.add(i), f) == WEOF { return -1; }
10510        i += 1;
10511    }
10512    0
10513}
10514
10515#[no_mangle]
10516pub unsafe extern "C" fn ungetwc(c: wint_t, f: *mut FILE) -> wint_t {
10517    if c == WEOF { return WEOF; }
10518    let mut buf = [0u8; 4];
10519    let n = wcrtomb(buf.as_mut_ptr() as *mut c_char, c as wchar_t, core::ptr::null_mut());
10520    if n == !0usize || n == 0 { return WEOF; }
10521    let mut i = n;
10522    while i > 0 {
10523        i -= 1;
10524        if ungetc(buf[i] as c_int, f) == -1 { return WEOF; }
10525    }
10526    c
10527}
10528
10529#[no_mangle]
10530pub unsafe extern "C" fn getwchar() -> wint_t { fgetwc(stdin) }
10531
10532#[no_mangle]
10533pub unsafe extern "C" fn putwchar(c: wchar_t) -> wint_t { fputwc(c, stdout) }
10534
10535// ============================================================
10536// wchar: swprintf / vswprintf / fwprintf / vfwprintf
10537// ============================================================
10538
10539unsafe fn wfmt_write_str(dst: *mut wchar_t, pos: usize, cap: usize, s: *const u8, len: usize) -> usize {
10540    let mut i = 0;
10541    while i < len {
10542        if pos + i < cap { *dst.add(pos + i) = *s.add(i) as wchar_t; }
10543        i += 1;
10544    }
10545    pos + len
10546}
10547
10548#[no_mangle]
10549pub unsafe extern "C" fn vswprintf(s: *mut wchar_t, n: usize, fmt: *const wchar_t, mut args: VaList) -> c_int {
10550    if n == 0 { return -1; }
10551    let cap = n - 1;
10552    let mut pos = 0usize;
10553    // ponytail: format specifiers are ASCII; narrow buffer suffices for parsing
10554    let mut fmt_narrow = [0u8; 256];
10555    let mut flen = 0usize;
10556    loop {
10557        let ch = *fmt.add(flen) as u32;
10558        if ch == 0 || flen >= 255 { break; }
10559        fmt_narrow[flen] = if ch < 128 { ch as u8 } else { b'?' };
10560        flen += 1;
10561    }
10562    fmt_narrow[flen] = 0;
10563    let mut fi = 0usize;
10564    macro_rules! wc {
10565        ($c:expr) => { if pos < cap { *s.add(pos) = $c as wchar_t; } pos += 1; }
10566    }
10567    loop {
10568        let c = fmt_narrow[fi];
10569        if c == 0 { break; }
10570        if c != b'%' { wc!(c); fi += 1; continue; }
10571        fi += 1;
10572        let mut flags: u8 = 0;
10573        loop {
10574            match fmt_narrow[fi] {
10575                b'-' => { flags |= FLAG_MINUS; fi += 1; }
10576                b'+' => { flags |= FLAG_PLUS; fi += 1; }
10577                b' ' => { flags |= FLAG_SPACE; fi += 1; }
10578                b'0' => { flags |= FLAG_ZERO; fi += 1; }
10579                b'#' => { flags |= FLAG_HASH; fi += 1; }
10580                _ => break,
10581            }
10582        }
10583        let mut width: usize = 0;
10584        if fmt_narrow[fi] == b'*' {
10585            let w = args.next_arg::<c_int>();
10586            if w < 0 { flags |= FLAG_MINUS; width = (-w) as usize; } else { width = w as usize; }
10587            fi += 1;
10588        } else {
10589            while fmt_narrow[fi] >= b'0' && fmt_narrow[fi] <= b'9' {
10590                width = width * 10 + (fmt_narrow[fi] - b'0') as usize; fi += 1;
10591            }
10592        }
10593        let mut precision: i32 = -1;
10594        if fmt_narrow[fi] == b'.' {
10595            fi += 1;
10596            if fmt_narrow[fi] == b'*' {
10597                let p = args.next_arg::<c_int>();
10598                precision = if p < 0 { -1 } else { p }; fi += 1;
10599            } else {
10600                precision = 0;
10601                while fmt_narrow[fi] >= b'0' && fmt_narrow[fi] <= b'9' {
10602                    precision = precision * 10 + (fmt_narrow[fi] - b'0') as i32; fi += 1;
10603                }
10604            }
10605        }
10606        let len_mod = fmt_narrow[fi];
10607        if len_mod == b'h' || len_mod == b'l' || len_mod == b'j' || len_mod == b'z' || len_mod == b't' || len_mod == b'L' {
10608            fi += 1;
10609            let spec = fmt_narrow[fi];
10610            if (len_mod == b'h' && spec == b'h') || (len_mod == b'l' && spec == b'l') {
10611                fi += 1;
10612                let spec2 = fmt_narrow[fi];
10613                match (len_mod, spec, spec2) {
10614                    (b'h', b'h', b'n') => { let p = args.next_arg::<*mut c_void>(); if !p.is_null() { *(p as *mut u8) = pos as u8; } }
10615                    (b'l', b'l', b'n') => { let p = args.next_arg::<*mut c_void>(); if !p.is_null() { *(p as *mut c_longlong) = pos as c_longlong; } }
10616                    (b'l', b'l', b'd') | (b'l', b'l', b'i') => {
10617                        let val = args.next_arg::<c_longlong>();
10618                        let neg = val < 0;
10619                        let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
10620                        let b = format_u64(abs);
10621                        let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
10622                        let mut fbuf = [0u8; 32];
10623                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
10624                        for k in 0..len { wc!(fbuf[k]); }
10625                    }
10626                    (b'l', b'l', b'u') => {
10627                        let val = args.next_arg::<c_ulonglong>();
10628                        let b = format_u64(val as u64);
10629                        let mut fbuf = [0u8; 32];
10630                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
10631                        for k in 0..len { wc!(fbuf[k]); }
10632                    }
10633                    (b'l', b'l', b'x') => {
10634                        let val = args.next_arg::<c_ulonglong>();
10635                        let b = format_hex(val as u64, false);
10636                        let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
10637                        let mut fbuf = [0u8; 32];
10638                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10639                        for k in 0..len { wc!(fbuf[k]); }
10640                    }
10641                    (b'l', b'l', b'X') => {
10642                        let val = args.next_arg::<c_ulonglong>();
10643                        let b = format_hex(val as u64, true);
10644                        let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
10645                        let mut fbuf = [0u8; 32];
10646                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10647                        for k in 0..len { wc!(fbuf[k]); }
10648                    }
10649                    (b'l', b'l', b'o') => {
10650                        let val = args.next_arg::<c_ulonglong>();
10651                        let b = format_octal(val as u64, flags & FLAG_HASH != 0);
10652                        let mut fbuf = [0u8; 32];
10653                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
10654                        for k in 0..len { wc!(fbuf[k]); }
10655                    }
10656                    _ => { wc!(b'%'); wc!(len_mod); wc!(spec); wc!(spec2); }
10657                }
10658            } else {
10659                let lm = if (len_mod == b'z' || len_mod == b't') && spec != b'n' { b'l' } else { len_mod };
10660                match (lm, spec) {
10661                    (b'h', b'n') => { let p = args.next_arg::<*mut c_void>(); if !p.is_null() { *(p as *mut u16) = pos as u16; } }
10662                    (b'l', b'n') => { let p = args.next_arg::<*mut c_void>(); if !p.is_null() { *(p as *mut c_long) = pos as c_long; } }
10663                    (b'z', b'n') | (b't', b'n') => { let p = args.next_arg::<*mut c_void>(); if !p.is_null() { *(p as *mut usize) = pos; } }
10664                    (b'j', b'n') => { let p = args.next_arg::<*mut c_void>(); if !p.is_null() { *(p as *mut c_ulonglong) = pos as c_ulonglong; } }
10665                    (b'l', b'd') | (b'l', b'i') => {
10666                        let val = args.next_arg::<c_long>();
10667                        let neg = val < 0;
10668                        let abs = if neg { val.wrapping_neg() as u64 } else { val as u64 };
10669                        let b = format_u64(abs);
10670                        let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
10671                        let mut fbuf = [0u8; 32];
10672                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
10673                        for k in 0..len { wc!(fbuf[k]); }
10674                    }
10675                    (b'l', b'u') => {
10676                        let val = args.next_arg::<c_ulong>();
10677                        let b = format_u64(val as u64);
10678                        let mut fbuf = [0u8; 32];
10679                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
10680                        for k in 0..len { wc!(fbuf[k]); }
10681                    }
10682                    (b'l', b'x') => {
10683                        let val = args.next_arg::<c_ulong>();
10684                        let b = format_hex(val as u64, false);
10685                        let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
10686                        let mut fbuf = [0u8; 32];
10687                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10688                        for k in 0..len { wc!(fbuf[k]); }
10689                    }
10690                    (b'l', b'X') => {
10691                        let val = args.next_arg::<c_ulong>();
10692                        let b = format_hex(val as u64, true);
10693                        let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
10694                        let mut fbuf = [0u8; 32];
10695                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10696                        for k in 0..len { wc!(fbuf[k]); }
10697                    }
10698                    (b'l', b'o') => {
10699                        let val = args.next_arg::<c_ulong>();
10700                        let b = format_octal(val as u64, flags & FLAG_HASH != 0);
10701                        let mut fbuf = [0u8; 32];
10702                        let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
10703                        for k in 0..len { wc!(fbuf[k]); }
10704                    }
10705                    (b'l', b'c') => {
10706                        let ch = args.next_arg::<wint_t>();
10707                        wc!(ch);
10708                    }
10709                    (b'l', b's') => {
10710                        let ws_arg = args.next_arg::<*const wchar_t>();
10711                        if ws_arg.is_null() {
10712                            let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
10713                            if flags & FLAG_MINUS != 0 {
10714                                for k in 0..slen { wc!(b"(null)"[k]); }
10715                                for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10716                            } else {
10717                                for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10718                                for k in 0..slen { wc!(b"(null)"[k]); }
10719                            }
10720                        } else {
10721                            let mut wlen = 0usize;
10722                            loop {
10723                                let ch = *ws_arg.add(wlen);
10724                                if ch == 0 { break; }
10725                                if precision >= 0 && wlen >= precision as usize { break; }
10726                                wlen += 1;
10727                            }
10728                            if flags & FLAG_MINUS != 0 {
10729                                for k in 0..wlen { wc!(*ws_arg.add(k)); }
10730                                for _ in 0..width.saturating_sub(wlen) { wc!(b' '); }
10731                            } else {
10732                                for _ in 0..width.saturating_sub(wlen) { wc!(b' '); }
10733                                for k in 0..wlen { wc!(*ws_arg.add(k)); }
10734                            }
10735                        }
10736                    }
10737                    (b'l', b'f') | (b'l', b'F') | (b'l', b'e') | (b'l', b'E')
10738                    | (b'l', b'g') | (b'l', b'G') | (b'l', b'a') | (b'l', b'A') => {
10739                        let val = args.next_arg::<f64>();
10740                        let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
10741                        let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
10742                        let mut fbuf = [0u8; 4224];
10743                        let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
10744                        let mut wbuf = [0u8; 4224];
10745                        let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
10746                        for k in 0..wlen { wc!(wbuf[k]); }
10747                    }
10748                    (b'L', b'f') | (b'L', b'F') | (b'L', b'e') | (b'L', b'E')
10749                    | (b'L', b'g') | (b'L', b'G') | (b'L', b'a') | (b'L', b'A') => {
10750                        #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
10751                        let val = {
10752                            let lo: u64 = args.next_arg::<u64>();
10753                            let hi: u64 = args.next_arg::<u64>();
10754                            let combined: u128 = ((hi as u128) << 64) | (lo as u128);
10755                            f128::from_bits(combined) as f64
10756                        };
10757                        #[cfg(target_arch = "x86_64")]
10758                        let val = args.next_arg::<f64>();
10759                        let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
10760                        let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
10761                        let mut fbuf = [0u8; 4224];
10762                        let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
10763                        let mut wbuf = [0u8; 4224];
10764                        let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
10765                        for k in 0..wlen { wc!(wbuf[k]); }
10766                    }
10767                    _ => { wc!(b'%'); wc!(len_mod); wc!(spec); }
10768                }
10769            }
10770        } else {
10771            let spec = fmt_narrow[fi];
10772            match spec {
10773                b'd' | b'i' => {
10774                    let d = args.next_arg::<c_int>();
10775                    let neg = d < 0;
10776                    let abs = if neg { d.wrapping_neg() as u64 } else { d as u64 };
10777                    let b = format_u64(abs);
10778                    let sign = if neg { Some(b'-') } else if flags & FLAG_PLUS != 0 { Some(b'+') } else if flags & FLAG_SPACE != 0 { Some(b' ') } else { None };
10779                    let mut fbuf = [0u8; 32];
10780                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, sign, None, precision, width, flags, false);
10781                    for k in 0..len { wc!(fbuf[k]); }
10782                }
10783                b'u' => {
10784                    let u = args.next_arg::<c_uint>();
10785                    let b = format_u64(u as u64);
10786                    let mut fbuf = [0u8; 32];
10787                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, false);
10788                    for k in 0..len { wc!(fbuf[k]); }
10789                }
10790                b'x' => {
10791                    let x = args.next_arg::<c_uint>();
10792                    let b = format_hex(x as u64, false);
10793                    let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'x') } else { None };
10794                    let mut fbuf = [0u8; 32];
10795                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10796                    for k in 0..len { wc!(fbuf[k]); }
10797                }
10798                b'X' => {
10799                    let x = args.next_arg::<c_uint>();
10800                    let b = format_hex(x as u64, true);
10801                    let prefix = if flags & FLAG_HASH != 0 && !(b.1 == 1 && b.0[0] == b'0') { Some(b'X') } else { None };
10802                    let mut fbuf = [0u8; 32];
10803                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, prefix, precision, width, flags, false);
10804                    for k in 0..len { wc!(fbuf[k]); }
10805                }
10806                b'o' => {
10807                    let o = args.next_arg::<c_uint>();
10808                    let b = format_octal(o as u64, flags & FLAG_HASH != 0);
10809                    let mut fbuf = [0u8; 32];
10810                    let len = format_int(fbuf.as_mut_ptr(), b.0.as_ptr(), b.1, None, None, precision, width, flags, flags & FLAG_HASH != 0);
10811                    for k in 0..len { wc!(fbuf[k]); }
10812                }
10813                b'f' | b'F' | b'e' | b'E' | b'g' | b'G' | b'a' | b'A' => {
10814                    let val = args.next_arg::<f64>();
10815                    let ucase = spec == b'F' || spec == b'E' || spec == b'G' || spec == b'A';
10816                    let ftype = match spec | 0x20 { b'f' => FMT_F, b'e' => FMT_E, b'g' => FMT_G, b'a' => FMT_A, _ => FMT_F };
10817                    let mut fbuf = [0u8; 4224];
10818                    let flen = format_f64_full(fbuf.as_mut_ptr(), val, ftype, precision, flags, ucase);
10819                    let mut wbuf = [0u8; 4224];
10820                    let wlen = apply_width_flags(wbuf.as_mut_ptr(), fbuf.as_ptr(), flen, width, flags);
10821                    for k in 0..wlen { wc!(wbuf[k]); }
10822                }
10823                b'c' => {
10824                    let ch = args.next_arg::<c_int>();
10825                    wc!(ch as u8);
10826                }
10827                b's' => {
10828                    let p = args.next_arg::<*const c_char>();
10829                    if p.is_null() {
10830                        let slen = if precision >= 0 { (precision as usize).min(6) } else { 6 };
10831                        if flags & FLAG_MINUS != 0 {
10832                            for k in 0..slen { wc!(b"(null)"[k]); }
10833                            for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10834                        } else {
10835                            for _ in 0..width.saturating_sub(slen) { wc!(b' '); }
10836                            for k in 0..slen { wc!(b"(null)"[k]); }
10837                        }
10838                    } else {
10839                        let mut wbuf_local = [0i32; 256];
10840                        let mut wcount = 0usize;
10841                        let mut byte_pos = 0usize;
10842                        let pbytes = p as *const u8;
10843                        loop {
10844                            if precision >= 0 && wcount >= precision as usize { break; }
10845                            if wcount >= 256 { break; }
10846                            let mut wc_val: c_int = 0;
10847                            let consumed = mbrtowc(&mut wc_val as *mut c_int, p.add(byte_pos) as *const c_char, 256, core::ptr::null_mut());
10848                            if consumed == !0usize || consumed == !1usize {
10849                                wbuf_local[wcount] = *pbytes.add(byte_pos) as c_int;
10850                                byte_pos += 1;
10851                                wcount += 1;
10852                            } else if consumed == 0 {
10853                                break;
10854                            } else {
10855                                wbuf_local[wcount] = wc_val;
10856                                byte_pos += consumed;
10857                                wcount += 1;
10858                            }
10859                        }
10860                        if flags & FLAG_MINUS != 0 {
10861                            for k in 0..wcount { wc!(wbuf_local[k]); }
10862                            for _ in 0..width.saturating_sub(wcount) { wc!(b' '); }
10863                        } else {
10864                            for _ in 0..width.saturating_sub(wcount) { wc!(b' '); }
10865                            for k in 0..wcount { wc!(wbuf_local[k]); }
10866                        }
10867                    }
10868                }
10869                b'p' => {
10870                    wc!(b'0'); wc!(b'x');
10871                    let p = args.next_arg::<*const c_void>();
10872                    let b = format_hex(p as u64, false);
10873                    for k in 0..b.1 { wc!(b.0[k]); }
10874                }
10875                b'n' => {
10876                    let p = args.next_arg::<*mut c_void>();
10877                    if !p.is_null() { *(p as *mut c_int) = pos as c_int; }
10878                }
10879                b'%' => { wc!(b'%'); }
10880                _ => { wc!(b'%'); wc!(spec); }
10881            }
10882        }
10883        fi += 1;
10884    }
10885    let null_pos = if pos < cap { pos } else { cap };
10886    *s.add(null_pos) = 0;
10887    if pos > cap { -1 } else { pos as c_int }
10888}
10889
10890#[no_mangle]
10891pub unsafe extern "C" fn swprintf(s: *mut wchar_t, n: usize, fmt: *const wchar_t, args: ...) -> c_int {
10892    vswprintf(s, n, fmt, args)
10893}
10894
10895#[no_mangle]
10896pub unsafe extern "C" fn vfwprintf(f: *mut FILE, fmt: *const wchar_t, args: VaList) -> c_int {
10897    let mut buf = [0i32; 4096];
10898    let r = vswprintf(buf.as_mut_ptr(), 4096, fmt, args);
10899    if r < 0 { return r; }
10900    let mut i = 0;
10901    while i < r as usize {
10902        let mut mb = [0u8; 4];
10903        let n = wcrtomb(mb.as_mut_ptr() as *mut c_char, buf[i], core::ptr::null_mut());
10904        if n == !0usize { return -1; }
10905        if fwrite(mb.as_ptr() as *const c_void, 1, n, f) != n { return -1; }
10906        i += 1;
10907    }
10908    r
10909}
10910
10911#[no_mangle]
10912pub unsafe extern "C" fn fwprintf(f: *mut FILE, fmt: *const wchar_t, args: ...) -> c_int {
10913    vfwprintf(f, fmt, args)
10914}
10915
10916// ============================================================
10917// wchar: vswscanf / swscanf / vfwscanf / fwscanf / vwscanf / wscanf
10918// ============================================================
10919
10920// Convert wchar_t format to byte format (ASCII cast, format specifiers are ASCII)
10921unsafe fn wcsfmt_to_mbs(dst: *mut u8, dst_len: usize, src: *const wchar_t) {
10922    let mut i = 0usize;
10923    loop {
10924        let ch = *src.add(i) as u32;
10925        if ch == 0 || i >= dst_len - 1 { break; }
10926        *dst.add(i) = if ch < 128 { ch as u8 } else { b'?' };
10927        i += 1;
10928    }
10929    *dst.add(i) = 0;
10930}
10931
10932#[no_mangle]
10933pub unsafe extern "C" fn vswscanf(s: *const wchar_t, fmt: *const wchar_t, mut args: VaList) -> c_int {
10934    let mut mbs_buf = [0u8; 4096];
10935    let mut i = 0usize;
10936    let mut mb_pos = 0usize;
10937    loop {
10938        let wc = *s.add(i) as c_int;
10939        if wc == 0 { break; }
10940        let mut mb = [0u8; 4];
10941        let n = wcrtomb(mb.as_mut_ptr() as *mut c_char, wc, core::ptr::null_mut());
10942        if n == !0usize || n == 0 { break; }
10943        if mb_pos + n >= mbs_buf.len() { break; }
10944        let mut k = 0usize;
10945        while k < n { mbs_buf[mb_pos + k] = mb[k]; k += 1; }
10946        mb_pos += n;
10947        i += 1;
10948    }
10949    mbs_buf[mb_pos] = 0;
10950    let mut mbs_fmt = [0u8; 4096];
10951    wcsfmt_to_mbs(mbs_fmt.as_mut_ptr(), mbs_fmt.len(), fmt);
10952    do_vsscanf(mbs_buf.as_ptr(), mb_pos, mbs_fmt.as_ptr() as *const c_char, &mut args, core::ptr::null_mut())
10953}
10954
10955#[no_mangle]
10956pub unsafe extern "C" fn swscanf(s: *const wchar_t, fmt: *const wchar_t, args: ...) -> c_int {
10957    vswscanf(s, fmt, args)
10958}
10959
10960#[no_mangle]
10961pub unsafe extern "C" fn vfwscanf(f: *mut FILE, fmt: *const wchar_t, mut args: VaList) -> c_int {
10962    let start_pos = ftello(f);
10963    if start_pos < 0 { return -1; }
10964    let mut buf = [0u8; 4096];
10965    let mut n = 0usize;
10966    loop {
10967        if n >= buf.len() - 1 { break; }
10968        let c = fgetc(f);
10969        if c == -1 { break; }
10970        buf[n] = c as u8;
10971        n += 1;
10972    }
10973    buf[n] = 0;
10974    let mut mbs_fmt = [0u8; 4096];
10975    wcsfmt_to_mbs(mbs_fmt.as_mut_ptr(), mbs_fmt.len(), fmt);
10976    let mut consumed = 0usize;
10977    let hit_eof = (*f)._eof != 0;
10978    let result = do_vsscanf(buf.as_ptr(), n, mbs_fmt.as_ptr() as *const c_char, &mut args, &mut consumed);
10979    let _ = fseeko(f, start_pos + consumed as i64, SEEK_SET);
10980    if hit_eof && consumed == n {
10981        (*f)._eof = 1;
10982    }
10983    result
10984}
10985
10986#[no_mangle]
10987pub unsafe extern "C" fn fwscanf(f: *mut FILE, fmt: *const wchar_t, args: ...) -> c_int {
10988    vfwscanf(f, fmt, args)
10989}
10990
10991#[no_mangle]
10992pub unsafe extern "C" fn vwscanf(fmt: *const wchar_t, args: VaList) -> c_int {
10993    vfwscanf(stdin, fmt, args)
10994}
10995
10996#[no_mangle]
10997pub unsafe extern "C" fn wscanf(fmt: *const wchar_t, args: ...) -> c_int {
10998    vfwscanf(stdin, fmt, args)
10999}
11000
11001// ============================================================
11002// Time: internal helpers
11003// ============================================================
11004
11005const LEAPOCH: i64 = 946684800 + 86400 * (31 + 29);
11006const DAYS_PER_400Y: i64 = 365 * 400 + 97;
11007const DAYS_PER_100Y: i64 = 365 * 100 + 24;
11008const DAYS_PER_4Y: i64 = 365 * 4 + 1;
11009
11010const SECS_THROUGH_MONTH: [i32; 12] = [
11011    0, 31*86400, 59*86400, 90*86400, 120*86400, 151*86400,
11012    181*86400, 212*86400, 243*86400, 273*86400, 304*86400, 334*86400,
11013];
11014
11015const DAYS_IN_MONTH: [i32; 12] = [31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29];
11016
11017unsafe fn year_to_secs(year: i64, is_leap: &mut bool) -> i64 {
11018    if year - 2 <= 136 {
11019        let y = year as i32;
11020        let mut leaps = (y - 68) >> 2;
11021        if (y - 68) & 3 == 0 { leaps -= 1; *is_leap = true; } else { *is_leap = false; }
11022        return 31536000 * (y as i64 - 70) + 86400 * leaps as i64;
11023    }
11024    let mut cycles = ((year - 100) / 400) as i32;
11025    let mut rem = ((year - 100) % 400) as i32;
11026    if rem < 0 { cycles -= 1; rem += 400; }
11027    let (centuries, leaps);
11028    if rem == 0 { *is_leap = true; centuries = 0; leaps = 0; }
11029    else {
11030        let c;
11031        if rem >= 200 { if rem >= 300 { c = 3; rem -= 300; } else { c = 2; rem -= 200; } }
11032        else { if rem >= 100 { c = 1; rem -= 100; } else { c = 0; } }
11033        centuries = c;
11034        if rem == 0 { *is_leap = false; leaps = 0; }
11035        else { leaps = rem / 4; rem %= 4; *is_leap = rem == 0; }
11036    }
11037    let total_leaps = leaps + 97 * cycles + 24 * centuries - (*is_leap as i32);
11038    (year - 100) * 31536000 + total_leaps as i64 * 86400 + 946684800 + 86400
11039}
11040
11041fn month_to_secs(month: i32, is_leap: bool) -> i32 {
11042    let mut t = SECS_THROUGH_MONTH[month as usize];
11043    if is_leap && month >= 2 { t += 86400; }
11044    t
11045}
11046
11047unsafe fn secs_to_tm(t: i64, tm: &mut tm) -> bool {
11048    if t < (i32::MIN as i64) * 31622400 || t > (i32::MAX as i64) * 31622400 { return false; }
11049    let secs = t - LEAPOCH;
11050    let mut days = secs / 86400;
11051    let mut remsecs = (secs % 86400) as i32;
11052    if remsecs < 0 { remsecs += 86400; days -= 1; }
11053    let mut wday = ((3 + days) % 7) as i32;
11054    if wday < 0 { wday += 7; }
11055    let mut qc_cycles = (days / DAYS_PER_400Y) as i32;
11056    let mut remdays = (days % DAYS_PER_400Y) as i32;
11057    if remdays < 0 { remdays += DAYS_PER_400Y as i32; qc_cycles -= 1; }
11058    let mut c_cycles = remdays / DAYS_PER_100Y as i32;
11059    if c_cycles == 4 { c_cycles -= 1; }
11060    remdays -= c_cycles * DAYS_PER_100Y as i32;
11061    let mut q_cycles = remdays / DAYS_PER_4Y as i32;
11062    if q_cycles == 25 { q_cycles -= 1; }
11063    remdays -= q_cycles * DAYS_PER_4Y as i32;
11064    let mut remyears = remdays / 365;
11065    if remyears == 4 { remyears -= 1; }
11066    remdays -= remyears * 365;
11067    let leap = remyears == 0 && (q_cycles != 0 || c_cycles == 0);
11068    let mut yday = remdays + 31 + 28 + leap as i32;
11069    if yday >= 365 + leap as i32 { yday -= 365 + leap as i32; }
11070    let years = remyears as i64 + 4 * q_cycles as i64 + 100 * c_cycles as i64 + 400 * qc_cycles as i64;
11071    let mut months = 0i32;
11072    let mut rd = remdays;
11073    for m in 0..12 {
11074        if DAYS_IN_MONTH[m] <= rd { rd -= DAYS_IN_MONTH[m]; } else { months = m as i32; break; }
11075    }
11076    let mut adj_years = years;
11077    if months >= 10 { months -= 12; adj_years += 1; }
11078    if adj_years + 100 > i32::MAX as i64 || adj_years + 100 < i32::MIN as i64 { return false; }
11079    tm.tm_year = (adj_years + 100) as c_int;
11080    tm.tm_mon = months + 2;
11081    tm.tm_mday = rd + 1;
11082    tm.tm_wday = wday;
11083    tm.tm_yday = yday;
11084    tm.tm_hour = remsecs / 3600;
11085    tm.tm_min = remsecs / 60 % 60;
11086    tm.tm_sec = remsecs % 60;
11087    true
11088}
11089
11090unsafe fn tm_to_secs(tm: *const tm) -> i64 {
11091    let mut year = (*tm).tm_year as i64;
11092    let mut month = (*tm).tm_mon;
11093    if month >= 12 || month < 0 {
11094        let adj = month / 12;
11095        month %= 12;
11096        if month < 0 { month += 12; }
11097        year += adj as i64;
11098    }
11099    let mut is_leap = false;
11100    let mut t = year_to_secs(year, &mut is_leap);
11101    t += month_to_secs(month, is_leap) as i64;
11102    t += 86400 * ((*tm).tm_mday - 1) as i64;
11103    t += 3600 * (*tm).tm_hour as i64;
11104    t += 60 * (*tm).tm_min as i64;
11105    t += (*tm).tm_sec as i64;
11106    t
11107}
11108
11109static mut TM_BUF: tm = tm {
11110    tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0,
11111    tm_year: 0, tm_wday: 0, tm_yday: 0, tm_isdst: 0,
11112    tm_gmtoff: 0, tm_zone: core::ptr::null(),
11113};
11114
11115static mut UTC_STR: [c_char; 4] = [b'U' as c_char, b'T' as c_char, b'C' as c_char, 0];
11116
11117const CLOCK_PROCESS_CPUTIME_ID: c_int = 2;
11118
11119// ============================================================
11120// Time: core functions
11121// ============================================================
11122
11123#[no_mangle]
11124pub unsafe extern "C" fn time(t: *mut TimeT) -> TimeT {
11125    let mut ts: timespec = core::mem::zeroed();
11126    let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
11127    if !t.is_null() { *t = ts.tv_sec; }
11128    ts.tv_sec
11129}
11130
11131#[no_mangle]
11132pub unsafe extern "C" fn difftime(t1: TimeT, t0: TimeT) -> f64 {
11133    (t1 as i64 - t0 as i64) as f64
11134}
11135
11136#[no_mangle]
11137pub unsafe extern "C" fn clock() -> ClockT {
11138    let mut ts: timespec = core::mem::zeroed();
11139    let _ = sys_clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mut ts);
11140    ts.tv_sec * 1000000 + ts.tv_nsec / 1000
11141}
11142
11143#[no_mangle]
11144pub unsafe extern "C" fn gmtime(t: *const TimeT) -> *mut tm {
11145    gmtime_r(t, &raw mut TM_BUF)
11146}
11147
11148#[no_mangle]
11149pub unsafe extern "C" fn gmtime_r(t: *const TimeT, tm: *mut tm) -> *mut tm {
11150    if !secs_to_tm(*t as i64, &mut *tm) { ERRNO = EOVERFLOW; return core::ptr::null_mut(); }
11151    (*tm).tm_isdst = 0;
11152    (*tm).tm_gmtoff = 0;
11153    (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
11154    tm
11155}
11156
11157#[no_mangle]
11158pub unsafe extern "C" fn localtime(t: *const TimeT) -> *mut tm { gmtime(t) }
11159
11160#[no_mangle]
11161pub unsafe extern "C" fn localtime_r(t: *const TimeT, tm: *mut tm) -> *mut tm { gmtime_r(t, tm) }
11162
11163#[no_mangle]
11164pub unsafe extern "C" fn mktime(tm: *mut tm) -> TimeT {
11165    let t = tm_to_secs(tm as *const tm);
11166    if !secs_to_tm(t, &mut *tm) { ERRNO = EOVERFLOW; return -1; }
11167    (*tm).tm_isdst = 0;
11168    (*tm).tm_gmtoff = 0;
11169    (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
11170    t as TimeT
11171}
11172
11173#[no_mangle]
11174pub unsafe extern "C" fn timegm(tm: *mut tm) -> TimeT {
11175    let t = tm_to_secs(tm as *const tm);
11176    if !secs_to_tm(t, &mut *tm) { ERRNO = EOVERFLOW; return -1; }
11177    (*tm).tm_isdst = 0;
11178    (*tm).tm_gmtoff = 0;
11179    (*tm).tm_zone = core::ptr::addr_of!(UTC_STR).cast::<c_char>();
11180    t as TimeT
11181}
11182
11183static mut ASCTIME_BUF: [c_char; 26] = [0; 26];
11184
11185const DAY_NAMES: [&[u8]; 7] = [b"Sun\0", b"Mon\0", b"Tue\0", b"Wed\0", b"Thu\0", b"Fri\0", b"Sat\0"];
11186const MON_NAMES: [&[u8]; 12] = [b"Jan\0", b"Feb\0", b"Mar\0", b"Apr\0", b"May\0", b"Jun\0", b"Jul\0", b"Aug\0", b"Sep\0", b"Oct\0", b"Nov\0", b"Dec\0"];
11187
11188#[no_mangle]
11189pub unsafe extern "C" fn asctime(tm: *const tm) -> *mut c_char {
11190    asctime_r(tm, core::ptr::addr_of_mut!(ASCTIME_BUF).cast::<c_char>())
11191}
11192
11193#[no_mangle]
11194pub unsafe extern "C" fn asctime_r(tm: *const tm, buf: *mut c_char) -> *mut c_char {
11195    let wday = if (*tm).tm_wday >= 0 && (*tm).tm_wday < 7 { (*tm).tm_wday as usize } else { 0 };
11196    let mon = if (*tm).tm_mon >= 0 && (*tm).tm_mon < 12 { (*tm).tm_mon as usize } else { 0 };
11197    let dn = DAY_NAMES[wday];
11198    let mn = MON_NAMES[mon];
11199    let mut p = 0;
11200    for k in 0..3 { *buf.add(p) = *dn.as_ptr().add(k) as c_char; p += 1; }
11201    *buf.add(p) = b' ' as c_char; p += 1;
11202    for k in 0..3 { *buf.add(p) = *mn.as_ptr().add(k) as c_char; p += 1; }
11203    *buf.add(p) = b' ' as c_char; p += 1;
11204    let v = (*tm).tm_mday;
11205    *buf.add(p) = (b'0' + (v / 10) as u8) as c_char; p += 1;
11206    *buf.add(p) = (b'0' + (v % 10) as u8) as c_char; p += 1;
11207    *buf.add(p) = b' ' as c_char; p += 1;
11208    let hh = (*tm).tm_hour;
11209    *buf.add(p) = (b'0' + (hh / 10) as u8) as c_char; p += 1;
11210    *buf.add(p) = (b'0' + (hh % 10) as u8) as c_char; p += 1;
11211    *buf.add(p) = b':' as c_char; p += 1;
11212    let mm = (*tm).tm_min;
11213    *buf.add(p) = (b'0' + (mm / 10) as u8) as c_char; p += 1;
11214    *buf.add(p) = (b'0' + (mm % 10) as u8) as c_char; p += 1;
11215    *buf.add(p) = b':' as c_char; p += 1;
11216    let ss = (*tm).tm_sec;
11217    *buf.add(p) = (b'0' + (ss / 10) as u8) as c_char; p += 1;
11218    *buf.add(p) = (b'0' + (ss % 10) as u8) as c_char; p += 1;
11219    *buf.add(p) = b' ' as c_char; p += 1;
11220    let yr = (*tm).tm_year + 1900;
11221    let mut tmp = [0u8; 4];
11222    let mut v2 = yr;
11223    for k in (0..4).rev() { tmp[k] = b'0' + (v2 % 10) as u8; v2 /= 10; }
11224    for k in 0..4 { *buf.add(p) = tmp[k] as c_char; p += 1; }
11225    *buf.add(p) = b'\n' as c_char; p += 1;
11226    *buf.add(p) = 0;
11227    buf
11228}
11229
11230#[no_mangle]
11231pub unsafe extern "C" fn ctime(t: *const TimeT) -> *mut c_char { asctime(gmtime(t)) }
11232
11233#[no_mangle]
11234pub unsafe extern "C" fn ctime_r(t: *const TimeT, buf: *mut c_char) -> *mut c_char {
11235    let mut tmp: tm = core::mem::zeroed();
11236    gmtime_r(t, &mut tmp);
11237    asctime_r(&tmp, buf)
11238}
11239
11240// ============================================================
11241// Time: clock_getres / clock_settime / clock_nanosleep / gettimeofday
11242// ============================================================
11243
11244unsafe fn sys_clock_getres(clockid: c_int, ts: *mut timespec) -> i64 {
11245    <Arch as Syscalls>::syscall2(SYS_CLOCK_GETRES, clockid as i64, ts as i64)
11246}
11247
11248unsafe fn sys_clock_settime(clockid: c_int, ts: *const timespec) -> i64 {
11249    <Arch as Syscalls>::syscall2(SYS_CLOCK_SETTIME, clockid as i64, ts as i64)
11250}
11251
11252unsafe fn sys_clock_nanosleep(clockid: c_int, flags: c_int, req: *const timespec, rem: *mut timespec) -> i64 {
11253    <Arch as Syscalls>::syscall4(SYS_CLOCK_NANOSLEEP, clockid as i64, flags as i64, req as i64, rem as i64)
11254}
11255
11256#[no_mangle]
11257pub unsafe extern "C" fn clock_getres(clockid: c_int, ts: *mut timespec) -> c_int { if sys_clock_getres(clockid, ts) < 0 { -1 } else { 0 } }
11258
11259#[no_mangle]
11260pub unsafe extern "C" fn clock_settime(clockid: c_int, ts: *const timespec) -> c_int { if sys_clock_settime(clockid, ts) < 0 { -1 } else { 0 } }
11261
11262#[no_mangle]
11263pub unsafe extern "C" fn clock_nanosleep(clockid: c_int, flags: c_int, req: *const timespec, rem: *mut timespec) -> c_int {
11264    let r = sys_clock_nanosleep(clockid, flags, req, rem);
11265    if r < 0 { (-r) as c_int } else { 0 }
11266}
11267
11268#[no_mangle]
11269pub unsafe extern "C" fn gettimeofday(tv: *mut timeval, _tz: *mut c_void) -> c_int {
11270    if tv.is_null() { return 0; }
11271    let mut ts: timespec = core::mem::zeroed();
11272    let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
11273    (*tv).tv_sec = ts.tv_sec;
11274    (*tv).tv_usec = ts.tv_nsec / 1000;
11275    0
11276}
11277
11278// ============================================================
11279// Time: strftime
11280// ============================================================
11281
11282fn is_leap_year(y: i32) -> bool {
11283    let yr = if y > i32::MAX - 1900 { y - 2000 } else { y + 1900 };
11284    yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0)
11285}
11286
11287fn week_num(tm: &tm) -> i32 {
11288    let mut val = (tm.tm_yday + 7 - ((tm.tm_wday + 6) % 7)) / 7;
11289    if (tm.tm_wday + 371 - tm.tm_yday - 2).rem_euclid(7) <= 2 { val += 1; }
11290    if val == 0 {
11291        val = 52;
11292        let dec31 = (tm.tm_wday + 7 - tm.tm_yday - 1).rem_euclid(7);
11293        if dec31 == 4 || (dec31 == 5 && is_leap_year(tm.tm_year % 400 - 1)) { val += 1; }
11294    } else if val == 53 {
11295        let jan1 = (tm.tm_wday + 371 - tm.tm_yday).rem_euclid(7);
11296        if jan1 != 4 && (jan1 != 3 || !is_leap_year(tm.tm_year)) { val = 1; }
11297    }
11298    val
11299}
11300
11301// Langinfo constants for strftime
11302const ABDAY_1: c_int = 0x20000;
11303const DAY_1: c_int = 0x20007;
11304const ABMON_1: c_int = 0x2000E;
11305const MON_1: c_int = 0x2001A;
11306const AM_STR_LI: c_int = 0x20026;
11307const PM_STR_LI: c_int = 0x20027;
11308const D_T_FMT: c_int = 0x20028;
11309const D_FMT: c_int = 0x20029;
11310const T_FMT: c_int = 0x2002A;
11311const T_FMT_AMPM: c_int = 0x2002B;
11312
11313// Format an i64 into buf as decimal with zero/sign padding. Returns (ptr_to_start, length).
11314// pad: '-' = no pad, '_' = space pad, '0' or 0 = zero pad. width: minimum digits (excluding sign).
11315unsafe fn num_fmt(buf: &mut [u8; 100], val: i64, pad: u8, width: usize) -> (*const u8, usize) {
11316    let negative = val < 0;
11317    let mut v = if negative { -val as u64 } else { val as u64 };
11318    let mut tmp = [0u8; 24];
11319    let mut pos = 24usize;
11320    if v == 0 { pos -= 1; tmp[pos] = b'0'; }
11321    while v > 0 { pos -= 1; tmp[pos] = b'0' + (v % 10) as u8; v /= 10; }
11322    let digits = 24 - pos;
11323    let sign_chars = if negative { 1 } else { 0 };
11324    let needed = sign_chars + digits;
11325    let fill = if width > needed { width - needed } else { 0 };
11326    let total = fill + needed;
11327    let mut p = 0usize;
11328    match pad {
11329        b'-' => { /* no fill */ }
11330        b'_' => {
11331            for _ in 0..fill { buf[p] = b' '; p += 1; }
11332            if negative { buf[p] = b'-'; p += 1; }
11333        }
11334        _ => {
11335            if negative { buf[p] = b'-'; p += 1; }
11336            for _ in 0..fill { buf[p] = b'0'; p += 1; }
11337        }
11338    }
11339    for i in 0..digits { buf[p] = tmp[pos + i]; p += 1; }
11340    (buf.as_ptr(), total)
11341}
11342
11343// Copy a null-terminated C string into buf. Returns (ptr, len).
11344unsafe fn str_to_buf(buf: &mut [u8; 100], s: *const c_char) -> (*const u8, usize) {
11345    let mut k = 0usize;
11346    while *s.add(k) != 0 {
11347        buf[k] = *s.add(k) as u8;
11348        k += 1;
11349    }
11350    (buf.as_ptr(), k)
11351}
11352
11353// Core format dispatcher. Returns (ptr, len) where ptr points into buf or a static string.
11354// pad=0 means use default; returns (null, 0) for unknown specifiers.
11355unsafe fn __strftime_fmt_1(buf: &mut [u8; 100], f: u8, tm: *const tm, pad: u8) -> (*const u8, usize) {
11356    let mut val: i64;
11357    let mut width: usize = 2;
11358    let mut def_pad: u8 = b'0';
11359    let fmt: *const c_char;
11360
11361    match f {
11362        b'a' => {
11363            if (*tm).tm_wday as u32 > 6 { return (b"\0".as_ptr(), 0); }
11364            let p = nl_langinfo(ABDAY_1 + (*tm).tm_wday);
11365            return str_to_buf(buf, p);
11366        }
11367        b'A' => {
11368            if (*tm).tm_wday as u32 > 6 { return (b"\0".as_ptr(), 0); }
11369            let p = nl_langinfo(DAY_1 + (*tm).tm_wday);
11370            return str_to_buf(buf, p);
11371        }
11372        b'h' | b'b' => {
11373            if (*tm).tm_mon as u32 > 11 { return (b"\0".as_ptr(), 0); }
11374            let p = nl_langinfo(ABMON_1 + (*tm).tm_mon);
11375            return str_to_buf(buf, p);
11376        }
11377        b'B' => {
11378            if (*tm).tm_mon as u32 > 11 { return (b"\0".as_ptr(), 0); }
11379            let p = nl_langinfo(MON_1 + (*tm).tm_mon);
11380            return str_to_buf(buf, p);
11381        }
11382        b'c' => {
11383            let p = nl_langinfo(D_T_FMT);
11384            let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
11385            return (buf.as_ptr(), l);
11386        }
11387        b'C' => {
11388            val = (1900i64 + (*tm).tm_year as i64) / 100;
11389            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11390        }
11391        b'e' => { def_pad = b'_'; }
11392        b'd' => {
11393            val = (*tm).tm_mday as i64;
11394            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11395        }
11396        b'D' => {
11397            fmt = b"%m/%d/%y\0".as_ptr() as *const c_char;
11398            let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
11399            return (buf.as_ptr(), l);
11400        }
11401        b'F' => {
11402            fmt = b"%Y-%m-%d\0".as_ptr() as *const c_char;
11403            let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
11404            return (buf.as_ptr(), l);
11405        }
11406        b'g' | b'G' => {
11407            val = (*tm).tm_year as i64 + 1900;
11408            if (*tm).tm_yday < 3 && week_num(&*tm) != 1 { val -= 1; }
11409            else if (*tm).tm_yday > 360 && week_num(&*tm) == 1 { val += 1; }
11410            if f == b'g' { val %= 100; }
11411            else { width = 4; }
11412            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11413        }
11414        b'H' => {
11415            val = (*tm).tm_hour as i64;
11416            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11417        }
11418        b'I' => {
11419            val = (*tm).tm_hour as i64;
11420            if val == 0 { val = 12; }
11421            else if val > 12 { val -= 12; }
11422            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11423        }
11424        b'j' => {
11425            val = (*tm).tm_yday as i64 + 1;
11426            width = 3;
11427            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11428        }
11429        b'm' => {
11430            val = (*tm).tm_mon as i64 + 1;
11431            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11432        }
11433        b'M' => {
11434            val = (*tm).tm_min as i64;
11435            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11436        }
11437        b'n' => { buf[0] = b'\n'; return (buf.as_ptr(), 1); }
11438        b'p' => {
11439            let p = if (*tm).tm_hour >= 12 { nl_langinfo(PM_STR_LI) } else { nl_langinfo(AM_STR_LI) };
11440            return str_to_buf(buf, p);
11441        }
11442        b'r' => {
11443            let p = nl_langinfo(T_FMT_AMPM);
11444            let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
11445            return (buf.as_ptr(), l);
11446        }
11447        b'R' => {
11448            fmt = b"%H:%M\0".as_ptr() as *const c_char;
11449            let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
11450            return (buf.as_ptr(), l);
11451        }
11452        b's' => {
11453            val = tm_to_secs(tm) - (*tm).tm_gmtoff as i64;
11454            width = 1;
11455            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11456        }
11457        b'S' => {
11458            val = (*tm).tm_sec as i64;
11459            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11460        }
11461        b't' => { buf[0] = b'\t'; return (buf.as_ptr(), 1); }
11462        b'T' => {
11463            fmt = b"%H:%M:%S\0".as_ptr() as *const c_char;
11464            let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, fmt, tm);
11465            return (buf.as_ptr(), l);
11466        }
11467        b'u' => {
11468            val = if (*tm).tm_wday != 0 { (*tm).tm_wday as i64 } else { 7 };
11469            width = 1;
11470            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11471        }
11472        b'U' => {
11473            val = ((*tm).tm_yday as u64 + 7 - (*tm).tm_wday as u64) as i64 / 7;
11474            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11475        }
11476        b'W' => {
11477            val = ((*tm).tm_yday as u64 + 7 - ((*tm).tm_wday as u64 + 6) % 7) as i64 / 7;
11478            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11479        }
11480        b'V' => {
11481            val = week_num(&*tm) as i64;
11482            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11483        }
11484        b'w' => {
11485            val = (*tm).tm_wday as i64;
11486            width = 1;
11487            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11488        }
11489        b'x' => {
11490            let p = nl_langinfo(D_FMT);
11491            let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
11492            return (buf.as_ptr(), l);
11493        }
11494        b'X' => {
11495            let p = nl_langinfo(T_FMT);
11496            let l = __strftime_l(buf.as_mut_ptr() as *mut c_char, 100, p, tm);
11497            return (buf.as_ptr(), l);
11498        }
11499        b'y' => {
11500            val = (1900i64 + (*tm).tm_year as i64) % 100;
11501            if val < 0 { val = -val; }
11502            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11503        }
11504        b'Y' => {
11505            val = (*tm).tm_year as i64 + 1900;
11506            if val >= 10000 {
11507                let mut tmp = [0u8; 100];
11508                let (_, k) = num_fmt(&mut tmp, val, b'-', 1);
11509                buf[0] = b'+';
11510                for i in 0..k { buf[1 + i] = tmp[i]; }
11511                return (buf.as_ptr(), 1 + k);
11512            }
11513            width = 4;
11514            return num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width);
11515        }
11516        b'z' => {
11517            if (*tm).tm_isdst < 0 { return (b"\0".as_ptr(), 0); }
11518            let gmtoff = (*tm).tm_gmtoff as i64;
11519            let sign = if gmtoff >= 0 { b'+' } else { b'-' };
11520            let off = if gmtoff < 0 { -gmtoff } else { gmtoff };
11521            let hh = (off / 3600) as i32;
11522            let mm = ((off % 3600) / 60) as i32;
11523            buf[0] = sign;
11524            buf[1] = b'0' + (hh / 10) as u8;
11525            buf[2] = b'0' + (hh % 10) as u8;
11526            buf[3] = b'0' + (mm / 10) as u8;
11527            buf[4] = b'0' + (mm % 10) as u8;
11528            return (buf.as_ptr(), 5);
11529        }
11530        b'Z' => {
11531            if (*tm).tm_isdst < 0 || (*tm).tm_zone.is_null() { return (b"\0".as_ptr(), 0); }
11532            return str_to_buf(buf, (*tm).tm_zone);
11533        }
11534        b'%' => { buf[0] = b'%'; return (buf.as_ptr(), 1); }
11535        _ => { return (core::ptr::null(), 0); }
11536    }
11537    // fallthrough for 'e' (def_pad='_', same logic as 'd')
11538    val = (*tm).tm_mday as i64;
11539    num_fmt(buf, val, if pad != 0 { pad } else { def_pad }, width)
11540}
11541
11542unsafe fn __strftime_l(s: *mut c_char, n: usize, f: *const c_char, tm: *const tm) -> usize {
11543    let mut l: usize = 0;
11544    let mut fi: usize = 0;
11545    while l < n {
11546        let ch = *f.add(fi) as u8;
11547        if ch == 0 {
11548            *s.add(l) = 0;
11549            return l;
11550        }
11551        if ch != b'%' {
11552            *s.add(l) = ch as c_char;
11553            l += 1;
11554            fi += 1;
11555            continue;
11556        }
11557        fi += 1;
11558        // Parse flags
11559        let mut pad: u8 = 0;
11560        let fc = *f.add(fi) as u8;
11561        if fc == b'-' || fc == b'_' || fc == b'0' { pad = fc; fi += 1; }
11562        let plus = *f.add(fi) as u8 == b'+';
11563        if plus { fi += 1; }
11564        // Parse width
11565        let mut width: usize = 0;
11566        let mut p_idx = fi;
11567        {
11568            let fc2 = *f.add(fi) as u8;
11569            if fc2 >= b'0' && fc2 <= b'9' {
11570                let mut w: usize = 0;
11571                while { let c = *f.add(p_idx) as u8; c >= b'0' && c <= b'9' } {
11572                    w = w * 10 + (*f.add(p_idx) as usize - b'0' as usize);
11573                    p_idx += 1;
11574                }
11575                width = w;
11576            }
11577        }
11578        let spec_ch = *f.add(p_idx) as u8;
11579        if spec_ch == b'C' || spec_ch == b'F' || spec_ch == b'G' || spec_ch == b'Y' {
11580            if width == 0 && p_idx != fi { width = 1; }
11581        } else {
11582            width = 0;
11583        }
11584        fi = p_idx;
11585        // Skip E/O modifier
11586        let fc3 = *f.add(fi) as u8;
11587        if fc3 == b'E' || fc3 == b'O' { fi += 1; }
11588        let fch = *f.add(fi) as u8;
11589        // Call formatter
11590        let mut buf = [0u8; 100];
11591        let (t, k) = __strftime_fmt_1(&mut buf, fch, tm, pad);
11592        if t.is_null() { break; }
11593        let mut k = k;
11594        let mut t = t;
11595        if width != 0 {
11596            // Strip sign and leading zeros, count remaining digits
11597            if *t == b'+' || *t == b'-' { t = t.add(1); k -= 1; }
11598            while k > 0 && *t == b'0' && k > 1 && *t.add(1) >= b'0' && *t.add(1) <= b'9' {
11599                t = t.add(1); k -= 1;
11600            }
11601            if width < k { width = k; }
11602            let mut d: usize = 0;
11603            while d < k && *t.add(d) >= b'0' && *t.add(d) <= b'9' { d += 1; }
11604            if (*tm).tm_year < -1900 {
11605                if l < n { *s.add(l) = b'-' as c_char; }
11606                l += 1;
11607                width -= 1;
11608            } else if plus && d + (width - k) >= (if spec_ch == b'C' { 3 } else { 5 }) {
11609                if l < n { *s.add(l) = b'+' as c_char; }
11610                l += 1;
11611                width -= 1;
11612            }
11613            while width > k && l < n {
11614                *s.add(l) = b'0' as c_char;
11615                l += 1;
11616                width -= 1;
11617            }
11618        }
11619        let copy = if k > n - l { n - l } else { k };
11620        core::ptr::copy_nonoverlapping(t, s.add(l) as *mut u8, copy);
11621        l += copy;
11622        fi += 1;
11623    }
11624    if n > 0 {
11625        if l == n { l = n - 1; }
11626        *s.add(l) = 0;
11627    }
11628    0
11629}
11630
11631#[no_mangle]
11632pub unsafe extern "C" fn strftime(s: *mut c_char, maxsize: usize, fmt: *const c_char, tm: *const tm) -> usize {
11633    __strftime_l(s, maxsize, fmt, tm)
11634}
11635
11636// ============================================================
11637// Time: strptime
11638// ============================================================
11639
11640unsafe fn match_prefix(s: *const u8, prefix: &[u8]) -> bool {
11641    for i in 0..prefix.len() {
11642        if *s.add(i) == 0 || *s.add(i) != prefix[i] { return false; }
11643    }
11644    true
11645}
11646
11647unsafe fn match_ci_prefix(s: *const u8, prefix: &[u8]) -> bool {
11648    for i in 0..prefix.len() {
11649        let c = *s.add(i);
11650        if c == 0 { return false; }
11651        if c.to_ascii_lowercase() != prefix[i].to_ascii_lowercase() { return false; }
11652    }
11653    true
11654}
11655
11656unsafe fn parse_int(p: *const u8, max_digits: usize) -> (i32, *const u8) {
11657    let mut val = 0i32;
11658    let mut np = p;
11659    let mut count = 0;
11660    while *np >= b'0' && *np <= b'9' && count < max_digits {
11661        val = val * 10 + (*np - b'0') as i32;
11662        np = np.add(1);
11663        count += 1;
11664    }
11665    if count == 0 { (0, p) } else { (val, np) }
11666}
11667
11668unsafe fn parse_range(p: *const u8, min: i32, max: i32) -> (i32, *const u8) {
11669    let (val, np) = parse_int(p, 4);
11670    if np == p || val < min || val > max { (0, p) } else { (val, np) }
11671}
11672
11673fn is_ascii_space(c: u8) -> bool {
11674    c == b' ' || c == b'\t' || c == b'\n' || c == b'\r' || c == 0x0c || c == 0x0b
11675}
11676
11677#[no_mangle]
11678pub unsafe extern "C" fn strptime(s: *const c_char, fmt: *const c_char, tm: *mut tm) -> *mut c_char {
11679    let mut p = s as *const u8;
11680    let mut f = fmt as *const u8;
11681    let mut want_century = 0i32;
11682    let mut century = 0i32;
11683    let mut relyear = 0i32;
11684    while *f != 0 {
11685        if *f != b'%' {
11686            if is_ascii_space(*f) {
11687                while *p != 0 && is_ascii_space(*p) { p = p.add(1); }
11688            } else {
11689                if *p != *f { return core::ptr::null_mut(); }
11690                p = p.add(1);
11691            }
11692            f = f.add(1);
11693            continue;
11694        }
11695        f = f.add(1);
11696        if *f == b'+' { f = f.add(1); }
11697        while *f >= b'0' && *f <= b'9' { f = f.add(1); }
11698        if *f == b'E' || *f == b'O' { f = f.add(1); }
11699        match *f {
11700            b'a' | b'A' => {
11701                let mut found = false;
11702                for i in 0..7 {
11703                    let names: [&[u8]; 7] = [b"Sunday", b"Monday", b"Tuesday", b"Wednesday", b"Thursday", b"Friday", b"Saturday"];
11704                    let snames: [&[u8]; 7] = [b"Sun", b"Mon", b"Tue", b"Wed", b"Thu", b"Fri", b"Sat"];
11705                    if match_prefix(p, names[i]) { (*tm).tm_wday = i as c_int; p = p.add(names[i].len()); found = true; break; }
11706                    if match_prefix(p, snames[i]) { (*tm).tm_wday = i as c_int; p = p.add(snames[i].len()); found = true; break; }
11707                }
11708                if !found { return core::ptr::null_mut(); }
11709            }
11710            b'b' | b'B' | b'h' => {
11711                let mut found = false;
11712                for i in 0..12 {
11713                    let names: [&[u8]; 12] = [b"January", b"February", b"March", b"April", b"May", b"June", b"July", b"August", b"September", b"October", b"November", b"December"];
11714                    let snames: [&[u8]; 12] = [b"Jan", b"Feb", b"Mar", b"Apr", b"May", b"Jun", b"Jul", b"Aug", b"Sep", b"Oct", b"Nov", b"Dec"];
11715                    if match_prefix(p, names[i]) { (*tm).tm_mon = i as c_int; p = p.add(names[i].len()); found = true; break; }
11716                    if match_prefix(p, snames[i]) { (*tm).tm_mon = i as c_int; p = p.add(snames[i].len()); found = true; break; }
11717                }
11718                if !found { return core::ptr::null_mut(); }
11719            }
11720            b'C' => {
11721                let (v, np) = parse_int(p, 2);
11722                if np == p { return core::ptr::null_mut(); }
11723                century = v;
11724                want_century |= 2;
11725                p = np;
11726            }
11727            b'd' | b'e' => {
11728                let (v, np) = parse_range(p, 1, 31);
11729                if np == p { return core::ptr::null_mut(); }
11730                (*tm).tm_mday = v;
11731                p = np;
11732            }
11733            b'D' => {
11734                let r = strptime(p as *const c_char, b"%m/%d/%y\0".as_ptr() as *const c_char, tm);
11735                if r.is_null() { return core::ptr::null_mut(); }
11736                p = r as *const u8;
11737            }
11738            b'F' => {
11739                let (yv, ynp) = parse_int(p, 4);
11740                if ynp == p { return core::ptr::null_mut(); }
11741                (*tm).tm_year = yv - 1900;
11742                p = ynp;
11743                if *p != b'-' { return core::ptr::null_mut(); }
11744                p = p.add(1);
11745                let (mv, mnp) = parse_range(p, 1, 12);
11746                if mnp == p { return core::ptr::null_mut(); }
11747                (*tm).tm_mon = mv - 1;
11748                p = mnp;
11749                if *p != b'-' { return core::ptr::null_mut(); }
11750                p = p.add(1);
11751                let (dv, dnp) = parse_range(p, 1, 31);
11752                if dnp == p { return core::ptr::null_mut(); }
11753                (*tm).tm_mday = dv;
11754                p = dnp;
11755            }
11756            b'H' | b'I' => {
11757                let (v, np) = parse_range(p, 0, 23);
11758                if np == p { return core::ptr::null_mut(); }
11759                (*tm).tm_hour = v;
11760                p = np;
11761            }
11762            b'j' => {
11763                let (v, np) = parse_range(p, 1, 366);
11764                if np == p { return core::ptr::null_mut(); }
11765                (*tm).tm_yday = v - 1;
11766                p = np;
11767            }
11768            b'm' => {
11769                let (v, np) = parse_range(p, 1, 12);
11770                if np == p { return core::ptr::null_mut(); }
11771                (*tm).tm_mon = v - 1;
11772                p = np;
11773            }
11774            b'M' => {
11775                let (v, np) = parse_range(p, 0, 59);
11776                if np == p { return core::ptr::null_mut(); }
11777                (*tm).tm_min = v;
11778                p = np;
11779            }
11780            b'n' | b't' => {
11781                while *p != 0 && is_ascii_space(*p) { p = p.add(1); }
11782            }
11783            b'p' => {
11784                if match_ci_prefix(p, b"AM") {
11785                    if (*tm).tm_hour == 12 { (*tm).tm_hour = 0; }
11786                    p = p.add(2);
11787                } else if match_ci_prefix(p, b"PM") {
11788                    if (*tm).tm_hour < 12 { (*tm).tm_hour += 12; }
11789                    p = p.add(2);
11790                } else { return core::ptr::null_mut(); }
11791            }
11792            b'r' => {
11793                let r = strptime(p as *const c_char, b"%I:%M:%S %p\0".as_ptr() as *const c_char, tm);
11794                if r.is_null() { return core::ptr::null_mut(); }
11795                p = r as *const u8;
11796            }
11797            b'R' => {
11798                let r = strptime(p as *const c_char, b"%H:%M\0".as_ptr() as *const c_char, tm);
11799                if r.is_null() { return core::ptr::null_mut(); }
11800                p = r as *const u8;
11801            }
11802            b's' => {
11803                let neg = if *p == b'-' { p = p.add(1); true } else { false };
11804                if *p < b'0' || *p > b'9' { return core::ptr::null_mut(); }
11805                let mut val = 0i64;
11806                while *p >= b'0' && *p <= b'9' {
11807                    val = val * 10 + (*p - b'0') as i64;
11808                    p = p.add(1);
11809                }
11810                if neg { val = -val; }
11811                secs_to_tm(val, &mut *tm);
11812            }
11813            b'S' => {
11814                let (v, np) = parse_range(p, 0, 60);
11815                if np == p { return core::ptr::null_mut(); }
11816                (*tm).tm_sec = v;
11817                p = np;
11818            }
11819            b'T' => {
11820                let r = strptime(p as *const c_char, b"%H:%M:%S\0".as_ptr() as *const c_char, tm);
11821                if r.is_null() { return core::ptr::null_mut(); }
11822                p = r as *const u8;
11823            }
11824            b'U' | b'W' => {
11825                let (_, np) = parse_range(p, 0, 53);
11826                if np == p { return core::ptr::null_mut(); }
11827                p = np;
11828            }
11829            b'V' => {
11830                let (_, np) = parse_range(p, 1, 53);
11831                if np == p { return core::ptr::null_mut(); }
11832                p = np;
11833            }
11834            b'w' => {
11835                let (v, np) = parse_range(p, 0, 6);
11836                if np == p { return core::ptr::null_mut(); }
11837                (*tm).tm_wday = v;
11838                p = np;
11839            }
11840            b'y' => {
11841                let (v, np) = parse_int(p, 2);
11842                if np == p { return core::ptr::null_mut(); }
11843                relyear = v;
11844                want_century |= 1;
11845                p = np;
11846            }
11847            b'Y' => {
11848                let neg = if *p == b'-' { p = p.add(1); true } else { false };
11849                let (v, np) = parse_int(p, 4);
11850                if np == p { return core::ptr::null_mut(); }
11851                (*tm).tm_year = if neg { -(v + 1900) } else { v - 1900 };
11852                want_century = 0;
11853                p = np;
11854            }
11855            b'z' => {
11856                if *p != b'+' && *p != b'-' { return core::ptr::null_mut(); }
11857                let neg = *p == b'-';
11858                p = p.add(1);
11859                let mut off = 0i64;
11860                let mut digits = 0;
11861                while digits < 4 && *p >= b'0' && *p <= b'9' {
11862                    off = off * 10 + (*p - b'0') as i64;
11863                    p = p.add(1);
11864                    digits += 1;
11865                }
11866                if digits == 0 { return core::ptr::null_mut(); }
11867                let (hh, mm) = if digits <= 2 { (off, 0i64) } else { (off / 100, off % 100) };
11868                (*tm).tm_gmtoff = (hh * 3600 + mm * 60) * if neg { -1 } else { 1 };
11869            }
11870            b'%' => {
11871                if *p != b'%' { return core::ptr::null_mut(); }
11872                p = p.add(1);
11873            }
11874            _ => { return core::ptr::null_mut(); }
11875        }
11876        f = f.add(1);
11877    }
11878    if want_century != 0 {
11879        (*tm).tm_year = relyear;
11880        if want_century & 2 != 0 { (*tm).tm_year += century * 100 - 1900; }
11881        else if (*tm).tm_year <= 68 { (*tm).tm_year += 100; }
11882    }
11883    p as *mut c_char
11884}
11885
11886// ============================================================
11887// Time: tzset / daylight / timezone / tzname
11888// ============================================================
11889
11890#[no_mangle]
11891pub static mut daylight: c_int = 0;
11892#[no_mangle]
11893pub static mut timezone: c_long = 0;
11894#[no_mangle]
11895pub static mut tzname: [*mut c_char; 2] = [b"UTC\0".as_ptr() as *mut c_char, b"UTC\0".as_ptr() as *mut c_char];
11896
11897#[no_mangle]
11898pub unsafe extern "C" fn tzset() {
11899    daylight = 0;
11900    timezone = 0;
11901}
11902
11903// ============================================================
11904// system()
11905// ============================================================
11906
11907#[no_mangle]
11908pub unsafe extern "C" fn system(cmd: *const c_char) -> c_int {
11909    if cmd.is_null() {
11910        // ponytail: test shell availability via fork+exec
11911        let pid = sys_fork();
11912        if pid == 0 {
11913            let sh = b"/bin/sh\0".as_ptr() as *const c_char;
11914            let dash_c = b"-c\0".as_ptr() as *const c_char;
11915            let exit0 = b"exit 0\0".as_ptr() as *const c_char;
11916            let argv = [b"sh\0".as_ptr() as *const c_char, dash_c, exit0, core::ptr::null()];
11917            sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
11918            _exit(127);
11919        }
11920        if pid < 0 { return -1; }
11921        let mut status: c_int = 0;
11922        loop {
11923            let r = sys_wait4(pid as c_int, &mut status, 0, core::ptr::null_mut());
11924            if r >= 0 { return status; }
11925            if r != -4 { return -1; } // not EINTR
11926        }
11927    }
11928
11929    let sa_ignore = sigaction {
11930        sa_handler: SIG_IGN,
11931        sa_flags: SA_RESTORER,
11932        sa_restorer: sig_restorer as *const () as usize,
11933        sa_mask: [0],
11934    };
11935    let mut oldint: sigaction = core::mem::zeroed();
11936    let mut oldquit: sigaction = core::mem::zeroed();
11937
11938    sys_rt_sigaction(SIGINT, &sa_ignore, &mut oldint, 8);
11939    sys_rt_sigaction(SIGQUIT, &sa_ignore, &mut oldquit, 8);
11940
11941    let mut block_set: SigSetT = 0;
11942    block_set |= 1u64 << (SIGCHLD - 1);
11943    let mut oldmask: SigSetT = 0;
11944    sys_rt_sigprocmask(SIG_BLOCK, &block_set, &mut oldmask, 8);
11945
11946    let pid = sys_fork();
11947
11948    if pid == 0 {
11949        sys_rt_sigaction(SIGINT, &oldint, core::ptr::null_mut(), 8);
11950        sys_rt_sigaction(SIGQUIT, &oldquit, core::ptr::null_mut(), 8);
11951        sys_rt_sigprocmask(SIG_SETMASK, &oldmask, core::ptr::null_mut(), 8);
11952
11953        let sh = b"/bin/sh\0".as_ptr() as *const c_char;
11954        let argv = [
11955            b"sh\0".as_ptr() as *const c_char,
11956            b"-c\0".as_ptr() as *const c_char,
11957            cmd,
11958            core::ptr::null(),
11959        ];
11960        sys_execve(sh, argv.as_ptr(), __environ as *const *const c_char);
11961        _exit(127);
11962    }
11963
11964    let mut status: c_int = -1;
11965    if pid > 0 {
11966        loop {
11967            let r = sys_wait4(pid as c_int, &mut status, 0, core::ptr::null_mut());
11968            if r >= 0 { break; }
11969            if r != -4 { break; } // not EINTR
11970        }
11971    }
11972
11973    sys_rt_sigaction(SIGINT, &oldint, core::ptr::null_mut(), 8);
11974    sys_rt_sigaction(SIGQUIT, &oldquit, core::ptr::null_mut(), 8);
11975    sys_rt_sigprocmask(SIG_SETMASK, &oldmask, core::ptr::null_mut(), 8);
11976
11977    status
11978}
11979
11980// ============================================================
11981// errno: strerror / strerror_r / environ alias
11982// ============================================================
11983
11984const EPERM_VAL: c_int = 1;
11985const ENOENT_VAL: c_int = 2;
11986const ESRCH_VAL: c_int = 3;
11987const EINTR_VAL: c_int = 4;
11988const EIO_VAL: c_int = 5;
11989const ENXIO_VAL: c_int = 6;
11990const E2BIG_VAL: c_int = 7;
11991const ENOEXEC_VAL: c_int = 8;
11992const EBADF_VAL: c_int = 9;
11993const ECHILD_VAL: c_int = 10;
11994const EAGAIN_VAL: c_int = 11;
11995const ENOMEM_VAL: c_int = 12;
11996const EACCES_VAL: c_int = 13;
11997const EFAULT_VAL: c_int = 14;
11998const ENOTBLK_VAL: c_int = 15;
11999const EBUSY_VAL: c_int = 16;
12000const EEXIST_VAL: c_int = 17;
12001const EXDEV_VAL: c_int = 18;
12002const ENODEV_VAL: c_int = 19;
12003const ENOTDIR_VAL: c_int = 20;
12004const EISDIR_VAL: c_int = 21;
12005const EINVAL_VAL: c_int = 22;
12006const ENFILE_VAL: c_int = 23;
12007const EMFILE_VAL: c_int = 24;
12008const ENOTTY_VAL: c_int = 25;
12009const ETXTBSY_VAL: c_int = 26;
12010const EFBIG_VAL: c_int = 27;
12011const ENOSPC_VAL: c_int = 28;
12012const ESPIPE_VAL: c_int = 29;
12013const EROFS_VAL: c_int = 30;
12014const EMLINK_VAL: c_int = 31;
12015const EPIPE_VAL: c_int = 32;
12016const EDOM_VAL: c_int = 33;
12017const ERANGE_VAL: c_int = 34;
12018const EDEADLK_VAL: c_int = 35;
12019const ENAMETOOLONG_VAL: c_int = 36;
12020const ENOLCK_VAL: c_int = 37;
12021const ENOSYS_VAL: c_int = 38;
12022const ENOTEMPTY_VAL: c_int = 39;
12023const ELOOP_VAL: c_int = 40;
12024const EWOULDBLOCK_VAL: c_int = 11;
12025const ENOMSG_VAL: c_int = 42;
12026const EIDRM_VAL: c_int = 43;
12027const ECHRNG_VAL: c_int = 44;
12028const EL2NSYNC_VAL: c_int = 45;
12029const EL3HLT_VAL: c_int = 46;
12030const EL3RST_VAL: c_int = 47;
12031const ELNRNG_VAL: c_int = 48;
12032const EUNATCH_VAL: c_int = 49;
12033const ENOCSI_VAL: c_int = 50;
12034const EL2HLT_VAL: c_int = 51;
12035const EBADE_VAL: c_int = 52;
12036const EBADR_VAL: c_int = 53;
12037const EXFULL_VAL: c_int = 54;
12038const ENOANO_VAL: c_int = 55;
12039const EBADRQC_VAL: c_int = 56;
12040const EBADSLT_VAL: c_int = 57;
12041const EBFONT_VAL: c_int = 59;
12042const ENOSTR_VAL: c_int = 60;
12043const ENODATA_VAL: c_int = 61;
12044const ETIME_VAL: c_int = 62;
12045const ENOSR_VAL: c_int = 63;
12046const ENONET_VAL: c_int = 64;
12047const ENOPKG_VAL: c_int = 65;
12048const EREMOTE_VAL: c_int = 66;
12049const ENOLINK_VAL: c_int = 67;
12050const EADV_VAL: c_int = 68;
12051const ESRMNT_VAL: c_int = 69;
12052const ECOMM_VAL: c_int = 70;
12053const EPROTO_VAL: c_int = 71;
12054const EMULTIHOP_VAL: c_int = 72;
12055const EDOTDOT_VAL: c_int = 73;
12056const EBADMSG_VAL: c_int = 74;
12057const EOVERFLOW_VAL: c_int = 75;
12058const ENOTUNIQ_VAL: c_int = 76;
12059const EBADFD_VAL: c_int = 77;
12060const EREMCHG_VAL: c_int = 78;
12061const ELIBACC_VAL: c_int = 79;
12062const ELIBBAD_VAL: c_int = 80;
12063const ELIBSCN_VAL: c_int = 81;
12064const ELIBMAX_VAL: c_int = 82;
12065const ELIBEXEC_VAL: c_int = 83;
12066const EILSEQ_VAL: c_int = 84;
12067const ERESTART_VAL: c_int = 85;
12068const ESTRPIPE_VAL: c_int = 86;
12069const EUSERS_VAL: c_int = 87;
12070const ENOTSOCK_VAL: c_int = 88;
12071const EDESTADDRREQ_VAL: c_int = 89;
12072const EMSGSIZE_VAL: c_int = 90;
12073const EPROTOTYPE_VAL: c_int = 91;
12074const ENOPROTOOPT_VAL: c_int = 92;
12075const EPROTONOSUPPORT_VAL: c_int = 93;
12076const ESOCKTNOSUPPORT_VAL: c_int = 94;
12077const EOPNOTSUPP_VAL: c_int = 95;
12078const ENOTSUP_VAL: c_int = 95;
12079const EPFNOSUPPORT_VAL: c_int = 96;
12080const EAFNOSUPPORT_VAL: c_int = 97;
12081const EADDRINUSE_VAL: c_int = 98;
12082const EADDRNOTAVAIL_VAL: c_int = 99;
12083const ENETDOWN_VAL: c_int = 100;
12084const ENETUNREACH_VAL: c_int = 101;
12085const ENETRESET_VAL: c_int = 102;
12086const ECONNABORTED_VAL: c_int = 103;
12087const ECONNRESET_VAL: c_int = 104;
12088const ENOBUFS_VAL: c_int = 105;
12089const EISCONN_VAL: c_int = 106;
12090const ENOTCONN_VAL: c_int = 107;
12091const ESHUTDOWN_VAL: c_int = 108;
12092const ETOOMANYREFS_VAL: c_int = 109;
12093const ETIMEDOUT_VAL: c_int = 110;
12094const ECONNREFUSED_VAL: c_int = 111;
12095const EHOSTDOWN_VAL: c_int = 112;
12096const EHOSTUNREACH_VAL: c_int = 113;
12097const EALREADY_VAL: c_int = 114;
12098const EINPROGRESS_VAL: c_int = 115;
12099const ESTALE_VAL: c_int = 116;
12100const EUCLEAN_VAL: c_int = 117;
12101const ENOTNAM_VAL: c_int = 118;
12102const ENAVAIL_VAL: c_int = 119;
12103const EISNAM_VAL: c_int = 120;
12104const EREMOTEIO_VAL: c_int = 121;
12105const EDQUOT_VAL: c_int = 122;
12106const ENOMEDIUM_VAL: c_int = 123;
12107const EMEDIUMTYPE_VAL: c_int = 124;
12108const ECANCELED_VAL: c_int = 125;
12109const ENOKEY_VAL: c_int = 126;
12110const EKEYEXPIRED_VAL: c_int = 127;
12111const EKEYREVOKED_VAL: c_int = 128;
12112const EKEYREJECTED_VAL: c_int = 129;
12113const EOWNERDEAD_VAL: c_int = 130;
12114const ENOTRECOVERABLE_VAL: c_int = 131;
12115const ERFKILL_VAL: c_int = 132;
12116const EHWPOISON_VAL: c_int = 133;
12117
12118// ponytail: static error string table indexed by errno
12119static ERR_STRS: [&[u8]; 134] = [
12120    b"Success\0",                     // 0
12121    b"Operation not permitted\0",     // 1
12122    b"No such file or directory\0",   // 2
12123    b"No such process\0",             // 3
12124    b"Interrupted system call\0",     // 4
12125    b"Input/output error\0",          // 5
12126    b"No such device or address\0",   // 6
12127    b"Argument list too long\0",      // 7
12128    b"Exec format error\0",           // 8
12129    b"Bad file descriptor\0",         // 9
12130    b"No child processes\0",          // 10
12131    b"Resource temporarily unavailable\0", // 11
12132    b"Cannot allocate memory\0",      // 12
12133    b"Permission denied\0",           // 13
12134    b"Bad address\0",                 // 14
12135    b"Block device required\0",       // 15
12136    b"Device or resource busy\0",     // 16
12137    b"File exists\0",                 // 17
12138    b"Invalid cross-device link\0",   // 18
12139    b"No such device\0",              // 19
12140    b"Not a directory\0",             // 20
12141    b"Is a directory\0",              // 21
12142    b"Invalid argument\0",            // 22
12143    b"Too many open files in system\0", // 23
12144    b"Too many open files\0",         // 24
12145    b"Inappropriate ioctl for device\0", // 25
12146    b"Text file busy\0",              // 26
12147    b"File too large\0",              // 27
12148    b"No space left on device\0",     // 28
12149    b"Illegal seek\0",                // 29
12150    b"Read-only file system\0",       // 30
12151    b"Too many links\0",              // 31
12152    b"Broken pipe\0",                 // 32
12153    b"Numerical argument out of domain\0", // 33
12154    b"Numerical result out of range\0", // 34
12155    b"Resource deadlock avoided\0",   // 35
12156    b"File name too long\0",          // 36
12157    b"No locks available\0",          // 37
12158    b"Function not implemented\0",    // 38
12159    b"Directory not empty\0",         // 39
12160    b"Too many levels of symbolic links\0", // 40
12161    b"Unknown error 41\0",            // 41
12162    b"No message of desired type\0",  // 42
12163    b"Identifier removed\0",          // 43
12164    b"Channel number out of range\0", // 44
12165    b"Level 2 not synchronized\0",    // 45
12166    b"Level 3 halted\0",              // 46
12167    b"Level 3 reset\0",               // 47
12168    b"Link number out of range\0",    // 48
12169    b"Protocol driver not attached\0", // 49
12170    b"No CSI structure available\0",  // 50
12171    b"Level 2 halted\0",              // 51
12172    b"Invalid exchange\0",            // 52
12173    b"Invalid request descriptor\0",  // 53
12174    b"Exchange full\0",               // 54
12175    b"No anode\0",                    // 55
12176    b"Invalid request code\0",        // 56
12177    b"Invalid slot\0",                // 57
12178    b"Unknown error 58\0",            // 58
12179    b"Bad font file format\0",        // 59
12180    b"Device not a stream\0",         // 60
12181    b"No data available\0",           // 61
12182    b"Timer expired\0",               // 62
12183    b"Out of streams resources\0",    // 63
12184    b"Machine is not on the network\0", // 64
12185    b"Package not installed\0",       // 65
12186    b"Object is remote\0",            // 66
12187    b"Link has been severed\0",       // 67
12188    b"Advertise error\0",             // 68
12189    b"Srmount error\0",               // 69
12190    b"Communication error on send\0", // 70
12191    b"Protocol error\0",              // 71
12192    b"Multihop attempted\0",          // 72
12193    b"RFS specific error\0",          // 73
12194    b"Bad message\0",                 // 74
12195    b"Value too large for defined data type\0", // 75
12196    b"Name not unique on network\0",  // 76
12197    b"File descriptor in bad state\0", // 77
12198    b"Remote address changed\0",      // 78
12199    b"Can not access a needed shared library\0", // 79
12200    b"Accessing a corrupted shared library\0", // 80
12201    b".lib section in a.out corrupted\0", // 81
12202    b"Attempting to link in too many shared libraries\0", // 82
12203    b"Cannot exec a shared library directly\0", // 83
12204    b"Invalid or incomplete multibyte or wide character\0", // 84
12205    b"Interrupted system call should be restarted\0", // 85
12206    b"Streams pipe error\0",          // 86
12207    b"Too many users\0",              // 87
12208    b"Socket operation on non-socket\0", // 88
12209    b"Destination address required\0", // 89
12210    b"Message too long\0",            // 90
12211    b"Protocol wrong type for socket\0", // 91
12212    b"Protocol not available\0",      // 92
12213    b"Protocol not supported\0",      // 93
12214    b"Socket type not supported\0",   // 94
12215    b"Operation not supported\0",     // 95
12216    b"Protocol family not supported\0", // 96
12217    b"Address family not supported by protocol\0", // 97
12218    b"Address already in use\0",      // 98
12219    b"Cannot assign requested address\0", // 99
12220    b"Network is down\0",             // 100
12221    b"Network is unreachable\0",      // 101
12222    b"Network dropped connection on reset\0", // 102
12223    b"Software caused connection abort\0", // 103
12224    b"Connection reset by peer\0",    // 104
12225    b"No buffer space available\0",   // 105
12226    b"Transport endpoint is already connected\0", // 106
12227    b"Transport endpoint is not connected\0", // 107
12228    b"Cannot send after transport endpoint shutdown\0", // 108
12229    b"Too many references: cannot splice\0", // 109
12230    b"Connection timed out\0",        // 110
12231    b"Connection refused\0",          // 111
12232    b"Host is down\0",                // 112
12233    b"No route to host\0",            // 113
12234    b"Operation already in progress\0", // 114
12235    b"Operation now in progress\0",   // 115
12236    b"Stale file handle\0",           // 116
12237    b"Structure needs cleaning\0",    // 117
12238    b"Not a XENIX named type file\0", // 118
12239    b"No XENIX semaphores available\0", // 119
12240    b"Is a named type file\0",        // 120
12241    b"Remote I/O error\0",            // 121
12242    b"Quota exceeded\0",              // 122
12243    b"No medium found\0",             // 123
12244    b"Wrong medium type\0",           // 124
12245    b"Operation canceled\0",          // 125
12246    b"Required key not available\0",  // 126
12247    b"Key has expired\0",             // 127
12248    b"Key has been revoked\0",        // 128
12249    b"Key was rejected by service\0", // 129
12250    b"Owner died\0",                  // 130
12251    b"State not recoverable\0",       // 131
12252    b"Operation not possible due to RF-kill\0", // 132
12253    b"Memory page has hardware error\0", // 133
12254];
12255
12256#[no_mangle]
12257pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
12258    if errnum < 0 || errnum as usize >= ERR_STRS.len() {
12259        // ponytail: static buf for unknown errors
12260        static mut UNKNOWN_BUF: [c_char; 32] = [0; 32];
12261        let prefix = b"Unknown error \0";
12262        let mut i = 0;
12263        while prefix[i] != 0 {
12264            UNKNOWN_BUF[i] = prefix[i] as c_char;
12265            i += 1;
12266        }
12267        let (buf, len) = format_u64(errnum as u64);
12268        for j in 0..len {
12269            UNKNOWN_BUF[i] = buf[20 - len + j] as c_char;
12270            i += 1;
12271        }
12272        UNKNOWN_BUF[i] = 0;
12273        return core::ptr::addr_of_mut!(UNKNOWN_BUF).cast::<c_char>();
12274    }
12275    ERR_STRS[errnum as usize].as_ptr() as *mut c_char
12276}
12277
12278#[no_mangle]
12279pub unsafe extern "C" fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: usize) -> c_int {
12280    let s = strerror(errnum);
12281    let slen = strlen(s as *const c_char);
12282    if slen >= buflen {
12283        if buflen > 0 {
12284            core::ptr::copy_nonoverlapping(s as *const u8, buf as *mut u8, buflen - 1);
12285            *buf.add(buflen - 1) = 0;
12286        }
12287        return 34; // ERANGE
12288    }
12289    core::ptr::copy_nonoverlapping(s as *const u8, buf as *mut u8, slen + 1);
12290    0
12291}
12292
12293// ponytail: `environ` alias for tests that use extern char **environ
12294#[no_mangle]
12295pub static mut environ: *mut *mut c_char = core::ptr::null_mut();
12296
12297// keep environ in sync with __environ
12298unsafe fn sync_environ() {
12299    environ = __environ;
12300}
12301
12302// ============================================================
12303// unistd extensions: pipe, dup, dup2, fcntl, access, unlink, etc.
12304// ============================================================
12305
12306#[inline]
12307unsafe fn sys_dup(oldfd: i32) -> i64 {
12308    <Arch as Syscalls>::syscall1(SYS_DUP, oldfd as i64)
12309}
12310
12311#[inline]unsafe fn sys_dup2(oldfd: i32, newfd: i32) -> i64 {
12312    // ponytail: dup3 with flags=0 is equivalent to dup2
12313    sys_dup3(oldfd, newfd, 0)
12314}
12315
12316#[inline]
12317unsafe fn sys_access(path: *const u8, mode: i32) -> i64 {
12318    <Arch as Syscalls>::syscall4(SYS_FACCESSAT, AT_FDCWD as i64, path as i64, mode as i64, 0)
12319}
12320
12321#[inline]unsafe fn sys_unlink(path: *const u8) -> i64 {
12322    sys_unlinkat(AT_FDCWD, path, 0)
12323}
12324
12325#[inline]unsafe fn sys_rmdir(path: *const u8) -> i64 {
12326    sys_unlinkat(AT_FDCWD, path, 512) // AT_REMOVEDIR
12327}
12328
12329#[inline]
12330unsafe fn sys_chdir(path: *const u8) -> i64 {
12331    <Arch as Syscalls>::syscall1(SYS_CHDIR, path as i64)
12332}
12333
12334#[inline]
12335unsafe fn sys_getcwd(buf: *mut u8, size: usize) -> i64 {
12336    <Arch as Syscalls>::syscall2(SYS_GETCWD, buf as i64, size as i64)
12337}
12338
12339#[inline]
12340unsafe fn sys_sethostname(name: *const u8, len: usize) -> i64 {
12341    <Arch as Syscalls>::syscall2(SYS_SETHOSTNAME, name as i64, len as i64)
12342}
12343
12344#[inline]
12345unsafe fn sys_gethostname(buf: *mut u8, len: usize) -> i64 {
12346    #[repr(C)]
12347    struct UtsName {
12348        sysname: [u8; 65],
12349        nodename: [u8; 65],
12350        release: [u8; 65],
12351        version: [u8; 65],
12352        machine: [u8; 65],
12353        domainname: [u8; 65],
12354    }
12355    let mut uts: UtsName = core::mem::zeroed();
12356    let result = <Arch as Syscalls>::syscall1(SYS_UNAME, &mut uts as *mut UtsName as i64);
12357    if result < 0 {
12358        return result;
12359    }
12360    let nlen = strlen(uts.nodename.as_ptr() as *const c_char);
12361    let copylen = if nlen < len { nlen } else { if len > 0 { len - 1 } else { 0 } };
12362    core::ptr::copy_nonoverlapping(uts.nodename.as_ptr(), buf, copylen);
12363    if len > 0 { *buf.add(copylen) = 0; }
12364    0
12365}
12366
12367unsafe fn sys_truncate(path: *const u8, length: i64) -> i64 {
12368    <Arch as Syscalls>::syscall2(SYS_TRUNCATE, path as i64, length as i64)
12369}
12370
12371unsafe fn sys_ftruncate(fd: i32, length: i64) -> i64 {
12372    <Arch as Syscalls>::syscall2(SYS_FTRUNCATE, fd as i64, length as i64)
12373}
12374
12375unsafe fn sys_nanosleep(req: *const timespec, rem: *mut timespec) -> i64 {
12376    <Arch as Syscalls>::syscall2(SYS_NANOSLEEP, req as i64, rem as i64)
12377}
12378
12379const ITIMER_REAL: i32 = 0;
12380
12381#[repr(C)]
12382struct itimerval {
12383    it_interval: timeval,
12384    it_value: timeval,
12385}
12386
12387unsafe fn sys_alarm(seconds: c_uint) -> i64 {
12388    let mut new: itimerval = core::mem::zeroed();
12389    new.it_value.tv_sec = seconds as c_long;
12390    let mut old: itimerval = core::mem::zeroed();
12391    let r = <Arch as Syscalls>::syscall3(
12392        SYS_SETITIMER,
12393        ITIMER_REAL as i64,
12394        &new as *const _ as i64,
12395        &mut old as *mut _ as i64,
12396    );
12397    if r < 0 {
12398        return r;
12399    }
12400    old.it_value.tv_sec as i64
12401}
12402
12403unsafe fn sys_pause() -> i64 {
12404    #[cfg(target_arch = "x86_64")]
12405    { <Arch as Syscalls>::syscall0(SYS_PAUSE) }
12406    #[cfg(target_arch = "aarch64")]
12407    { <Arch as Syscalls>::syscall4(SYS_PPOLL, 0, 0, 0, 0) }
12408    #[cfg(target_arch = "riscv64")]
12409    { <Arch as Syscalls>::syscall4(SYS_PPOLL, 0, 0, 0, 0) }
12410}
12411
12412unsafe fn sys_fsync(fd: i32) -> i64 {
12413    <Arch as Syscalls>::syscall1(SYS_FSYNC, fd as i64)
12414}
12415
12416unsafe fn sys_fdatasync(fd: i32) -> i64 {
12417    <Arch as Syscalls>::syscall1(SYS_FDATASYNC, fd as i64)
12418}
12419
12420unsafe fn sys_sync() {
12421    let _ = <Arch as Syscalls>::syscall0(SYS_SYNC);
12422}
12423
12424unsafe fn sys_symlink(target: *const u8, linkpath: *const u8) -> i64 {
12425    <Arch as Syscalls>::syscall3(SYS_SYMLINKAT, target as i64, AT_FDCWD as i64, linkpath as i64)
12426}
12427
12428unsafe fn sys_symlinkat(target: *const u8, newdirfd: i32, linkpath: *const u8) -> i64 {
12429    <Arch as Syscalls>::syscall3(SYS_SYMLINKAT, target as i64, newdirfd as i64, linkpath as i64)
12430}
12431
12432unsafe fn sys_readlinkat(dirfd: i32, path: *const u8, buf: *mut u8, bufsiz: usize) -> i64 {
12433    <Arch as Syscalls>::syscall4(SYS_READLINKAT, dirfd as i64, path as i64, buf as i64, bufsiz as i64)
12434}
12435
12436unsafe fn sys_linkat(olddirfd: i32, oldpath: *const u8, newdirfd: i32, newpath: *const u8, flags: i32) -> i64 {
12437    <Arch as Syscalls>::syscall5(SYS_LINKAT, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64, flags as i64)
12438}
12439
12440unsafe fn sys_fchmod(fd: i32, mode: u32) -> i64 {
12441    <Arch as Syscalls>::syscall2(SYS_FCHMOD, fd as i64, mode as i64)
12442}
12443
12444unsafe fn sys_fchmodat(dirfd: i32, path: *const u8, mode: u32, flags: i32) -> i64 {
12445    <Arch as Syscalls>::syscall4(SYS_FCHMODAT, dirfd as i64, path as i64, mode as i64, flags as i64)
12446}
12447
12448unsafe fn sys_umask(mask: u32) -> u32 {
12449    <Arch as Syscalls>::syscall1(SYS_UMASK, mask as i64) as u32
12450}
12451
12452unsafe fn sys_getgroups(size: i32, list: *mut c_uint) -> i64 {
12453    <Arch as Syscalls>::syscall2(SYS_GETGROUPS, size as i64, list as i64)
12454}
12455
12456unsafe fn sys_setuid(uid: c_uint) -> i64 {
12457    <Arch as Syscalls>::syscall1(SYS_SETUID, uid as i64)
12458}
12459
12460unsafe fn sys_setgid(gid: c_uint) -> i64 {
12461    <Arch as Syscalls>::syscall1(SYS_SETGID, gid as i64)
12462}
12463
12464unsafe fn sys_setsid() -> i64 {
12465    <Arch as Syscalls>::syscall0(SYS_SETSID)
12466}
12467
12468unsafe fn sys_setpgid(pid: c_int, pgid: c_int) -> i64 {
12469    <Arch as Syscalls>::syscall2(SYS_SETPGID, pid as i64, pgid as i64)
12470}
12471
12472unsafe fn sys_getpgid(pid: c_int) -> i64 {
12473    <Arch as Syscalls>::syscall1(SYS_GETPGID, pid as i64)
12474}
12475
12476unsafe fn sys_getsid(pid: c_int) -> i64 {
12477    <Arch as Syscalls>::syscall1(SYS_GETSID, pid as i64)
12478}
12479
12480unsafe fn sys_mkdirat(dirfd: i32, path: *const u8, mode: u32) -> i64 {
12481    <Arch as Syscalls>::syscall3(SYS_MKDIRAT, dirfd as i64, path as i64, mode as i64)
12482}
12483
12484// Public C ABI wrappers for unistd
12485
12486#[no_mangle]
12487pub unsafe extern "C" fn pipe(fds: *mut c_int) -> c_int {
12488    let r = sys_pipe2(fds, 0);
12489    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12490    0
12491}
12492
12493#[no_mangle]
12494pub unsafe extern "C" fn pipe2(fds: *mut c_int, flags: c_int) -> c_int {
12495    let r = sys_pipe2(fds, flags);
12496    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12497    0
12498}
12499
12500#[no_mangle]
12501pub unsafe extern "C" fn dup(oldfd: c_int) -> c_int {
12502    let r = sys_dup(oldfd);
12503    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12504    r as c_int
12505}
12506
12507#[no_mangle]
12508pub unsafe extern "C" fn dup2(oldfd: c_int, newfd: c_int) -> c_int {
12509    let r = sys_dup2(oldfd, newfd);
12510    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12511    r as c_int
12512}
12513
12514#[no_mangle]
12515pub unsafe extern "C" fn dup3(oldfd: c_int, newfd: c_int, flags: c_int) -> c_int {
12516    let r = sys_dup3(oldfd, newfd, flags);
12517    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12518    r as c_int
12519}
12520
12521#[no_mangle]
12522pub unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, mut args: ...) -> c_int {
12523    let r = match cmd {
12524        F_GETFD | F_GETFL => sys_fcntl(fd, cmd, 0),
12525        F_SETFD | F_SETFL | F_DUPFD | F_DUPFD_CLOEXEC => {
12526            let arg = args.next_arg::<c_int>();
12527            sys_fcntl(fd, cmd, arg as i64)
12528        }
12529        F_GETLK | F_SETLK | F_SETLKW => {
12530            let arg = args.next_arg::<*mut c_void>();
12531            sys_fcntl(fd, cmd, arg as i64)
12532        }
12533        _ => sys_fcntl(fd, cmd, 0),
12534    };
12535    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12536    r as c_int
12537}
12538
12539#[no_mangle]
12540pub unsafe extern "C" fn access(path: *const c_char, mode: c_int) -> c_int {
12541    let r = sys_access(path as *const u8, mode);
12542    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12543    0
12544}
12545
12546#[no_mangle]
12547pub unsafe extern "C" fn unlink(path: *const c_char) -> c_int {
12548    let r = sys_unlink(path as *const u8);
12549    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12550    0
12551}
12552
12553#[no_mangle]
12554pub unsafe extern "C" fn rmdir(path: *const c_char) -> c_int {
12555    let r = sys_rmdir(path as *const u8);
12556    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12557    0
12558}
12559
12560#[no_mangle]
12561pub unsafe extern "C" fn chdir(path: *const c_char) -> c_int {
12562    let r = sys_chdir(path as *const u8);
12563    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12564    0
12565}
12566
12567#[no_mangle]
12568pub unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char {
12569    if buf.is_null() {
12570        // allocate
12571        let alloc_size = if size == 0 { 256 } else { size };
12572        let p = malloc(alloc_size) as *mut c_char;
12573        if p.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
12574        let r = sys_getcwd(p as *mut u8, alloc_size);
12575        if r < 0 { free(p as *mut c_void); ERRNO = (-r) as c_int; return core::ptr::null_mut(); }
12576        return p;
12577    }
12578    if size == 0 { ERRNO = EINVAL; return core::ptr::null_mut(); }
12579    let r = sys_getcwd(buf as *mut u8, size);
12580    if r < 0 { ERRNO = (-r) as c_int; return core::ptr::null_mut(); }
12581    buf
12582}
12583
12584#[no_mangle]
12585pub unsafe extern "C" fn gethostname(name: *mut c_char, len: usize) -> c_int {
12586    let r = sys_gethostname(name as *mut u8, len);
12587    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12588    0
12589}
12590
12591// ponytail: getpagesize - hardcoded 4096 for x86_64
12592#[no_mangle]
12593pub extern "C" fn getpagesize() -> c_int {
12594    4096
12595}
12596
12597#[no_mangle]
12598pub unsafe extern "C" fn truncate(path: *const c_char, length: i64) -> c_int {
12599    let r = sys_truncate(path as *const u8, length);
12600    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12601    0
12602}
12603
12604#[no_mangle]
12605pub unsafe extern "C" fn ftruncate(fd: c_int, length: i64) -> c_int {
12606    let r = sys_ftruncate(fd, length);
12607    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12608    0
12609}
12610
12611#[no_mangle]
12612pub unsafe extern "C" fn nanosleep(req: *const timespec, rem: *mut timespec) -> c_int {
12613    pthread_testcancel();
12614    let r = sys_nanosleep(req, rem);
12615    pthread_testcancel();
12616    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12617    0
12618}
12619
12620#[no_mangle]
12621pub unsafe extern "C" fn sleep(seconds: c_uint) -> c_uint {
12622    let req = timespec { tv_sec: seconds as c_long, tv_nsec: 0 };
12623    let mut rem: timespec = core::mem::zeroed();
12624    pthread_testcancel();
12625    let r = sys_nanosleep(&req, &mut rem);
12626    pthread_testcancel();
12627    if r < 0 {
12628        let e = (-r) as c_int;
12629        if e == EINTR { return rem.tv_sec as c_uint; }
12630    }
12631    0
12632}
12633
12634#[no_mangle]
12635pub unsafe extern "C" fn usleep(usec: c_uint) -> c_int {
12636    let req = timespec { tv_sec: (usec / 1000000) as c_long, tv_nsec: ((usec % 1000000) * 1000) as c_long };
12637    pthread_testcancel();
12638    let r = sys_nanosleep(&req, core::ptr::null_mut());
12639    pthread_testcancel();
12640    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12641    0
12642}
12643
12644#[no_mangle]
12645pub unsafe extern "C" fn alarm(seconds: c_uint) -> c_uint {
12646    sys_alarm(seconds) as c_uint
12647}
12648
12649#[no_mangle]
12650pub unsafe extern "C" fn pause() -> c_int {
12651    pthread_testcancel();
12652    sys_pause();
12653    pthread_testcancel();
12654    ERRNO = EINTR;
12655    -1
12656}
12657
12658#[no_mangle]
12659pub unsafe extern "C" fn fsync(fd: c_int) -> c_int {
12660    let r = sys_fsync(fd);
12661    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12662    0
12663}
12664
12665#[no_mangle]
12666pub unsafe extern "C" fn fdatasync(fd: c_int) -> c_int {
12667    let r = sys_fdatasync(fd);
12668    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12669    0
12670}
12671
12672#[no_mangle]
12673pub unsafe extern "C" fn sync() {
12674    sys_sync();
12675}
12676
12677#[no_mangle]
12678pub unsafe extern "C" fn symlink(target: *const c_char, linkpath: *const c_char) -> c_int {
12679    let r = sys_symlinkat(target as *const u8, AT_FDCWD, linkpath as *const u8);
12680    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12681    0
12682}
12683
12684#[no_mangle]
12685pub unsafe extern "C" fn readlink(path: *const c_char, buf: *mut c_char, bufsiz: usize) -> isize {
12686    let r = sys_readlinkat(AT_FDCWD, path as *const u8, buf as *mut u8, bufsiz);
12687    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12688    r as isize
12689}
12690
12691#[no_mangle]
12692pub unsafe extern "C" fn link(oldpath: *const c_char, newpath: *const c_char) -> c_int {
12693    let r = sys_linkat(AT_FDCWD, oldpath as *const u8, AT_FDCWD, newpath as *const u8, 0);
12694    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12695    0
12696}
12697
12698#[no_mangle]
12699pub unsafe extern "C" fn chmod(path: *const c_char, mode: c_uint) -> c_int {
12700    let r = sys_fchmodat(AT_FDCWD, path as *const u8, mode, 0);
12701    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12702    0
12703}
12704
12705#[no_mangle]
12706pub unsafe extern "C" fn fchmod(fd: c_int, mode: c_uint) -> c_int {
12707    let r = sys_fchmod(fd, mode);
12708    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12709    0
12710}
12711
12712#[no_mangle]
12713pub unsafe extern "C" fn umask(mask: c_uint) -> c_uint {
12714    sys_umask(mask) as c_uint
12715}
12716
12717#[no_mangle]
12718pub unsafe extern "C" fn isatty(fd: c_int) -> c_int {
12719    let mut ws: winsize = core::mem::zeroed();
12720    if sys_ioctl(fd, TIOCGWINSZ, &mut ws as *mut winsize as *mut u8) == 0 { 1 } else { 0 }
12721}
12722
12723#[no_mangle]
12724pub unsafe extern "C" fn getlogin() -> *mut c_char {
12725    static mut LOGIN_BUF: [c_char; 32] = [0; 32];
12726    let pw = getpwuid(crate::getuid());
12727    if pw.is_null() { return core::ptr::null_mut(); }
12728    let n = crate::strlen((*pw).pw_name);
12729    if n + 1 > LOGIN_BUF.len() { return core::ptr::null_mut(); }
12730    core::ptr::copy_nonoverlapping((*pw).pw_name, LOGIN_BUF.as_mut_ptr(), n + 1);
12731    LOGIN_BUF.as_mut_ptr()
12732}
12733
12734#[no_mangle]
12735pub unsafe extern "C" fn getgroups(size: c_int, list: *mut c_uint) -> c_int {
12736    let r = sys_getgroups(size, list);
12737    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12738    r as c_int
12739}
12740
12741#[no_mangle]
12742pub unsafe extern "C" fn setuid(uid: c_uint) -> c_int {
12743    let r = sys_setuid(uid);
12744    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12745    0
12746}
12747
12748#[no_mangle]
12749pub unsafe extern "C" fn setgid(gid: c_uint) -> c_int {
12750    let r = sys_setgid(gid);
12751    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12752    0
12753}
12754
12755#[no_mangle]
12756pub unsafe extern "C" fn seteuid(euid: c_uint) -> c_int {
12757    // ponytail: on Linux, setreuid(-1, euid) sets effective uid
12758    let r = sys_setuid(euid);
12759    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12760    0
12761}
12762
12763#[no_mangle]
12764pub unsafe extern "C" fn setegid(egid: c_uint) -> c_int {
12765    let r = sys_setgid(egid);
12766    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12767    0
12768}
12769
12770#[no_mangle]
12771pub unsafe extern "C" fn setreuid(ruid: c_uint, euid: c_uint) -> c_int {
12772    let r = <Arch as Syscalls>::syscall2(sysno(113, 145), ruid as i64, euid as i64);
12773    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
12774}
12775
12776
12777
12778#[no_mangle]
12779pub unsafe extern "C" fn setsid() -> c_int {
12780    let r = sys_setsid();
12781    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12782    r as c_int
12783}
12784
12785#[no_mangle]
12786pub unsafe extern "C" fn setpgid(pid: c_int, pgid: c_int) -> c_int {
12787    let r = sys_setpgid(pid, pgid);
12788    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12789    0
12790}
12791
12792#[no_mangle]
12793pub unsafe extern "C" fn getpgid(pid: c_int) -> c_int {
12794    let r = sys_getpgid(pid);
12795    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12796    r as c_int
12797}
12798
12799#[no_mangle]
12800pub unsafe extern "C" fn getsid(pid: c_int) -> c_int {
12801    let r = sys_getsid(pid);
12802    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12803    r as c_int
12804}
12805
12806#[no_mangle]
12807pub unsafe extern "C" fn getpgrp() -> c_int {
12808    sys_getpgid(0) as c_int
12809}
12810
12811#[no_mangle]
12812pub unsafe extern "C" fn setpgrp() -> c_int {
12813    setpgid(0, 0)
12814}
12815
12816#[no_mangle]
12817pub unsafe extern "C" fn mkstemp(template: *mut c_char) -> c_int {
12818    if template.is_null() { ERRNO = EINVAL; return -1; }
12819    let len = strlen(template as *const c_char);
12820    if len < 6 { ERRNO = EINVAL; return -1; }
12821    let x_start = len - 6;
12822    // check that last 6 chars are XXXXXX
12823    for i in x_start..len {
12824        if *template.add(i) != b'X' as c_char { ERRNO = EINVAL; return -1; }
12825    }
12826    let mut ts: timespec = core::mem::zeroed();
12827    let _ = sys_clock_gettime(CLOCK_REALTIME, &mut ts);
12828    let mut ctr: u32 = ts.tv_nsec as u32;
12829    for _ in 0..100 {
12830        ctr = ctr.wrapping_mul(1103515245).wrapping_add(12345);
12831        let seed = ctr;
12832        // fill XXXXXX with random hex chars
12833        let hex = b"0123456789abcdef";
12834        let mut s = seed;
12835        for i in x_start..len {
12836            *template.add(i) = hex[(s & 0xf) as usize] as c_char;
12837            s >>= 4;
12838        }
12839        let fd = sys_open(template as *const u8, (O_RDWR | O_CREAT | O_EXCL) as i64, 0o600);
12840        if fd >= 0 { return fd as c_int; }
12841        let e = (-fd) as c_int;
12842        if e != EEXIST_VAL { ERRNO = e; return -1; }
12843    }
12844    ERRNO = EEXIST_VAL;
12845    -1
12846}
12847
12848#[no_mangle]
12849pub unsafe extern "C" fn mkdir(path: *const c_char, mode: c_uint) -> c_int {
12850    let r = sys_mkdirat(AT_FDCWD, path as *const u8, mode);
12851    if r < 0 { ERRNO = (-r) as c_int; return -1; }
12852    0
12853}
12854
12855// ============================================================
12856// libgen: basename / dirname
12857// ============================================================
12858
12859#[no_mangle]
12860pub unsafe extern "C" fn dirname(s: *mut c_char) -> *mut c_char {
12861    if s.is_null() || *s == 0 {
12862        return b".\0".as_ptr() as *mut c_char;
12863    }
12864    let mut i = strlen(s as *const c_char);
12865    i = i.wrapping_sub(1);
12866    // skip trailing slashes
12867    while i > 0 && *s.add(i) == b'/' as c_char {
12868        i = i.wrapping_sub(1);
12869    }
12870    if i == 0 && *s.add(0) == b'/' as c_char {
12871        return b"/\0".as_ptr() as *mut c_char;
12872    }
12873    // skip non-slashes
12874    while i > 0 && *s.add(i) != b'/' as c_char {
12875        i = i.wrapping_sub(1);
12876    }
12877    if i == 0 {
12878        if *s.add(0) == b'/' as c_char {
12879            return b"/\0".as_ptr() as *mut c_char;
12880        }
12881        return b".\0".as_ptr() as *mut c_char;
12882    }
12883    // skip slashes
12884    while i > 0 && *s.add(i - 1) == b'/' as c_char {
12885        i = i.wrapping_sub(1);
12886    }
12887    if i == 0 {
12888        return b"/\0".as_ptr() as *mut c_char;
12889    }
12890    *s.add(i) = 0;
12891    s
12892}
12893
12894#[no_mangle]
12895pub unsafe extern "C" fn basename(s: *mut c_char) -> *mut c_char {
12896    if s.is_null() || *s == 0 {
12897        return b".\0".as_ptr() as *mut c_char;
12898    }
12899    let mut i = strlen(s as *const c_char);
12900    i = i.wrapping_sub(1);
12901    // strip trailing slashes
12902    while i > 0 && *s.add(i) == b'/' as c_char {
12903        *s.add(i) = 0;
12904        i = i.wrapping_sub(1);
12905    }
12906    // find last slash
12907    while i > 0 && *s.add(i - 1) != b'/' as c_char {
12908        i = i.wrapping_sub(1);
12909    }
12910    s.add(i)
12911}
12912
12913// ============================================================
12914// arpa/inet: inet_pton / inet_ntop / inet_addr / inet_ntoa / inet_aton
12915// ============================================================
12916
12917const AF_INET_VAL: c_int = 2;
12918const AF_INET6_VAL: c_int = 10;
12919const EAFNOSUPPORT: c_int = 97;
12920const ENOSPC_VAL2: c_int = 28;
12921
12922unsafe fn inet_pton_v4(s: *const u8, a: *mut u8) -> c_int {
12923    let mut p = s;
12924    let mut i = 0;
12925    while i < 4 {
12926        let oct_start = p;
12927        let mut v: u32 = 0;
12928        let mut j: u32 = 0;
12929        while j < 3 && *p >= b'0' && *p <= b'9' {
12930            v = v * 10 + (*p - b'0') as u32;
12931            p = p.add(1);
12932            j += 1;
12933        }
12934        if j == 0 || (j > 1 && *oct_start == b'0') || v > 255 { return 0; }
12935        *a.add(i) = v as u8;
12936        if *p == 0 && i == 3 { return 1; }
12937        if *p != b'.' { return 0; }
12938        p = p.add(1);
12939        i += 1;
12940    }
12941    0
12942}
12943
12944unsafe fn inet_pton_v6(s: *const u8, a: *mut u8) -> c_int {
12945    let mut ip = [0u16; 8];
12946    let mut p = s;
12947    let mut i: usize = 0;
12948    let mut brk: isize = -1;
12949    let mut need_v4 = false;
12950    let mut v4_start: *const u8 = core::ptr::null();
12951
12952    if *p == b':' {
12953        p = p.add(1);
12954        if *p != b':' { return 0; }
12955    }
12956
12957    loop {
12958        if *p == b':' && brk < 0 {
12959            brk = i as isize;
12960            ip[i & 7] = 0;
12961            p = p.add(1);
12962            if *p == 0 { break; }
12963            if i == 7 { return 0; }
12964            i += 1;
12965            continue;
12966        }
12967        v4_start = p;
12968        let mut v: u16 = 0;
12969        let mut j = 0;
12970        while j < 4 {
12971            let d = hex_digit(*p);
12972            if d < 0 { break; }
12973            v = v * 16 + d as u16;
12974            p = p.add(1);
12975            j += 1;
12976        }
12977        if j == 0 { return 0; }
12978        ip[i & 7] = v;
12979        if *p == 0 && (brk >= 0 || i == 7) { break; }
12980        if i == 7 { return 0; }
12981        if *p != b':' {
12982            if *p != b'.' || (i < 6 && brk < 0) { return 0; }
12983            need_v4 = true;
12984            i += 1;
12985            ip[i & 7] = 0;
12986            break;
12987        }
12988        p = p.add(1);
12989        i += 1;
12990    }
12991
12992    if brk >= 0 {
12993        // expand :: : move trailing fields to the end and zero the gap
12994        let trail_count = i + 1 - brk as usize;
12995        let dest_start = brk as usize + 7 - i;
12996        // move backwards to avoid overwrite in the overlapping case
12997        for j in (0..trail_count).rev() {
12998            ip[dest_start + j] = ip[brk as usize + j];
12999        }
13000        for j in 0..(7 - i) {
13001            ip[brk as usize + j] = 0;
13002        }
13003    }
13004
13005    for k in 0..8 {
13006        *a.add(k * 2) = (ip[k] >> 8) as u8;
13007        *a.add(k * 2 + 1) = (ip[k] & 0xff) as u8;
13008    }
13009
13010    if need_v4 {
13011        if inet_pton_v4(v4_start, a.add(12)) <= 0 { return 0; }
13012    }
13013    1
13014}
13015
13016unsafe fn hex_digit(c: u8) -> i32 {
13017    if c >= b'0' && c <= b'9' { (c - b'0') as i32 }
13018    else if c >= b'a' && c <= b'f' { (c - b'a' + 10) as i32 }
13019    else if c >= b'A' && c <= b'F' { (c - b'A' + 10) as i32 }
13020    else { -1 }
13021}
13022
13023#[no_mangle]
13024pub unsafe extern "C" fn inet_pton(af: c_int, s: *const c_char, a: *mut c_void) -> c_int {
13025    if af == AF_INET_VAL {
13026        inet_pton_v4(s as *const u8, a as *mut u8)
13027    } else if af == AF_INET6_VAL {
13028        inet_pton_v6(s as *const u8, a as *mut u8)
13029    } else {
13030        ERRNO = EAFNOSUPPORT;
13031        -1
13032    }
13033}
13034
13035#[no_mangle]
13036pub unsafe extern "C" fn inet_ntop(af: c_int, a: *const c_void, s: *mut c_char, size: u32) -> *mut c_char {
13037    if af == AF_INET_VAL {
13038        let b = a as *const u8;
13039        let needed = 16; // "255.255.255.255\0"
13040        if size < needed as u32 { ERRNO = ENOSPC_VAL2; return core::ptr::null_mut(); }
13041        let mut pos = 0;
13042        for i in 0..4 {
13043            if i > 0 { *s.add(pos) = b'.' as c_char; pos += 1; }
13044            let (buf, len) = format_u64(*b.add(i) as u64);
13045            for j in 0..len { *s.add(pos) = buf[j] as c_char; pos += 1; }
13046        }
13047        *s.add(pos) = 0;
13048        s
13049    } else if af == AF_INET6_VAL {
13050        let b = a as *const u8;
13051        let needed = 46; // max IPv6
13052        if size < needed as u32 { ERRNO = ENOSPC_VAL2; return core::ptr::null_mut(); }
13053        let mut words = [0u16; 8];
13054        for i in 0..8 {
13055            words[i] = ((*b.add(i * 2) as u16) << 8) | (*b.add(i * 2 + 1) as u16);
13056        }
13057        // IPv4-mapped: ::ffff:a.b.c.d
13058        let mut pos = 0usize;
13059        if words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0
13060            && words[4] == 0 && words[5] == 0xffff
13061        {
13062            let prefix = b"::ffff:";
13063            for k in 0..prefix.len() { *s.add(pos) = prefix[k] as c_char; pos += 1; }
13064            for idx in 0..4 {
13065                if idx > 0 { *s.add(pos) = b'.' as c_char; pos += 1; }
13066                let octet = *b.add(12 + idx);
13067                if octet >= 100 {
13068                    *s.add(pos) = (b'0' + octet / 100) as c_char; pos += 1;
13069                    *s.add(pos) = (b'0' + (octet / 10) % 10) as c_char; pos += 1;
13070                } else if octet >= 10 {
13071                    *s.add(pos) = (b'0' + octet / 10) as c_char; pos += 1;
13072                }
13073                *s.add(pos) = (b'0' + octet % 10) as c_char; pos += 1;
13074            }
13075            *s.add(pos) = 0;
13076            return s;
13077        }
13078        // find longest run of zeros
13079        let mut best_start: isize = -1;
13080        let mut best_len: usize = 0;
13081        let mut j: usize = 0;
13082        while j < 8 {
13083            if words[j] == 0 {
13084                let mut k = j;
13085                while k < 8 && words[k] == 0 { k += 1; }
13086                let run = k - j;
13087                if run > best_len { best_start = j as isize; best_len = run; }
13088                j = k;
13089            } else {
13090                j += 1;
13091            }
13092        }
13093        let mut i: usize = 0;
13094        let mut prev_in_run = false;
13095        while i < 8 {
13096            let in_run = best_len >= 2 && i >= best_start as usize && i < best_start as usize + best_len;
13097            if in_run {
13098                if i == best_start as usize {
13099                    *s.add(pos) = b':' as c_char; pos += 1;
13100                    *s.add(pos) = b':' as c_char; pos += 1;
13101                }
13102                i += 1;
13103                prev_in_run = true;
13104                continue;
13105            }
13106            if i > 0 && !prev_in_run {
13107                *s.add(pos) = b':' as c_char; pos += 1;
13108            }
13109            let (buf, len) = format_hex(words[i] as u64, false);
13110            for k in 0..len { *s.add(pos) = buf[k] as c_char; pos += 1; }
13111            i += 1;
13112            prev_in_run = false;
13113        }
13114        *s.add(pos) = 0;
13115        s
13116    } else {
13117        ERRNO = EAFNOSUPPORT;
13118        core::ptr::null_mut()
13119    }
13120}
13121
13122#[no_mangle]
13123pub unsafe extern "C" fn inet_aton(s: *const c_char, dest: *mut c_void) -> c_int {
13124    let a = dest as *mut u8;
13125    let mut p = s as *const u8;
13126    let mut vals = [0u64; 4];
13127    let mut i = 0usize;
13128    while i < 4 {
13129        if *p < b'0' || *p > b'9' { return 0; }
13130        let mut base = 10u32;
13131        if *p == b'0' {
13132            let c = *p.add(1);
13133            if c == b'x' || c == b'X' {
13134                base = 16;
13135                p = p.add(2);
13136                if !((*p >= b'0' && *p <= b'9')
13137                    || (*p >= b'a' && *p <= b'f')
13138                    || (*p >= b'A' && *p <= b'F')) {
13139                    return 0;
13140                }
13141            } else {
13142                base = 8;
13143            }
13144        }
13145        let mut v: u64 = 0;
13146        let start = p;
13147        loop {
13148            let c = *p;
13149            let d = if c >= b'0' && c <= b'9' {
13150                (c - b'0') as u64
13151            } else if base == 16 && c >= b'a' && c <= b'f' {
13152                (c - b'a' + 10) as u64
13153            } else if base == 16 && c >= b'A' && c <= b'F' {
13154                (c - b'A' + 10) as u64
13155            } else {
13156                break;
13157            };
13158            v = v * (base as u64) + d;
13159            p = p.add(1);
13160        }
13161        if p == start { return 0; }
13162        vals[i] = v;
13163        if *p == 0 {
13164            break;
13165        }
13166        if *p != b'.' || i == 3 { return 0; }
13167        p = p.add(1);
13168        i += 1;
13169    }
13170    if i == 4 { return 0; }
13171    if i < 1 { vals[1] = vals[0] & 0xffffff; vals[0] >>= 24; }
13172    if i < 2 { vals[2] = vals[1] & 0xffff; vals[1] >>= 16; }
13173    if i < 3 { vals[3] = vals[2] & 0xff; vals[2] >>= 8; }
13174    for j in 0..4 {
13175        if vals[j] > 255 { return 0; }
13176        *a.add(j) = vals[j] as u8;
13177    }
13178    1
13179}
13180
13181#[no_mangle]
13182pub unsafe extern "C" fn inet_addr(s: *const c_char) -> u32 {
13183    let mut a = [0u8; 4];
13184    if inet_aton(s, a.as_mut_ptr() as *mut c_void) == 1 {
13185        u32::from_ne_bytes(a)
13186    } else {
13187        !0u32 // INADDR_NONE
13188    }
13189}
13190
13191#[no_mangle]
13192pub unsafe extern "C" fn inet_ntoa(addr: u32) -> *mut c_char {
13193    static mut NTOA_BUF: [c_char; 16] = [0; 16];
13194    let b = addr.to_ne_bytes();
13195    let mut pos = 0;
13196    for i in 0..4 {
13197        if i > 0 { NTOA_BUF[pos] = b'.' as c_char; pos += 1; }
13198        let (buf, len) = format_u64(b[i] as u64);
13199        for j in 0..len { NTOA_BUF[pos] = buf[j] as c_char; pos += 1; }
13200    }
13201    NTOA_BUF[pos] = 0;
13202    core::ptr::addr_of_mut!(NTOA_BUF).cast::<c_char>()
13203}
13204
13205// ponytail: inet_network/inet_makeaddr/inet_lnaof/inet_netof - simple implementations
13206#[no_mangle]
13207pub unsafe extern "C" fn inet_network(s: *const c_char) -> u32 {
13208    inet_addr(s).to_be()
13209}
13210
13211#[no_mangle]
13212pub extern "C" fn inet_makeaddr(net: c_int, host: c_int) -> u32 {
13213    let addr: u32;
13214    if (net as u32) < 128 {
13215        addr = (net as u32) << 24;
13216    } else if (net as u32) < 0x10000 {
13217        addr = (net as u32) << 16;
13218    } else if (net as u32) < 0x1000000 {
13219        addr = (net as u32) << 8;
13220    } else {
13221        addr = net as u32;
13222    }
13223    addr | (host as u32 & 0xffffffff)
13224}
13225
13226#[no_mangle]
13227pub extern "C" fn inet_lnaof(addr: u32) -> c_int {
13228    let h = u32::from_be(addr);
13229    if h < 0x80000000 { (h & 0x00ffffff) as c_int }
13230    else if h < 0xc0000000 { (h & 0x0000ffff) as c_int }
13231    else { (h & 0x000000ff) as c_int }
13232}
13233
13234#[no_mangle]
13235pub extern "C" fn inet_netof(addr: u32) -> c_int {
13236    let h = u32::from_be(addr);
13237    if h < 0x80000000 { (h >> 24) as c_int }
13238    else if h < 0xc0000000 { (h >> 16) as c_int }
13239    else { (h >> 8) as c_int }
13240}
13241
13242// ============================================================
13243// stdlib: strtod / strtof / strtold
13244// ============================================================
13245
13246// ponytail: correctly-rounded float parser.
13247// Decimal: collects digits into buffer, uses core::str::FromStr.
13248// Hex: u128 integer arithmetic with round-to-nearest-even.
13249// is_f32: true for strtof (f32::from_str), false for strtod/strtold (f64::from_str).
13250unsafe fn parse_float(s: *const u8, endptr: *mut *mut u8, is_f32: bool) -> f64 {
13251    let mut p = s;
13252    // skip whitespace
13253    while *p == b' ' || *p == b'\t' || *p == b'\n' || *p == b'\r' { p = p.add(1); }
13254    let mut neg = false;
13255    if *p == b'-' { neg = true; p = p.add(1); }
13256    else if *p == b'+' { p = p.add(1); }
13257
13258    // inf
13259    if (*p | 0x20) == b'i'
13260        && (*p.add(1) | 0x20) == b'n'
13261        && (*p.add(2) | 0x20) == b'f'
13262    {
13263        p = p.add(3);
13264        // optionally consume "inity"
13265        if (*p | 0x20) == b'i'
13266            && (*p.add(1) | 0x20) == b't'
13267            && (*p.add(2) | 0x20) == b'y'
13268        {
13269            p = p.add(3);
13270        }
13271        if !endptr.is_null() { *endptr = p as *mut u8; }
13272        return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
13273    }
13274    // nan
13275    if (*p | 0x20) == b'n'
13276        && (*p.add(1) | 0x20) == b'a'
13277        && (*p.add(2) | 0x20) == b'n'
13278    {
13279        p = p.add(3);
13280        // optionally consume (n-char-sequence)
13281        if *p == b'(' {
13282            p = p.add(1);
13283            while *p != 0 && *p != b')' { p = p.add(1); }
13284            if *p == b')' { p = p.add(1); }
13285        }
13286        if !endptr.is_null() { *endptr = p as *mut u8; }
13287        return if neg { -f64::NAN } else { f64::NAN };
13288    }
13289
13290    // hex float
13291    if *p == b'0' && (*p.add(1) == b'x' || *p.add(1) == b'X') {
13292        p = p.add(2);
13293        let mut mant: u128 = 0;
13294        let mut frac_hex: u32 = 0;
13295        let mut found = false;
13296        let mut in_frac = false;
13297
13298        loop {
13299            if let Some(d) = hex_val(*p) {
13300                if mant <= u128::MAX / 16 {
13301                    mant = mant * 16 + d as u128;
13302                }
13303                if in_frac { frac_hex += 1; }
13304                p = p.add(1);
13305                found = true;
13306            } else if *p == b'.' && !in_frac {
13307                in_frac = true;
13308                p = p.add(1);
13309            } else {
13310                break;
13311            }
13312        }
13313
13314        if !found {
13315            if !endptr.is_null() { *endptr = s as *mut u8; }
13316            return 0.0;
13317        }
13318
13319        // binary exponent p[+-]N
13320        let mut bin_exp: i32 = 0;
13321        if *p == b'p' || *p == b'P' {
13322            p = p.add(1);
13323            let mut exp_neg = false;
13324            if *p == b'-' { exp_neg = true; p = p.add(1); }
13325            else if *p == b'+' { p = p.add(1); }
13326            while *p >= b'0' && *p <= b'9' {
13327                if bin_exp < 100000 {
13328                    bin_exp = bin_exp * 10 + (*p - b'0') as i32;
13329                }
13330                p = p.add(1);
13331            }
13332            if exp_neg { bin_exp = -bin_exp; }
13333        }
13334
13335        if !endptr.is_null() { *endptr = p as *mut u8; }
13336        if mant == 0 { return if neg { -0.0 } else { 0.0 }; }
13337
13338        let total_exp = bin_exp as i64 - 4 * frac_hex as i64;
13339        return hex_mant_to_f64(mant, total_exp, neg);
13340    }
13341
13342    // decimal: collect into buffer, use from_str for correct rounding
13343    let mut buf = [0u8; 65536];
13344    let mut n = 0usize;
13345    let mut found_digit = false;
13346
13347    while *p >= b'0' && *p <= b'9' {
13348        if n < 65535 { buf[n] = *p; n += 1; }
13349        p = p.add(1);
13350        found_digit = true;
13351    }
13352    if *p == b'.' {
13353        if n < 65535 { buf[n] = b'.'; n += 1; }
13354        p = p.add(1);
13355        while *p >= b'0' && *p <= b'9' {
13356            if n < 65535 { buf[n] = *p; n += 1; }
13357            p = p.add(1);
13358            found_digit = true;
13359        }
13360    }
13361    if !found_digit {
13362        if !endptr.is_null() { *endptr = s as *mut u8; }
13363        return 0.0;
13364    }
13365    if *p == b'e' || *p == b'E' {
13366        if n < 65535 { buf[n] = b'e'; n += 1; }
13367        p = p.add(1);
13368        if *p == b'-' || *p == b'+' {
13369            if n < 65535 { buf[n] = *p; n += 1; }
13370            p = p.add(1);
13371        }
13372        while *p >= b'0' && *p <= b'9' {
13373            if n < 65535 { buf[n] = *p; n += 1; }
13374            p = p.add(1);
13375        }
13376    }
13377
13378    if !endptr.is_null() { *endptr = p as *mut u8; }
13379    let s_str = core::str::from_utf8_unchecked(
13380        core::slice::from_raw_parts(buf.as_ptr(), n),
13381    );
13382    if is_f32 {
13383        match <f32 as core::str::FromStr>::from_str(s_str) {
13384            Ok(v) => { let r = v as f64; if neg { -r } else { r } }
13385            Err(_) => { if !endptr.is_null() { *endptr = s as *mut u8; } 0.0 }
13386        }
13387    } else {
13388        match <f64 as core::str::FromStr>::from_str(s_str) {
13389            Ok(v) => if neg { -v } else { v },
13390            Err(_) => { if !endptr.is_null() { *endptr = s as *mut u8; } 0.0 }
13391        }
13392    }
13393}
13394
13395// Convert hex mantissa integer to f64 with correct rounding.
13396// mant: integer from parsed hex digits. total_exp: bin_exp - 4 * frac_hex_digits.
13397// Value = mant * 2^total_exp.
13398fn hex_mant_to_f64(mant: u128, total_exp: i64, neg: bool) -> f64 {
13399    if mant == 0 { return if neg { -0.0 } else { 0.0 }; }
13400
13401    let msb = (127 - mant.leading_zeros()) as i64;
13402    let unbiased_exp = msb + total_exp;
13403    let biased_exp = unbiased_exp + 1023;
13404
13405    // Overflow → infinity
13406    if biased_exp >= 2047 {
13407        return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
13408    }
13409
13410    // Subnormal or underflow
13411    if biased_exp <= 0 {
13412        // subnormal: biased_exp=0, effective exponent=-1022
13413        // mantissa = round(mant * 2^(total_exp + 1074))
13414        let shift = total_exp + 1074;
13415        if shift < 0 {
13416            return if neg { -0.0 } else { 0.0 };
13417        }
13418        if shift > 128 {
13419            return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
13420        }
13421        let shifted = mant << (shift as u32);
13422        let mantissa52 = (shifted as u64) & 0x000FFFFFFFFFFFFF;
13423        let guard = ((shifted >> 52) & 1) != 0;
13424        let sticky = (shifted >> 53) != 0;
13425        let mut result = mantissa52;
13426        if guard && (sticky || (result & 1) != 0) {
13427            result += 1;
13428            if result > 0x000FFFFFFFFFFFFF {
13429                // carry → smallest normal
13430                return if neg { -f64::from_bits(1u64 << 52) } else { f64::from_bits(1u64 << 52) };
13431            }
13432        }
13433        return if neg { -f64::from_bits(result) } else { f64::from_bits(result) };
13434    }
13435
13436    // Normal: biased_exp in [1, 2046]
13437    let shift = msb - 52;
13438
13439    if shift <= 0 {
13440        // fewer than 53 bits, no rounding needed
13441        let mantissa = ((mant as u64) & ((1u64 << msb as u32) - 1)) << ((-shift) as u32);
13442        let bits = ((biased_exp as u64) << 52) | mantissa;
13443        return if neg { -f64::from_bits(bits) } else { f64::from_bits(bits) };
13444    }
13445
13446    // shift > 0: round to nearest even
13447    let mantissa = ((mant >> shift as u32) as u64) & 0x000FFFFFFFFFFFFF;
13448    let guard = ((mant >> (shift as u32 - 1)) & 1) != 0;
13449    let sticky = if shift > 1 {
13450        (mant & ((1u128 << (shift as u32 - 1)) - 1)) != 0
13451    } else { false };
13452
13453    let mut result_mant = mantissa;
13454    let mut result_exp = biased_exp;
13455    if guard && (sticky || (result_mant & 1) != 0) {
13456        result_mant += 1;
13457        if result_mant > 0x000FFFFFFFFFFFFF {
13458            result_mant = 0;
13459            result_exp += 1;
13460            if result_exp >= 2047 {
13461                return if neg { f64::NEG_INFINITY } else { f64::INFINITY };
13462            }
13463        }
13464    }
13465
13466    let bits = ((result_exp as u64) << 52) | result_mant;
13467    if neg { -f64::from_bits(bits) } else { f64::from_bits(bits) }
13468}
13469
13470unsafe fn hex_val(c: u8) -> Option<u8> {
13471    if c >= b'0' && c <= b'9' { Some(c - b'0') }
13472    else if c >= b'a' && c <= b'f' { Some(c - b'a' + 10) }
13473    else if c >= b'A' && c <= b'F' { Some(c - b'A' + 10) }
13474    else { None }
13475}
13476
13477#[no_mangle]
13478pub unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> f64 {
13479    let mut end: *mut u8 = s as *mut u8;
13480    let r = parse_float(s as *const u8, &mut end, false);
13481    if !endptr.is_null() { *endptr = end as *mut c_char; }
13482    r
13483}
13484
13485#[no_mangle]
13486pub unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> f32 {
13487    let mut end: *mut u8 = s as *mut u8;
13488    let r = parse_float(s as *const u8, &mut end, true);
13489    if !endptr.is_null() { *endptr = end as *mut c_char; }
13490    r as f32
13491}
13492
13493#[no_mangle]
13494#[cfg(target_arch = "x86_64")]
13495pub unsafe extern "C" fn strtold(s: *const c_char, endptr: *mut *mut c_char) -> f64 {
13496    strtod(s, endptr)
13497}
13498
13499#[no_mangle]
13500#[cfg(target_arch = "aarch64")]
13501pub unsafe extern "C" fn strtold(s: *const c_char, endptr: *mut *mut c_char) -> f128 {
13502    strtod(s, endptr) as f128
13503}
13504
13505#[no_mangle]
13506#[cfg(target_arch = "riscv64")]
13507pub unsafe extern "C" fn strtold(s: *const c_char, endptr: *mut *mut c_char) -> f128 {
13508    strtod(s, endptr) as f128
13509}
13510
13511#[no_mangle]
13512pub unsafe extern "C" fn atof(s: *const c_char) -> f64 {
13513    strtod(s, core::ptr::null_mut())
13514}
13515
13516// ============================================================
13517// stdio: open_memstream / fmemopen
13518// ============================================================
13519
13520#[repr(C)]
13521struct MsCookie {
13522    bufp: *mut *mut c_char,
13523    sizep: *mut usize,
13524    pos: usize,
13525    len: usize,
13526    buf: *mut u8,
13527    space: usize,
13528}
13529
13530#[repr(C)]
13531struct MfCookie {
13532    pos: usize,
13533    len: usize,
13534    size: usize,
13535    buf: *mut u8,
13536    mode: c_char,
13537}
13538
13539unsafe extern "C" fn ms_seek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
13540    let c = (*f).cookie as *mut MsCookie;
13541    if whence < 0 || whence > 2 { ERRNO = EINVAL; return -1; }
13542    let base: i64 = match whence {
13543        0 => 0,
13544        1 => (*c).pos as i64,
13545        2 => (*c).len as i64,
13546        _ => { ERRNO = EINVAL; return -1; }
13547    };
13548    if off < -base || off > isize::MAX as i64 - base { ERRNO = EINVAL; return -1; }
13549    (*c).pos = (base + off) as usize;
13550    (*c).pos as i64
13551}
13552
13553unsafe extern "C" fn ms_write(f: *mut FILE, buf: *const u8, len: usize) -> usize {
13554    let c = (*f).cookie as *mut MsCookie;
13555    let buffered = (*f).wpos as usize - (*f).wbase as usize;
13556    if buffered > 0 {
13557        (*f).wpos = (*f).wbase;
13558        if ms_write(f, (*f).wbase, buffered) < buffered { return 0; }
13559    }
13560    if len == 0 { return 0; }
13561    if (*c).pos + len >= (*c).space {
13562        let new_space = 2 * (*c).space + 1 | (*c).pos + len + 1;
13563        let newbuf = realloc((*c).buf as *mut c_void, new_space) as *mut u8;
13564        if newbuf.is_null() { return 0; }
13565        *(*c).bufp = newbuf as *mut c_char;
13566        core::ptr::write_bytes(newbuf.add((*c).space), 0, new_space - (*c).space);
13567        (*c).buf = newbuf;
13568        (*c).space = new_space;
13569    }
13570    core::ptr::copy_nonoverlapping(buf, (*c).buf.add((*c).pos), len);
13571    (*c).pos += len;
13572    if (*c).pos >= (*c).len { (*c).len = (*c).pos; }
13573    *(*c).sizep = (*c).pos;
13574    len
13575}
13576
13577unsafe extern "C" fn ms_close(_f: *mut FILE) -> c_int {
13578    0
13579}
13580
13581#[no_mangle]
13582pub unsafe extern "C" fn open_memstream(bufp: *mut *mut c_char, sizep: *mut usize) -> *mut FILE {
13583    if bufp.is_null() || sizep.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
13584    let f = calloc(1, core::mem::size_of::<FILE>() + UNGET + BUFSIZ) as *mut FILE;
13585    if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
13586    let buf_area = buf_ptr(f);
13587    init_file(f, -1, b"w\0".as_ptr() as *const c_char, Some(ms_close), buf_area, BUFSIZ);
13588    (*f).flags = F_NORD | F_SVB;
13589    (*f).lbf = -1;
13590    let c = calloc(1, core::mem::size_of::<MsCookie>()) as *mut MsCookie;
13591    if c.is_null() { free(f as *mut c_void); ERRNO = ENOMEM; return core::ptr::null_mut(); }
13592    (*c).bufp = bufp;
13593    (*c).sizep = sizep;
13594    (*c).pos = 0;
13595    (*c).len = 0;
13596    (*c).buf = core::ptr::null_mut();
13597    (*c).space = 0;
13598    (*f).cookie = c as *mut c_void;
13599    (*f).write_fn = Some(ms_write);
13600    (*f).seek_fn = Some(ms_seek);
13601    *bufp = core::ptr::null_mut();
13602    *sizep = 0;
13603    f
13604}
13605
13606unsafe extern "C" fn mseek(f: *mut FILE, off: i64, whence: c_int) -> i64 {
13607    let c = (*f).cookie as *mut MfCookie;
13608    if whence < 0 || whence > 2 { ERRNO = EINVAL; return -1; }
13609    let base: i64 = match whence {
13610        0 => 0,
13611        1 => (*c).pos as i64,
13612        2 => (*c).len as i64,
13613        _ => { ERRNO = EINVAL; return -1; }
13614    };
13615    if off < -base || off > (*c).size as i64 - base { ERRNO = EINVAL; return -1; }
13616    (*c).pos = (base + off) as usize;
13617    (*c).pos as i64
13618}
13619
13620unsafe extern "C" fn mread(f: *mut FILE, buf: *mut u8, len: usize) -> usize {
13621    let c = (*f).cookie as *mut MfCookie;
13622    let mut rem = if (*c).pos <= (*c).len { (*c).len - (*c).pos } else { 0 };
13623    let mut l = len;
13624    if l > rem {
13625        l = rem;
13626        (*f).flags |= F_EOF;
13627    }
13628    core::ptr::copy_nonoverlapping((*c).buf.add((*c).pos), buf, l);
13629    (*c).pos += l;
13630    rem -= l;
13631    if rem > (*f).buf_size { rem = (*f).buf_size; }
13632    (*f).rpos = (*f).buf;
13633    (*f).rend = (*f).buf.add(rem);
13634    core::ptr::copy_nonoverlapping((*c).buf.add((*c).pos), (*f).rpos, rem);
13635    (*c).pos += rem;
13636    l
13637}
13638
13639unsafe extern "C" fn mwrite(f: *mut FILE, buf: *const u8, len: usize) -> usize {
13640    let c = (*f).cookie as *mut MfCookie;
13641    let buffered = (*f).wpos as usize - (*f).wbase as usize;
13642    if buffered > 0 {
13643        (*f).wpos = (*f).wbase;
13644        if mwrite(f, (*f).wbase, buffered) < buffered { return 0; }
13645    }
13646    if len == 0 { return 0; }
13647    if (*c).mode == b'a' as c_char { (*c).pos = (*c).len; }
13648    let rem = (*c).size - (*c).pos;
13649    let mut l = len;
13650    if l > rem { l = rem; }
13651    core::ptr::copy_nonoverlapping(buf, (*c).buf.add((*c).pos), l);
13652    (*c).pos += l;
13653    if (*c).pos > (*c).len {
13654        (*c).len = (*c).pos;
13655        if (*c).len < (*c).size {
13656            *(*c).buf.add((*c).len) = 0;
13657        } else if ((*f).flags & F_NORD) != 0 && (*c).size > 0 {
13658            *(*c).buf.add((*c).size - 1) = 0;
13659        }
13660    }
13661    l
13662}
13663
13664unsafe extern "C" fn mclose(_f: *mut FILE) -> c_int {
13665    0
13666}
13667
13668#[no_mangle]
13669pub unsafe extern "C" fn fmemopen(buf: *mut c_void, size: usize, mode: *const c_char) -> *mut FILE {
13670    if mode.is_null() { ERRNO = EINVAL; return core::ptr::null_mut(); }
13671    let m = *mode;
13672    if m != b'r' as c_char && m != b'w' as c_char && m != b'a' as c_char {
13673        ERRNO = EINVAL; return core::ptr::null_mut();
13674    }
13675    let has_plus = !strchr(mode as *const u8, b'+' as c_int).is_null();
13676    let need_alloc = buf.is_null();
13677    let alloc_size = core::mem::size_of::<FILE>() + UNGET + BUFSIZ + if need_alloc { size } else { 0 };
13678    let f = calloc(1, alloc_size) as *mut FILE;
13679    if f.is_null() { ERRNO = ENOMEM; return core::ptr::null_mut(); }
13680    let buf_area = buf_ptr(f);
13681    init_file(f, -1, mode, Some(mclose), buf_area, BUFSIZ);
13682    (*f).flags |= F_SVB;
13683    let actual_buf: *mut u8 = if need_alloc {
13684        (f as *mut u8).add(alloc_size - size)
13685    } else {
13686        buf as *mut u8
13687    };
13688    if need_alloc { core::ptr::write_bytes(actual_buf, 0, size); }
13689    let c = calloc(1, core::mem::size_of::<MfCookie>()) as *mut MfCookie;
13690    if c.is_null() { free(f as *mut c_void); ERRNO = ENOMEM; return core::ptr::null_mut(); }
13691    (*c).buf = actual_buf;
13692    (*c).size = size;
13693    (*c).mode = m;
13694    (*f).cookie = c as *mut c_void;
13695    (*f).read_fn = Some(mread);
13696    (*f).write_fn = Some(mwrite);
13697    (*f).seek_fn = Some(mseek);
13698    if !has_plus { (*f).flags = if m == b'r' as c_char { F_NOWR } else { F_NORD }; }
13699    if m == b'r' as c_char {
13700        (*c).len = size;
13701    } else if m == b'a' as c_char {
13702        (*c).len = strnlen(actual_buf, size);
13703        (*c).pos = (*c).len;
13704    } else if has_plus {
13705        *actual_buf = 0;
13706    }
13707    f
13708}
13709
13710// ============================================================
13711// Stat (for ftok)
13712// ============================================================
13713
13714#[repr(C)]
13715struct kernel_stat64 {
13716    st_dev: u64,
13717    st_ino: u64,
13718    st_nlink: u64,
13719    st_mode: u32,
13720    st_uid: u32,
13721    st_gid: u32,
13722    __pad0: c_int,
13723    st_rdev: u64,
13724    st_size: i64,
13725    st_blksize: i64,
13726    st_blocks: i64,
13727    st_atime: i64,
13728    st_atime_nsec: i64,
13729    st_mtime: i64,
13730    st_mtime_nsec: i64,
13731    st_ctime: i64,
13732    st_ctime_nsec: i64,
13733    __unused: [i64; 3],
13734}
13735
13736// sys_stat = 4 on x86_64
13737#[inline]
13738unsafe fn sys_stat(path: *const u8, statbuf: *mut kernel_stat64) -> i64 {
13739    <Arch as Syscalls>::syscall4(SYS_NEWFSTATAT, AT_FDCWD as i64, path as i64, statbuf as i64, 0)
13740}
13741
13742// ============================================================
13743// Search: hcreate/hdestroy/hsearch (hash table)
13744// ============================================================
13745
13746const HSEARCH_MINSIZE: usize = 8;
13747
13748#[repr(C)]
13749#[derive(Copy, Clone)]
13750pub struct HSearchEntry {
13751    key: *mut c_char,
13752    data: *mut c_void,
13753}
13754
13755#[repr(C)]
13756struct HTab {
13757    entries: *mut HSearchEntry,
13758    mask: usize,
13759    used: usize,
13760}
13761
13762#[repr(C)]
13763pub struct HSearchData {
13764    tab: *mut HTab,
13765    __unused1: c_uint,
13766    __unused2: c_uint,
13767}
13768
13769// ponytail: single static hash table for non-_r variants
13770static mut HTAB_DATA: HSearchData = HSearchData {
13771    tab: core::ptr::null_mut(),
13772    __unused1: 0,
13773    __unused2: 0,
13774};
13775
13776unsafe fn keyhash(k: *const c_char) -> usize {
13777    let mut h: usize = 0;
13778    let mut p = k;
13779    while *p != 0 {
13780        h = h.wrapping_mul(31).wrapping_add(*p as usize);
13781        p = p.add(1);
13782    }
13783    h
13784}
13785
13786unsafe fn htab_lookup(key: *const c_char, hash: usize, htab: *mut HSearchData) -> *mut HSearchEntry {
13787    let tab = (*htab).tab;
13788    let mask = (*tab).mask;
13789    let entries = (*tab).entries;
13790    let mut i = hash;
13791    let mut j: usize = 1;
13792    loop {
13793        let e = entries.add(i & mask);
13794        if (*e).key.is_null() || strcmp((*e).key as *const u8, key as *const u8) == 0 {
13795            return e;
13796        }
13797        i = i.wrapping_add(j);
13798        j += 1;
13799    }
13800}
13801
13802unsafe fn htab_resize(nel: usize, htab: *mut HSearchData) -> c_int {
13803    let tab = (*htab).tab;
13804    let old_entries = (*tab).entries;
13805    let old_size = (*tab).mask + 1;
13806
13807    let mut newsize: usize = HSEARCH_MINSIZE;
13808    while newsize < nel {
13809        let Some(next) = newsize.checked_mul(2) else {
13810            ERRNO = ENOMEM;
13811            return 0;
13812        };
13813        newsize = next;
13814    }
13815
13816    let new_entries = calloc(newsize, core::mem::size_of::<HSearchEntry>()) as *mut HSearchEntry;
13817    if new_entries.is_null() {
13818        ERRNO = ENOMEM;
13819        return 0;
13820    }
13821    (*tab).entries = new_entries;
13822    (*tab).mask = newsize - 1;
13823
13824    if !old_entries.is_null() {
13825        for idx in 0..old_size {
13826            let old_e = old_entries.add(idx);
13827            if !(*old_e).key.is_null() {
13828                let h = keyhash((*old_e).key);
13829                let mut i = h;
13830                let mut j: usize = 1;
13831                loop {
13832                    let e = new_entries.add(i & (*tab).mask);
13833                    if (*e).key.is_null() {
13834                        *e = *old_e;
13835                        break;
13836                    }
13837                    i = i.wrapping_add(j);
13838                    j += 1;
13839                }
13840            }
13841        }
13842        free(old_entries as *mut c_void);
13843    }
13844    1
13845}
13846
13847unsafe fn hcreate_r_impl(nel: usize, htab: *mut HSearchData) -> c_int {
13848    if nel == 0 || nel > (1usize << 30) {
13849        ERRNO = ENOMEM;
13850        return 0;
13851    }
13852    (*htab).tab = calloc(1, core::mem::size_of::<HTab>()) as *mut HTab;
13853    if (*htab).tab.is_null() {
13854        ERRNO = ENOMEM;
13855        return 0;
13856    }
13857    if htab_resize(nel, htab) == 0 {
13858        free((*htab).tab as *mut c_void);
13859        (*htab).tab = core::ptr::null_mut();
13860        return 0;
13861    }
13862    1
13863}
13864
13865unsafe fn hdestroy_r_impl(htab: *mut HSearchData) {
13866    if !(*htab).tab.is_null() {
13867        if !(*(*htab).tab).entries.is_null() {
13868            free((*(*htab).tab).entries as *mut c_void);
13869        }
13870        free((*htab).tab as *mut c_void);
13871        (*htab).tab = core::ptr::null_mut();
13872    }
13873}
13874
13875unsafe fn hsearch_r_impl(item: HSearchEntry, action: c_int, retval: *mut *mut HSearchEntry, htab: *mut HSearchData) -> c_int {
13876    let hash = keyhash(item.key);
13877    let e = htab_lookup(item.key, hash, htab);
13878
13879    if !(*e).key.is_null() {
13880        *retval = e;
13881        return 1;
13882    }
13883    if action == 0 { // FIND
13884        *retval = core::ptr::null_mut();
13885        return 0;
13886    }
13887    // ENTER
13888    let item_key = item.key;
13889    *e = item;
13890    (*(*htab).tab).used += 1;
13891    if (*(*htab).tab).used > (*(*htab).tab).mask - (*(*htab).tab).mask / 4 {
13892        if htab_resize(2 * (*(*htab).tab).used, htab) == 0 {
13893            (*(*htab).tab).used -= 1;
13894            (*e).key = core::ptr::null_mut();
13895            *retval = core::ptr::null_mut();
13896            return 0;
13897        }
13898        let e2 = htab_lookup(item_key, hash, htab);
13899        *retval = e2;
13900        return 1;
13901    }
13902    *retval = e;
13903    1
13904}
13905
13906#[no_mangle]
13907pub unsafe extern "C" fn hcreate(nel: usize) -> c_int {
13908    hcreate_r_impl(nel, core::ptr::addr_of_mut!(HTAB_DATA))
13909}
13910
13911#[no_mangle]
13912pub unsafe extern "C" fn hdestroy() {
13913    hdestroy_r_impl(core::ptr::addr_of_mut!(HTAB_DATA));
13914}
13915
13916#[no_mangle]
13917pub unsafe extern "C" fn hsearch(item: HSearchEntry, action: c_int) -> *mut HSearchEntry {
13918    let mut e: *mut HSearchEntry = core::ptr::null_mut();
13919    hsearch_r_impl(item, action, &mut e, core::ptr::addr_of_mut!(HTAB_DATA));
13920    e
13921}
13922
13923#[no_mangle]
13924pub unsafe extern "C" fn hcreate_r(nel: usize, htab: *mut HSearchData) -> c_int {
13925    hcreate_r_impl(nel, htab)
13926}
13927
13928#[no_mangle]
13929pub unsafe extern "C" fn hdestroy_r(htab: *mut HSearchData) {
13930    hdestroy_r_impl(htab);
13931}
13932
13933#[no_mangle]
13934pub unsafe extern "C" fn hsearch_r(item: HSearchEntry, action: c_int, retval: *mut *mut HSearchEntry, htab: *mut HSearchData) -> c_int {
13935    hsearch_r_impl(item, action, retval, htab)
13936}
13937
13938// ============================================================
13939// Search: insque / remque
13940// ============================================================
13941
13942#[repr(C)]
13943struct QueNode {
13944    next: *mut QueNode,
13945    prev: *mut QueNode,
13946}
13947
13948#[no_mangle]
13949pub unsafe extern "C" fn insque(element: *mut c_void, pred: *mut c_void) {
13950    let e = element as *mut QueNode;
13951    let p = pred as *mut QueNode;
13952    if p.is_null() {
13953        (*e).next = core::ptr::null_mut();
13954        (*e).prev = core::ptr::null_mut();
13955        return;
13956    }
13957    (*e).next = (*p).next;
13958    (*e).prev = p;
13959    (*p).next = e;
13960    if !(*e).next.is_null() {
13961        (*(*e).next).prev = e;
13962    }
13963}
13964
13965#[no_mangle]
13966pub unsafe extern "C" fn remque(element: *mut c_void) {
13967    let e = element as *mut QueNode;
13968    if !(*e).next.is_null() {
13969        (*(*e).next).prev = (*e).prev;
13970    }
13971    if !(*e).prev.is_null() {
13972        (*(*e).prev).next = (*e).next;
13973    }
13974}
13975
13976// ============================================================
13977// Search: lsearch / lfind
13978// ============================================================
13979
13980#[no_mangle]
13981pub unsafe extern "C" fn lsearch(
13982    key: *const c_void,
13983    base: *mut c_void,
13984    nelp: *mut usize,
13985    width: usize,
13986    compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
13987) -> *mut c_void {
13988    let n = *nelp;
13989    let p = base as *mut u8;
13990    for i in 0..n {
13991        let elem = p.add(i * width);
13992        if compar.unwrap()(key, elem as *const c_void) == 0 {
13993            return elem as *mut c_void;
13994        }
13995    }
13996    let dest = p.add(n * width);
13997    memcpy(dest as *mut c_void, key as *const c_void, width);
13998    *nelp = n + 1;
13999    dest as *mut c_void
14000}
14001
14002#[no_mangle]
14003pub unsafe extern "C" fn lfind(
14004    key: *const c_void,
14005    base: *const c_void,
14006    nelp: *mut usize,
14007    width: usize,
14008    compar: Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>,
14009) -> *mut c_void {
14010    let n = *nelp;
14011    let p = base as *const u8;
14012    for i in 0..n {
14013        let elem = p.add(i * width);
14014        if compar.unwrap()(key, elem as *const c_void) == 0 {
14015            return elem as *mut c_void;
14016        }
14017    }
14018    core::ptr::null_mut()
14019}
14020
14021// ============================================================
14022// Search: tsearch / tfind / tdelete / twalk / tdestroy (BST, no balancing)
14023// ============================================================
14024
14025// ponytail: simple BST, no balancing; correct for tests, O(n) worst case
14026#[repr(C)]
14027pub struct TreeNode {
14028    key: *const c_void,
14029    left: *mut TreeNode,
14030    right: *mut TreeNode,
14031}
14032
14033type ComparFn = Option<unsafe extern "C" fn(*const c_void, *const c_void) -> c_int>;
14034
14035unsafe fn bst_new(key: *const c_void) -> *mut TreeNode {
14036    let n = calloc(1, core::mem::size_of::<TreeNode>()) as *mut TreeNode;
14037    if !n.is_null() {
14038        (*n).key = key;
14039        (*n).left = core::ptr::null_mut();
14040        (*n).right = core::ptr::null_mut();
14041    }
14042    n
14043}
14044
14045#[no_mangle]
14046pub unsafe extern "C" fn tsearch(
14047    key: *const c_void,
14048    rootp: *mut *mut TreeNode,
14049    compar: ComparFn,
14050) -> *mut c_void {
14051    if rootp.is_null() {
14052        return core::ptr::null_mut();
14053    }
14054    let mut pp = rootp;
14055    loop {
14056        let n = *pp;
14057        if n.is_null() {
14058            let r = bst_new(key);
14059            if r.is_null() {
14060                return core::ptr::null_mut();
14061            }
14062            *pp = r;
14063            return r as *mut c_void;
14064        }
14065        let c = compar.unwrap()(key, (*n).key);
14066        if c == 0 {
14067            return n as *mut c_void;
14068        }
14069        if c < 0 {
14070            pp = &mut (*n).left;
14071        } else {
14072            pp = &mut (*n).right;
14073        }
14074    }
14075}
14076
14077#[no_mangle]
14078pub unsafe extern "C" fn tfind(
14079    key: *const c_void,
14080    rootp: *const *mut TreeNode,
14081    compar: ComparFn,
14082) -> *mut c_void {
14083    if rootp.is_null() {
14084        return core::ptr::null_mut();
14085    }
14086    let mut n = *rootp;
14087    loop {
14088        if n.is_null() {
14089            return core::ptr::null_mut();
14090        }
14091        let c = compar.unwrap()(key, (*n).key);
14092        if c == 0 {
14093            return n as *mut c_void;
14094        }
14095        if c < 0 {
14096            n = (*n).left;
14097        } else {
14098            n = (*n).right;
14099        }
14100    }
14101}
14102
14103#[no_mangle]
14104pub unsafe extern "C" fn tdelete(
14105    key: *const c_void,
14106    rootp: *mut *mut TreeNode,
14107    compar: ComparFn,
14108) -> *mut c_void {
14109    if rootp.is_null() {
14110        return core::ptr::null_mut();
14111    }
14112    let mut pp = rootp;
14113    loop {
14114        let n = *pp;
14115        if n.is_null() {
14116            return core::ptr::null_mut();
14117        }
14118        let c = compar.unwrap()(key, (*n).key);
14119        if c == 0 {
14120            break;
14121        }
14122        if c < 0 {
14123            pp = &mut (*n).left;
14124        } else {
14125            pp = &mut (*n).right;
14126        }
14127    }
14128    let n = *pp;
14129    // parent is *rootp if we went to root, otherwise the node above
14130    let parent = *rootp;
14131    if !(*n).left.is_null() {
14132        // replace with in-order predecessor
14133        let mut q = &mut (*n).left;
14134        while !(*(*q)).right.is_null() {
14135            q = &mut (*(*q)).right;
14136        }
14137        let pred = *q;
14138        // swap keys
14139        (*n).key = (*pred).key;
14140        // remove predecessor
14141        *q = (*pred).left;
14142        free(pred as *mut c_void);
14143    } else {
14144        // replace with right child (may be null)
14145        *pp = (*n).right;
14146        free(n as *mut c_void);
14147    }
14148    parent as *mut c_void
14149}
14150
14151#[no_mangle]
14152pub unsafe extern "C" fn twalk(
14153    root: *const TreeNode,
14154    action: Option<unsafe extern "C" fn(*const c_void, c_int, c_int)>,
14155) {
14156    unsafe fn walk(
14157        node: *const TreeNode,
14158        action: Option<unsafe extern "C" fn(*const c_void, c_int, c_int)>,
14159        depth: c_int,
14160    ) {
14161        if node.is_null() {
14162            return;
14163        }
14164        let is_leaf = (*node).left.is_null() && (*node).right.is_null();
14165        if is_leaf {
14166            action.unwrap()(node as *const c_void, 3, depth); // leaf
14167        } else {
14168            action.unwrap()(node as *const c_void, 0, depth); // preorder
14169            walk((*node).left, action, depth + 1);
14170            action.unwrap()(node as *const c_void, 1, depth); // postorder (left done)
14171            walk((*node).right, action, depth + 1);
14172            action.unwrap()(node as *const c_void, 2, depth); // endorder
14173        }
14174    }
14175    walk(root, action, 0);
14176}
14177
14178#[no_mangle]
14179pub unsafe extern "C" fn tdestroy(root: *mut TreeNode, freekey: Option<unsafe extern "C" fn(*mut c_void)>) {
14180    if root.is_null() {
14181        return;
14182    }
14183    tdestroy((*root).left, freekey);
14184    tdestroy((*root).right, freekey);
14185    if let Some(f) = freekey {
14186        f((*root).key as *mut c_void);
14187    }
14188    free(root as *mut c_void);
14189}
14190
14191// ============================================================
14192// fnmatch: full POSIX pattern matching
14193// ============================================================
14194
14195const FNM_PATHNAME: c_int = 0x1;
14196const FNM_NOESCAPE: c_int = 0x2;
14197const FNM_PERIOD: c_int = 0x4;
14198const FNM_LEADING_DIR: c_int = 0x8;
14199const FNM_CASEFOLD: c_int = 0x10;
14200const FNM_NOMATCH: c_int = 1;
14201
14202const FNM_END: c_int = 0;
14203const FNM_STAR: c_int = -5;
14204const FNM_QUESTION: c_int = -4;
14205const FNM_BRACKET: c_int = -3;
14206const FNM_UNMATCHABLE: c_int = -2;
14207
14208fn ascii_tolower(c: u8) -> u8 {
14209    if c >= b'A' && c <= b'Z' { c + 32 } else { c }
14210}
14211
14212fn ascii_toupper(c: u8) -> u8 {
14213    if c >= b'a' && c <= b'z' { c - 32 } else { c }
14214}
14215
14216fn ascii_casefold(k: u8) -> u8 {
14217    let upper = ascii_toupper(k);
14218    if upper != k { upper } else { ascii_tolower(k) }
14219}
14220
14221/// Get next byte from pattern, classifying it.
14222/// Returns (token_type, bytes_consumed).
14223unsafe fn pat_next(pat: *const u8, m: usize, flags: c_int) -> (c_int, usize) {
14224    if m == 0 || *pat == 0 {
14225        return (FNM_END, 0);
14226    }
14227    let mut p = pat;
14228    let mut step = 1usize;
14229    let mut esc = false;
14230    if *p == b'\\' && !(flags & FNM_NOESCAPE != 0) && *p.add(1) != 0 {
14231        p = p.add(1);
14232        step = 2;
14233        esc = true;
14234    }
14235    if *p == b'[' && !esc {
14236        // scan for matching ]
14237        let mut k = 1usize;
14238        if k < m && (*pat.add(k) == b'^' || *pat.add(k) == b'!') { k += 1; }
14239        if k < m && *pat.add(k) == b']' { k += 1; }
14240        while k < m && *pat.add(k) != 0 && *pat.add(k) != b']' {
14241            if k + 1 < m && *pat.add(k) == b'[' &&
14242               (*pat.add(k+1) == b':' || *pat.add(k+1) == b'.' || *pat.add(k+1) == b'=') {
14243                let z = *pat.add(k+1);
14244                k += 2;
14245                if k < m { k += 1; }
14246                while k < m && *pat.add(k) != 0 && (*pat.add(k-1) != z || *pat.add(k) != b']') { k += 1; }
14247                if k == m || *pat.add(k) == 0 { break; }
14248            }
14249            k += 1;
14250        }
14251        if k == m || *pat.add(k) == 0 {
14252            // unmatched [ is literal
14253            return (b'[' as c_int, 1);
14254        }
14255        return (FNM_BRACKET, k + 1);
14256    }
14257    if *p == b'*' && !esc {
14258        return (FNM_STAR, 1);
14259    }
14260    if *p == b'?' && !esc {
14261        return (FNM_QUESTION, 1);
14262    }
14263    (*p as c_int, step)
14264}
14265
14266unsafe fn match_class(name: &[u8], k: u8, kfold: u8) -> bool {
14267    let eq = |c: u8| k == c || kfold == c;
14268    let in_range = |lo: u8, hi: u8| (k >= lo && k <= hi) || (kfold >= lo && kfold <= hi);
14269    match name {
14270        b"alnum" => in_range(b'0', b'9') || in_range(b'A', b'Z') || in_range(b'a', b'z'),
14271        b"alpha" => in_range(b'A', b'Z') || in_range(b'a', b'z'),
14272        b"blank" => eq(b' ') || eq(b'\t'),
14273        b"cntrl" => k < 0x20 || k == 0x7f,
14274        b"digit" => in_range(b'0', b'9'),
14275        b"graph" => k >= 0x21 && k <= 0x7e,
14276        b"lower" => in_range(b'a', b'z'),
14277        b"print" => k >= 0x20 && k <= 0x7e,
14278        b"punct" =>
14279            (k >= 0x21 && k <= 0x2f) ||
14280            (k >= 0x3a && k <= 0x40) ||
14281            (k >= 0x5b && k <= 0x60) ||
14282            (k >= 0x7b && k <= 0x7e),
14283        b"space" => eq(b' ') || eq(b'\t') || eq(b'\n') || eq(b'\r') || eq(0x0c) || eq(0x0b),
14284        b"upper" => in_range(b'A', b'Z'),
14285        b"xdigit" => in_range(b'0', b'9') || in_range(b'A', b'F') || in_range(b'a', b'f'),
14286        _ => false,
14287    }
14288}
14289
14290/// Match a bracket expression [class] against char k.
14291unsafe fn match_bracket(mut p: *const u8, k: u8, kfold: u8) -> bool {
14292    let mut inv = false;
14293    p = p.add(1); // skip [
14294    if *p == b'^' || *p == b'!' {
14295        inv = true;
14296        p = p.add(1);
14297    }
14298    // handle ] as first char
14299    if *p == b']' {
14300        if k == b']' { return !inv; }
14301        p = p.add(1);
14302    } else if *p == b'-' {
14303        if k == b'-' { return !inv; }
14304        p = p.add(1);
14305    }
14306    while *p != b']' && *p != 0 {
14307        if *p == b'-' && *p.add(1) != b']' && *p.add(1) != 0 {
14308            // range: previous char to next char
14309            let lo = *p.sub(1);
14310            let hi = *p.add(1);
14311            if lo <= hi && (k >= lo && k <= hi || kfold >= lo && kfold <= hi) {
14312                return !inv;
14313            }
14314            p = p.add(2);
14315        } else if *p == b'[' && (*p.add(1) == b':' || *p.add(1) == b'.' || *p.add(1) == b'=') {
14316            let z = *p.add(1);
14317            let start = p.add(2);
14318            let mut q = start;
14319            while *q != 0 && (*q != z || *q.add(1) != b']') { q = q.add(1); }
14320            if *q != 0 {
14321                let len = (q as usize) - (start as usize);
14322                if len > 0 {
14323                    let inner = core::slice::from_raw_parts(start, len);
14324                    let matched =
14325                        if z == b':' { match_class(inner, k, kfold) }
14326                        else { len == 1 && (inner[0] == k || inner[0] == kfold) };
14327                    if matched { return !inv; }
14328                }
14329                p = q.add(2);
14330                continue;
14331            }
14332        } else {
14333            if *p == k || *p == kfold {
14334                return !inv;
14335            }
14336            p = p.add(1);
14337        }
14338    }
14339    inv
14340}
14341
14342/// Core fnmatch for a single path component (no FNM_PATHNAME splitting).
14343unsafe fn fnmatch_internal(pat: *const u8, str: *const u8, flags: c_int) -> c_int {
14344    // Handle leading .
14345    if flags & FNM_PERIOD != 0 && *str == b'.' && *pat != b'.' {
14346        return FNM_NOMATCH;
14347    }
14348
14349    let mut p = pat;
14350    let mut s = str;
14351
14352    // Consume pattern up to first *
14353    loop {
14354        let (tok, step) = pat_next(p, usize::MAX, flags);
14355        match tok {
14356            FNM_END => {
14357                return if *s == 0 { 0 } else { FNM_NOMATCH };
14358            }
14359            FNM_STAR => {
14360                p = p.add(1);
14361                break;
14362            }
14363            FNM_QUESTION => {
14364                if *s == 0 { return FNM_NOMATCH; }
14365                s = s.add(1);
14366                p = p.add(step);
14367            }
14368            FNM_BRACKET => {
14369                if *s == 0 { return FNM_NOMATCH; }
14370                let k = *s;
14371                let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
14372                if !match_bracket(p, k, kfold) { return FNM_NOMATCH; }
14373                p = p.add(step);
14374                s = s.add(1);
14375            }
14376            c => {
14377                if *s == 0 { return FNM_NOMATCH; }
14378                let k = *s;
14379                let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
14380                if k as c_int != c && kfold as c_int != c { return FNM_NOMATCH; }
14381                p = p.add(step);
14382                s = s.add(1);
14383            }
14384        }
14385    }
14386
14387    // Now p points after first *, rest of pattern is variable
14388    // Factor: find tail after last * and count fixed chars needed
14389    let mut ptail = p;
14390    let mut tailcnt: usize = 0;
14391    let mut pp = p;
14392    loop {
14393        let (tok, step) = pat_next(pp, usize::MAX, flags);
14394        if tok == FNM_END { break; }
14395        if tok == FNM_STAR {
14396            tailcnt = 0;
14397            ptail = pp.add(1);
14398        } else {
14399            tailcnt += 1;
14400        }
14401        pp = pp.add(step);
14402    }
14403
14404    // str must have at least tailcnt chars
14405    let slen = strlen(s as *const c_char);
14406    if slen < tailcnt { return FNM_NOMATCH; }
14407
14408    // Match tail: ptail..end against str[tailcnt from end]
14409    let stail = s.add(slen - tailcnt);
14410    let mut tp = ptail;
14411    let mut ts = stail;
14412    loop {
14413        let (tok, step) = pat_next(tp, usize::MAX, flags);
14414        tp = tp.add(step);
14415        if tok == FNM_END {
14416            break;
14417        }
14418        let k = *ts;
14419        if k == 0 { return FNM_NOMATCH; }
14420        let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
14421        match tok {
14422            FNM_QUESTION => { ts = ts.add(1); }
14423            FNM_BRACKET => {
14424                if !match_bracket(tp.sub(step), k, kfold) { return FNM_NOMATCH; }
14425                ts = ts.add(1);
14426            }
14427            c => {
14428                if k as c_int != c && kfold as c_int != c { return FNM_NOMATCH; }
14429                ts = ts.add(1);
14430            }
14431        }
14432    }
14433
14434    let endstr = stail;
14435    let endpat = ptail;
14436
14437    let mut cp = p;
14438    let mut cs = s;
14439    while cp < endpat {
14440        let (tok, step) = pat_next(cp, usize::MAX, flags);
14441        if tok == FNM_STAR {
14442            cp = cp.add(step);
14443            cs = s;
14444            continue;
14445        }
14446        let comp_start = cp;
14447        let mut ok = false;
14448        let mut try_s = cs;
14449        while try_s < endstr {
14450            let mut tmp_p = comp_start;
14451            let mut tmp_s = try_s;
14452            let mut matched = true;
14453            loop {
14454                let (t, st) = pat_next(tmp_p, usize::MAX, flags);
14455                if t == FNM_STAR || t == FNM_END {
14456                    cp = tmp_p;
14457                    cs = tmp_s;
14458                    ok = true;
14459                    break;
14460                }
14461                if *tmp_s == 0 {
14462                    matched = false;
14463                    break;
14464                }
14465                let k = *tmp_s;
14466                let kfold = if flags & FNM_CASEFOLD != 0 { ascii_casefold(k) } else { k };
14467                match t {
14468                    FNM_QUESTION => {
14469                        tmp_s = tmp_s.add(1);
14470                    }
14471                    FNM_BRACKET => {
14472                        if !match_bracket(tmp_p, k, kfold) {
14473                            matched = false;
14474                            break;
14475                        }
14476                        tmp_s = tmp_s.add(1);
14477                    }
14478                    c => {
14479                        if k as c_int != c && kfold as c_int != c {
14480                            matched = false;
14481                            break;
14482                        }
14483                        tmp_s = tmp_s.add(1);
14484                    }
14485                }
14486                tmp_p = tmp_p.add(st);
14487            }
14488            if ok { break; }
14489            if !matched {
14490                try_s = try_s.add(1);
14491            }
14492        }
14493        if !ok {
14494            return FNM_NOMATCH;
14495        }
14496    }
14497    0
14498}
14499
14500#[no_mangle]
14501pub unsafe extern "C" fn fnmatch(pat: *const c_char, str: *const c_char, flags: c_int) -> c_int {
14502    let pat = pat as *const u8;
14503    let str = str as *const u8;
14504
14505    if flags & FNM_PATHNAME != 0 {
14506        // Split on /
14507        let mut s = str;
14508        let mut p = pat;
14509        loop {
14510            // find next / in str
14511            let mut send = s;
14512            while *send != 0 && *send != b'/' { send = send.add(1); }
14513            // find next / in pat
14514            let mut pend = p;
14515            loop {
14516                let (tok, step) = pat_next(pend, usize::MAX, flags);
14517                if tok == FNM_END || (tok >= 0 && tok as u8 == b'/') {
14518                    break;
14519                }
14520                pend = pend.add(step);
14521            }
14522            let (ptok, pstep) = pat_next(pend, usize::MAX, flags);
14523            let pat_is_slash = ptok >= 0 && ptok as u8 == b'/';
14524            let str_is_slash = *send == b'/';
14525            if pat_is_slash != str_is_slash && (*send != 0 || !(flags & FNM_LEADING_DIR != 0)) {
14526                return FNM_NOMATCH;
14527            }
14528            // match component
14529            // We need a null-terminated copy of the component
14530            let plen = (pend as usize) - (p as usize);
14531            let slen = (send as usize) - (s as usize);
14532            // Use stack buffers for components
14533            // ponytail: max component 1024 bytes
14534            if plen > 1024 || slen > 1024 { return FNM_NOMATCH; }
14535            let mut pbuf = [0u8; 1025];
14536            let mut sbuf = [0u8; 1025];
14537            core::ptr::copy_nonoverlapping(p, pbuf.as_mut_ptr(), plen);
14538            pbuf[plen] = 0;
14539            core::ptr::copy_nonoverlapping(s, sbuf.as_mut_ptr(), slen);
14540            sbuf[slen] = 0;
14541            if fnmatch_internal(pbuf.as_ptr(), sbuf.as_ptr(), flags & !FNM_LEADING_DIR) != 0 {
14542                return FNM_NOMATCH;
14543            }
14544            if !pat_is_slash {
14545                return 0;
14546            }
14547            s = send.add(1);
14548            p = pend.add(pstep);
14549        }
14550    }
14551
14552    if flags & FNM_LEADING_DIR != 0 {
14553        // Try matching at each /
14554        let mut s = str;
14555        while *s != 0 {
14556            if *s == b'/' {
14557                // temporarily null-terminate
14558                // ponytail: we need to copy. Use a simple approach.
14559                let len = (s as usize) - (str as usize);
14560                // Just call fnmatch_internal with a temp buffer
14561                if len < 4096 {
14562                    let mut buf = [0u8; 4096];
14563                    core::ptr::copy_nonoverlapping(str, buf.as_mut_ptr(), len);
14564                    buf[len] = 0;
14565                    if fnmatch_internal(pat, buf.as_ptr(), flags) == 0 {
14566                        return 0;
14567                    }
14568                }
14569            }
14570            s = s.add(1);
14571        }
14572    }
14573
14574    fnmatch_internal(pat, str, flags)
14575}
14576
14577// ============================================================
14578// mntent: setmntent/endmntent/getmntent/getmntent_r/addmntent/hasmntopt
14579// ============================================================
14580
14581#[no_mangle]
14582pub unsafe extern "C" fn setmntent(name: *const c_char, mode: *const c_char) -> *mut FILE {
14583    fopen(name, mode)
14584}
14585
14586#[no_mangle]
14587pub unsafe extern "C" fn endmntent(f: *mut FILE) -> c_int {
14588    if !f.is_null() {
14589        fclose(f);
14590    }
14591    1
14592}
14593
14594// ponytail: static buffers for getmntent (non-_r variant)
14595static mut MNTENT_MNT: MntEnt = MntEnt {
14596    mnt_fsname: core::ptr::null_mut(),
14597    mnt_dir: core::ptr::null_mut(),
14598    mnt_type: core::ptr::null_mut(),
14599    mnt_opts: core::ptr::null_mut(),
14600    mnt_freq: 0,
14601    mnt_passno: 0,
14602};
14603
14604#[repr(C)]
14605pub struct MntEnt {
14606    mnt_fsname: *mut c_char,
14607    mnt_dir: *mut c_char,
14608    mnt_type: *mut c_char,
14609    mnt_opts: *mut c_char,
14610    mnt_freq: c_int,
14611    mnt_passno: c_int,
14612}
14613
14614unsafe fn unescape_ent(beg: *mut c_char) -> *mut c_char {
14615    let mut dest = beg;
14616    let mut src = beg;
14617    while *src != 0 {
14618        if *src != b'\\' as c_char {
14619            *dest = *src;
14620            dest = dest.add(1);
14621            src = src.add(1);
14622            continue;
14623        }
14624        // backslash
14625        if *src.add(1) == b'\\' as c_char {
14626            src = src.add(1);
14627            *dest = *src;
14628            dest = dest.add(1);
14629            src = src.add(1);
14630            continue;
14631        }
14632        // octal escape
14633        let mut val: u8 = 0;
14634        let mut cnt = 0;
14635        let mut sp = src.add(1);
14636        while cnt < 3 && *sp >= b'0' as c_char && *sp <= b'7' as c_char {
14637            val = val * 8 + (*sp as u8 - b'0');
14638            sp = sp.add(1);
14639            cnt += 1;
14640        }
14641        if cnt > 0 {
14642            *dest = val as c_char;
14643            dest = dest.add(1);
14644            src = sp;
14645        } else {
14646            *dest = *src;
14647            dest = dest.add(1);
14648            src = src.add(1);
14649        }
14650    }
14651    *dest = 0;
14652    beg
14653}
14654
14655unsafe fn parse_mntent_line(
14656    linebuf: *mut c_char,
14657    mnt: *mut MntEnt,
14658) -> *mut MntEnt {
14659    let _len = strlen(linebuf as *const c_char);
14660    // skip comments and empty lines
14661    // parse: fsname dir type opts freq passno
14662    let mut p = linebuf;
14663    // skip leading whitespace
14664    while *p == b' ' as c_char || *p == b'\t' as c_char || *p == b'\n' as c_char || *p == b'\r' as c_char {
14665        p = p.add(1);
14666    }
14667    if *p == 0 || *p == b'#' as c_char {
14668        return core::ptr::null_mut();
14669    }
14670
14671    // fsname
14672    (*mnt).mnt_fsname = p;
14673    while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
14674        p = p.add(1);
14675    }
14676    if *p == 0 { return core::ptr::null_mut(); }
14677    *p = 0;
14678    p = p.add(1);
14679    while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14680
14681    // dir
14682    (*mnt).mnt_dir = p;
14683    while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
14684        p = p.add(1);
14685    }
14686    if *p == 0 { return core::ptr::null_mut(); }
14687    *p = 0;
14688    p = p.add(1);
14689    while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14690
14691    // type
14692    (*mnt).mnt_type = p;
14693    while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
14694        p = p.add(1);
14695    }
14696    if *p == 0 { return core::ptr::null_mut(); }
14697    *p = 0;
14698    p = p.add(1);
14699    while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14700
14701    // opts
14702    (*mnt).mnt_opts = p;
14703    while *p != 0 && *p != b' ' as c_char && *p != b'\t' as c_char && *p != b'\n' as c_char {
14704        p = p.add(1);
14705    }
14706    if *p != 0 {
14707        *p = 0;
14708        p = p.add(1);
14709    }
14710    if *(*mnt).mnt_opts == 0 {
14711        (*mnt).mnt_opts = b"defaults\0".as_ptr() as *mut c_char;
14712    }
14713
14714    // freq and passno
14715    (*mnt).mnt_freq = 0;
14716    (*mnt).mnt_passno = 0;
14717    // skip whitespace
14718    while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14719    if *p >= b'0' as c_char && *p <= b'9' as c_char {
14720        (*mnt).mnt_freq = (*p - b'0' as c_char) as c_int;
14721        p = p.add(1);
14722        while *p >= b'0' as c_char && *p <= b'9' as c_char {
14723            (*mnt).mnt_freq = (*mnt).mnt_freq * 10 + (*p - b'0' as c_char) as c_int;
14724            p = p.add(1);
14725        }
14726    }
14727    while *p == b' ' as c_char || *p == b'\t' as c_char { p = p.add(1); }
14728    if *p >= b'0' as c_char && *p <= b'9' as c_char {
14729        (*mnt).mnt_passno = (*p - b'0' as c_char) as c_int;
14730        p = p.add(1);
14731        while *p >= b'0' as c_char && *p <= b'9' as c_char {
14732            (*mnt).mnt_passno = (*mnt).mnt_passno * 10 + (*p - b'0' as c_char) as c_int;
14733            p = p.add(1);
14734        }
14735    }
14736
14737    // unescape
14738    unescape_ent((*mnt).mnt_fsname);
14739    unescape_ent((*mnt).mnt_dir);
14740    unescape_ent((*mnt).mnt_type);
14741    unescape_ent((*mnt).mnt_opts);
14742
14743    mnt
14744}
14745
14746// Use a sentinel pointer to detect internal buffer usage
14747// ponytail: cast integer to pointer for sentinel
14748static SENTINEL_PTR: usize = 1;
14749
14750// Read one char from FILE buffer directly (avoids musl's static fgets ABI mismatch)
14751unsafe fn mntent_fgetc(f: *mut FILE) -> c_int {
14752    fgetc(f)
14753}
14754
14755unsafe fn mntent_fgets(buf: *mut c_char, n: usize, f: *mut FILE) -> *mut c_char {
14756    if n == 0 { return core::ptr::null_mut(); }
14757    let max = n - 1;
14758    let mut i = 0usize;
14759    while i < max {
14760        let c = mntent_fgetc(f);
14761        if c == -1 { if i == 0 { return core::ptr::null_mut(); } break; }
14762        *buf.add(i) = c as c_char;
14763        i += 1;
14764        if c == b'\n' as c_int { break; }
14765    }
14766    *buf.add(i) = 0;
14767    buf
14768}
14769
14770#[no_mangle]
14771pub unsafe extern "C" fn getmntent_r(
14772    f: *mut FILE,
14773    mnt: *mut MntEnt,
14774    mut linebuf: *mut c_char,
14775    _buflen: c_int,
14776) -> *mut MntEnt {
14777    let use_internal = linebuf as usize == SENTINEL_PTR;
14778
14779    (*mnt).mnt_freq = 0;
14780    (*mnt).mnt_passno = 0;
14781
14782    // ponytail: static 4KB line buffer for getmntent
14783    static mut INTERNAL_BUF: [c_char; 4096] = [0; 4096];
14784
14785    loop {
14786        if use_internal {
14787            linebuf = core::ptr::addr_of_mut!(INTERNAL_BUF).cast::<c_char>();
14788        }
14789        let res = mntent_fgets(linebuf, 4096, f);
14790        if res.is_null() {
14791            return core::ptr::null_mut();
14792        }
14793        let mut has_newline = false;
14794        let mut p = linebuf;
14795        while *p != 0 { if *p == b'\n' as c_char { has_newline = true; break; } p = p.add(1); }
14796        if !has_newline {
14797            ERRNO = 34;
14798            return core::ptr::null_mut();
14799        }
14800        let result = parse_mntent_line(linebuf, mnt);
14801        if !result.is_null() {
14802            return result;
14803        }
14804    }
14805}
14806
14807#[no_mangle]
14808pub unsafe extern "C" fn getmntent(f: *mut FILE) -> *mut MntEnt {
14809    getmntent_r(f, core::ptr::addr_of_mut!(MNTENT_MNT), SENTINEL_PTR as *mut c_char, 0)
14810}
14811
14812#[no_mangle]
14813pub unsafe extern "C" fn addmntent(f: *mut FILE, mnt: *const MntEnt) -> c_int {
14814    fseek(f, 0, 2); // SEEK_END
14815    let written = fprintf(
14816        f,
14817        b"%s\t%s\t%s\t%s\t%d\t%d\n\0".as_ptr() as *const c_char,
14818        (*mnt).mnt_fsname,
14819        (*mnt).mnt_dir,
14820        (*mnt).mnt_type,
14821        (*mnt).mnt_opts,
14822        (*mnt).mnt_freq,
14823        (*mnt).mnt_passno,
14824    );
14825    if written < 0 { 1 } else { 0 }
14826}
14827
14828#[no_mangle]
14829pub unsafe extern "C" fn hasmntopt(mnt: *const MntEnt, opt: *const c_char) -> *mut c_char {
14830    let l = strlen(opt as *const c_char);
14831    let mut p = (*mnt).mnt_opts;
14832    loop {
14833        if strncmp(p as *const u8, opt as *const u8, l) == 0 {
14834            let after = *p.add(l);
14835            if after == 0 || after == b',' as c_char || after == b'=' as c_char {
14836                return p;
14837            }
14838        }
14839        let comma = strchr(p as *const u8, b',' as c_int);
14840        if comma.is_null() {
14841            return core::ptr::null_mut();
14842        }
14843        p = comma.add(1) as *mut c_char;
14844    }
14845}
14846
14847// ============================================================
14848// SysV IPC: ftok, msg*, sem*, shm*
14849// x86_64 direct syscalls: msgget=68, msgsnd=69, msgrcv=70, msgctl=71
14850//   semget=64, semop=65, semctl=66, semtimedop=220
14851//   shmget=29, shmat=30, shmctl=31, shmdt=67
14852// ============================================================
14853
14854const EEXIST: c_int = 17;
14855const ENAMETOOLONG: c_int = 36;
14856const EMFILE: c_int = 24;
14857const EIDRM: c_int = 43;
14858
14859#[inline]
14860unsafe fn sys_msgget(key: c_int, msgflg: c_int) -> i64 {
14861    <Arch as Syscalls>::syscall2(SYS_MSGGET, key as i64, msgflg as i64)
14862}
14863
14864#[inline]
14865unsafe fn sys_msgsnd(msqid: c_int, msgp: *const c_void, msgsz: usize, msgflg: c_int) -> i64 {
14866    <Arch as Syscalls>::syscall4(SYS_MSGSND, msqid as i64, msgp as i64, msgsz as i64, msgflg as i64)
14867}
14868
14869#[inline]
14870unsafe fn sys_msgrcv(msqid: c_int, msgp: *mut c_void, msgsz: usize, msgtyp: c_long, msgflg: c_int) -> i64 {
14871    <Arch as Syscalls>::syscall5(SYS_MSGRCV, msqid as i64, msgp as i64, msgsz as i64, msgtyp as i64, msgflg as i64)
14872}
14873
14874#[inline]
14875unsafe fn sys_msgctl(msqid: c_int, cmd: c_int, buf: *mut c_void) -> i64 {
14876    <Arch as Syscalls>::syscall3(SYS_MSGCTL, msqid as i64, cmd as i64, buf as i64)
14877}
14878
14879#[inline]
14880unsafe fn sys_semget(key: c_int, nsems: c_int, semflg: c_int) -> i64 {
14881    <Arch as Syscalls>::syscall3(SYS_SEMGET, key as i64, nsems as i64, semflg as i64)
14882}
14883
14884#[inline]
14885unsafe fn sys_semop(semid: c_int, sops: *const c_void, nsops: usize) -> i64 {
14886    <Arch as Syscalls>::syscall3(SYS_SEMOP, semid as i64, sops as i64, nsops as i64)
14887}
14888
14889#[inline]
14890unsafe fn sys_semctl(semid: c_int, semnum: c_int, cmd: c_int, arg: *mut c_void) -> i64 {
14891    <Arch as Syscalls>::syscall4(SYS_SEMCTL, semid as i64, semnum as i64, cmd as i64, arg as i64)
14892}
14893
14894#[inline]
14895unsafe fn sys_shmget(key: c_int, size: usize, shmflg: c_int) -> i64 {
14896    <Arch as Syscalls>::syscall3(SYS_SHMGET, key as i64, size as i64, shmflg as i64)
14897}
14898
14899#[inline]
14900unsafe fn sys_shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> i64 {
14901    <Arch as Syscalls>::syscall3(SYS_SHMAT, shmid as i64, shmaddr as i64, shmflg as i64)
14902}
14903
14904#[inline]
14905unsafe fn sys_shmdt(shmaddr: *const c_void) -> i64 {
14906    <Arch as Syscalls>::syscall1(SYS_SHMDT, shmaddr as i64)
14907}
14908
14909#[inline]
14910unsafe fn sys_shmctl(shmid: c_int, cmd: c_int, buf: *mut c_void) -> i64 {
14911    <Arch as Syscalls>::syscall3(SYS_SHMCTL, shmid as i64, cmd as i64, buf as i64)
14912}
14913
14914// ftok
14915#[no_mangle]
14916pub unsafe extern "C" fn ftok(path: *const c_char, id: c_int) -> c_int {
14917    let mut st: kernel_stat64 = core::mem::zeroed();
14918    let r = sys_stat(path as *const u8, &mut st);
14919    if r < 0 {
14920        ERRNO = (-r) as c_int;
14921        return -1;
14922    }
14923    ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16) | (((id as u32 & 0xff) << 24)) as u64) as c_int
14924}
14925
14926// msgget
14927#[no_mangle]
14928pub unsafe extern "C" fn msgget(key: c_int, msgflg: c_int) -> c_int {
14929    let r = sys_msgget(key, msgflg);
14930    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14931}
14932
14933// msgsnd
14934#[no_mangle]
14935pub unsafe extern "C" fn msgsnd(msqid: c_int, msgp: *const c_void, msgsz: usize, msgflg: c_int) -> c_int {
14936    let r = sys_msgsnd(msqid, msgp, msgsz, msgflg);
14937    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14938}
14939
14940// msgrcv
14941#[no_mangle]
14942pub unsafe extern "C" fn msgrcv(msqid: c_int, msgp: *mut c_void, msgsz: usize, msgtyp: c_long, msgflg: c_int) -> isize {
14943    let r = sys_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
14944    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
14945}
14946
14947// msgctl
14948#[no_mangle]
14949pub unsafe extern "C" fn msgctl(msqid: c_int, cmd: c_int, buf: *mut c_void) -> c_int {
14950    let r = sys_msgctl(msqid, cmd, buf);
14951    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14952}
14953
14954// semget
14955#[no_mangle]
14956pub unsafe extern "C" fn semget(key: c_int, nsems: c_int, semflg: c_int) -> c_int {
14957    if nsems > 65535 { ERRNO = 22; return -1; }
14958    let r = sys_semget(key, nsems, semflg);
14959    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14960}
14961
14962// semop
14963#[no_mangle]
14964pub unsafe extern "C" fn semop(semid: c_int, sops: *const c_void, nsops: usize) -> c_int {
14965    let r = sys_semop(semid, sops, nsops);
14966    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14967}
14968
14969// semctl - C variadic
14970#[no_mangle]
14971pub unsafe extern "C" fn semctl(semid: c_int, semnum: c_int, cmd: c_int, mut args: ...) -> c_int {
14972    let mut arg: *mut c_void = core::ptr::null_mut();
14973    // Commands that take the union semun argument
14974    match cmd {
14975        16 | 13 | 17 | 1 | 3 | 2 | 0x102 | 0x104 | 0x106 => {
14976            arg = args.next_arg::<*mut c_void>();
14977        }
14978        _ => {}
14979    }
14980    let r = sys_semctl(semid, semnum, cmd, arg);
14981    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14982}
14983
14984// shmget
14985#[no_mangle]
14986pub unsafe extern "C" fn shmget(key: c_int, size: usize, shmflg: c_int) -> c_int {
14987    let r = sys_shmget(key, size, shmflg);
14988    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
14989}
14990
14991// shmat
14992#[no_mangle]
14993pub unsafe extern "C" fn shmat(shmid: c_int, shmaddr: *const c_void, shmflg: c_int) -> *mut c_void {
14994    let r = sys_shmat(shmid, shmaddr, shmflg);
14995    if (r as usize) > (-(4096isize as isize)) as usize {
14996        ERRNO = (-r) as c_int;
14997        return core::ptr::null_mut();
14998    }
14999    r as *mut c_void
15000}
15001
15002// shmdt
15003#[no_mangle]
15004pub unsafe extern "C" fn shmdt(shmaddr: *const c_void) -> c_int {
15005    let r = sys_shmdt(shmaddr);
15006    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
15007}
15008
15009// shmctl
15010#[no_mangle]
15011pub unsafe extern "C" fn shmctl(shmid: c_int, cmd: c_int, buf: *mut c_void) -> c_int {
15012    let r = sys_shmctl(shmid, cmd, buf);
15013    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
15014}
15015
15016// ============================================================
15017// Startup: __libc_start_main
15018//
15019// musl crt1.o _start_c calls:
15020//   __libc_start_main(main, argc, argv, _init, _fini, rtld_fini, stack_end)
15021// ============================================================
15022
15023// Auxiliary vector pointer, populated by the dynamic linker before
15024// constructors run so getauxval() works during early startup.
15025#[no_mangle]
15026pub static mut __auxv: *const usize = core::ptr::null();
15027
15028#[no_mangle]
15029pub static mut __progname: *mut c_char = core::ptr::null_mut();
15030#[no_mangle]
15031pub static mut __progname_full: *mut c_char = core::ptr::null_mut();
15032#[no_mangle]
15033pub static mut program_invocation_name: *mut c_char = core::ptr::null_mut();
15034#[no_mangle]
15035pub static mut program_invocation_short_name: *mut c_char = core::ptr::null_mut();
15036
15037#[no_mangle]
15038pub static in6addr_any: [u8; 16] = [0; 16];
15039#[no_mangle]
15040pub static in6addr_loopback: [u8; 16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1];
15041
15042#[no_mangle]
15043pub static mut __daylight: c_int = 0;
15044#[no_mangle]
15045pub static mut __timezone: c_long = 0;
15046#[no_mangle]
15047pub static mut __tzname: [*mut c_char; 2] = [core::ptr::null_mut(); 2];
15048
15049#[no_mangle]
15050pub unsafe extern "C" fn getauxval(type_: c_ulong) -> c_ulong {
15051    let mut p = __auxv;
15052    if p.is_null() {
15053        return 0;
15054    }
15055    loop {
15056        let tag = *p;
15057        if tag == 0 {
15058            return 0;
15059        }
15060        if tag == type_ as usize {
15061            return *p.add(1) as c_ulong;
15062        }
15063        p = p.add(2);
15064    }
15065}
15066
15067type MainFn = unsafe extern "C" fn(c_int, *const *const c_char, *const *const c_char) -> c_int;
15068type InitFn = unsafe extern "C" fn();
15069
15070#[no_mangle]
15071pub unsafe extern "C" fn __libc_start_main(
15072    main: MainFn,
15073    argc: c_int,
15074    argv: *const *const c_char,
15075    _init: *const c_void,
15076    _fini: *const c_void,
15077    _rtld_fini: *const c_void,
15078    _stack_end: *const c_void,
15079) -> ! {
15080    let envp = argv.add((argc + 1) as usize);
15081    __environ = envp as *mut *mut c_char;
15082    environ = __environ; // sync environ alias
15083    ___environ = __environ;
15084    _environ = __environ;
15085
15086    // glibc-compatible program name globals.
15087    if !argv.is_null() && argc > 0 {
15088        let argv0 = *argv;
15089        __progname_full = argv0 as *mut c_char;
15090        program_invocation_name = argv0 as *mut c_char;
15091        let mut base = argv0;
15092        let mut p = argv0;
15093        while *p != 0 {
15094            if *p == b'/' as c_char { base = p.add(1); }
15095            p = p.add(1);
15096        }
15097        __progname = base as *mut c_char;
15098        program_invocation_short_name = base as *mut c_char;
15099    }
15100
15101    __stdio_init();
15102
15103    let mut set: SigSetT = 0;
15104    sigemptyset(&mut set);
15105    sigaddset(&mut set, SIGCANCEL);
15106    sigprocmask(SIG_UNBLOCK, &set, core::ptr::null_mut());
15107
15108    if !_init.is_null() {
15109        let init_fn: InitFn = core::mem::transmute(_init);
15110        init_fn();
15111    }
15112
15113    // aarch64/riscv64 GCC reads __stack_chk_guard as a global (GOT-based for PIE),
15114    // so we must initialize it from AT_RANDOM before calling main.
15115    // x86_64 uses %fs:0x28 which the kernel already set up.
15116    #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
15117    {
15118        let random_ptr = getauxval(25) as *const u8; // AT_RANDOM = 25
15119        if !random_ptr.is_null() {
15120            let a = core::ptr::read_unaligned(random_ptr as *const u64);
15121            let b = core::ptr::read_unaligned(random_ptr.add(8) as *const u64);
15122            __stack_chk_guard = (a ^ b) as usize;
15123        } else {
15124            // ponytail: fallback entropy, not crypto-grade but nonzero
15125            __stack_chk_guard = 0xdefaced_cafebeef;
15126        }
15127    }
15128
15129    let result = main(argc, argv, envp);
15130
15131    if !_fini.is_null() {
15132        let fini_fn: InitFn = core::mem::transmute(_fini);
15133        fini_fn();
15134    }
15135
15136    exit(result);
15137}
15138
15139type LdsoDlopenFn = unsafe extern "C" fn(*const c_char, c_int) -> *mut c_void;
15140type LdsoDlsymFn = unsafe extern "C" fn(*mut c_void, *const c_char) -> *mut c_void;
15141type LdsoDlcloseFn = unsafe extern "C" fn(*mut c_void) -> c_int;
15142type LdsoDlerrorFn = unsafe extern "C" fn() -> *const c_char;
15143
15144static mut LDSO_DLOPEN: Option<LdsoDlopenFn> = None;
15145static mut LDSO_DLSYM: Option<LdsoDlsymFn> = None;
15146static mut LDSO_DLCLOSE: Option<LdsoDlcloseFn> = None;
15147static mut LDSO_DLERROR: Option<LdsoDlerrorFn> = None;
15148
15149#[no_mangle]
15150pub unsafe extern "C" fn __ldso_register_dlopen(f: LdsoDlopenFn) {
15151    LDSO_DLOPEN = Some(f);
15152}
15153
15154#[no_mangle]
15155pub unsafe extern "C" fn __ldso_register_dlsym(f: LdsoDlsymFn) {
15156    LDSO_DLSYM = Some(f);
15157}
15158
15159#[no_mangle]
15160pub unsafe extern "C" fn __ldso_register_dlclose(f: LdsoDlcloseFn) {
15161    LDSO_DLCLOSE = Some(f);
15162}
15163
15164#[no_mangle]
15165pub unsafe extern "C" fn __ldso_register_dlerror(f: LdsoDlerrorFn) {
15166    LDSO_DLERROR = Some(f);
15167}
15168
15169#[no_mangle]
15170pub unsafe extern "C" fn dlopen(filename: *const c_char, flags: c_int) -> *mut c_void {
15171    if let Some(f) = LDSO_DLOPEN {
15172        f(filename, flags)
15173    } else {
15174        null_mut()
15175    }
15176}
15177
15178#[no_mangle]
15179pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void {
15180    if let Some(f) = LDSO_DLSYM {
15181        f(handle, symbol)
15182    } else {
15183        null_mut()
15184    }
15185}
15186
15187#[no_mangle]
15188pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
15189    if let Some(f) = LDSO_DLCLOSE {
15190        f(handle)
15191    } else {
15192        0
15193    }
15194}
15195
15196#[no_mangle]
15197pub unsafe extern "C" fn dlerror() -> *const c_char {
15198    if let Some(f) = LDSO_DLERROR {
15199        f()
15200    } else {
15201        core::ptr::null()
15202    }
15203}
15204
15205include!("crypt_impl.rs");
15206include!("statvfs.rs");
15207include!("daemon.rs");
15208include!("dn_expand.rs");
15209include!("lrand48.rs");
15210include!("strverscmp.rs");
15211include!("syscall.rs");
15212include!("pthread_atfork.rs");
15213include!("fenv.rs");
15214include!("locale_ctype.rs");
15215include!("regression_stubs.rs");
15216include!("netdb_extra.rs");
15217include!("compat_extra.rs");
15218include!("stdio_extra.rs");
15219include!("ns_parse.rs");
15220include!("fts.rs");
15221include!("ifaddrs.rs");
15222include!("dl_extra.rs");
15223include!("des.rs");
15224include!("path_extra.rs");
15225include!("wordexp.rs");
15226include!("getopt_impl.rs");
15227
15228// ============================================================
15229// regex.h
15230// ============================================================
15231
15232type regoff_t = c_int;
15233
15234#[repr(C)]
15235pub struct regex_t {
15236    pub re_nsub: usize,
15237    pub __opaque: *mut c_void,
15238    pub __padding: [*mut c_void; 4],
15239    pub __nsub2: usize,
15240    pub __padding2: c_char,
15241}
15242
15243#[repr(C)]
15244pub struct regmatch_t {
15245    pub rm_so: regoff_t,
15246    pub rm_eo: regoff_t,
15247}
15248
15249include!("regex.rs");
15250
15251#[cfg(test)]
15252mod libc_unit_stub {
15253    #[test]
15254    fn stub() {
15255        assert!(true);
15256    }
15257}
15258
15259// ============================================================
15260// Missing math functions - simple implementations
15261// ============================================================
15262
15263#[inline]
15264pub(crate) fn fmax_impl(x: f64, y: f64) -> f64 {
15265    if x.is_nan() { return y; }
15266    if y.is_nan() { return x; }
15267    if x == 0.0 && y == 0.0 {
15268        return if x.is_sign_negative() && y.is_sign_negative() { -0.0 } else { 0.0 };
15269    }
15270    if x > y { x } else { y }
15271}
15272
15273#[inline]
15274pub(crate) fn fmin_impl(x: f64, y: f64) -> f64 {
15275    if x.is_nan() { return y; }
15276    if y.is_nan() { return x; }
15277    if x == 0.0 && y == 0.0 {
15278        return if x.is_sign_negative() || y.is_sign_negative() { -0.0 } else { 0.0 };
15279    }
15280    if x < y { x } else { y }
15281}
15282
15283#[inline]
15284pub(crate) fn fmaxf_impl(x: f32, y: f32) -> f32 {
15285    if x.is_nan() { return y; }
15286    if y.is_nan() { return x; }
15287    if x == 0.0 && y == 0.0 {
15288        return if x.is_sign_negative() && y.is_sign_negative() { -0.0 } else { 0.0 };
15289    }
15290    if x > y { x } else { y }
15291}
15292
15293#[inline]
15294pub(crate) fn fminf_impl(x: f32, y: f32) -> f32 {
15295    if x.is_nan() { return y; }
15296    if y.is_nan() { return x; }
15297    if x == 0.0 && y == 0.0 {
15298        return if x.is_sign_negative() || y.is_sign_negative() { -0.0 } else { 0.0 };
15299    }
15300    if x < y { x } else { y }
15301}
15302
15303#[inline(never)]
15304#[no_mangle]
15305pub unsafe extern "C" fn fmax(x: f64, y: f64) -> f64 {
15306    fmax_impl(x, y)
15307}
15308
15309#[inline(never)]
15310#[no_mangle]
15311pub unsafe extern "C" fn fmin(x: f64, y: f64) -> f64 {
15312    fmin_impl(x, y)
15313}
15314
15315#[no_mangle]
15316pub unsafe extern "C" fn fminf(x: f32, y: f32) -> f32 {
15317    fminf_impl(x, y)
15318}
15319
15320#[no_mangle]
15321pub unsafe extern "C" fn fdim(x: f64, y: f64) -> f64 {
15322    if x.is_nan() || y.is_nan() {
15323        return f64::NAN;
15324    }
15325    if x > y { x - y } else { 0.0 }
15326}
15327
15328#[no_mangle]
15329pub unsafe extern "C" fn fma(x: f64, y: f64, z: f64) -> f64 {
15330    if (x.is_infinite() && y == 0.0) || (y.is_infinite() && x == 0.0) {
15331        feraiseexcept(FE_INVALID);
15332        return f64::NAN;
15333    }
15334    if x.is_nan() || y.is_nan() || z.is_nan() {
15335        return f64::NAN;
15336    }
15337    let r = libm::fma(x, y, z);
15338    // inf-inf is invalid; libm may return NaN without raising.
15339    if r.is_nan() {
15340        feraiseexcept(FE_INVALID);
15341    }
15342    r
15343}
15344
15345#[no_mangle]
15346pub unsafe extern "C" fn ilogb(x: f64) -> i32 {
15347    if x.is_nan() {
15348        feraiseexcept(FE_INVALID);
15349        return -0x7fffffff - 1; // FP_ILOGBNAN
15350    }
15351    if x == 0.0 || x.is_infinite() {
15352        feraiseexcept(FE_INVALID);
15353        return if x == 0.0 { -0x7fffffff - 1 } else { 0x7fffffff };
15354    }
15355    let bits = x.to_bits();
15356    let exp = ((bits >> 52) & 0x7ff) as i32;
15357    if exp == 0 {
15358        // subnormal
15359        let mut v = bits & 0xfffffffffffff;
15360        let mut e = -1022;
15361        while v < (1u64 << 52) { v <<= 1; e -= 1; }
15362        e
15363    } else {
15364        exp - 1023
15365    }
15366}
15367
15368#[no_mangle]
15369pub unsafe extern "C" fn logb(x: f64) -> f64 {
15370    if x.is_nan() { return x; }
15371    if x == 0.0 { return __math_divzero(1); }
15372    let bits = x.to_bits();
15373    let exp = ((bits >> 52) & 0x7ff) as i32;
15374    if exp == 0 {
15375        // subnormal
15376        let mut v = bits & 0xfffffffffffff;
15377        let mut e = -1022i32;
15378        while v < (1u64 << 52) { v <<= 1; e -= 1; }
15379        e as f64
15380    } else if exp == 0x7ff {
15381        x * x // infinity * infinity = infinity (preserves sign)
15382    } else {
15383        (exp - 1023) as f64
15384    }
15385}
15386
15387#[no_mangle]
15388pub unsafe extern "C" fn nearbyint(x: f64) -> f64 {
15389    let had_inexact = fetestexcept(FE_INEXACT) & FE_INEXACT != 0;
15390    let r = libm::rint(x);
15391    if !had_inexact {
15392        feclearexcept(FE_INEXACT);
15393    }
15394    r
15395}
15396
15397#[no_mangle]
15398pub unsafe extern "C" fn nextafter(x: f64, y: f64) -> f64 {
15399    if x.is_nan() || y.is_nan() { return x + y; }
15400    if x == 0.0 && y == 0.0 { return y; }
15401    if x == y { return x; }
15402    let r = libm::nextafter(x, y);
15403    if r.is_infinite() && x.is_finite() {
15404        feraiseexcept(FE_OVERFLOW | FE_INEXACT);
15405    } else if r != x {
15406        let bits = r.to_bits();
15407        let is_subnormal = (bits & 0x7ff0000000000000) == 0 && (bits & 0xfffffffffffff) != 0;
15408        if r == 0.0 || is_subnormal {
15409            feraiseexcept(FE_UNDERFLOW | FE_INEXACT);
15410        }
15411    }
15412    r
15413}
15414
15415#[no_mangle]
15416pub unsafe extern "C" fn nexttoward(x: f64, y: f64) -> f64 {
15417    // On x86_64, long double = f64, so nexttoward = nextafter
15418    if x == 0.0 && y == 0.0 {
15419        return if y.is_sign_negative() { -0.0 } else { 0.0 };
15420    }
15421    nextafter(x, y)
15422}
15423
15424#[no_mangle]
15425pub unsafe extern "C" fn remainder(x: f64, y: f64) -> f64 {
15426    if x.is_nan() || y.is_nan() { return x + y; }
15427    if y == 0.0 || x.is_infinite() { return __math_invalid(x); }
15428    libm::remainder(x, y)
15429}
15430
15431#[no_mangle]
15432pub unsafe extern "C" fn remquo(x: f64, y: f64, quo: *mut i32) -> f64 {
15433    if x.is_nan() || y.is_nan() {
15434        if !quo.is_null() { *quo = 0; }
15435        return x + y;
15436    }
15437    if y == 0.0 || x.is_infinite() {
15438        if !quo.is_null() { *quo = 0; }
15439        return __math_invalid(x);
15440    }
15441    let (r, q) = libm::remquo(x, y);
15442    if !quo.is_null() { *quo = q; }
15443    r
15444}
15445
15446#[no_mangle]
15447pub unsafe extern "C" fn exp2(x: f64) -> f64 {
15448    exp2_impl(x)
15449}
15450
15451#[no_mangle]
15452pub unsafe extern "C" fn expm1(x: f64) -> f64 {
15453    let r = libm::expm1(x);
15454    // Raise UNDERFLOW for very small results that underflow
15455    if r != 0.0 && x != 0.0 && libm::fabs(x) < 1e-307 {
15456        feraiseexcept(FE_UNDERFLOW | FE_INEXACT);
15457    }
15458    r
15459}
15460
15461#[no_mangle]
15462pub unsafe extern "C" fn log1p(x: f64) -> f64 {
15463    if x == -1.0 {
15464        feraiseexcept(FE_DIVBYZERO);
15465        return f64::NEG_INFINITY;
15466    }
15467    libm::log1p(x)
15468}
15469
15470#[no_mangle]
15471pub unsafe extern "C" fn acosh(x: f64) -> f64 {
15472    if x < 1.0 {
15473        feraiseexcept(FE_INVALID);
15474        return f64::NAN;
15475    }
15476    libm::acosh(x)
15477}
15478
15479#[no_mangle]
15480pub unsafe extern "C" fn asinh(x: f64) -> f64 {
15481    if x == 0.0 { return x; }
15482    libm::asinh(x)
15483}
15484
15485#[no_mangle]
15486pub unsafe extern "C" fn atanh(x: f64) -> f64 {
15487    if x == 0.0 { return x; }
15488    let e = ((x.to_bits() >> 52) & 0x7ff) as i32;
15489    if e < 0x3ff - 32 {
15490        feraiseexcept(FE_INEXACT);
15491        if e == 0 { feraiseexcept(FE_UNDERFLOW); }
15492        return x;
15493    }
15494    if x == 1.0 {
15495        feraiseexcept(FE_DIVBYZERO);
15496        return f64::INFINITY;
15497    }
15498    if x == -1.0 {
15499        feraiseexcept(FE_DIVBYZERO);
15500        return f64::NEG_INFINITY;
15501    }
15502    if x.is_nan() { return x; }
15503    let ax = libm::fabs(x);
15504    if ax > 1.0 {
15505        feraiseexcept(FE_INVALID);
15506        return f64::NAN;
15507    }
15508    if ax < 0.5 {
15509        // For small x: use log1p formula with |x| and negate
15510        let r = libm::log1p(2.0 * (ax + ax * ax / (1.0 - ax))) / 2.0;
15511        if x < 0.0 { -r } else { r }
15512    } else {
15513        // For larger x: use log formula with |x| and negate
15514        let r = 0.5 * libm::log((1.0 + ax) / (1.0 - ax));
15515        if x < 0.0 { -r } else { r }
15516    }
15517}
15518
15519#[no_mangle]
15520pub unsafe extern "C" fn cbrt(x: f64) -> f64 {
15521    libm::cbrt(x)
15522}
15523
15524#[no_mangle]
15525pub unsafe extern "C" fn erf(x: f64) -> f64 {
15526    erf_impl(x)
15527}
15528
15529#[no_mangle]
15530pub unsafe extern "C" fn erfc(x: f64) -> f64 {
15531    erfc_impl(x)
15532}
15533
15534#[no_mangle]
15535pub unsafe extern "C" fn lgamma(x: f64) -> f64 {
15536    lgamma_impl(x)
15537}
15538
15539#[no_mangle]
15540pub unsafe extern "C" fn tgamma(x: f64) -> f64 {
15541    tgamma_impl(x)
15542}
15543
15544#[no_mangle]
15545pub unsafe extern "C" fn lround(x: f64) -> core::ffi::c_long {
15546    libm::round(x) as core::ffi::c_long
15547}
15548
15549#[no_mangle]
15550pub unsafe extern "C" fn llround(x: f64) -> i64 {
15551    libm::round(x) as i64
15552}
15553
15554// ============================================================
15555// Complex math functions - using (f64, f64) pairs
15556// ============================================================
15557
15558// Helper: complex number as (real, imag) pair
15559// cabs: magnitude = sqrt(re^2 + im^2)
15560#[no_mangle]
15561pub unsafe extern "C" fn cabs(z: (f64, f64)) -> f64 {
15562    libm::sqrt(z.0 * z.0 + z.1 * z.1)
15563}
15564
15565#[no_mangle]
15566pub unsafe extern "C" fn cabsf(z: (f32, f32)) -> f32 {
15567    libm::sqrtf(z.0 * z.0 + z.1 * z.1)
15568}
15569
15570#[no_mangle]
15571pub unsafe extern "C" fn cabsl(z: (f64, f64)) -> f64 {
15572    cabs(z)
15573}
15574
15575#[no_mangle]
15576pub unsafe extern "C" fn carg(z: (f64, f64)) -> f64 {
15577    libm::atan2(z.1, z.0)
15578}
15579
15580#[no_mangle]
15581pub unsafe extern "C" fn cargf(z: (f32, f32)) -> f32 {
15582    libm::atan2f(z.1, z.0)
15583}
15584
15585#[no_mangle]
15586pub unsafe extern "C" fn cargl(z: (f64, f64)) -> f64 {
15587    carg(z)
15588}
15589
15590#[no_mangle]
15591pub unsafe extern "C" fn cimag(z: (f64, f64)) -> f64 {
15592    z.1
15593}
15594
15595#[no_mangle]
15596pub unsafe extern "C" fn cimagf(z: (f32, f32)) -> f32 {
15597    z.1
15598}
15599
15600#[no_mangle]
15601pub unsafe extern "C" fn cimagl(z: (f64, f64)) -> f64 {
15602    z.1
15603}
15604
15605#[no_mangle]
15606pub unsafe extern "C" fn creal(z: (f64, f64)) -> f64 {
15607    z.0
15608}
15609
15610#[no_mangle]
15611pub unsafe extern "C" fn crealf(z: (f32, f32)) -> f32 {
15612    z.0
15613}
15614
15615#[no_mangle]
15616pub unsafe extern "C" fn creall(z: (f64, f64)) -> f64 {
15617    z.0
15618}
15619
15620#[no_mangle]
15621pub unsafe extern "C" fn conj(z: (f64, f64)) -> (f64, f64) {
15622    (z.0, -z.1)
15623}
15624
15625#[no_mangle]
15626pub unsafe extern "C" fn conjf(z: (f32, f32)) -> (f32, f32) {
15627    (z.0, -z.1)
15628}
15629
15630#[no_mangle]
15631pub unsafe extern "C" fn conjl(z: (f64, f64)) -> (f64, f64) {
15632    conj(z)
15633}
15634
15635#[no_mangle]
15636pub unsafe extern "C" fn cproj(z: (f64, f64)) -> (f64, f64) {
15637    if z.0.is_infinite() || z.1.is_infinite() {
15638        (f64::INFINITY, if z.1.is_sign_positive() { 0.0 } else { -0.0 })
15639    } else {
15640        z
15641    }
15642}
15643
15644#[no_mangle]
15645pub unsafe extern "C" fn cprojf(z: (f32, f32)) -> (f32, f32) {
15646    if z.0.is_infinite() || z.1.is_infinite() {
15647        (f32::INFINITY, if z.1.is_sign_positive() { 0.0 } else { -0.0 })
15648    } else {
15649        z
15650    }
15651}
15652
15653#[no_mangle]
15654pub unsafe extern "C" fn cprojl(z: (f64, f64)) -> (f64, f64) {
15655    cproj(z)
15656}
15657
15658// cexp: e^z = e^(re + i*im) = e^re * (cos(im) + i*sin(im))
15659#[no_mangle]
15660pub unsafe extern "C" fn cexp(z: (f64, f64)) -> (f64, f64) {
15661    let r = libm::exp(z.0);
15662    (r * libm::cos(z.1), r * libm::sin(z.1))
15663}
15664
15665#[no_mangle]
15666pub unsafe extern "C" fn cexpf(z: (f32, f32)) -> (f32, f32) {
15667    let r = libm::expf(z.0);
15668    (r * libm::cosf(z.1), r * libm::sinf(z.1))
15669}
15670
15671#[no_mangle]
15672pub unsafe extern "C" fn cexpl(z: (f64, f64)) -> (f64, f64) {
15673    cexp(z)
15674}
15675
15676// clog: ln(z) = ln|z| + i*arg(z)
15677#[no_mangle]
15678pub unsafe extern "C" fn clog(z: (f64, f64)) -> (f64, f64) {
15679    (libm::log(cabs(z)), carg(z))
15680}
15681
15682#[no_mangle]
15683pub unsafe extern "C" fn clogf(z: (f32, f32)) -> (f32, f32) {
15684    (libm::logf(cabsf(z)), cargf(z))
15685}
15686
15687#[no_mangle]
15688pub unsafe extern "C" fn clogl(z: (f64, f64)) -> (f64, f64) {
15689    clog(z)
15690}
15691
15692// csqrt: sqrt(z) = sqrt((|z|+re)/2) + i*sign(im)*sqrt((|z|-re)/2)
15693#[no_mangle]
15694pub unsafe extern "C" fn csqrt(z: (f64, f64)) -> (f64, f64) {
15695    let r = cabs(z);
15696    let sign = if z.1 < 0.0 { -1.0 } else { 1.0 };
15697    (libm::sqrt((r + z.0) / 2.0), sign * libm::sqrt((r - z.0) / 2.0))
15698}
15699
15700#[no_mangle]
15701pub unsafe extern "C" fn csqrtf(z: (f32, f32)) -> (f32, f32) {
15702    let r = cabsf(z);
15703    let sign = if z.1 < 0.0 { -1.0f32 } else { 1.0f32 };
15704    (libm::sqrtf((r + z.0) / 2.0), sign * libm::sqrtf((r - z.0) / 2.0))
15705}
15706
15707#[no_mangle]
15708pub unsafe extern "C" fn csqrtl(z: (f64, f64)) -> (f64, f64) {
15709    csqrt(z)
15710}
15711
15712// cpow: z^w = e^(w * log(z))
15713#[no_mangle]
15714pub unsafe extern "C" fn cpow(z: (f64, f64), w: (f64, f64)) -> (f64, f64) {
15715    let log_z = clog(z);
15716    let exp_arg = (w.0 * log_z.0 - w.1 * log_z.1, w.0 * log_z.1 + w.1 * log_z.0);
15717    cexp(exp_arg)
15718}
15719
15720#[no_mangle]
15721pub unsafe extern "C" fn cpowf(z: (f32, f32), w: (f32, f32)) -> (f32, f32) {
15722    let log_z = clogf(z);
15723    let exp_arg = (w.0 * log_z.0 - w.1 * log_z.1, w.0 * log_z.1 + w.1 * log_z.0);
15724    cexpf(exp_arg)
15725}
15726
15727#[no_mangle]
15728pub unsafe extern "C" fn cpowl(z: (f64, f64), w: (f64, f64)) -> (f64, f64) {
15729    cpow(z, w)
15730}
15731
15732// ccos: cos(z) = cos(re)*cosh(im) - i*sin(re)*sinh(im)
15733#[no_mangle]
15734pub unsafe extern "C" fn ccos(z: (f64, f64)) -> (f64, f64) {
15735    (libm::cos(z.0) * libm::cosh(z.1), -libm::sin(z.0) * libm::sinh(z.1))
15736}
15737
15738#[no_mangle]
15739pub unsafe extern "C" fn ccosf(z: (f32, f32)) -> (f32, f32) {
15740    (libm::cosf(z.0) * libm::coshf(z.1), -libm::sinf(z.0) * libm::sinhf(z.1))
15741}
15742
15743#[no_mangle]
15744pub unsafe extern "C" fn ccosl(z: (f64, f64)) -> (f64, f64) {
15745    ccos(z)
15746}
15747
15748// csin: sin(z) = sin(re)*cosh(im) + i*cos(re)*sinh(im)
15749#[no_mangle]
15750pub unsafe extern "C" fn csin(z: (f64, f64)) -> (f64, f64) {
15751    (libm::sin(z.0) * libm::cosh(z.1), libm::cos(z.0) * libm::sinh(z.1))
15752}
15753
15754#[no_mangle]
15755pub unsafe extern "C" fn csinf(z: (f32, f32)) -> (f32, f32) {
15756    (libm::sinf(z.0) * libm::coshf(z.1), libm::cosf(z.0) * libm::sinhf(z.1))
15757}
15758
15759#[no_mangle]
15760pub unsafe extern "C" fn csinl(z: (f64, f64)) -> (f64, f64) {
15761    csin(z)
15762}
15763
15764// ctan: tan(z) = sin(2re)/(cos(2re)+cosh(2im)) + i*sinh(2im)/(cos(2re)+cosh(2im))
15765#[no_mangle]
15766pub unsafe extern "C" fn ctan(z: (f64, f64)) -> (f64, f64) {
15767    let d = libm::cos(2.0 * z.0) + libm::cosh(2.0 * z.1);
15768    (libm::sin(2.0 * z.0) / d, libm::sinh(2.0 * z.1) / d)
15769}
15770
15771#[no_mangle]
15772pub unsafe extern "C" fn ctanf(z: (f32, f32)) -> (f32, f32) {
15773    let d = libm::cosf(2.0 * z.0) + libm::coshf(2.0 * z.1);
15774    (libm::sinf(2.0 * z.0) / d, libm::sinhf(2.0 * z.1) / d)
15775}
15776
15777#[no_mangle]
15778pub unsafe extern "C" fn ctanl(z: (f64, f64)) -> (f64, f64) {
15779    ctan(z)
15780}
15781
15782// ccosh: cosh(z) = cosh(re)*cos(im) + i*sinh(re)*sin(im)
15783#[no_mangle]
15784pub unsafe extern "C" fn ccosh(z: (f64, f64)) -> (f64, f64) {
15785    (libm::cosh(z.0) * libm::cos(z.1), libm::sinh(z.0) * libm::sin(z.1))
15786}
15787
15788#[no_mangle]
15789pub unsafe extern "C" fn ccoshf(z: (f32, f32)) -> (f32, f32) {
15790    (libm::coshf(z.0) * libm::cosf(z.1), libm::sinhf(z.0) * libm::sinf(z.1))
15791}
15792
15793#[no_mangle]
15794pub unsafe extern "C" fn ccoshl(z: (f64, f64)) -> (f64, f64) {
15795    ccosh(z)
15796}
15797
15798// csinh: sinh(z) = sinh(re)*cos(im) + i*cosh(re)*sin(im)
15799#[no_mangle]
15800pub unsafe extern "C" fn csinh(z: (f64, f64)) -> (f64, f64) {
15801    (libm::sinh(z.0) * libm::cos(z.1), libm::cosh(z.0) * libm::sin(z.1))
15802}
15803
15804#[no_mangle]
15805pub unsafe extern "C" fn csinhf(z: (f32, f32)) -> (f32, f32) {
15806    (libm::sinhf(z.0) * libm::cosf(z.1), libm::coshf(z.0) * libm::sinf(z.1))
15807}
15808
15809#[no_mangle]
15810pub unsafe extern "C" fn csinhl(z: (f64, f64)) -> (f64, f64) {
15811    csinh(z)
15812}
15813
15814// ctanh: tanh(z) = sinh(2re)/(cosh(2re)+cos(2im)) + i*sin(2im)/(cosh(2re)+cos(2im))
15815#[no_mangle]
15816pub unsafe extern "C" fn ctanh(z: (f64, f64)) -> (f64, f64) {
15817    let d = libm::cosh(2.0 * z.0) + libm::cos(2.0 * z.1);
15818    (libm::sinh(2.0 * z.0) / d, libm::sin(2.0 * z.1) / d)
15819}
15820
15821#[no_mangle]
15822pub unsafe extern "C" fn ctanhf(z: (f32, f32)) -> (f32, f32) {
15823    let d = libm::coshf(2.0 * z.0) + libm::cosf(2.0 * z.1);
15824    (libm::sinhf(2.0 * z.0) / d, libm::sinf(2.0 * z.1) / d)
15825}
15826
15827#[no_mangle]
15828pub unsafe extern "C" fn ctanhl(z: (f64, f64)) -> (f64, f64) {
15829    ctanh(z)
15830}
15831
15832// cacos: acos(z) = pi/2 - asin(z)
15833// asin(z) = -i * log(i*z + sqrt(1 - z^2))
15834#[no_mangle]
15835pub unsafe extern "C" fn cacos(z: (f64, f64)) -> (f64, f64) {
15836    let asin_z = casin(z);
15837    (3.14159265358979323846264338327950288419716939937510582097494459230781640 / 2.0 - asin_z.0, -asin_z.1)
15838}
15839
15840#[no_mangle]
15841pub unsafe extern "C" fn cacosf(z: (f32, f32)) -> (f32, f32) {
15842    let asin_z = casinf(z);
15843    (3.14159265358979323846264338327950288419716939937510582097494459230781640f32 / 2.0 - asin_z.0, -asin_z.1)
15844}
15845
15846#[no_mangle]
15847pub unsafe extern "C" fn cacosl(z: (f64, f64)) -> (f64, f64) {
15848    cacos(z)
15849}
15850
15851// casin: asin(z) = -i * log(i*z + sqrt(1 - z^2))
15852#[no_mangle]
15853pub unsafe extern "C" fn casin(z: (f64, f64)) -> (f64, f64) {
15854    // i*z = (-z.1, z.0)
15855    let iz = (-z.1, z.0);
15856    // 1 - z^2 = 1 - (z.0^2 - z.1^2 + 2i*z.0*z.1) = (1 - z.0^2 + z.1^2, -2*z.0*z.1)
15857    let one_minus_z2 = (1.0 - z.0 * z.0 + z.1 * z.1, -2.0 * z.0 * z.1);
15858    let sqrt_val = csqrt(one_minus_z2);
15859    let arg = clog((iz.0 + sqrt_val.0, iz.1 + sqrt_val.1));
15860    // -i * log(...) = (arg.1, -arg.0)
15861    (arg.1, -arg.0)
15862}
15863
15864#[no_mangle]
15865pub unsafe extern "C" fn casinf(z: (f32, f32)) -> (f32, f32) {
15866    let iz = (-z.1, z.0);
15867    let one_minus_z2 = (1.0 - z.0 * z.0 + z.1 * z.1, -2.0 * z.0 * z.1);
15868    let sqrt_val = csqrtf(one_minus_z2);
15869    let arg = clogf((iz.0 + sqrt_val.0, iz.1 + sqrt_val.1));
15870    (arg.1, -arg.0)
15871}
15872
15873#[no_mangle]
15874pub unsafe extern "C" fn casinl(z: (f64, f64)) -> (f64, f64) {
15875    casin(z)
15876}
15877
15878// catan: atan(z) = (i/2) * log((1 - i*z)/(1 + i*z))
15879#[no_mangle]
15880pub unsafe extern "C" fn catan(z: (f64, f64)) -> (f64, f64) {
15881    // i*z = (-z.1, z.0)
15882    // 1 - i*z = (1 + z.1, -z.0)
15883    // 1 + i*z = (1 - z.1, z.0)
15884    let num = (1.0 + z.1, -z.0);
15885    let den = (1.0 - z.1, z.0);
15886    let ratio = cdiv(num, den);
15887    let log_ratio = clog(ratio);
15888    // (i/2) * log = (-log.1/2, log.0/2)
15889    (-log_ratio.1 / 2.0, log_ratio.0 / 2.0)
15890}
15891
15892#[no_mangle]
15893pub unsafe extern "C" fn catanf(z: (f32, f32)) -> (f32, f32) {
15894    let num = (1.0 + z.1, -z.0);
15895    let den = (1.0 - z.1, z.0);
15896    let ratio = cdivf(num, den);
15897    let log_ratio = clogf(ratio);
15898    (-log_ratio.1 / 2.0, log_ratio.0 / 2.0)
15899}
15900
15901#[no_mangle]
15902pub unsafe extern "C" fn catanl(z: (f64, f64)) -> (f64, f64) {
15903    catan(z)
15904}
15905
15906// Helper: complex division
15907fn cdiv(a: (f64, f64), b: (f64, f64)) -> (f64, f64) {
15908    let d = b.0 * b.0 + b.1 * b.1;
15909    ((a.0 * b.0 + a.1 * b.1) / d, (a.1 * b.0 - a.0 * b.1) / d)
15910}
15911
15912fn cdivf(a: (f32, f32), b: (f32, f32)) -> (f32, f32) {
15913    let d = b.0 * b.0 + b.1 * b.1;
15914    ((a.0 * b.0 + a.1 * b.1) / d, (a.1 * b.0 - a.0 * b.1) / d)
15915}
15916
15917// cacosh: acosh(z) = log(z + sqrt(z^2 - 1))
15918#[no_mangle]
15919pub unsafe extern "C" fn cacosh(z: (f64, f64)) -> (f64, f64) {
15920    let z2 = (z.0 * z.0 - z.1 * z.1, 2.0 * z.0 * z.1);
15921    let z2_minus_1 = (z2.0 - 1.0, z2.1);
15922    let sqrt_val = csqrt(z2_minus_1);
15923    clog((z.0 + sqrt_val.0, z.1 + sqrt_val.1))
15924}
15925
15926#[no_mangle]
15927pub unsafe extern "C" fn cacoshf(z: (f32, f32)) -> (f32, f32) {
15928    let z2 = (z.0 * z.0 - z.1 * z.1, 2.0 * z.0 * z.1);
15929    let z2_minus_1 = (z2.0 - 1.0, z2.1);
15930    let sqrt_val = csqrtf(z2_minus_1);
15931    clogf((z.0 + sqrt_val.0, z.1 + sqrt_val.1))
15932}
15933
15934#[no_mangle]
15935pub unsafe extern "C" fn cacoshl(z: (f64, f64)) -> (f64, f64) {
15936    cacosh(z)
15937}
15938
15939// casinh: asinh(z) = log(z + sqrt(z^2 + 1))
15940#[no_mangle]
15941pub unsafe extern "C" fn casinh(z: (f64, f64)) -> (f64, f64) {
15942    let z2 = (z.0 * z.0 - z.1 * z.1, 2.0 * z.0 * z.1);
15943    let z2_plus_1 = (z2.0 + 1.0, z2.1);
15944    let sqrt_val = csqrt(z2_plus_1);
15945    clog((z.0 + sqrt_val.0, z.1 + sqrt_val.1))
15946}
15947
15948#[no_mangle]
15949pub unsafe extern "C" fn casinhf(z: (f32, f32)) -> (f32, f32) {
15950    let z2 = (z.0 * z.0 - z.1 * z.1, 2.0 * z.0 * z.1);
15951    let z2_plus_1 = (z2.0 + 1.0, z2.1);
15952    let sqrt_val = csqrtf(z2_plus_1);
15953    clogf((z.0 + sqrt_val.0, z.1 + sqrt_val.1))
15954}
15955
15956#[no_mangle]
15957pub unsafe extern "C" fn casinhl(z: (f64, f64)) -> (f64, f64) {
15958    casinh(z)
15959}
15960
15961// catanh: atanh(z) = (1/2) * log((1+z)/(1-z))
15962#[no_mangle]
15963pub unsafe extern "C" fn catanh(z: (f64, f64)) -> (f64, f64) {
15964    let num = (1.0 + z.0, z.1);
15965    let den = (1.0 - z.0, -z.1);
15966    let ratio = cdiv(num, den);
15967    let log_ratio = clog(ratio);
15968    (log_ratio.0 / 2.0, log_ratio.1 / 2.0)
15969}
15970
15971#[no_mangle]
15972pub unsafe extern "C" fn catanhf(z: (f32, f32)) -> (f32, f32) {
15973    let num = (1.0 + z.0, z.1);
15974    let den = (1.0 - z.0, -z.1);
15975    let ratio = cdivf(num, den);
15976    let log_ratio = clogf(ratio);
15977    (log_ratio.0 / 2.0, log_ratio.1 / 2.0)
15978}
15979
15980#[no_mangle]
15981pub unsafe extern "C" fn catanhl(z: (f64, f64)) -> (f64, f64) {
15982    catanh(z)
15983}
15984
15985// ============================================================
15986// Float math functions (f32 versions)
15987// ============================================================
15988
15989#[inline(never)]
15990#[no_mangle]
15991pub unsafe extern "C" fn fmaxf(x: f32, y: f32) -> f32 {
15992    fmaxf_impl(x, y)
15993}
15994
15995#[no_mangle]
15996pub unsafe extern "C" fn fdimf(x: f32, y: f32) -> f32 {
15997    if x.is_nan() || y.is_nan() {
15998        return f32::NAN;
15999    }
16000    if x > y { x - y } else { 0.0 }
16001}
16002
16003#[no_mangle]
16004pub unsafe extern "C" fn fmaf(x: f32, y: f32, z: f32) -> f32 {
16005    if (x.is_infinite() && y == 0.0) || (y.is_infinite() && x == 0.0) {
16006        feraiseexcept(FE_INVALID);
16007        return f32::NAN;
16008    }
16009    if x.is_nan() || y.is_nan() || z.is_nan() {
16010        return f32::NAN;
16011    }
16012    let r = libm::fmaf(x, y, z);
16013    if r.is_nan() {
16014        feraiseexcept(FE_INVALID);
16015    }
16016    r
16017}
16018
16019#[no_mangle]
16020pub unsafe extern "C" fn ilogbf(x: f32) -> i32 {
16021    if x.is_nan() {
16022        feraiseexcept(FE_INVALID);
16023        return -0x7fffffff - 1;
16024    }
16025    if x == 0.0 || x.is_infinite() {
16026        feraiseexcept(FE_INVALID);
16027        return if x == 0.0 { -0x7fffffff - 1 } else { 0x7fffffff };
16028    }
16029    let bits = x.to_bits();
16030    let exp = ((bits >> 23) & 0xff) as i32;
16031    if exp == 0 {
16032        let mut v = bits & 0x7fffff;
16033        let mut e = -126;
16034        while v < (1u32 << 23) { v <<= 1; e -= 1; }
16035        e
16036    } else {
16037        exp - 127
16038    }
16039}
16040
16041#[no_mangle]
16042pub unsafe extern "C" fn logbf(x: f32) -> f32 {
16043    if x.is_nan() { return x; }
16044    if x == 0.0 { return __math_divzerof(1); }
16045    let bits = x.to_bits();
16046    let exp = ((bits >> 23) & 0xff) as i32;
16047    if exp == 0 {
16048        let mut v = bits & 0x7fffff;
16049        let mut e = -126i32;
16050        while v < (1u32 << 23) { v <<= 1; e -= 1; }
16051        e as f32
16052    } else if exp == 0xff {
16053        x * x
16054    } else {
16055        (exp - 127) as f32
16056    }
16057}
16058
16059#[no_mangle]
16060pub unsafe extern "C" fn nearbyintf(x: f32) -> f32 {
16061    let had_inexact = fetestexcept(FE_INEXACT) & FE_INEXACT != 0;
16062    let r = libm::rintf(x);
16063    if !had_inexact {
16064        feclearexcept(FE_INEXACT);
16065    }
16066    r
16067}
16068
16069#[no_mangle]
16070pub unsafe extern "C" fn nextafterf(x: f32, y: f32) -> f32 {
16071    if x.is_nan() || y.is_nan() { return x + y; }
16072    if x == 0.0 && y == 0.0 { return y; }
16073    if x == y { return x; }
16074    let r = libm::nextafterf(x, y);
16075    if r.is_infinite() && x.is_finite() {
16076        feraiseexcept(FE_OVERFLOW | FE_INEXACT);
16077    } else if r != x {
16078        let bits = r.to_bits();
16079        let is_subnormal = (bits & 0x7f800000) == 0 && (bits & 0x7fffff) != 0;
16080        if r == 0.0 || is_subnormal {
16081            feraiseexcept(FE_UNDERFLOW | FE_INEXACT);
16082        }
16083    }
16084    r
16085}
16086
16087#[no_mangle]
16088#[cfg(target_arch = "x86_64")]
16089pub unsafe extern "C" fn nexttowardf(x: f32, y: f64) -> f32 {
16090    if y.is_nan() { return (x as f64 + y) as f32; }
16091    if x == 0.0 && y == 0.0 {
16092        return if y.is_sign_negative() { -0.0 } else { 0.0 };
16093    }
16094    if (x as f64) == y { return x; }
16095    nextafterf(x, if y > x as f64 { f32::INFINITY } else { f32::NEG_INFINITY })
16096}
16097
16098#[no_mangle]
16099#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
16100pub unsafe extern "C" fn nexttowardf(x: f32, y: f128) -> f32 {
16101    if y.is_nan() { return (x as f128 + y) as f32; }
16102    if (x as f128) == y { return x; }
16103    nextafterf(x, if y > x as f128 { f32::INFINITY } else { f32::NEG_INFINITY })
16104}
16105
16106#[no_mangle]
16107pub unsafe extern "C" fn remainderf(x: f32, y: f32) -> f32 {
16108    if x.is_nan() || y.is_nan() { return x + y; }
16109    if y == 0.0 || x.is_infinite() { return __math_invalidf(x); }
16110    libm::remainderf(x, y)
16111}
16112
16113#[no_mangle]
16114pub unsafe extern "C" fn remquof(x: f32, y: f32, quo: *mut i32) -> f32 {
16115    if x.is_nan() || y.is_nan() {
16116        if !quo.is_null() { *quo = 0; }
16117        return x + y;
16118    }
16119    if y == 0.0 || x.is_infinite() {
16120        if !quo.is_null() { *quo = 0; }
16121        return __math_invalidf(x);
16122    }
16123    let (r, q) = libm::remquof(x, y);
16124    if !quo.is_null() { *quo = q; }
16125    r
16126}
16127
16128#[no_mangle]
16129pub unsafe extern "C" fn exp2f(x: f32) -> f32 {
16130    if x == f32::INFINITY { return f32::INFINITY; }
16131    if x == f32::NEG_INFINITY { return 0.0; }
16132    if x.is_nan() { return f32::NAN; }
16133    let r = libm::exp2f(x);
16134    if r.is_infinite() && x.is_finite() {
16135        feraiseexcept(FE_OVERFLOW | FE_INEXACT);
16136    } else if r == 0.0 && x < -149.0 {
16137        feraiseexcept(FE_UNDERFLOW | FE_INEXACT);
16138    } else if r != 0.0 && x != libm::truncf(x) {
16139        let bits = r.to_bits();
16140        if (bits & 0x7f800000) == 0 {
16141            feraiseexcept(FE_UNDERFLOW | FE_INEXACT);
16142        }
16143    }
16144    r
16145}
16146
16147#[no_mangle]
16148pub unsafe extern "C" fn expm1f(x: f32) -> f32 {
16149    libm::expm1f(x)
16150}
16151
16152#[no_mangle]
16153pub unsafe extern "C" fn log1pf(x: f32) -> f32 {
16154    if x == -1.0 {
16155        feraiseexcept(FE_DIVBYZERO);
16156        return f32::NEG_INFINITY;
16157    }
16158    libm::log1pf(x)
16159}
16160
16161#[no_mangle]
16162pub unsafe extern "C" fn acoshf(x: f32) -> f32 {
16163    if x < 1.0 {
16164        feraiseexcept(FE_INVALID);
16165        return f32::NAN;
16166    }
16167    libm::acoshf(x)
16168}
16169
16170#[no_mangle]
16171pub unsafe extern "C" fn asinhf(x: f32) -> f32 {
16172    if x == 0.0 { return x; }
16173    libm::asinhf(x)
16174}
16175
16176#[no_mangle]
16177pub unsafe extern "C" fn atanhf(x: f32) -> f32 {
16178    if x == 0.0 { return x; }
16179    let e = ((x.to_bits() >> 23) & 0xff) as i32;
16180    if e < 0x7f - 32 {
16181        feraiseexcept(FE_INEXACT);
16182        if e == 0 { feraiseexcept(FE_UNDERFLOW); }
16183        return x;
16184    }
16185    if x == 1.0 {
16186        feraiseexcept(FE_DIVBYZERO);
16187        return f32::INFINITY;
16188    }
16189    if x == -1.0 {
16190        feraiseexcept(FE_DIVBYZERO);
16191        return f32::NEG_INFINITY;
16192    }
16193    if x.is_nan() { return x; }
16194    let ax = libm::fabsf(x);
16195    if ax > 1.0 {
16196        feraiseexcept(FE_INVALID);
16197        return f32::NAN;
16198    }
16199    if ax < 0.5 {
16200        let r = libm::log1pf(2.0 * (ax + ax * ax / (1.0 - ax))) / 2.0;
16201        if x < 0.0 { -r } else { r }
16202    } else {
16203        let r = 0.5 * libm::logf((1.0 + ax) / (1.0 - ax));
16204        if x < 0.0 { -r } else { r }
16205    }
16206}
16207
16208#[no_mangle]
16209pub unsafe extern "C" fn cbrtf(x: f32) -> f32 {
16210    libm::cbrtf(x)
16211}
16212
16213#[no_mangle]
16214pub unsafe extern "C" fn erff(x: f32) -> f32 {
16215    libm::erff(x)
16216}
16217
16218#[no_mangle]
16219pub unsafe extern "C" fn erfcf(x: f32) -> f32 {
16220    libm::erfcf(x)
16221}
16222
16223#[no_mangle]
16224pub unsafe extern "C" fn lgammaf(x: f32) -> f32 {
16225    if x.is_nan() {
16226        crate::signgam = 1;
16227        return x;
16228    }
16229    if x == 0.0 {
16230        crate::signgam = if x.is_sign_negative() { -1 } else { 1 };
16231        feraiseexcept(FE_DIVBYZERO);
16232        return f32::INFINITY;
16233    }
16234    let (r, sign) = libm::lgammaf_r(x);
16235    crate::signgam = sign;
16236    r
16237}
16238
16239#[no_mangle]
16240pub unsafe extern "C" fn tgammaf(x: f32) -> f32 {
16241    if x.is_nan() { return x; }
16242    if x == 0.0 {
16243        feraiseexcept(FE_DIVBYZERO);
16244        return if x.is_sign_negative() { f32::NEG_INFINITY } else { f32::INFINITY };
16245    }
16246    if x.is_infinite() {
16247        return if x.is_sign_negative() { __math_invalidf(x) } else { f32::INFINITY };
16248    }
16249    if x < 0.0 && x == libm::floorf(x) {
16250        feraiseexcept(FE_INVALID);
16251        return f32::NAN;
16252    }
16253    libm::tgammaf(x)
16254}
16255
16256#[no_mangle]
16257pub unsafe extern "C" fn lroundf(x: f32) -> core::ffi::c_long {
16258    libm::roundf(x) as core::ffi::c_long
16259}
16260
16261#[no_mangle]
16262pub unsafe extern "C" fn llroundf(x: f32) -> i64 {
16263    libm::roundf(x) as i64
16264}
16265
16266// ============================================================
16267// Wide char functions
16268// ============================================================
16269
16270#[no_mangle]
16271pub unsafe extern "C" fn wcscasecmp(s1: *const u32, s2: *const u32) -> i32 {
16272    let mut i = 0;
16273    loop {
16274        let c1 = *s1.add(i);
16275        let c2 = *s2.add(i);
16276        if c1 == 0 || c2 == 0 { return (c1 as i32) - (c2 as i32); }
16277        let l1 = if c1 >= 'A' as u32 && c1 <= 'Z' as u32 { c1 + 32 } else { c1 };
16278        let l2 = if c2 >= 'A' as u32 && c2 <= 'Z' as u32 { c2 + 32 } else { c2 };
16279        if l1 != l2 { return (l1 as i32) - (l2 as i32); }
16280        i += 1;
16281    }
16282}
16283
16284#[no_mangle]
16285pub unsafe extern "C" fn wcscasecmp_l(s1: *const u32, s2: *const u32, _loc: *mut core::ffi::c_void) -> i32 {
16286    wcscasecmp(s1, s2)
16287}
16288
16289#[no_mangle]
16290pub unsafe extern "C" fn wcsncasecmp(s1: *const u32, s2: *const u32, n: usize) -> i32 {
16291    let mut i = 0;
16292    while i < n {
16293        let c1 = *s1.add(i);
16294        let c2 = *s2.add(i);
16295        if c1 == 0 || c2 == 0 { return (c1 as i32) - (c2 as i32); }
16296        let l1 = if c1 >= 'A' as u32 && c1 <= 'Z' as u32 { c1 + 32 } else { c1 };
16297        let l2 = if c2 >= 'A' as u32 && c2 <= 'Z' as u32 { c2 + 32 } else { c2 };
16298        if l1 != l2 { return (l1 as i32) - (l2 as i32); }
16299        i += 1;
16300    }
16301    0
16302}
16303
16304#[no_mangle]
16305pub unsafe extern "C" fn wcsncasecmp_l(s1: *const u32, s2: *const u32, n: usize, _loc: *mut core::ffi::c_void) -> i32 {
16306    wcsncasecmp(s1, s2, n)
16307}
16308
16309#[no_mangle]
16310pub unsafe extern "C" fn wcscoll(s1: *const u32, s2: *const u32) -> i32 {
16311    // ponytail: simplified collation - just compare codepoints
16312    let mut i = 0;
16313    loop {
16314        let c1 = *s1.add(i);
16315        let c2 = *s2.add(i);
16316        if c1 == 0 || c2 == 0 { return (c1 as i32) - (c2 as i32); }
16317        if c1 != c2 { return (c1 as i32) - (c2 as i32); }
16318        i += 1;
16319    }
16320}
16321
16322#[no_mangle]
16323pub unsafe extern "C" fn wcstok(s: *mut u32, sep: *const u32, p: *mut *mut u32) -> *mut u32 {
16324    let mut src = if s.is_null() { *p } else { s };
16325    // Skip leading separators
16326    while *src != 0 && *sep.add(0) == *src { src = src.add(1); }
16327    if *src == 0 { return core::ptr::null_mut(); }
16328    let start = src;
16329    // Find end of token
16330    while *src != 0 && *sep.add(0) != *src { src = src.add(1); }
16331    if *src != 0 {
16332        *src = 0;
16333        *p = src.add(1);
16334    } else {
16335        *p = src;
16336    }
16337    start
16338}
16339
16340#[no_mangle]
16341pub unsafe extern "C" fn wcswcs(haystack: *const u32, needle: *const u32) -> *mut u32 {
16342    if *needle == 0 { return haystack as *mut u32; }
16343    let mut i = 0;
16344    while *haystack.add(i) != 0 {
16345        let mut j = 0;
16346        while *needle.add(j) != 0 && *haystack.add(i + j) == *needle.add(j) {
16347            j += 1;
16348        }
16349        if *needle.add(j) == 0 { return haystack.add(i) as *mut u32; }
16350        i += 1;
16351    }
16352    core::ptr::null_mut()
16353}
16354
16355#[no_mangle]
16356pub unsafe extern "C" fn wcswidth(s: *const u32, n: usize) -> i32 {
16357    let mut width = 0i32;
16358    let mut i = 0;
16359    while i < n {
16360        let c = *s.add(i);
16361        if c == 0 { break; }
16362        // ponytail: simplified width - assume all printable chars are width 1
16363        width += 1;
16364        i += 1;
16365    }
16366    width
16367}
16368
16369#[no_mangle]
16370pub unsafe extern "C" fn wcsftime(s: *mut u32, maxsize: usize, fmt: *const u32, tm: *const c_void) -> usize {
16371    if s.is_null() || fmt.is_null() || maxsize == 0 { return 0; }
16372    // Convert the wide format string to multibyte, let strftime do the work,
16373    // then convert the result back.
16374    let mut cfmt = [0u8; 1024];
16375    let mut o = 0usize;
16376    let mut i = 0usize;
16377    let mut st: c_uint = 0;
16378    while *fmt.add(i) != 0 && o + 8 < cfmt.len() {
16379        let n = wcrtomb(
16380            cfmt.as_mut_ptr().add(o) as *mut c_char,
16381            *fmt.add(i) as c_int,
16382            &mut st as *mut c_uint,
16383        );
16384        if n == !0usize { return 0; }
16385        o += n;
16386        i += 1;
16387    }
16388    cfmt[o] = 0;
16389    let mut out = [0u8; 4096];
16390    let mut lim = maxsize.saturating_mul(4);
16391    if lim > out.len() { lim = out.len(); }
16392    let n = strftime(out.as_mut_ptr() as *mut c_char, lim, cfmt.as_ptr() as *const c_char, tm as *const tm);
16393    if n == 0 { return 0; }
16394    let mut ws = 0usize;
16395    let mut p = 0usize;
16396    while p < n && ws + 1 < maxsize {
16397        let mut wc: c_int = 0;
16398        let mut st2: c_uint = 0;
16399        let r = mbrtowc(&mut wc, out.as_ptr().add(p) as *const c_char, n - p, &mut st2);
16400        if r == !0usize { return 0; }
16401        if r == 0 || r == !1usize { break; }
16402        *s.add(ws) = wc as u32;
16403        ws += 1;
16404        p += r;
16405    }
16406    *s.add(ws) = 0;
16407    ws
16408}
16409
16410#[no_mangle]
16411pub unsafe extern "C" fn mbsnrtowcs(
16412    dst: *mut u32,
16413    src: *mut *const u8,
16414    nms: usize,
16415    len: usize,
16416    st: *mut core::ffi::c_void,
16417) -> usize {
16418    if src.is_null() { return 0; }
16419    let mut s = *src;
16420    if s.is_null() { return 0; }
16421    let state = st as *mut c_uint;
16422    let limit = if dst.is_null() { usize::MAX } else { len };
16423    let mut count = 0usize;
16424    let mut n = nms;
16425    while count < limit && n > 0 {
16426        let c = *s;
16427        if c == 0 {
16428            if !dst.is_null() {
16429                if count < len { *dst.add(count) = 0; }
16430                *src = core::ptr::null();
16431            }
16432            return count;
16433        }
16434        let mut wc: c_int = 0;
16435        let r = mbrtowc(&mut wc, s as *const c_char, n, state);
16436        if r == !0usize {
16437            *src = s;
16438            return !0usize;
16439        }
16440        if r == !1usize { break; }
16441        if !dst.is_null() { *dst.add(count) = wc as u32; }
16442        count += 1;
16443        s = s.add(r);
16444        n -= r;
16445    }
16446    *src = s;
16447    count
16448}
16449
16450#[no_mangle]
16451pub unsafe extern "C" fn wcsnrtombs(dst: *mut u8, src: *mut *const u32, nwc: usize, len: usize, _st: *mut core::ffi::c_void) -> usize {
16452    let mut count = 0;
16453    let mut s = *src;
16454    let mut d = dst;
16455    while count < len && count < nwc {
16456        let c = *s;
16457        if c == 0 { break; }
16458        if !d.is_null() {
16459            if c < 0x80 {
16460                *d = c as u8;
16461                d = d.add(1);
16462                count += 1;
16463            } else if c < 0x800 {
16464                if count + 2 > len { break; }
16465                *d = 0xc0 | (c >> 6) as u8;
16466                *d.add(1) = 0x80 | (c & 0x3f) as u8;
16467                d = d.add(2);
16468                count += 2;
16469            } else if c < 0x10000 {
16470                if count + 3 > len { break; }
16471                *d = 0xe0 | (c >> 12) as u8;
16472                *d.add(1) = 0x80 | ((c >> 6) & 0x3f) as u8;
16473                *d.add(2) = 0x80 | (c & 0x3f) as u8;
16474                d = d.add(3);
16475                count += 3;
16476            } else {
16477                if count + 4 > len { break; }
16478                *d = 0xf0 | (c >> 18) as u8;
16479                *d.add(1) = 0x80 | ((c >> 12) & 0x3f) as u8;
16480                *d.add(2) = 0x80 | ((c >> 6) & 0x3f) as u8;
16481                *d.add(3) = 0x80 | (c & 0x3f) as u8;
16482                d = d.add(4);
16483                count += 4;
16484            }
16485        }
16486        s = s.add(1);
16487    }
16488    if !dst.is_null() { *src = s; }
16489    count
16490}
16491
16492// ============================================================
16493// Thread sync functions (C11 threads)
16494// ============================================================
16495
16496
16497// C11 thread types
16498pub type thrd_start_t = Option<unsafe extern "C" fn(arg: *mut core::ffi::c_void) -> i32>;
16499
16500// Thread function stubs - these need actual implementation
16501#[no_mangle]
16502pub unsafe extern "C" fn thrd_create(thr: *mut usize, func: thrd_start_t, arg: *mut core::ffi::c_void) -> i32 {
16503    let mut thread: u64 = 0;
16504    let r = pthread_create(&mut thread, core::ptr::null(), core::mem::transmute(func), arg);
16505    if r == 0 {
16506        *thr = thread as usize;
16507        0 // thrd_success
16508    } else {
16509        -1 // thrd_nomem
16510    }
16511}
16512
16513#[no_mangle]
16514pub unsafe extern "C" fn thrd_join(thr: usize, res: *mut i32) -> i32 {
16515    let mut retval: *mut core::ffi::c_void = core::ptr::null_mut();
16516    let r = pthread_join(thr as u64, &mut retval);
16517    if r == 0 {
16518        if !res.is_null() { *res = retval as i32; }
16519        0
16520    } else {
16521        -1
16522    }
16523}
16524
16525#[no_mangle]
16526pub unsafe extern "C" fn thrd_exit(res: i32) {
16527    pthread_exit(res as *mut core::ffi::c_void);
16528}
16529
16530#[no_mangle]
16531pub unsafe extern "C" fn thrd_detach(thr: usize) -> i32 {
16532    let r = pthread_detach(thr as u64);
16533    if r == 0 { 0 } else { -1 }
16534}
16535
16536#[no_mangle]
16537pub unsafe extern "C" fn thrd_current() -> usize {
16538    pthread_self() as usize
16539}
16540
16541#[no_mangle]
16542pub unsafe extern "C" fn thrd_equal(thr1: usize, thr2: usize) -> i32 {
16543    (thr1 == thr2) as i32
16544}
16545
16546#[no_mangle]
16547pub unsafe extern "C" fn thrd_sleep(duration: *const core::ffi::c_void, remaining: *mut core::ffi::c_void) -> i32 {
16548    nanosleep(duration as *const timespec, remaining as *mut timespec)
16549}
16550
16551#[no_mangle]
16552pub unsafe extern "C" fn thrd_yield() {
16553    sched_yield();
16554}
16555
16556// Mutex
16557#[no_mangle]
16558pub unsafe extern "C" fn mtx_init(mtx: *mut usize, _mtx_type: i32) -> i32 {
16559    let r = pthread_mutex_init(mtx as *mut pthread_mutex_t, core::ptr::null());
16560    if r == 0 { 0 } else { -1 }
16561}
16562
16563#[no_mangle]
16564pub unsafe extern "C" fn mtx_lock(mtx: *mut usize) -> i32 {
16565    let r = pthread_mutex_lock(mtx as *mut pthread_mutex_t);
16566    if r == 0 { 0 } else { -1 }
16567}
16568
16569#[no_mangle]
16570pub unsafe extern "C" fn mtx_trylock(mtx: *mut usize) -> i32 {
16571    let r = pthread_mutex_trylock(mtx as *mut pthread_mutex_t);
16572    if r == 0 { 0 } else { -1 }
16573}
16574
16575#[no_mangle]
16576pub unsafe extern "C" fn mtx_unlock(mtx: *mut usize) -> i32 {
16577    let r = pthread_mutex_unlock(mtx as *mut pthread_mutex_t);
16578    if r == 0 { 0 } else { -1 }
16579}
16580
16581#[no_mangle]
16582pub unsafe extern "C" fn mtx_destroy(mtx: *mut usize) {
16583    pthread_mutex_destroy(mtx as *mut pthread_mutex_t);
16584}
16585
16586#[no_mangle]
16587pub unsafe extern "C" fn mtx_timedlock(mtx: *mut usize, ts: *const core::ffi::c_void) -> i32 {
16588    let r = pthread_mutex_timedlock(mtx as *mut pthread_mutex_t, ts as *const timespec);
16589    if r == 0 { 0 } else { -1 }
16590}
16591
16592// Condition variable
16593#[no_mangle]
16594pub unsafe extern "C" fn cnd_init(cnd: *mut usize) -> i32 {
16595    let r = pthread_cond_init(cnd as *mut pthread_cond_t, core::ptr::null());
16596    if r == 0 { 0 } else { -1 }
16597}
16598
16599#[no_mangle]
16600pub unsafe extern "C" fn cnd_signal(cnd: *mut usize) -> i32 {
16601    let r = pthread_cond_signal(cnd as *mut pthread_cond_t);
16602    if r == 0 { 0 } else { -1 }
16603}
16604
16605#[no_mangle]
16606pub unsafe extern "C" fn cnd_broadcast(cnd: *mut usize) -> i32 {
16607    let r = pthread_cond_broadcast(cnd as *mut pthread_cond_t);
16608    if r == 0 { 0 } else { -1 }
16609}
16610
16611#[no_mangle]
16612pub unsafe extern "C" fn cnd_wait(cnd: *mut usize, mtx: *mut usize) -> i32 {
16613    let r = pthread_cond_wait(cnd as *mut pthread_cond_t, mtx as *mut pthread_mutex_t);
16614    if r == 0 { 0 } else { -1 }
16615}
16616
16617#[no_mangle]
16618pub unsafe extern "C" fn cnd_timedwait(cnd: *mut usize, mtx: *mut usize, ts: *const core::ffi::c_void) -> i32 {
16619    let r = pthread_cond_timedwait(cnd as *mut pthread_cond_t, mtx as *mut pthread_mutex_t, ts as *const timespec);
16620    if r == 0 { 0 } else { -1 }
16621}
16622
16623#[no_mangle]
16624pub unsafe extern "C" fn cnd_destroy(cnd: *mut usize) {
16625    pthread_cond_destroy(cnd as *mut pthread_cond_t);
16626}
16627
16628// Thread-specific storage
16629#[no_mangle]
16630pub unsafe extern "C" fn tss_create(key: *mut u32, dtor: Option<unsafe extern "C" fn(*mut core::ffi::c_void)>) -> i32 {
16631    let r = pthread_key_create(key, dtor);
16632    if r == 0 { 0 } else { -1 }
16633}
16634
16635#[no_mangle]
16636pub unsafe extern "C" fn tss_delete(key: u32) {
16637    pthread_key_delete(key);
16638}
16639
16640#[no_mangle]
16641pub unsafe extern "C" fn tss_set(key: u32, val: *mut core::ffi::c_void) -> i32 {
16642    let r = pthread_setspecific(key, val);
16643    if r == 0 { 0 } else { -1 }
16644}
16645
16646#[no_mangle]
16647pub unsafe extern "C" fn tss_get(key: u32) -> *mut core::ffi::c_void {
16648    pthread_getspecific(key)
16649}
16650
16651// call_once
16652#[no_mangle]
16653pub unsafe extern "C" fn call_once(flag: *mut u32, func: Option<unsafe extern "C" fn()>) {
16654    if *flag == 0 {
16655        if let Some(f) = func { f(); }
16656        *flag = 1;
16657    }
16658}
16659
16660// ============================================================
16661// Network functions
16662// ============================================================
16663
16664// accept4 - Linux-specific extension
16665#[no_mangle]
16666pub unsafe extern "C" fn accept4(fd: i32, addr: *mut core::ffi::c_void, addrlen: *mut u32, flags: i32) -> i32 {
16667    <Arch as Syscalls>::syscall4(SYS_ACCEPT4, fd as i64, addr as i64, addrlen as i64, flags as i64) as i32
16668}
16669
16670// getifaddrs / freeifaddrs
16671// ============================================================
16672// epoll/eventfd/signalfd/timerfd
16673// ============================================================
16674
16675#[no_mangle]
16676pub unsafe extern "C" fn epoll_create(size: i32) -> i32 {
16677    #[cfg(target_arch = "x86_64")]
16678    { <Arch as Syscalls>::syscall1(SYS_EPOLL_CREATE, size as i64) as i32 }
16679    #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
16680    {
16681        if size < 1 {
16682            ERRNO = EINVAL;
16683            return -1;
16684        }
16685        <Arch as Syscalls>::syscall1(SYS_EPOLL_CREATE1, 0) as i32
16686    }
16687}
16688
16689#[no_mangle]
16690pub unsafe extern "C" fn epoll_create1(flags: i32) -> i32 {
16691    <Arch as Syscalls>::syscall1(SYS_EPOLL_CREATE1, flags as i64) as i32
16692}
16693
16694#[no_mangle]
16695pub unsafe extern "C" fn epoll_ctl(epfd: i32, op: i32, fd: i32, event: *mut core::ffi::c_void) -> i32 {
16696    <Arch as Syscalls>::syscall4(SYS_EPOLL_CTL, epfd as i64, op as i64, fd as i64, event as i64) as i32
16697}
16698
16699#[no_mangle]
16700pub unsafe extern "C" fn epoll_wait(epfd: i32, events: *mut core::ffi::c_void, maxevents: i32, timeout: i32) -> i32 {
16701    <Arch as Syscalls>::syscall4(SYS_EPOLL_WAIT, epfd as i64, events as i64, maxevents as i64, timeout as i64) as i32
16702}
16703
16704#[no_mangle]
16705pub unsafe extern "C" fn epoll_pwait(epfd: i32, events: *mut core::ffi::c_void, maxevents: i32, timeout: i32, sigmask: *const u64) -> i32 {
16706    <Arch as Syscalls>::syscall6(SYS_EPOLL_WAIT, epfd as i64, events as i64, maxevents as i64, timeout as i64, sigmask as i64, 8) as i32
16707}
16708
16709#[no_mangle]
16710pub unsafe extern "C" fn eventfd(initval: u32, flags: i32) -> i32 {
16711    <Arch as Syscalls>::syscall2(SYS_EVENTFD2, initval as i64, flags as i64) as i32
16712}
16713
16714#[no_mangle]
16715pub unsafe extern "C" fn eventfd_read(fd: i32, value: *mut u64) -> i32 {
16716    let n = crate::read(fd, value as *mut core::ffi::c_void, 8);
16717    if n == 8 { 0 } else { -1 }
16718}
16719
16720#[no_mangle]
16721pub unsafe extern "C" fn eventfd_write(fd: i32, value: u64) -> i32 {
16722    let n = crate::write(fd, &value as *const u64 as *const core::ffi::c_void, 8);
16723    if n == 8 { 0 } else { -1 }
16724}
16725
16726#[no_mangle]
16727pub unsafe extern "C" fn signalfd(fd: i32, mask: *const u64, flags: i32) -> i32 {
16728    <Arch as Syscalls>::syscall4(SYS_SIGNALFD4, fd as i64, mask as i64, 8, flags as i64) as i32
16729}
16730
16731#[no_mangle]
16732pub unsafe extern "C" fn timerfd_create(clockid: i32, flags: i32) -> i32 {
16733    <Arch as Syscalls>::syscall2(SYS_TIMERFD_CREATE, clockid as i64, flags as i64) as i32
16734}
16735
16736#[no_mangle]
16737pub unsafe extern "C" fn timerfd_settime(fd: i32, flags: i32, new_value: *const core::ffi::c_void, old_value: *mut core::ffi::c_void) -> i32 {
16738    <Arch as Syscalls>::syscall4(SYS_TIMERFD_SETTIME, fd as i64, flags as i64, new_value as i64, old_value as i64) as i32
16739}
16740
16741#[no_mangle]
16742pub unsafe extern "C" fn timerfd_gettime(fd: i32, curr_value: *mut core::ffi::c_void) -> i32 {
16743    <Arch as Syscalls>::syscall2(SYS_TIMERFD_GETTIME, fd as i64, curr_value as i64) as i32
16744}
16745
16746// ============================================================
16747// System functions
16748// ============================================================
16749
16750#[no_mangle]
16751pub unsafe extern "C" fn prctl(option: i32, mut args: ...) -> i32 {
16752    let a1 = args.next_arg::<i64>();
16753    let a2 = args.next_arg::<i64>();
16754    let a3 = args.next_arg::<i64>();
16755    let a4 = args.next_arg::<i64>();
16756    <Arch as Syscalls>::syscall5(SYS_PRCTL, option as i64, a1, a2, a3, a4) as i32
16757}
16758
16759#[no_mangle]
16760pub unsafe extern "C" fn quotactl(cmd: i32, special: *const core::ffi::c_char, id: i32, addr: *mut core::ffi::c_char) -> i32 {
16761    <Arch as Syscalls>::syscall4(sysno(179, 60), cmd as i64, special as i64, id as i64, addr as i64) as i32
16762}
16763
16764#[no_mangle]
16765pub unsafe extern "C" fn klogctl(type_: i32, bufp: *mut core::ffi::c_char, len: i32) -> i32 {
16766    <Arch as Syscalls>::syscall3(sysno(103, 116), type_ as i64, bufp as i64, len as i64) as i32
16767}
16768
16769static mut SYSLOG_IDENT: [core::ffi::c_char; 64] = [0; 64];
16770static mut SYSLOG_OPTIONS: i32 = 0;
16771static mut SYSLOG_FACILITY: i32 = 1;
16772
16773#[no_mangle]
16774pub unsafe extern "C" fn openlog(ident: *const core::ffi::c_char, option: i32, facility: i32) {
16775    SYSLOG_OPTIONS = option;
16776    SYSLOG_FACILITY = facility & 0x3f8;
16777    SYSLOG_IDENT[0] = 0;
16778    if !ident.is_null() {
16779        let mut i = 0;
16780        while i < 63 && *ident.add(i) != 0 {
16781            SYSLOG_IDENT[i] = *ident.add(i);
16782            i += 1;
16783        }
16784        SYSLOG_IDENT[i] = 0;
16785    }
16786}
16787
16788#[repr(C)]
16789struct SockAddrUn {
16790    sun_family: u16,
16791    sun_path: [core::ffi::c_char; 108],
16792}
16793
16794unsafe fn syslog_emit(priority: i32, msg: *const core::ffi::c_char, len: usize) {
16795    let mut out = [0u8; 1200];
16796    let mut o = 0usize;
16797    let pri = (SYSLOG_FACILITY | (priority & 7)) as u32;
16798    out[o] = b'<'; o += 1;
16799    if pri >= 100 { out[o] = b'0' + (pri / 100) as u8; o += 1; }
16800    if pri >= 10 { out[o] = b'0' + ((pri / 10) % 10) as u8; o += 1; }
16801    out[o] = b'0' + (pri % 10) as u8; o += 1;
16802    out[o] = b'>'; o += 1;
16803    let mut i = 0;
16804    while i < 63 && SYSLOG_IDENT[i] != 0 && o + 1 < out.len() {
16805        out[o] = SYSLOG_IDENT[i] as u8; o += 1; i += 1;
16806    }
16807    if SYSLOG_OPTIONS & 1 != 0 {
16808        out[o] = b'['; o += 1;
16809        let mut pid = crate::getpid() as u32;
16810        let mut digits = [0u8; 10];
16811        let mut d = 0;
16812        if pid == 0 { digits[0] = b'0'; d = 1; }
16813        while pid > 0 { digits[d] = b'0' + (pid % 10) as u8; pid /= 10; d += 1; }
16814        while d > 0 { d -= 1; out[o] = digits[d]; o += 1; }
16815        out[o] = b']'; o += 1;
16816    }
16817    out[o] = b':'; o += 1; out[o] = b' '; o += 1;
16818    let copy = core::cmp::min(len, out.len() - o - 1);
16819    core::ptr::copy_nonoverlapping(msg as *const u8, out.as_mut_ptr().add(o), copy);
16820    o += copy;
16821    let fd = crate::socket(AF_UNIX, SOCK_DGRAM, 0);
16822    if fd >= 0 {
16823        let mut sa: SockAddrUn = core::mem::zeroed();
16824        sa.sun_family = AF_UNIX as u16;
16825        let path = b"/dev/log";
16826        for i in 0..path.len() { sa.sun_path[i] = path[i] as core::ffi::c_char; }
16827        let r = crate::sendto(fd, out.as_ptr() as *const core::ffi::c_void, o, 0, &sa as *const SockAddrUn as *const crate::sockaddr, core::mem::size_of::<SockAddrUn>() as u32);
16828        crate::close(fd);
16829        if r >= 0 { return; }
16830    }
16831    crate::write(2, out.as_ptr() as *const core::ffi::c_void, o);
16832    crate::write(2, b"\n".as_ptr() as *const core::ffi::c_void, 1);
16833}
16834
16835#[no_mangle]
16836pub unsafe extern "C" fn vsyslog(priority: c_int, fmt: *const c_char, ap: VaList) {
16837    let mut msg = [0 as c_char; 1024];
16838    let n = vsnprintf(msg.as_mut_ptr(), msg.len(), fmt, ap);
16839    if n > 0 { syslog_emit(priority, msg.as_ptr(), core::cmp::min(n as usize, msg.len() - 1)); }
16840}
16841
16842#[no_mangle]
16843pub unsafe extern "C" fn syslog(priority: c_int, fmt: *const c_char, args: ...) {
16844    vsyslog(priority, fmt, args);
16845}
16846
16847#[no_mangle]
16848pub unsafe extern "C" fn closelog() {
16849    // Nothing to do
16850}
16851
16852#[no_mangle]
16853pub unsafe extern "C" fn setlogmask(mask: i32) -> i32 {
16854    static mut LOG_MASK: i32 = 0x01 | 0x02 | 0x04 | 0x08 | 0x10 | 0x20 | 0x40 | 0x80;
16855    let old = LOG_MASK;
16856    if mask != 0 { LOG_MASK = mask; }
16857    old
16858}
16859
16860#[no_mangle]
16861pub unsafe extern "C" fn acct(filename: *const core::ffi::c_char) -> i32 {
16862    <Arch as Syscalls>::syscall1(SYS_ACCT, filename as i64) as i32
16863}
16864
16865#[no_mangle]
16866pub unsafe extern "C" fn swapon(path: *const core::ffi::c_char, flags: i32) -> i32 {
16867    <Arch as Syscalls>::syscall2(SYS_SWAPON, path as i64, flags as i64) as i32
16868}
16869
16870#[no_mangle]
16871pub unsafe extern "C" fn swapoff(path: *const core::ffi::c_char) -> i32 {
16872    <Arch as Syscalls>::syscall1(SYS_SWAPOFF, path as i64) as i32
16873}
16874
16875#[no_mangle]
16876pub unsafe extern "C" fn syncfs(fd: i32) -> i32 {
16877    <Arch as Syscalls>::syscall1(SYS_SYNCFS, fd as i64) as i32
16878}
16879
16880#[no_mangle]
16881pub unsafe extern "C" fn sync_file_range(fd: i32, offset: i64, nbytes: u64, flags: u32) -> i32 {
16882    <Arch as Syscalls>::syscall4(sysno(277, 84), fd as i64, offset, nbytes as i64, flags as i64) as i32
16883}
16884
16885#[no_mangle]
16886pub unsafe extern "C" fn posix_fadvise(fd: i32, offset: i64, len: u64, advice: i32) -> i32 {
16887    <Arch as Syscalls>::syscall4(sysno(221, 223), fd as i64, offset, len as i64, advice as i64) as i32
16888}
16889
16890#[no_mangle]
16891pub unsafe extern "C" fn posix_fallocate(fd: i32, offset: i64, len: u64) -> i32 {
16892    <Arch as Syscalls>::syscall3(SYS_FALLOCATE, fd as i64, offset, len as i64) as i32
16893}
16894
16895#[no_mangle]
16896pub unsafe extern "C" fn readahead(fd: i32, offset: i64, count: usize) -> i32 {
16897    <Arch as Syscalls>::syscall3(sysno(187, 213), fd as i64, offset, count as i64) as i32
16898}
16899
16900#[no_mangle]
16901pub unsafe extern "C" fn fallocate(fd: i32, mode: i32, offset: i64, len: u64) -> i32 {
16902    <Arch as Syscalls>::syscall4(SYS_FALLOCATE, fd as i64, mode as i64, offset, len as i64) as i32
16903}
16904
16905// ============================================================
16906// Terminal functions
16907// ============================================================
16908
16909#[no_mangle]
16910pub unsafe extern "C" fn tcgetattr(fd: i32, termios_p: *mut core::ffi::c_void) -> i32 {
16911    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5401, termios_p as i64) as i32
16912}
16913
16914#[no_mangle]
16915pub unsafe extern "C" fn tcsetattr(fd: i32, optional_actions: i32, termios_p: *const core::ffi::c_void) -> i32 {
16916    let cmd = match optional_actions {
16917        0 => 0x5402,
16918        1 => 0x5403,
16919        2 => 0x5404,
16920        _ => 0x5402,
16921    };
16922    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, cmd, termios_p as i64) as i32
16923}
16924
16925#[no_mangle]
16926pub unsafe extern "C" fn tcdrain(fd: i32) -> i32 {
16927    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5409, 1) as i32
16928}
16929
16930#[no_mangle]
16931pub unsafe extern "C" fn tcflush(fd: i32, queue_selector: i32) -> i32 {
16932    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x540B, queue_selector as i64) as i32
16933}
16934
16935#[no_mangle]
16936pub unsafe extern "C" fn tcflow(fd: i32, action: i32) -> i32 {
16937    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x540A, action as i64) as i32
16938}
16939
16940#[no_mangle]
16941pub unsafe extern "C" fn tcsendbreak(fd: i32, duration: i32) -> i32 {
16942    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5425, duration as i64) as i32
16943}
16944
16945#[no_mangle]
16946pub unsafe extern "C" fn tcgetsid(fd: i32) -> i32 {
16947    let mut sid: i32 = 0;
16948    let r = <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5429, &mut sid as *mut i32 as i64);
16949    if r < 0 { -1 } else { sid }
16950}
16951
16952#[no_mangle]
16953pub unsafe extern "C" fn tcgetpgrp(fd: i32) -> i32 {
16954    let mut pgrp: i32 = 0;
16955    let r = <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x540F, &mut pgrp as *mut i32 as i64);
16956    if r < 0 { -1 } else { pgrp }
16957}
16958
16959#[no_mangle]
16960pub unsafe extern "C" fn tcsetpgrp(fd: i32, pgrp: i32) -> i32 {
16961    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5410, &pgrp as *const i32 as i64) as i32
16962}
16963
16964// ============================================================
16965// Memory locking functions
16966// ============================================================
16967
16968// ============================================================
16969
16970// ============================================================
16971// POSIX message queue functions
16972// ============================================================
16973
16974#[no_mangle]
16975pub unsafe extern "C" fn mq_open(name: *const core::ffi::c_char, oflag: i32, _args: ...) -> i64 {
16976    crate::open(name, oflag, 0) as i64
16977}
16978
16979#[no_mangle]
16980pub unsafe extern "C" fn mq_close(mqdes: i64) -> i32 {
16981    crate::close(mqdes as i32)
16982}
16983
16984#[no_mangle]
16985pub unsafe extern "C" fn mq_unlink(name: *const core::ffi::c_char) -> i32 {
16986    crate::unlink(name)
16987}
16988
16989#[no_mangle]
16990pub unsafe extern "C" fn mq_send(mqdes: i64, msg_ptr: *const core::ffi::c_char, msg_len: usize, _msg_prio: u32) -> i32 {
16991    let r = crate::write(mqdes as i32, msg_ptr as *const core::ffi::c_void, msg_len) as i32;
16992    if r >= 0 { mq_notify_fire(mqdes); }
16993    r
16994}
16995
16996#[no_mangle]
16997pub unsafe extern "C" fn mq_receive(mqdes: i64, msg_ptr: *mut core::ffi::c_char, msg_len: usize, _msg_prio: *mut u32) -> isize {
16998    crate::read(mqdes as i32, msg_ptr as *mut core::ffi::c_void, msg_len)
16999}
17000
17001#[no_mangle]
17002pub unsafe extern "C" fn mq_timedsend(mqdes: i64, msg_ptr: *const core::ffi::c_char, msg_len: usize, msg_prio: u32, _abs_timeout: *const core::ffi::c_void) -> i32 {
17003    mq_send(mqdes, msg_ptr, msg_len, msg_prio)
17004}
17005
17006#[no_mangle]
17007pub unsafe extern "C" fn mq_timedreceive(mqdes: i64, msg_ptr: *mut core::ffi::c_char, msg_len: usize, msg_prio: *mut u32, _abs_timeout: *const core::ffi::c_void) -> isize {
17008    mq_receive(mqdes, msg_ptr, msg_len, msg_prio)
17009}
17010
17011// ============================================================
17012// pthread functions
17013// ============================================================
17014
17015#[no_mangle]
17016pub unsafe extern "C" fn pthread_getaffinity_np(thread: usize, cpusetsize: usize, cpuset: *mut u8) -> i32 {
17017    sched_getaffinity(thread as i32, cpusetsize, cpuset)
17018}
17019
17020#[no_mangle]
17021pub unsafe extern "C" fn pthread_setaffinity_np(thread: usize, cpusetsize: usize, cpuset: *const u8) -> i32 {
17022    sched_setaffinity(thread as i32, cpusetsize, cpuset)
17023}
17024
17025// ============================================================
17026// sched functions
17027// ============================================================
17028
17029#[no_mangle]
17030pub unsafe extern "C" fn sched_yield() -> i32 {
17031    <Arch as Syscalls>::syscall0(sysno(24, 124)) as i32
17032}
17033
17034#[no_mangle]
17035pub unsafe extern "C" fn sched_get_priority_max(policy: i32) -> i32 {
17036    <Arch as Syscalls>::syscall1(sysno(146, 125), policy as i64) as i32
17037}
17038
17039#[no_mangle]
17040pub unsafe extern "C" fn sched_get_priority_min(policy: i32) -> i32 {
17041    <Arch as Syscalls>::syscall1(sysno(147, 126), policy as i64) as i32
17042}
17043
17044#[no_mangle]
17045pub unsafe extern "C" fn sched_getparam(pid: i32, param: *mut core::ffi::c_void) -> i32 {
17046    <Arch as Syscalls>::syscall2(sysno(143, 121), pid as i64, param as i64) as i32
17047}
17048
17049#[no_mangle]
17050pub unsafe extern "C" fn sched_setparam(pid: i32, param: *const core::ffi::c_void) -> i32 {
17051    <Arch as Syscalls>::syscall2(sysno(142, 118), pid as i64, param as i64) as i32
17052}
17053
17054#[no_mangle]
17055pub unsafe extern "C" fn sched_getscheduler(pid: i32) -> i32 {
17056    <Arch as Syscalls>::syscall1(sysno(145, 120), pid as i64) as i32
17057}
17058
17059#[no_mangle]
17060pub unsafe extern "C" fn sched_setscheduler(pid: i32, policy: i32, param: *const core::ffi::c_void) -> i32 {
17061    <Arch as Syscalls>::syscall3(sysno(144, 119), pid as i64, policy as i64, param as i64) as i32
17062}
17063
17064#[no_mangle]
17065pub unsafe extern "C" fn sched_setaffinity(pid: i32, cpusetsize: usize, cpuset: *const u8) -> i32 {
17066    <Arch as Syscalls>::syscall3(sysno(203, 122), pid as i64, cpusetsize as i64, cpuset as i64) as i32
17067}
17068
17069#[no_mangle]
17070pub unsafe extern "C" fn sched_getaffinity(pid: i32, cpusetsize: usize, cpuset: *mut u8) -> i32 {
17071    <Arch as Syscalls>::syscall3(sysno(204, 123), pid as i64, cpusetsize as i64, cpuset as i64) as i32
17072}
17073
17074#[no_mangle]
17075pub unsafe extern "C" fn sched_getcpu() -> i32 {
17076    let mut cpu: i32 = 0;
17077    <Arch as Syscalls>::syscall3(sysno(309, 168), &mut cpu as *mut i32 as i64, 0, 0);
17078    cpu
17079}
17080
17081#[no_mangle]
17082pub unsafe extern "C" fn sched_rr_get_interval(pid: i32, tp: *mut core::ffi::c_void) -> i32 {
17083    <Arch as Syscalls>::syscall2(sysno(148, 127), pid as i64, tp as i64) as i32
17084}
17085
17086// ============================================================
17087// timer/clock functions
17088// ============================================================
17089
17090#[no_mangle]
17091pub unsafe extern "C" fn timer_create(clockid: i32, sevp: *mut core::ffi::c_void, timerid: *mut i32) -> i32 {
17092    <Arch as Syscalls>::syscall3(sysno(222, 107), clockid as i64, sevp as i64, timerid as i64) as i32
17093}
17094
17095#[no_mangle]
17096pub unsafe extern "C" fn timer_delete(timerid: i32) -> i32 {
17097    <Arch as Syscalls>::syscall1(sysno(226, 111), timerid as i64) as i32
17098}
17099
17100#[no_mangle]
17101pub unsafe extern "C" fn timer_settime(timerid: i32, flags: i32, new_value: *const core::ffi::c_void, old_value: *mut core::ffi::c_void) -> i32 {
17102    <Arch as Syscalls>::syscall4(sysno(223, 110), timerid as i64, flags as i64, new_value as i64, old_value as i64) as i32
17103}
17104
17105#[no_mangle]
17106pub unsafe extern "C" fn timer_gettime(timerid: i32, curr_value: *mut core::ffi::c_void) -> i32 {
17107    <Arch as Syscalls>::syscall2(sysno(224, 108), timerid as i64, curr_value as i64) as i32
17108}
17109
17110#[no_mangle]
17111pub unsafe extern "C" fn timer_getoverrun(timerid: i32) -> i32 {
17112    <Arch as Syscalls>::syscall1(sysno(225, 109), timerid as i64) as i32
17113}
17114
17115#[no_mangle]
17116pub unsafe extern "C" fn clock_adjtime(_clockid: i32, buf: *mut core::ffi::c_void) -> i32 {
17117    <Arch as Syscalls>::syscall2(SYS_ADJTIMEX, buf as i64, 0) as i32
17118}
17119
17120#[no_mangle]
17121pub unsafe extern "C" fn clock_getcpuclockid(pid: i32, clockid: *mut i32) -> i32 {
17122    if clockid.is_null() { return EINVAL; }
17123    let id: i32 = ((-(pid as i64) - 1) * 8 + 2) as i32;
17124    let mut ts: timespec = core::mem::zeroed();
17125    let r = <Arch as Syscalls>::syscall2(SYS_CLOCK_GETRES, id as i64, &mut ts as *mut timespec as i64);
17126    if r < 0 {
17127        let e = (-r) as c_int;
17128        return if e == EINVAL { 3 } else { e };
17129    }
17130    *clockid = id;
17131    0
17132}
17133
17134// ============================================================
17135// String functions
17136// ============================================================
17137
17138#[no_mangle]
17139pub unsafe extern "C" fn strcoll(s1: *const core::ffi::c_char, s2: *const core::ffi::c_char) -> i32 {
17140    // ponytail: simplified collation - just strcmp
17141    let mut i = 0;
17142    loop {
17143        let c1 = *s1.add(i) as u8;
17144        let c2 = *s2.add(i) as u8;
17145        if c1 == 0 || c2 == 0 { return (c1 as i32) - (c2 as i32); }
17146        if c1 != c2 { return (c1 as i32) - (c2 as i32); }
17147        i += 1;
17148    }
17149}
17150
17151#[no_mangle]
17152pub unsafe extern "C" fn strxfrm(dest: *mut core::ffi::c_char, src: *const core::ffi::c_char, n: usize) -> usize {
17153    let mut i = 0;
17154    while i < n {
17155        let c = *src.add(i);
17156        *dest.add(i) = c;
17157        if c == 0 { break; }
17158        i += 1;
17159    }
17160    i
17161}
17162
17163// ============================================================
17164// Directory functions
17165// ============================================================
17166
17167#[no_mangle]
17168pub unsafe extern "C" fn scandir(dirp: *const core::ffi::c_char, _namelist: *mut *mut *mut core::ffi::c_void, _filter: Option<unsafe extern "C" fn(*const core::ffi::c_void) -> i32>, _compar: Option<unsafe extern "C" fn(*const core::ffi::c_void, *const core::ffi::c_void) -> i32>) -> i32 {
17169    let dir = opendir(dirp);
17170    if dir.is_null() { return -1; }
17171    let mut count = 0;
17172    loop {
17173        let ent = readdir(dir);
17174        if ent.is_null() { break; }
17175        count += 1;
17176    }
17177    closedir(dir);
17178    count
17179}
17180
17181#[no_mangle]
17182pub unsafe extern "C" fn alphasort(a: *const *const core::ffi::c_void, b: *const *const core::ffi::c_void) -> i32 {
17183    let s1 = *a as *const core::ffi::c_char;
17184    let s2 = *b as *const core::ffi::c_char;
17185    crate::strcmp(s1 as *const u8, s2 as *const u8)
17186}
17187
17188#[no_mangle]
17189pub unsafe extern "C" fn versionsort(a: *const *const core::ffi::c_void, b: *const *const core::ffi::c_void) -> i32 {
17190    let s1 = *a as *const core::ffi::c_char;
17191    let s2 = *b as *const core::ffi::c_char;
17192    crate::strcmp(s1 as *const u8, s2 as *const u8)
17193}
17194
17195// ============================================================
17196
17197
17198// ============================================================
17199// err functions
17200// ============================================================
17201
17202unsafe fn vwarn_impl(fmt: *const c_char, ap: VaList, with_errno: bool) {
17203    let mut buf = [0 as c_char; 1024];
17204    let n = vsnprintf(buf.as_mut_ptr(), buf.len(), fmt, ap);
17205    if n > 0 {
17206        let l = core::cmp::min(n as usize, buf.len() - 1);
17207        crate::write(2, buf.as_ptr() as *const c_void, l);
17208    }
17209    if with_errno {
17210        let e = ERRNO;
17211        crate::write(2, b": ".as_ptr() as *const c_void, 2);
17212        let msg = strerror(e);
17213        crate::write(2, msg as *const c_void, crate::strlen(msg));
17214    }
17215    crate::write(2, b"\n".as_ptr() as *const c_void, 1);
17216}
17217
17218#[no_mangle]
17219pub unsafe extern "C" fn verr(eval: c_int, fmt: *const c_char, ap: VaList) {
17220    vwarn_impl(fmt, ap, true);
17221    crate::exit(eval);
17222}
17223
17224#[no_mangle]
17225pub unsafe extern "C" fn verrx(eval: c_int, fmt: *const c_char, ap: VaList) {
17226    vwarn_impl(fmt, ap, false);
17227    crate::exit(eval);
17228}
17229
17230#[no_mangle]
17231pub unsafe extern "C" fn vwarn(fmt: *const c_char, ap: VaList) {
17232    vwarn_impl(fmt, ap, true);
17233}
17234
17235#[no_mangle]
17236pub unsafe extern "C" fn vwarnx(fmt: *const c_char, ap: VaList) {
17237    vwarn_impl(fmt, ap, false);
17238}
17239
17240#[no_mangle]
17241pub unsafe extern "C" fn err(eval: c_int, fmt: *const c_char, args: ...) {
17242    verr(eval, fmt, args);
17243}
17244
17245#[no_mangle]
17246pub unsafe extern "C" fn errx(eval: c_int, fmt: *const c_char, args: ...) {
17247    verrx(eval, fmt, args);
17248}
17249
17250#[no_mangle]
17251pub unsafe extern "C" fn warn(fmt: *const c_char, args: ...) {
17252    vwarn(fmt, args);
17253}
17254
17255#[no_mangle]
17256pub unsafe extern "C" fn warnx(fmt: *const c_char, args: ...) {
17257    vwarnx(fmt, args);
17258}
17259
17260// ============================================================
17261// ecvt functions
17262// ============================================================
17263
17264#[no_mangle]
17265pub unsafe extern "C" fn ecvt(value: f64, ndigit: i32, decpt: *mut i32, sign: *mut i32) -> *mut core::ffi::c_char {
17266    static mut BUF: [core::ffi::c_char; 80] = [0; 80];
17267    if value < 0.0 { *sign = 1; } else { *sign = 0; }
17268    let v = if value < 0.0 { -value } else { value };
17269    if v == 0.0 { *decpt = 0; BUF[0] = 0; return BUF.as_mut_ptr(); }
17270    let mut d = 0i32;
17271    let mut tmp = v;
17272    while tmp >= 10.0 { tmp /= 10.0; d += 1; }
17273    while tmp < 1.0 { tmp *= 10.0; d -= 1; }
17274    *decpt = d + 1;
17275    let mut i = 0;
17276    let mut val = tmp;
17277    while i < ndigit as usize && i < 79 {
17278        let digit = val as i32;
17279        BUF[i] = (b'0' + digit as u8) as c_char;
17280        val = (val - digit as f64) * 10.0;
17281        i += 1;
17282    }
17283    BUF[i] = 0;
17284    BUF.as_mut_ptr()
17285}
17286
17287#[no_mangle]
17288pub unsafe extern "C" fn fcvt(value: f64, ndigit: i32, decpt: *mut i32, sign: *mut i32) -> *mut core::ffi::c_char {
17289    static mut BUF: [core::ffi::c_char; 80] = [0; 80];
17290    if value < 0.0 { *sign = 1; } else { *sign = 0; }
17291    let v = if value < 0.0 { -value } else { value };
17292    if v == 0.0 { *decpt = 0; BUF[0] = 0; return BUF.as_mut_ptr(); }
17293    let mut d = 0i32;
17294    let mut tmp = v;
17295    while tmp >= 10.0 { tmp /= 10.0; d += 1; }
17296    while tmp < 1.0 { tmp *= 10.0; d -= 1; }
17297    *decpt = d + 1;
17298    let mut val = tmp;
17299    let mut i = 0;
17300    while i < (*decpt) as usize && i < 79 {
17301        let digit = val as i32;
17302        BUF[i] = (b'0' + digit as u8) as c_char;
17303        val = (val - digit as f64) * 10.0;
17304        i += 1;
17305    }
17306    if ndigit > 0 && i < 79 {
17307        BUF[i] = '.' as c_char;
17308        i += 1;
17309        let mut frac = val;
17310        let mut j = 0;
17311        while j < ndigit as usize && i < 79 {
17312            let digit = frac as i32;
17313            BUF[i] = (b'0' + digit as u8) as c_char;
17314            frac = (frac - digit as f64) * 10.0;
17315            i += 1;
17316            j += 1;
17317        }
17318    }
17319    BUF[i] = 0;
17320    BUF.as_mut_ptr()
17321}
17322
17323#[no_mangle]
17324pub unsafe extern "C" fn gcvt(value: f64, _ndigit: i32, buf: *mut core::ffi::c_char) -> *mut core::ffi::c_char {
17325    // Simple implementation - convert to string
17326    if value == 0.0 {
17327        *buf = '0' as c_char;
17328        *buf.add(1) = 0;
17329        return buf;
17330    }
17331    let mut i = 0;
17332    let v = if value < 0.0 { *buf = '-' as c_char; i = 1; -value } else { value };
17333    // Integer part
17334    let mut int_part = v as i64;
17335    let mut digits = [0u8; 32];
17336    let mut di = 0;
17337    if int_part == 0 {
17338        digits[0] = 0;
17339        di = 1;
17340    } else {
17341        while int_part > 0 && di < 32 {
17342            digits[di] = (int_part % 10) as u8;
17343            int_part /= 10;
17344            di += 1;
17345        }
17346    }
17347    while di > 0 && i < 79 {
17348        di -= 1;
17349        *buf.add(i) = (b'0' + digits[di]) as c_char;
17350        i += 1;
17351    }
17352    *buf.add(i) = 0;
17353    buf
17354}
17355
17356// ============================================================
17357// usershell functions
17358// ============================================================
17359
17360static mut SHELLS: [*const core::ffi::c_char; 3] = [
17361    b"/bin/sh\0".as_ptr() as *const core::ffi::c_char,
17362    b"/bin/bash\0".as_ptr() as *const core::ffi::c_char,
17363    core::ptr::null(),
17364];
17365static mut SHELL_IDX: usize = 0;
17366
17367#[no_mangle]
17368pub unsafe extern "C" fn getusershell() -> *mut core::ffi::c_char {
17369    let s = SHELLS[SHELL_IDX];
17370    if s.is_null() {
17371        SHELL_IDX = 0;
17372        return core::ptr::null_mut();
17373    }
17374    SHELL_IDX += 1;
17375    s as *mut core::ffi::c_char
17376}
17377
17378#[no_mangle]
17379pub unsafe extern "C" fn setusershell() {
17380    SHELL_IDX = 0;
17381}
17382
17383#[no_mangle]
17384pub unsafe extern "C" fn endusershell() {
17385    SHELL_IDX = 0;
17386}
17387
17388// ============================================================
17389// ether functions
17390// ============================================================
17391
17392#[no_mangle]
17393pub unsafe extern "C" fn ether_aton(s: *const core::ffi::c_char) -> *mut u8 {
17394    static mut EA: [u8; 6] = [0; 6];
17395    if ether_aton_r(s, EA.as_mut_ptr()).is_null() { core::ptr::null_mut() } else { EA.as_mut_ptr() }
17396}
17397
17398#[no_mangle]
17399pub unsafe extern "C" fn ether_aton_r(s: *const core::ffi::c_char, ea: *mut u8) -> *mut u8 {
17400    if ea.is_null() { return core::ptr::null_mut(); }
17401    let mut i = 0;
17402    let mut j = 0;
17403    let mut val: u32 = 0;
17404    let mut digits = 0;
17405    while *s.add(i) != 0 && j < 6 {
17406        let c = *s.add(i);
17407        if c == ':' as c_char {
17408            if digits == 0 { return core::ptr::null_mut(); }
17409            *ea.add(j) = val as u8;
17410            j += 1;
17411            val = 0;
17412            digits = 0;
17413        } else if (c >= '0' as c_char && c <= '9' as c_char) || (c >= 'a' as c_char && c <= 'f' as c_char) || (c >= 'A' as c_char && c <= 'F' as c_char) {
17414            let d = if c >= '0' as c_char && c <= '9' as c_char { (c - '0' as c_char) as u32 }
17415                   else if c >= 'a' as c_char { (c - 'a' as c_char + 10) as u32 }
17416                   else { (c - 'A' as c_char + 10) as u32 };
17417            val = val * 16 + d;
17418            if val > 255 { return core::ptr::null_mut(); }
17419            digits += 1;
17420            if digits > 2 { return core::ptr::null_mut(); }
17421        } else {
17422            return core::ptr::null_mut();
17423        }
17424        i += 1;
17425    }
17426    if digits == 0 || j != 5 { return core::ptr::null_mut(); }
17427    *ea.add(j) = val as u8;
17428    ea
17429}
17430
17431#[no_mangle]
17432pub unsafe extern "C" fn ether_ntoa(ea: *const u8) -> *mut core::ffi::c_char {
17433    static mut BUF: [core::ffi::c_char; 18] = [0; 18];
17434    ether_ntoa_r(ea, BUF.as_mut_ptr());
17435    BUF.as_mut_ptr()
17436}
17437
17438#[no_mangle]
17439pub unsafe extern "C" fn ether_ntoa_r(ea: *const u8, buf: *mut core::ffi::c_char) -> *mut core::ffi::c_char {
17440    let a = *ea.add(0); let b = *ea.add(1); let c = *ea.add(2);
17441    let d = *ea.add(3); let e = *ea.add(4); let f = *ea.add(5);
17442    let hex = b"0123456789abcdef\0".as_ptr() as *const u8;
17443    let mut i = 0;
17444    *buf.add(i) = *hex.add((a >> 4) as usize) as c_char; i += 1;
17445    *buf.add(i) = *hex.add((a & 0xf) as usize) as c_char; i += 1;
17446    *buf.add(i) = ':' as c_char; i += 1;
17447    *buf.add(i) = *hex.add((b >> 4) as usize) as c_char; i += 1;
17448    *buf.add(i) = *hex.add((b & 0xf) as usize) as c_char; i += 1;
17449    *buf.add(i) = ':' as c_char; i += 1;
17450    *buf.add(i) = *hex.add((c >> 4) as usize) as c_char; i += 1;
17451    *buf.add(i) = *hex.add((c & 0xf) as usize) as c_char; i += 1;
17452    *buf.add(i) = ':' as c_char; i += 1;
17453    *buf.add(i) = *hex.add((d >> 4) as usize) as c_char; i += 1;
17454    *buf.add(i) = *hex.add((d & 0xf) as usize) as c_char; i += 1;
17455    *buf.add(i) = ':' as c_char; i += 1;
17456    *buf.add(i) = *hex.add((e >> 4) as usize) as c_char; i += 1;
17457    *buf.add(i) = *hex.add((e & 0xf) as usize) as c_char; i += 1;
17458    *buf.add(i) = ':' as c_char; i += 1;
17459    *buf.add(i) = *hex.add((f >> 4) as usize) as c_char; i += 1;
17460    *buf.add(i) = *hex.add((f & 0xf) as usize) as c_char; i += 1;
17461    *buf.add(i) = 0;
17462    buf
17463}
17464
17465// ============================================================
17466// utmpx functions
17467// ============================================================
17468
17469#[no_mangle]
17470pub unsafe extern "C" fn getutxent() -> *mut core::ffi::c_void {
17471    getutent()
17472}
17473
17474#[no_mangle]
17475pub unsafe extern "C" fn getutxid(ut: *const core::ffi::c_void) -> *mut core::ffi::c_void {
17476    getutid(ut)
17477}
17478
17479#[no_mangle]
17480pub unsafe extern "C" fn getutxline(ut: *const core::ffi::c_void) -> *mut core::ffi::c_void {
17481    getutline(ut)
17482}
17483
17484#[no_mangle]
17485pub unsafe extern "C" fn pututxline(ut: *const core::ffi::c_void) -> *mut core::ffi::c_void {
17486    pututline(ut)
17487}
17488
17489#[no_mangle]
17490pub unsafe extern "C" fn setutxent() {
17491    setutent()
17492}
17493
17494#[no_mangle]
17495pub unsafe extern "C" fn endutxent() {
17496    endutent()
17497}
17498
17499// ============================================================
17500// exec functions
17501// ============================================================
17502
17503#[no_mangle]
17504pub unsafe extern "C" fn execv(path: *const core::ffi::c_char, argv: *const *const core::ffi::c_char) -> i32 {
17505    crate::execve(path, argv, core::ptr::null())
17506}
17507
17508#[no_mangle]
17509pub unsafe extern "C" fn execlp(file: *const core::ffi::c_char, _args: ...) -> i32 {
17510    // Build argv from varargs
17511    let mut argv: [*const core::ffi::c_char; 64] = [core::ptr::null(); 64];
17512    let mut i = 0;
17513    let mut args = _args;
17514    loop {
17515        let arg = args.next_arg::<*const core::ffi::c_char>();
17516        if arg.is_null() { break; }
17517        argv[i] = arg;
17518        i += 1;
17519        if i >= 63 { break; }
17520    }
17521    argv[i] = core::ptr::null();
17522    execvp(file, argv.as_ptr())
17523}
17524
17525#[no_mangle]
17526pub unsafe extern "C" fn execvp(file: *const core::ffi::c_char, argv: *const *const core::ffi::c_char) -> i32 {
17527    // Search PATH for the executable
17528    let path = crate::getenv(b"PATH\0".as_ptr() as *const core::ffi::c_char);
17529    if path.is_null() { return -1; }
17530    // For now, just try to execute directly
17531    crate::execve(file, argv, core::ptr::null())
17532}
17533
17534#[no_mangle]
17535pub unsafe extern "C" fn fexecve(fd: i32, argv: *const *const core::ffi::c_char, envp: *const *const core::ffi::c_char) -> i32 {
17536    // Read /proc/self/fd/N to get the path
17537    let mut path: [core::ffi::c_char; 64] = [0; 64];
17538    let mut i = 0;
17539    let src = b"/proc/self/fd/\0".as_ptr() as *const core::ffi::c_char;
17540    while i < 63 && *src.add(i) != 0 { path[i] = *src.add(i); i += 1; }
17541    let mut n = fd as usize;
17542    if n == 0 { path[i] = '0' as c_char; i += 1; }
17543    while n > 0 && i < 63 {
17544        path[i] = (b'0' + (n % 10) as u8) as c_char;
17545        n /= 10;
17546        i += 1;
17547    }
17548    path[i] = 0;
17549    crate::execve(path.as_ptr(), argv, envp)
17550}
17551
17552// ============================================================
17553// conf functions
17554// ============================================================
17555
17556#[no_mangle]
17557pub unsafe extern "C" fn confstr(name: i32, buf: *mut core::ffi::c_char, len: usize) -> usize {
17558    match name {
17559        0 => { // _CS_PATH
17560            let s = b"/bin:/usr/bin\0".as_ptr() as *const core::ffi::c_char;
17561            let mut i = 0;
17562            while i < len - 1 && *s.add(i) != 0 { *buf.add(i) = *s.add(i); i += 1; }
17563            *buf.add(i) = 0;
17564            i + 1
17565        }
17566        1 => { // _CS_V6_WIDTH_RESTRICTED_ENVS
17567            let s = b"\0".as_ptr() as *const core::ffi::c_char;
17568            let mut i = 0;
17569            while i < len - 1 && *s.add(i) != 0 { *buf.add(i) = *s.add(i); i += 1; }
17570            *buf.add(i) = 0;
17571            i + 1
17572        }
17573        _ => 0,
17574    }
17575}
17576
17577#[no_mangle]
17578pub unsafe extern "C" fn pathconf(_path: *const core::ffi::c_char, name: i32) -> i64 {
17579    // Return default values
17580    match name {
17581        0 => 4096, // _PC_LINK_MAX
17582        1 => 255,  // _PC_MAX_CANON
17583        2 => 255,  // _PC_MAX_INPUT
17584        3 => 255,  // _PC_NAME_MAX
17585        4 => 4096, // _PC_PATH_MAX
17586        5 => 4096, // _PC_PIPE_BUF
17587        6 => 1,    // _PC_CHOWN_RESTRICTED
17588        7 => 0,    // _PC_NO_TRUNC
17589        8 => 0,    // _PC_VDISABLE
17590        _ => -1,
17591    }
17592}
17593
17594#[no_mangle]
17595pub unsafe extern "C" fn fpathconf(_fd: i32, name: i32) -> i64 {
17596    // Return default values
17597    match name {
17598        0 => 4096, // _PC_LINK_MAX
17599        1 => 255,  // _PC_MAX_CANON
17600        2 => 255,  // _PC_MAX_INPUT
17601        3 => 255,  // _PC_NAME_MAX
17602        4 => 4096, // _PC_PATH_MAX
17603        5 => 4096, // _PC_PIPE_BUF
17604        6 => 1,    // _PC_CHOWN_RESTRICTED
17605        7 => 0,    // _PC_NO_TRUNC
17606        8 => 0,    // _PC_VDISABLE
17607        _ => -1,
17608    }
17609}
17610
17611// ============================================================
17612// exp10 functions
17613// ============================================================
17614
17615#[no_mangle]
17616pub unsafe extern "C" fn exp10(x: f64) -> f64 {
17617    libm::pow(10.0, x)
17618}
17619
17620#[no_mangle]
17621pub unsafe extern "C" fn exp10f(x: f32) -> f32 {
17622    libm::powf(10.0, x)
17623}
17624
17625// ============================================================
17626// memory functions
17627// ============================================================
17628
17629#[no_mangle]
17630pub unsafe extern "C" fn explicit_bzero(s: *mut u8, n: usize) {
17631    core::ptr::write_bytes(s, 0, n);
17632    core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
17633}
17634
17635#[no_mangle]
17636pub unsafe extern "C" fn memccpy(dest: *mut u8, src: *const u8, c: i32, n: usize) -> *mut u8 {
17637    let mut i = 0;
17638    while i < n {
17639        let byte = *src.add(i);
17640        *dest.add(i) = byte;
17641        if byte == c as u8 {
17642            return dest.add(i + 1);
17643        }
17644        i += 1;
17645    }
17646    core::ptr::null_mut()
17647}
17648
17649// ============================================================
17650// *at functions
17651// ============================================================
17652
17653#[no_mangle]
17654pub unsafe extern "C" fn faccessat(dirfd: i32, pathname: *const core::ffi::c_char, mode: i32, flags: i32) -> i32 {
17655    <Arch as Syscalls>::syscall4(SYS_FACCESSAT, dirfd as i64, pathname as i64, mode as i64, flags as i64) as i32
17656}
17657
17658#[no_mangle]
17659pub unsafe extern "C" fn fchmodat(dirfd: i32, pathname: *const core::ffi::c_char, mode: u32, flags: i32) -> i32 {
17660    <Arch as Syscalls>::syscall4(SYS_FCHMODAT, dirfd as i64, pathname as i64, mode as i64, flags as i64) as i32
17661}
17662
17663#[no_mangle]
17664pub unsafe extern "C" fn fchownat(dirfd: i32, pathname: *const core::ffi::c_char, uid: u32, gid: u32, flags: i32) -> i32 {
17665    <Arch as Syscalls>::syscall5(sysno(260, 54), dirfd as i64, pathname as i64, uid as i64, gid as i64, flags as i64) as i32
17666}
17667
17668#[no_mangle]
17669pub unsafe extern "C" fn linkat(olddirfd: i32, oldpath: *const core::ffi::c_char, newdirfd: i32, newpath: *const core::ffi::c_char, flags: i32) -> i32 {
17670    <Arch as Syscalls>::syscall5(SYS_LINKAT, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64, flags as i64) as i32
17671}
17672
17673#[no_mangle]
17674pub unsafe extern "C" fn mkdirat(dirfd: i32, pathname: *const core::ffi::c_char, mode: u32) -> i32 {
17675    <Arch as Syscalls>::syscall3(SYS_MKDIRAT, dirfd as i64, pathname as i64, mode as i64) as i32
17676}
17677
17678#[no_mangle]
17679pub unsafe extern "C" fn mkfifoat(dirfd: i32, pathname: *const core::ffi::c_char, mode: u32) -> i32 {
17680    mknodat(dirfd, pathname, mode | 0o010000, 0)
17681}
17682
17683#[no_mangle]
17684pub unsafe extern "C" fn mknodat(dirfd: i32, pathname: *const core::ffi::c_char, mode: u32, dev: u64) -> i32 {
17685    <Arch as Syscalls>::syscall4(sysno(259, 33), dirfd as i64, pathname as i64, mode as i64, dev as i64) as i32
17686}
17687
17688#[no_mangle]
17689pub unsafe extern "C" fn readlinkat(dirfd: i32, pathname: *const core::ffi::c_char, buf: *mut core::ffi::c_char, bufsiz: usize) -> isize {
17690    <Arch as Syscalls>::syscall4(SYS_READLINKAT, dirfd as i64, pathname as i64, buf as i64, bufsiz as i64) as isize
17691}
17692
17693#[no_mangle]
17694pub unsafe extern "C" fn renameat(olddirfd: i32, oldpath: *const core::ffi::c_char, newdirfd: i32, newpath: *const core::ffi::c_char) -> i32 {
17695    <Arch as Syscalls>::syscall4(SYS_RENAMEAT2, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64) as i32
17696}
17697
17698#[no_mangle]
17699pub unsafe extern "C" fn renameat2(olddirfd: i32, oldpath: *const core::ffi::c_char, newdirfd: i32, newpath: *const core::ffi::c_char, flags: u32) -> i32 {
17700    <Arch as Syscalls>::syscall5(SYS_RENAMEAT2, olddirfd as i64, oldpath as i64, newdirfd as i64, newpath as i64, flags as i64) as i32
17701}
17702
17703#[no_mangle]
17704pub unsafe extern "C" fn symlinkat(target: *const core::ffi::c_char, newdirfd: i32, linkpath: *const core::ffi::c_char) -> i32 {
17705    <Arch as Syscalls>::syscall3(SYS_SYMLINKAT, target as i64, newdirfd as i64, linkpath as i64) as i32
17706}
17707
17708#[no_mangle]
17709pub unsafe extern "C" fn unlinkat(dirfd: i32, pathname: *const core::ffi::c_char, flags: i32) -> i32 {
17710    <Arch as Syscalls>::syscall3(SYS_UNLINKAT, dirfd as i64, pathname as i64, flags as i64) as i32
17711}
17712
17713#[no_mangle]
17714pub unsafe extern "C" fn utimes(filename: *const core::ffi::c_char, times: *const core::ffi::c_void) -> i32 {
17715    utimensat(AT_FDCWD, filename, times as *const timespec, 0)
17716}
17717
17718#[no_mangle]
17719pub unsafe extern "C" fn futimes(fd: i32, times: *const core::ffi::c_void) -> i32 {
17720    utimensat(fd, core::ptr::null(), times as *const timespec, 0)
17721}
17722
17723// ============================================================
17724// inotify functions
17725// ============================================================
17726
17727#[no_mangle]
17728pub unsafe extern "C" fn inotify_init() -> i32 {
17729    <Arch as Syscalls>::syscall1(sysno(253, 26), 0) as i32
17730}
17731
17732#[no_mangle]
17733pub unsafe extern "C" fn inotify_init1(flags: i32) -> i32 {
17734    <Arch as Syscalls>::syscall1(sysno(294, 26), flags as i64) as i32
17735}
17736
17737#[no_mangle]
17738pub unsafe extern "C" fn inotify_add_watch(fd: i32, pathname: *const core::ffi::c_char, mask: u32) -> i32 {
17739    <Arch as Syscalls>::syscall3(sysno(254, 27), fd as i64, pathname as i64, mask as i64) as i32
17740}
17741
17742#[no_mangle]
17743pub unsafe extern "C" fn inotify_rm_watch(fd: i32, wd: i32) -> i32 {
17744    <Arch as Syscalls>::syscall2(sysno(255, 28), fd as i64, wd as i64) as i32
17745}
17746
17747#[no_mangle]
17748pub unsafe extern "C" fn fanotify_init(flags: i32, event_f_flags: i32) -> i32 {
17749    <Arch as Syscalls>::syscall2(sysno(300, 262), flags as i64, event_f_flags as i64) as i32
17750}
17751
17752#[no_mangle]
17753pub unsafe extern "C" fn fanotify_mark(fd: i32, flags: i32, mask: u64, dirfd: i32, pathname: *const core::ffi::c_char) -> i32 {
17754    <Arch as Syscalls>::syscall5(sysno(301, 263), fd as i64, flags as i64, mask as i64, dirfd as i64, pathname as i64) as i32
17755}
17756
17757// ============================================================
17758// ffs functions
17759// ============================================================
17760
17761#[no_mangle]
17762pub unsafe extern "C" fn ffs(x: i32) -> i32 {
17763    if x == 0 { return 0; }
17764    x.trailing_zeros() as i32 + 1
17765}
17766
17767#[no_mangle]
17768pub unsafe extern "C" fn ffsl(x: i64) -> i32 {
17769    if x == 0 { return 0; }
17770    x.trailing_zeros() as i32 + 1
17771}
17772
17773#[no_mangle]
17774pub unsafe extern "C" fn ffsll(x: i64) -> i32 {
17775    if x == 0 { return 0; }
17776    x.trailing_zeros() as i32 + 1
17777}
17778
17779// ============================================================
17780// More system functions
17781// ============================================================
17782
17783#[no_mangle]
17784pub unsafe extern "C" fn fchdir(fd: i32) -> i32 {
17785    <Arch as Syscalls>::syscall1(SYS_FCHDIR, fd as i64) as i32
17786}
17787
17788#[no_mangle]
17789pub unsafe extern "C" fn fchown(fd: i32, uid: u32, gid: u32) -> i32 {
17790    <Arch as Syscalls>::syscall3(SYS_FCHOWN, fd as i64, uid as i64, gid as i64) as i32
17791}
17792
17793#[no_mangle]
17794pub unsafe extern "C" fn fdopendir(fd: i32) -> *mut core::ffi::c_void {
17795    // Convert fd to DIR*
17796    if fd < 0 { return core::ptr::null_mut(); }
17797    DIR_FD = fd;
17798    DIR_POS = 0;
17799    DIR_LEN = 0;
17800    &DIR_FD as *const i32 as *mut core::ffi::c_void
17801}
17802
17803#[no_mangle]
17804pub unsafe extern "C" fn getdtablesize() -> i32 {
17805    let mut rlim: Rlimit = core::mem::zeroed();
17806    if getrlimit(RLIMIT_NOFILE, &mut rlim) == 0 {
17807        rlim.rlim_cur as i32
17808    } else {
17809        1024
17810    }
17811}
17812
17813#[no_mangle]
17814pub unsafe extern "C" fn getentropy(buf: *mut u8, buflen: usize) -> i32 {
17815    getrandom(buf, buflen, 0) as i32
17816}
17817
17818#[no_mangle]
17819pub unsafe extern "C" fn getrandom(buf: *mut u8, buflen: usize, flags: u32) -> isize {
17820    <Arch as Syscalls>::syscall3(sysno(318, 278), buf as i64, buflen as i64, flags as i64) as isize
17821}
17822
17823#[no_mangle]
17824pub unsafe extern "C" fn killpg(pgrp: i32, sig: i32) -> i32 {
17825    <Arch as Syscalls>::syscall2(SYS_KILL, -pgrp as i64, sig as i64) as i32
17826}
17827
17828#[no_mangle]
17829pub unsafe extern "C" fn mkfifo(pathname: *const core::ffi::c_char, mode: u32) -> i32 {
17830    mknod(pathname, 0o010000 | mode, 0)
17831}
17832
17833// ============================================================
17834// Memory allocation functions
17835// ============================================================
17836
17837#[no_mangle]
17838pub unsafe extern "C" fn aligned_alloc(alignment: usize, size: usize) -> *mut core::ffi::c_void {
17839    alloc_aligned_impl(alignment, size) as *mut core::ffi::c_void
17840}
17841
17842#[no_mangle]
17843pub unsafe extern "C" fn memalign(alignment: usize, size: usize) -> *mut core::ffi::c_void {
17844    alloc_aligned_impl(alignment, size) as *mut core::ffi::c_void
17845}
17846
17847#[no_mangle]
17848pub unsafe extern "C" fn posix_memalign(memptr: *mut *mut core::ffi::c_void, alignment: usize, size: usize) -> i32 {
17849    if memptr.is_null() { return EINVAL; }
17850    if alignment < core::mem::size_of::<*mut core::ffi::c_void>() || !alignment.is_power_of_two() {
17851        return EINVAL;
17852    }
17853    let p = alloc_aligned_impl(alignment, size);
17854    if p.is_null() { return ENOMEM; }
17855    *memptr = p as *mut core::ffi::c_void;
17856    0
17857}
17858
17859#[no_mangle]
17860pub unsafe extern "C" fn valloc(size: usize) -> *mut core::ffi::c_void {
17861    alloc_aligned_impl(PAGE, size) as *mut core::ffi::c_void
17862}
17863
17864// ============================================================
17865// glob functions
17866// ============================================================
17867
17868// ============================================================
17869// wordexp functions
17870// ============================================================
17871
17872// ============================================================
17873// gettext functions
17874// ============================================================
17875
17876#[no_mangle]
17877pub unsafe extern "C" fn gettext(msgid: *const core::ffi::c_char) -> *const core::ffi::c_char {
17878    msgid
17879}
17880
17881#[no_mangle]
17882pub unsafe extern "C" fn dgettext(_domainname: *const core::ffi::c_char, msgid: *const core::ffi::c_char) -> *const core::ffi::c_char {
17883    msgid
17884}
17885
17886#[no_mangle]
17887pub unsafe extern "C" fn dcgettext(_domainname: *const core::ffi::c_char, msgid: *const core::ffi::c_char, _category: i32) -> *const core::ffi::c_char {
17888    msgid
17889}
17890
17891#[no_mangle]
17892pub unsafe extern "C" fn ngettext(msgid1: *const core::ffi::c_char, msgid2: *const core::ffi::c_char, n: u64) -> *const core::ffi::c_char {
17893    if n == 1 { msgid1 } else { msgid2 }
17894}
17895
17896#[no_mangle]
17897pub unsafe extern "C" fn dngettext(_domainname: *const core::ffi::c_char, msgid1: *const core::ffi::c_char, msgid2: *const core::ffi::c_char, n: u64) -> *const core::ffi::c_char {
17898    if n == 1 { msgid1 } else { msgid2 }
17899}
17900
17901#[no_mangle]
17902pub unsafe extern "C" fn dcngettext(_domainname: *const core::ffi::c_char, msgid1: *const core::ffi::c_char, msgid2: *const core::ffi::c_char, n: u64, _category: i32) -> *const core::ffi::c_char {
17903    if n == 1 { msgid1 } else { msgid2 }
17904}
17905
17906#[no_mangle]
17907pub unsafe extern "C" fn textdomain(domainname: *const core::ffi::c_char) -> *mut core::ffi::c_char {
17908    static mut DOMAIN: [core::ffi::c_char; 256] = [0; 256];
17909    if domainname.is_null() { return DOMAIN.as_mut_ptr(); }
17910    let mut i = 0;
17911    while i < 255 && *domainname.add(i) != 0 {
17912        DOMAIN[i] = *domainname.add(i);
17913        i += 1;
17914    }
17915    DOMAIN[i] = 0;
17916    DOMAIN.as_mut_ptr()
17917}
17918
17919#[no_mangle]
17920pub unsafe extern "C" fn bindtextdomain(_domainname: *const core::ffi::c_char, dirname: *const core::ffi::c_char) -> *mut core::ffi::c_char {
17921    dirname as *mut core::ffi::c_char
17922}
17923
17924#[no_mangle]
17925pub unsafe extern "C" fn bind_textdomain_codeset(_domainname: *const core::ffi::c_char, codeset: *const core::ffi::c_char) -> *mut core::ffi::c_char {
17926    codeset as *mut core::ffi::c_char
17927}
17928
17929// ============================================================
17930// Wide string functions
17931// ============================================================
17932
17933#[no_mangle]
17934pub unsafe extern "C" fn wmemcpy(dest: *mut u32, src: *const u32, n: usize) -> *mut u32 {
17935    let mut i = 0;
17936    while i < n {
17937        *dest.add(i) = *src.add(i);
17938        i += 1;
17939    }
17940    dest
17941}
17942
17943#[no_mangle]
17944pub unsafe extern "C" fn wmemmove(dest: *mut u32, src: *const u32, n: usize) -> *mut u32 {
17945    if dest as usize <= src as usize {
17946        let mut i = 0;
17947        while i < n {
17948            *dest.add(i) = *src.add(i);
17949            i += 1;
17950        }
17951    } else {
17952        let mut i = n;
17953        while i > 0 {
17954            i -= 1;
17955            *dest.add(i) = *src.add(i);
17956        }
17957    }
17958    dest
17959}
17960
17961#[no_mangle]
17962pub unsafe extern "C" fn wmemset(dest: *mut u32, c: u32, n: usize) -> *mut u32 {
17963    let mut i = 0;
17964    while i < n {
17965        *dest.add(i) = c;
17966        i += 1;
17967    }
17968    dest
17969}
17970
17971#[no_mangle]
17972pub unsafe extern "C" fn wmemcmp(s1: *const u32, s2: *const u32, n: usize) -> i32 {
17973    let mut i = 0;
17974    while i < n {
17975        let c1 = *s1.add(i);
17976        let c2 = *s2.add(i);
17977        if c1 != c2 { return (c1 as i32) - (c2 as i32); }
17978        i += 1;
17979    }
17980    0
17981}
17982
17983#[no_mangle]
17984pub unsafe extern "C" fn wmemchr(s: *const u32, c: u32, n: usize) -> *mut u32 {
17985    let mut i = 0;
17986    while i < n {
17987        if *s.add(i) == c { return s.add(i) as *mut u32; }
17988        i += 1;
17989    }
17990    core::ptr::null_mut()
17991}
17992
17993#[no_mangle]
17994pub unsafe extern "C" fn wcpcpy(dest: *mut u32, src: *const u32) -> *mut u32 {
17995    let mut i = 0;
17996    loop {
17997        let c = *src.add(i);
17998        *dest.add(i) = c;
17999        if c == 0 { return dest.add(i); }
18000        i += 1;
18001    }
18002}
18003
18004#[no_mangle]
18005pub unsafe extern "C" fn wcpncpy(dest: *mut u32, src: *const u32, n: usize) -> *mut u32 {
18006    let mut i = 0;
18007    while i < n {
18008        let c = *src.add(i);
18009        *dest.add(i) = c;
18010        if c == 0 { return dest.add(i); }
18011        i += 1;
18012    }
18013    dest.add(n)
18014}
18015
18016#[no_mangle]
18017pub unsafe extern "C" fn wprintf(fmt: *const wchar_t, args: ...) -> c_int {
18018    vfwprintf(stdout, fmt, args)
18019}
18020
18021#[no_mangle]
18022pub unsafe extern "C" fn vwprintf(fmt: *const wchar_t, ap: core::ffi::VaList) -> c_int {
18023    vfwprintf(stdout, fmt, ap)
18024}
18025
18026// ============================================================
18027// C32 functions
18028// ============================================================
18029
18030#[no_mangle]
18031pub unsafe extern "C" fn c16rtomb(s: *mut u8, c16: u16, ps: *mut core::ffi::c_void) -> usize {
18032    // UTF-16 to UTF-8, with surrogate pairs tracked in the mbstate.
18033    let state = ps as *mut u32;
18034    let saved: u32 = if state.is_null() { 0 } else { *state };
18035    if s.is_null() {
18036        if !state.is_null() { *state = 0; }
18037        return 1;
18038    }
18039    let cp: u32;
18040    if saved != 0 {
18041        if c16 < 0xdc00 || c16 > 0xdfff {
18042            if !state.is_null() { *state = 0; }
18043            ERRNO = EILSEQ;
18044            return !0usize;
18045        }
18046        cp = 0x10000 + (((saved - 0xd800) << 10) | ((c16 as u32) - 0xdc00));
18047        if !state.is_null() { *state = 0; }
18048    } else if c16 >= 0xd800 && c16 <= 0xdbff {
18049        if !state.is_null() { *state = c16 as u32; }
18050        return 0;
18051    } else if c16 >= 0xdc00 && c16 <= 0xdfff {
18052        ERRNO = EILSEQ;
18053        return !0usize;
18054    } else {
18055        cp = c16 as u32;
18056    }
18057    if cp < 0x80 {
18058        *s = cp as u8;
18059        1
18060    } else if cp < 0x800 {
18061        *s = (0xc0 | (cp >> 6)) as u8;
18062        *s.add(1) = (0x80 | (cp & 0x3f)) as u8;
18063        2
18064    } else if cp < 0x10000 {
18065        *s = (0xe0 | (cp >> 12)) as u8;
18066        *s.add(1) = (0x80 | ((cp >> 6) & 0x3f)) as u8;
18067        *s.add(2) = (0x80 | (cp & 0x3f)) as u8;
18068        3
18069    } else {
18070        *s = (0xf0 | (cp >> 18)) as u8;
18071        *s.add(1) = (0x80 | ((cp >> 12) & 0x3f)) as u8;
18072        *s.add(2) = (0x80 | ((cp >> 6) & 0x3f)) as u8;
18073        *s.add(3) = (0x80 | (cp & 0x3f)) as u8;
18074        4
18075    }
18076}
18077
18078#[no_mangle]
18079pub unsafe extern "C" fn c32rtomb(s: *mut u8, c32: u32, _ps: *mut core::ffi::c_void) -> usize {
18080    if s.is_null() { return 1; }
18081    if c32 > 0x10ffff || (c32 >= 0xd800 && c32 <= 0xdfff) {
18082        ERRNO = EILSEQ;
18083        return !0usize;
18084    }
18085    if c32 < 0x80 {
18086        *s = c32 as u8;
18087        1
18088    } else if c32 < 0x800 {
18089        *s = (0xc0 | (c32 >> 6)) as u8;
18090        *s.add(1) = (0x80 | (c32 & 0x3f)) as u8;
18091        2
18092    } else if c32 < 0x10000 {
18093        *s = (0xe0 | (c32 >> 12)) as u8;
18094        *s.add(1) = (0x80 | ((c32 >> 6) & 0x3f)) as u8;
18095        *s.add(2) = (0x80 | (c32 & 0x3f)) as u8;
18096        3
18097    } else {
18098        *s = (0xf0 | (c32 >> 18)) as u8;
18099        *s.add(1) = (0x80 | ((c32 >> 12) & 0x3f)) as u8;
18100        *s.add(2) = (0x80 | ((c32 >> 6) & 0x3f)) as u8;
18101        *s.add(3) = (0x80 | (c32 & 0x3f)) as u8;
18102        4
18103    }
18104}
18105
18106#[no_mangle]
18107pub unsafe extern "C" fn mbrtoc16(pc16: *mut u16, s: *const u8, n: usize, _ps: *mut core::ffi::c_void) -> usize {
18108    if s.is_null() { return 0; }
18109    if n == 0 { return 1; }
18110    let c = *s;
18111    if c == 0 { return 0; }
18112    if c < 0x80 {
18113        if !pc16.is_null() { *pc16 = c as u16; }
18114        return 1;
18115    }
18116    if c < 0xC2 { return 1; } // Invalid
18117    if c < 0xE0 {
18118        if n < 2 { return 1; }
18119        let c2 = *s.add(1);
18120        if (c2 & 0xC0) != 0x80 { return 1; }
18121        if !pc16.is_null() { *pc16 = ((((c & 0x1F) as u32) << 6) | ((c2 & 0x3F) as u32)) as u16; }
18122        return 2;
18123    }
18124    if c < 0xF0 {
18125        if n < 3 { return 1; }
18126        let c2 = *s.add(1);
18127        let c3 = *s.add(2);
18128        if (c2 & 0xC0) != 0x80 || (c3 & 0xC0) != 0x80 { return 1; }
18129        if !pc16.is_null() { *pc16 = ((((c & 0x0F) as u32) << 12) | (((c2 & 0x3F) as u32) << 6) | ((c3 & 0x3F) as u32)) as u16; }
18130        return 3;
18131    }
18132    1
18133}
18134
18135#[no_mangle]
18136pub unsafe extern "C" fn mbrtoc32(pc32: *mut u32, s: *const u8, n: usize, _ps: *mut core::ffi::c_void) -> usize {
18137    if s.is_null() { return 0; }
18138    if n == 0 { return 1; }
18139    let c = *s;
18140    if c == 0 { return 0; }
18141    if c < 0x80 {
18142        if !pc32.is_null() { *pc32 = c as u32; }
18143        return 1;
18144    }
18145    if c < 0xC2 { return 1; } // Invalid
18146    if c < 0xE0 {
18147        if n < 2 { return 1; }
18148        let c2 = *s.add(1);
18149        if (c2 & 0xC0) != 0x80 { return 1; }
18150        if !pc32.is_null() { *pc32 = (((c & 0x1F) as u32) << 6) | ((c2 & 0x3F) as u32); }
18151        return 2;
18152    }
18153    if c < 0xF0 {
18154        if n < 3 { return 1; }
18155        let c2 = *s.add(1);
18156        let c3 = *s.add(2);
18157        if (c2 & 0xC0) != 0x80 || (c3 & 0xC0) != 0x80 { return 1; }
18158        if !pc32.is_null() { *pc32 = (((c & 0x0F) as u32) << 12) | (((c2 & 0x3F) as u32) << 6) | ((c3 & 0x3F) as u32); }
18159        return 3;
18160    }
18161    if c < 0xF5 {
18162        if n < 4 { return 1; }
18163        let c2 = *s.add(1);
18164        let c3 = *s.add(2);
18165        let c4 = *s.add(3);
18166        if (c2 & 0xC0) != 0x80 || (c3 & 0xC0) != 0x80 || (c4 & 0xC0) != 0x80 { return 1; }
18167        if !pc32.is_null() { *pc32 = (((c & 0x07) as u32) << 18) | (((c2 & 0x3F) as u32) << 12) | (((c3 & 0x3F) as u32) << 6) | ((c4 & 0x3F) as u32); }
18168        return 4;
18169    }
18170    1
18171}
18172
18173// ============================================================
18174// Shadow functions
18175// ============================================================
18176
18177
18178
18179
18180// ============================================================
18181// chown functions
18182// ============================================================
18183
18184#[no_mangle]
18185pub unsafe extern "C" fn chown(path: *const core::ffi::c_char, uid: u32, gid: u32) -> i32 {
18186    <Arch as Syscalls>::syscall3(SYS_FCHOWNAT, AT_FDCWD as i64, path as i64, ((uid as u64) << 32 | gid as u64) as i64) as i32
18187}
18188
18189#[no_mangle]
18190pub unsafe extern "C" fn lchown(path: *const core::ffi::c_char, uid: u32, gid: u32) -> i32 {
18191    <Arch as Syscalls>::syscall4(SYS_FCHOWNAT, AT_FDCWD as i64, path as i64, ((uid as u64) << 32 | gid as u64) as i64, 0x100) as i32
18192}
18193
18194// ============================================================
18195// chroot functions
18196// ============================================================
18197
18198#[no_mangle]
18199pub unsafe extern "C" fn chroot(path: *const core::ffi::c_char) -> i32 {
18200    <Arch as Syscalls>::syscall1(SYS_CHROOT, path as i64) as i32
18201}
18202
18203#[no_mangle]
18204pub unsafe extern "C" fn get_current_dir_name() -> *mut core::ffi::c_char {
18205    static mut BUF: [core::ffi::c_char; 4096] = [0; 4096];
18206    let r = getcwd(BUF.as_mut_ptr(), 4096);
18207    if r.is_null() { core::ptr::null_mut() } else { BUF.as_mut_ptr() }
18208}
18209
18210// ============================================================
18211// I/O functions
18212// ============================================================
18213
18214#[no_mangle]
18215pub unsafe extern "C" fn creat(pathname: *const core::ffi::c_char, mode: u32) -> i32 {
18216    open(pathname, 0o100 | 0o200 | 0o1000, mode as i32)
18217}
18218
18219#[no_mangle]
18220pub unsafe extern "C" fn openat(dirfd: i32, pathname: *const core::ffi::c_char, flags: i32, mode: u32) -> i32 {
18221    <Arch as Syscalls>::syscall4(SYS_OPENAT, dirfd as i64, pathname as i64, flags as i64, mode as i64) as i32
18222}
18223
18224#[no_mangle]
18225pub unsafe extern "C" fn pwrite(fd: i32, buf: *const u8, count: usize, offset: i64) -> isize {
18226    <Arch as Syscalls>::syscall4(sysno(18, 68), fd as i64, buf as i64, count as i64, offset) as isize
18227}
18228
18229#[no_mangle]
18230pub unsafe extern "C" fn readv(fd: i32, iov: *const core::ffi::c_void, iovcnt: i32) -> isize {
18231    <Arch as Syscalls>::syscall3(sysno(19, 65), fd as i64, iov as i64, iovcnt as i64) as isize
18232}
18233
18234#[no_mangle]
18235pub unsafe extern "C" fn writev(fd: i32, iov: *const core::ffi::c_void, iovcnt: i32) -> isize {
18236    <Arch as Syscalls>::syscall3(sysno(20, 66), fd as i64, iov as i64, iovcnt as i64) as isize
18237}
18238
18239// ============================================================
18240// Lock functions
18241// ============================================================
18242
18243#[no_mangle]
18244pub unsafe extern "C" fn flock(fd: i32, operation: i32) -> i32 {
18245    <Arch as Syscalls>::syscall2(SYS_FLOCK, fd as i64, operation as i64) as i32
18246}
18247
18248#[no_mangle]
18249pub unsafe extern "C" fn lockf(fd: i32, cmd: i32, len: i64) -> i32 {
18250    let r = <Arch as Syscalls>::syscall3(SYS_FCNTL, fd as i64, if cmd == 0 { 7 } else if cmd == 1 { 6 } else { 5 } , len);
18251    if r < 0 { return -1; }
18252    0
18253}
18254
18255// ============================================================
18256// Hostname/login functions
18257// ============================================================
18258
18259#[no_mangle]
18260pub unsafe extern "C" fn getdomainname(name: *mut core::ffi::c_char, len: usize) -> i32 {
18261    if cfg!(target_arch = "x86_64") { <Arch as Syscalls>::syscall2(156, name as i64, len as i64) as i32 } else { ERRNO = 38; -1 }
18262}
18263
18264#[no_mangle]
18265pub unsafe extern "C" fn setdomainname(name: *const core::ffi::c_char, len: usize) -> i32 {
18266    <Arch as Syscalls>::syscall2(sysno(171, 162), name as i64, len as i64) as i32
18267}
18268
18269#[no_mangle]
18270pub unsafe extern "C" fn sethostname(name: *const core::ffi::c_char, len: usize) -> i32 {
18271    <Arch as Syscalls>::syscall2(SYS_SETHOSTNAME, name as i64, len as i64) as i32
18272}
18273
18274#[no_mangle]
18275pub unsafe extern "C" fn getlogin_r(name: *mut core::ffi::c_char, bufsize: usize) -> i32 {
18276    // Try to get from environment
18277    let user = crate::getenv(b"USER\0".as_ptr() as *const core::ffi::c_char);
18278    if user.is_null() { return 2; }
18279    let mut i = 0;
18280    while i < bufsize - 1 && *user.add(i) != 0 {
18281        *name.add(i) = *user.add(i);
18282        i += 1;
18283    }
18284    *name.add(i) = 0;
18285    0
18286}
18287
18288#[no_mangle]
18289pub unsafe extern "C" fn cuserid(s: *mut core::ffi::c_char) -> *mut core::ffi::c_char {
18290    let user = crate::getenv(b"USER\0".as_ptr() as *const core::ffi::c_char);
18291    if user.is_null() { return core::ptr::null_mut(); }
18292    if s.is_null() {
18293        static mut BUF: [core::ffi::c_char; 32] = [0; 32];
18294        let mut i = 0;
18295        while i < 31 && *user.add(i) != 0 { BUF[i] = *user.add(i); i += 1; }
18296        BUF[i] = 0;
18297        BUF.as_mut_ptr()
18298    } else {
18299        let mut i = 0;
18300        while i < 31 && *user.add(i) != 0 { *s.add(i) = *user.add(i); i += 1; }
18301        *s.add(i) = 0;
18302        s
18303    }
18304}
18305
18306// ============================================================
18307// Group and passwd functions
18308// ============================================================
18309
18310#[repr(C)]
18311#[derive(Copy, Clone)]
18312pub struct Passwd {
18313    pub pw_name: *mut c_char,
18314    pub pw_passwd: *mut c_char,
18315    pub pw_uid: u32,
18316    pub pw_gid: u32,
18317    pub pw_gecos: *mut c_char,
18318    pub pw_dir: *mut c_char,
18319    pub pw_shell: *mut c_char,
18320}
18321
18322#[repr(C)]
18323#[derive(Copy, Clone)]
18324pub struct Group {
18325    pub gr_name: *mut c_char,
18326    pub gr_passwd: *mut c_char,
18327    pub gr_gid: u32,
18328    pub gr_mem: *mut *mut c_char,
18329}
18330
18331static mut PWD_ENT: Passwd = Passwd {
18332    pw_name: core::ptr::null_mut(), pw_passwd: core::ptr::null_mut(),
18333    pw_uid: 0, pw_gid: 0, pw_gecos: core::ptr::null_mut(),
18334    pw_dir: core::ptr::null_mut(), pw_shell: core::ptr::null_mut(),
18335};
18336static mut PWD_BUF: [c_char; 1024] = [0; 1024];
18337static mut PWD_FILE: *mut FILE = core::ptr::null_mut();
18338
18339static mut GRP_ENT: Group = Group {
18340    gr_name: core::ptr::null_mut(), gr_passwd: core::ptr::null_mut(),
18341    gr_gid: 0, gr_mem: core::ptr::null_mut(),
18342};
18343static mut GRP_BUF: [c_char; 2048] = [0; 2048];
18344static mut GRP_MEM: [*mut c_char; 32] = [core::ptr::null_mut(); 32];
18345static mut GRP_FILE: *mut FILE = core::ptr::null_mut();
18346
18347unsafe fn parse_passwd(line: *const c_char, ent: *mut Passwd, buf: *mut c_char, buflen: usize) -> bool {
18348    let mut src = line;
18349    let mut o = 0usize;
18350    let mut fields: [*mut c_char; 7] = [core::ptr::null_mut(); 7];
18351    let mut n = 0usize;
18352    while n < 7 {
18353        let start = o;
18354        while *src != 0 && *src != b':' as c_char {
18355            if o + 1 >= buflen { return false; }
18356            *buf.add(o) = *src;
18357            o += 1;
18358            src = src.add(1);
18359        }
18360        *buf.add(o) = 0;
18361        o += 1;
18362        fields[n] = buf.add(start);
18363        n += 1;
18364        if *src == 0 { break; }
18365        src = src.add(1);
18366    }
18367    if n < 7 { return false; }
18368    (*ent).pw_name = fields[0];
18369    (*ent).pw_passwd = fields[1];
18370    (*ent).pw_uid = crate::strtol(fields[2], core::ptr::null_mut(), 10) as u32;
18371    (*ent).pw_gid = crate::strtol(fields[3], core::ptr::null_mut(), 10) as u32;
18372    (*ent).pw_gecos = fields[4];
18373    (*ent).pw_dir = fields[5];
18374    (*ent).pw_shell = fields[6];
18375    true
18376}
18377
18378unsafe fn parse_group(line: *const c_char, ent: *mut Group, buf: *mut c_char, buflen: usize) -> bool {
18379    let mut src = line;
18380    let mut o = 0usize;
18381    let mut fields: [*mut c_char; 4] = [core::ptr::null_mut(); 4];
18382    let mut n = 0usize;
18383    while n < 4 {
18384        let start = o;
18385        while *src != 0 && *src != b':' as c_char {
18386            if o + 1 >= buflen { return false; }
18387            *buf.add(o) = *src;
18388            o += 1;
18389            src = src.add(1);
18390        }
18391        *buf.add(o) = 0;
18392        o += 1;
18393        fields[n] = buf.add(start);
18394        n += 1;
18395        if *src == 0 { break; }
18396        src = src.add(1);
18397    }
18398    if n < 4 { return false; }
18399    (*ent).gr_name = fields[0];
18400    (*ent).gr_passwd = fields[1];
18401    (*ent).gr_gid = crate::strtol(fields[2], core::ptr::null_mut(), 10) as u32;
18402    let mut mi = 0usize;
18403    let mut m = fields[3];
18404    if *m != 0 {
18405        loop {
18406            if mi + 1 >= GRP_MEM.len() { break; }
18407            GRP_MEM[mi] = m;
18408            mi += 1;
18409            while *m != 0 && *m != b',' as c_char { m = m.add(1); }
18410            if *m == 0 { break; }
18411            *m = 0;
18412            m = m.add(1);
18413        }
18414    }
18415    GRP_MEM[mi] = core::ptr::null_mut();
18416    (*ent).gr_mem = GRP_MEM.as_mut_ptr();
18417    true
18418}
18419
18420#[no_mangle]
18421pub unsafe extern "C" fn getpwnam(name: *const c_char) -> *mut Passwd {
18422    if name.is_null() { return core::ptr::null_mut(); }
18423    setpwent();
18424    loop {
18425        let p = getpwent();
18426        if p.is_null() { break; }
18427        if crate::strcmp((*p).pw_name as *const u8, name as *const u8) == 0 { endpwent(); return p; }
18428    }
18429    endpwent();
18430    core::ptr::null_mut()
18431}
18432
18433#[no_mangle]
18434pub unsafe extern "C" fn getpwuid(uid: u32) -> *mut Passwd {
18435    setpwent();
18436    loop {
18437        let p = getpwent();
18438        if p.is_null() { break; }
18439        if (*p).pw_uid == uid { endpwent(); return p; }
18440    }
18441    endpwent();
18442    core::ptr::null_mut()
18443}
18444
18445#[no_mangle]
18446pub unsafe extern "C" fn setpwent() {
18447    endpwent();
18448    PWD_FILE = crate::fopen(b"/etc/passwd\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
18449}
18450
18451#[no_mangle]
18452pub unsafe extern "C" fn getpwent() -> *mut Passwd {
18453    if PWD_FILE.is_null() { setpwent(); if PWD_FILE.is_null() { return core::ptr::null_mut(); } }
18454    let mut line = [0 as c_char; 1024];
18455    loop {
18456        if crate::fgets(line.as_mut_ptr(), 1024, PWD_FILE).is_null() { return core::ptr::null_mut(); }
18457        if parse_passwd(line.as_ptr(), &raw mut PWD_ENT, PWD_BUF.as_mut_ptr(), PWD_BUF.len()) {
18458            return &raw mut PWD_ENT;
18459        }
18460    }
18461}
18462
18463#[no_mangle]
18464pub unsafe extern "C" fn endpwent() {
18465    if !PWD_FILE.is_null() { crate::fclose(PWD_FILE); PWD_FILE = core::ptr::null_mut(); }
18466}
18467
18468#[no_mangle]
18469pub unsafe extern "C" fn getpwnam_r(name: *const c_char, pwd: *mut Passwd, _buf: *mut c_char, _buflen: usize, result: *mut *mut Passwd) -> c_int {
18470    if result.is_null() { return EINVAL; }
18471    let p = getpwnam(name);
18472    if p.is_null() { *result = core::ptr::null_mut(); 0 } else { *pwd = *p; *result = pwd; 0 }
18473}
18474
18475#[no_mangle]
18476pub unsafe extern "C" fn getpwuid_r(uid: u32, pwd: *mut Passwd, _buf: *mut c_char, _buflen: usize, result: *mut *mut Passwd) -> c_int {
18477    if result.is_null() { return EINVAL; }
18478    let p = getpwuid(uid);
18479    if p.is_null() { *result = core::ptr::null_mut(); 0 } else { *pwd = *p; *result = pwd; 0 }
18480}
18481
18482#[no_mangle]
18483pub unsafe extern "C" fn fgetpwent(f: *mut FILE) -> *mut Passwd {
18484    if f.is_null() { return core::ptr::null_mut(); }
18485    let mut line = [0 as c_char; 1024];
18486    loop {
18487        if crate::fgets(line.as_mut_ptr(), 1024, f).is_null() { return core::ptr::null_mut(); }
18488        if parse_passwd(line.as_ptr(), &raw mut PWD_ENT, PWD_BUF.as_mut_ptr(), PWD_BUF.len()) {
18489            return &raw mut PWD_ENT;
18490        }
18491    }
18492}
18493
18494#[no_mangle]
18495pub unsafe extern "C" fn putpwent(f: *mut FILE, p: *const Passwd) -> c_int {
18496    if f.is_null() || p.is_null() { return -1; }
18497    crate::fprintf(f, b"%s:%s:%u:%u:%s:%s:%s\n\0".as_ptr() as *const c_char,
18498        (*p).pw_name, (*p).pw_passwd, (*p).pw_uid, (*p).pw_gid,
18499        (*p).pw_gecos, (*p).pw_dir, (*p).pw_shell)
18500}
18501
18502#[no_mangle]
18503pub unsafe extern "C" fn getgrnam(name: *const c_char) -> *mut Group {
18504    if name.is_null() { return core::ptr::null_mut(); }
18505    setgrent();
18506    loop {
18507        let g = getgrent();
18508        if g.is_null() { break; }
18509        if crate::strcmp((*g).gr_name as *const u8, name as *const u8) == 0 { endgrent(); return g; }
18510    }
18511    endgrent();
18512    core::ptr::null_mut()
18513}
18514
18515#[no_mangle]
18516pub unsafe extern "C" fn getgrgid(gid: u32) -> *mut Group {
18517    setgrent();
18518    loop {
18519        let g = getgrent();
18520        if g.is_null() { break; }
18521        if (*g).gr_gid == gid { endgrent(); return g; }
18522    }
18523    endgrent();
18524    core::ptr::null_mut()
18525}
18526
18527#[no_mangle]
18528pub unsafe extern "C" fn setgrent() {
18529    endgrent();
18530    GRP_FILE = crate::fopen(b"/etc/group\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
18531}
18532
18533#[no_mangle]
18534pub unsafe extern "C" fn getgrent() -> *mut Group {
18535    if GRP_FILE.is_null() { setgrent(); if GRP_FILE.is_null() { return core::ptr::null_mut(); } }
18536    let mut line = [0 as c_char; 1024];
18537    loop {
18538        if crate::fgets(line.as_mut_ptr(), 1024, GRP_FILE).is_null() { return core::ptr::null_mut(); }
18539        if parse_group(line.as_ptr(), &raw mut GRP_ENT, GRP_BUF.as_mut_ptr(), GRP_BUF.len()) {
18540            return &raw mut GRP_ENT;
18541        }
18542    }
18543}
18544
18545#[no_mangle]
18546pub unsafe extern "C" fn endgrent() {
18547    if !GRP_FILE.is_null() { crate::fclose(GRP_FILE); GRP_FILE = core::ptr::null_mut(); }
18548}
18549
18550#[no_mangle]
18551pub unsafe extern "C" fn getgrnam_r(name: *const c_char, grp: *mut Group, _buf: *mut c_char, _buflen: usize, result: *mut *mut Group) -> c_int {
18552    if result.is_null() { return EINVAL; }
18553    let g = getgrnam(name);
18554    if g.is_null() { *result = core::ptr::null_mut(); 0 } else { *grp = *g; *result = grp; 0 }
18555}
18556
18557#[no_mangle]
18558pub unsafe extern "C" fn getgrgid_r(gid: u32, grp: *mut Group, _buf: *mut c_char, _buflen: usize, result: *mut *mut Group) -> c_int {
18559    if result.is_null() { return EINVAL; }
18560    let g = getgrgid(gid);
18561    if g.is_null() { *result = core::ptr::null_mut(); 0 } else { *grp = *g; *result = grp; 0 }
18562}
18563
18564#[no_mangle]
18565pub unsafe extern "C" fn fgetgrent(f: *mut FILE) -> *mut Group {
18566    if f.is_null() { return core::ptr::null_mut(); }
18567    let mut line = [0 as c_char; 1024];
18568    loop {
18569        if crate::fgets(line.as_mut_ptr(), 1024, f).is_null() { return core::ptr::null_mut(); }
18570        if parse_group(line.as_ptr(), &raw mut GRP_ENT, GRP_BUF.as_mut_ptr(), GRP_BUF.len()) {
18571            return &raw mut GRP_ENT;
18572        }
18573    }
18574}
18575
18576#[no_mangle]
18577pub unsafe extern "C" fn putgrent(f: *mut FILE, g: *const Group) -> c_int {
18578    if f.is_null() || g.is_null() { return -1; }
18579    crate::fprintf(f, b"%s:%s:%u:\0".as_ptr() as *const c_char, (*g).gr_name, (*g).gr_passwd, (*g).gr_gid);
18580    if !(*g).gr_mem.is_null() {
18581        let mut i = 0;
18582        while !(*(*g).gr_mem.add(i)).is_null() {
18583            if i > 0 { crate::fputc(b',' as c_int, f); }
18584            crate::fputs(*(*g).gr_mem.add(i), f);
18585            i += 1;
18586        }
18587    }
18588    crate::fputc(b'\n' as c_int, f);
18589    0
18590}
18591
18592// ============================================================
18593// User/group functions
18594// ============================================================
18595
18596#[no_mangle]
18597pub unsafe extern "C" fn setgroups(ngroups: usize, gidset: *const u32) -> i32 {
18598    <Arch as Syscalls>::syscall2(SYS_SETGROUPS, ngroups as i64, gidset as i64) as i32
18599}
18600
18601#[no_mangle]
18602pub unsafe extern "C" fn setresuid(ruid: u32, euid: u32, suid: u32) -> i32 {
18603    <Arch as Syscalls>::syscall3(SYS_SETRESUID, ruid as i64, euid as i64, suid as i64) as i32
18604}
18605
18606#[no_mangle]
18607pub unsafe extern "C" fn setresgid(rgid: u32, egid: u32, sgid: u32) -> i32 {
18608    <Arch as Syscalls>::syscall3(SYS_SETRESGID, rgid as i64, egid as i64, sgid as i64) as i32
18609}
18610
18611#[no_mangle]
18612pub unsafe extern "C" fn getresuid(ruid: *mut u32, euid: *mut u32, suid: *mut u32) -> i32 {
18613    <Arch as Syscalls>::syscall3(SYS_GETRESUID, ruid as i64, euid as i64, suid as i64) as i32
18614}
18615
18616#[no_mangle]
18617pub unsafe extern "C" fn getresgid(rgid: *mut u32, egid: *mut u32, sgid: *mut u32) -> i32 {
18618    <Arch as Syscalls>::syscall3(SYS_GETRESGID, rgid as i64, egid as i64, sgid as i64) as i32
18619}
18620
18621// ============================================================
18622// Socket functions
18623// ============================================================
18624
18625#[no_mangle]
18626pub unsafe extern "C" fn sendmsg(fd: i32, msg: *const core::ffi::c_void, flags: i32) -> isize {
18627    <Arch as Syscalls>::syscall3(SYS_SENDMSG, fd as i64, msg as i64, flags as i64) as isize
18628}
18629
18630#[no_mangle]
18631pub unsafe extern "C" fn recvmsg(fd: i32, msg: *mut core::ffi::c_void, flags: i32) -> isize {
18632    <Arch as Syscalls>::syscall3(SYS_RECVMSG, fd as i64, msg as i64, flags as i64) as isize
18633}
18634
18635#[no_mangle]
18636pub unsafe extern "C" fn sendmmsg(fd: i32, msgvec: *mut core::ffi::c_void, vlen: u32, flags: i32) -> i32 {
18637    <Arch as Syscalls>::syscall4(sysno(307, 269), fd as i64, msgvec as i64, vlen as i64, flags as i64) as i32
18638}
18639
18640#[no_mangle]
18641pub unsafe extern "C" fn recvmmsg(fd: i32, msgvec: *mut core::ffi::c_void, vlen: u32, flags: i32, timeout: *mut core::ffi::c_void) -> i32 {
18642    <Arch as Syscalls>::syscall5(sysno(299, 243), fd as i64, msgvec as i64, vlen as i64, flags as i64, timeout as i64) as i32
18643}
18644
18645#[no_mangle]
18646pub unsafe extern "C" fn getpeername(fd: i32, addr: *mut core::ffi::c_void, addrlen: *mut u32) -> i32 {
18647    <Arch as Syscalls>::syscall3(sysno(52, 205), fd as i64, addr as i64, addrlen as i64) as i32
18648}
18649
18650#[no_mangle]
18651pub unsafe extern "C" fn getsockopt(fd: i32, level: i32, optname: i32, optval: *mut core::ffi::c_void, optlen: *mut u32) -> i32 {
18652    <Arch as Syscalls>::syscall5(sysno(55, 209), fd as i64, level as i64, optname as i64, optval as i64, optlen as i64) as i32
18653}
18654
18655// ============================================================
18656// stdio unlocked functions
18657// ============================================================
18658
18659#[no_mangle]
18660pub unsafe extern "C" fn ftrylockfile(file: *mut FILE) -> i32 {
18661    if file.is_null() { return EINVAL; }
18662    if (*file).lock < 0 { return 0; }
18663    let tid = sys_gettid() as c_int;
18664    let v = a_load(&raw const (*file).lock);
18665    if v == tid {
18666        (*file).lockcount += 1;
18667        return 0;
18668    }
18669    if v == 0 && a_cas(&raw mut (*file).lock, 0, tid) == 0 {
18670        (*file).lockcount = 1;
18671        return 0;
18672    }
18673    EBUSY
18674}
18675
18676#[no_mangle]
18677pub unsafe extern "C" fn getc_unlocked(file: *mut core::ffi::c_char) -> i32 {
18678    getc(file as *mut FILE)
18679}
18680
18681#[no_mangle]
18682pub unsafe extern "C" fn getchar_unlocked() -> i32 {
18683    getchar()
18684}
18685
18686#[no_mangle]
18687pub unsafe extern "C" fn putc_unlocked(c: i32, file: *mut core::ffi::c_char) -> i32 {
18688    putc(c, file as *mut FILE)
18689}
18690
18691#[no_mangle]
18692pub unsafe extern "C" fn putchar_unlocked(c: i32) -> i32 {
18693    putchar(c)
18694}
18695
18696// ============================================================
18697// getopt functions
18698// ============================================================
18699
18700#[no_mangle] pub static mut optarg: *mut core::ffi::c_char = core::ptr::null_mut();
18701#[no_mangle] pub static mut optind: i32 = 1;
18702#[no_mangle] pub static mut opterr: i32 = 1;
18703#[no_mangle] pub static mut optopt: i32 = '?' as i32;
18704#[no_mangle] pub static mut optreset: i32 = 0;
18705
18706// ============================================================
18707// Timer functions
18708// ============================================================
18709
18710#[no_mangle]
18711pub unsafe extern "C" fn getitimer(which: i32, curr_value: *mut core::ffi::c_void) -> i32 {
18712    <Arch as Syscalls>::syscall2(sysno(36, 102), which as i64, curr_value as i64) as i32
18713}
18714
18715#[no_mangle]
18716pub unsafe extern "C" fn setitimer(which: i32, new_value: *const core::ffi::c_void, old_value: *mut core::ffi::c_void) -> i32 {
18717    <Arch as Syscalls>::syscall3(sysno(38, 103), which as i64, new_value as i64, old_value as i64) as i32
18718}
18719
18720// ============================================================
18721// System info functions
18722// ============================================================
18723
18724#[no_mangle]
18725pub unsafe extern "C" fn getloadavg(loadavg: *mut f64, nelem: i32) -> i32 {
18726    let fd = crate::open(b"/proc/loadavg\0".as_ptr() as *const core::ffi::c_char, 0, 0);
18727    if fd < 0 { return -1; }
18728    let mut buf: [u8; 64] = [0; 64];
18729    let n = crate::read(fd, buf.as_mut_ptr() as *mut core::ffi::c_void, 63);
18730    crate::close(fd);
18731    if n <= 0 { return -1; }
18732    buf[n as usize] = 0;
18733    let mut i = 0;
18734    while i < nelem as usize && i < 3 {
18735        let val = crate::strtod((buf.as_ptr() as *const core::ffi::c_char).add(i * 5), core::ptr::null_mut());
18736        *loadavg.add(i) = val;
18737        i += 1;
18738    }
18739    i as i32
18740}
18741
18742#[no_mangle]
18743pub unsafe extern "C" fn get_nprocs() -> i32 {
18744    sysconf(84) as i32 // _SC_NPROCESSORS_ONLN
18745}
18746
18747#[no_mangle]
18748pub unsafe extern "C" fn get_nprocs_conf() -> i32 {
18749    sysconf(83) as i32 // _SC_NPROCESSORS_CONF
18750}
18751
18752#[no_mangle]
18753pub unsafe extern "C" fn get_avphys_pages() -> i64 {
18754    sysconf(86) // _SC_AVPHYS_PAGES
18755}
18756
18757#[no_mangle]
18758pub unsafe extern "C" fn get_phys_pages() -> i64 {
18759    sysconf(85) // _SC_PHYS_PAGES
18760}
18761
18762// ============================================================
18763// Capability functions
18764// ============================================================
18765
18766#[no_mangle]
18767pub unsafe extern "C" fn capget(header: *mut core::ffi::c_void, data: *mut core::ffi::c_void) -> i32 {
18768    <Arch as Syscalls>::syscall2(SYS_CAPGET, header as i64, data as i64) as i32
18769}
18770
18771#[no_mangle]
18772pub unsafe extern "C" fn capset(header: *const core::ffi::c_void, data: *const core::ffi::c_void) -> i32 {
18773    <Arch as Syscalls>::syscall2(SYS_CAPSET, header as i64, data as i64) as i32
18774}
18775
18776#[no_mangle]
18777pub unsafe extern "C" fn arch_prctl(code: i32, addr: u64) -> i32 {
18778    if cfg!(target_arch = "x86_64") { <Arch as Syscalls>::syscall2(158, code as i64, addr as i64) as i32 } else { ERRNO = 38; -1 }
18779}
18780
18781// ============================================================
18782// termios functions
18783// ============================================================
18784
18785#[no_mangle]
18786pub unsafe extern "C" fn cfgetospeed(termios_p: *const core::ffi::c_void) -> u32 {
18787    unsafe { *(termios_p as *const u32).add(1) }
18788}
18789
18790#[no_mangle]
18791pub unsafe extern "C" fn cfgetispeed(termios_p: *const core::ffi::c_void) -> u32 {
18792    unsafe { *(termios_p as *const u32).add(2) }
18793}
18794
18795#[no_mangle]
18796pub unsafe extern "C" fn cfsetospeed(termios_p: *mut core::ffi::c_void, speed: u32) -> i32 {
18797    unsafe { *(termios_p as *mut u32).add(1) = speed; }
18798    0
18799}
18800
18801#[no_mangle]
18802pub unsafe extern "C" fn cfsetispeed(termios_p: *mut core::ffi::c_void, speed: u32) -> i32 {
18803    unsafe { *(termios_p as *mut u32).add(2) = speed; }
18804    0
18805}
18806
18807#[no_mangle]
18808pub unsafe extern "C" fn cfmakeraw(termios_p: *mut core::ffi::c_void) {
18809    unsafe {
18810        let p = termios_p as *mut u32;
18811        *p.add(0) &= !0o37;
18812        *p.add(0) &= !(0o4000 | 0o2000 | 0o10000 | 0o20);
18813        *p.add(0) |= 0o60;
18814        *p.add(3) &= !0o17;
18815        *p.add(3) &= !(0o1000 | 0o40000000);
18816        *p.add(1) = 1;
18817        *p.add(2) = 0;
18818    }
18819}
18820
18821// ============================================================
18822// Resource functions
18823// ============================================================
18824
18825#[no_mangle]
18826pub unsafe extern "C" fn getrusage(who: i32, usage: *mut core::ffi::c_void) -> i32 {
18827    <Arch as Syscalls>::syscall2(sysno(98, 165), who as i64, usage as i64) as i32
18828}
18829
18830#[no_mangle]
18831pub unsafe extern "C" fn getpriority(which: i32, who: u32) -> i32 {
18832    <Arch as Syscalls>::syscall2(SYS_GETPRIORITY, which as i64, who as i64) as i32
18833}
18834
18835#[no_mangle]
18836pub unsafe extern "C" fn setpriority(which: i32, who: u32, prio: i32) -> i32 {
18837    <Arch as Syscalls>::syscall3(SYS_SETPRIORITY, which as i64, who as i64, prio as i64) as i32
18838}
18839
18840#[no_mangle]
18841pub unsafe extern "C" fn prlimit(pid: u32, resource: i32, new_limit: *const core::ffi::c_void, old_limit: *mut core::ffi::c_void) -> i32 {
18842    <Arch as Syscalls>::syscall4(sysno(302, 261), pid as i64, resource as i64, new_limit as i64, old_limit as i64) as i32
18843}
18844
18845// ============================================================
18846// fork/clone functions
18847// ============================================================
18848
18849#[no_mangle]
18850pub unsafe extern "C" fn clone(flags: u32, child_stack: *mut u8, _args: ...) -> i32 {
18851    <Arch as Syscalls>::syscall5(SYS_CLONE, flags as i64, child_stack as i64, 0, 0, 0) as i32
18852}
18853
18854#[no_mangle]
18855pub unsafe extern "C" fn _Fork() -> i32 {
18856    crate::fork()
18857}
18858
18859#[no_mangle]
18860pub unsafe extern "C" fn forkpty(amaster: *mut i32, name: *mut core::ffi::c_char, termp: *const core::ffi::c_void, winp: *const core::ffi::c_void) -> i32 {
18861    let mut master: i32 = 0;
18862    let mut slave: i32 = 0;
18863    if openpty(&mut master, &mut slave, name, termp, winp) < 0 { return -1; }
18864    let pid = crate::fork();
18865    if pid < 0 { crate::close(master); crate::close(slave); return -1; }
18866    if pid == 0 {
18867        crate::close(master);
18868        crate::setsid();
18869        crate::dup2(slave, 0);
18870        crate::dup2(slave, 1);
18871        crate::dup2(slave, 2);
18872    } else {
18873        crate::close(slave);
18874        if !amaster.is_null() { *amaster = master; }
18875    }
18876    pid
18877}
18878
18879#[no_mangle]
18880pub unsafe extern "C" fn openpty(amaster: *mut i32, aslave: *mut i32, name: *mut core::ffi::c_char, _termp: *const core::ffi::c_void, _winp: *const core::ffi::c_void) -> i32 {
18881    let master = crate::open(b"/dev/ptmx\0".as_ptr() as *const core::ffi::c_char, 0o2000, 0);
18882    if master < 0 { return -1; }
18883    grantpt(master);
18884    unlockpt(master);
18885    let slave_name = ptsname(master);
18886    if slave_name.is_null() { crate::close(master); return -1; }
18887    let slave = crate::open(slave_name, 0o2000, 0);
18888    if slave < 0 { crate::close(master); return -1; }
18889    if !amaster.is_null() { *amaster = master; }
18890    if !aslave.is_null() { *aslave = slave; }
18891    if !name.is_null() { crate::strcpy(name as *mut u8, slave_name as *const u8); }
18892    0
18893}
18894
18895#[no_mangle]
18896pub unsafe extern "C" fn login_tty(fd: i32) -> i32 {
18897    crate::setsid();
18898    crate::dup2(fd, 0);
18899    crate::dup2(fd, 1);
18900    crate::dup2(fd, 2);
18901    0
18902}
18903
18904// ============================================================
18905// dl functions
18906// ============================================================
18907
18908#[no_mangle]
18909pub unsafe extern "C" fn __dls2b() {}
18910#[no_mangle]
18911pub unsafe extern "C" fn __dls3() {}
18912#[no_mangle]
18913pub unsafe extern "C" fn _dlstart() {}
18914
18915// ============================================================
18916// string functions
18917// ============================================================
18918
18919#[no_mangle]
18920pub unsafe extern "C" fn index(s: *const core::ffi::c_char, c: i32) -> *mut core::ffi::c_char {
18921    let mut i = 0;
18922    loop {
18923        let ch = *s.add(i);
18924        if ch == c as core::ffi::c_char { return s.add(i) as *mut core::ffi::c_char; }
18925        if ch == 0 { return core::ptr::null_mut(); }
18926        i += 1;
18927    }
18928}
18929
18930#[no_mangle]
18931pub unsafe extern "C" fn rindex(s: *const core::ffi::c_char, c: i32) -> *mut core::ffi::c_char {
18932    let mut last = core::ptr::null_mut();
18933    let mut i = 0;
18934    loop {
18935        let ch = *s.add(i);
18936        if ch == 0 { return last; }
18937        if ch == c as core::ffi::c_char { last = s.add(i) as *mut core::ffi::c_char; }
18938        i += 1;
18939    }
18940}
18941
18942// ============================================================
18943// intmax functions
18944// ============================================================
18945
18946#[no_mangle]
18947pub unsafe extern "C" fn imaxabs(j: i64) -> i64 {
18948    j.abs()
18949}
18950
18951#[no_mangle]
18952pub unsafe extern "C" fn imaxdiv(numer: i64, denom: i64) -> (i64, i64) {
18953    (numer / denom, numer % denom)
18954}
18955
18956// ============================================================
18957// herror functions
18958// ============================================================
18959
18960#[no_mangle]
18961pub static mut h_errno: i32 = 0;
18962
18963#[no_mangle]
18964pub unsafe extern "C" fn __h_errno_location() -> *mut i32 {
18965    &mut h_errno
18966}
18967
18968#[no_mangle]
18969pub unsafe extern "C" fn herror(s: *const core::ffi::c_char) {
18970    if !s.is_null() { crate::write(2, s as *const core::ffi::c_void, crate::strlen(s)); }
18971    crate::write(2, b": ".as_ptr() as *const core::ffi::c_void, 2);
18972    crate::write(2, hstrerror(*__h_errno_location()) as *const core::ffi::c_void, crate::strlen(hstrerror(*__h_errno_location())));
18973    crate::write(2, b"\n".as_ptr() as *const core::ffi::c_void, 1);
18974}
18975
18976#[no_mangle]
18977pub unsafe extern "C" fn hstrerror(_err: i32) -> *const core::ffi::c_char {
18978    b"Unknown error\0".as_ptr() as *const core::ffi::c_char
18979}
18980
18981// ============================================================
18982// gettid function
18983// ============================================================
18984
18985#[no_mangle]
18986pub unsafe extern "C" fn gettid() -> i32 {
18987    <Arch as Syscalls>::syscall0(SYS_GETTID) as i32
18988}
18989
18990// ============================================================
18991// ioctl functions
18992// ============================================================
18993
18994#[no_mangle]
18995pub unsafe extern "C" fn ioctl(fd: i32, request: u32, mut args: ...) -> i32 {
18996    let arg = args.next_arg::<i64>();
18997    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, request as i64, arg) as i32
18998}
18999
19000#[no_mangle]
19001pub unsafe extern "C" fn ioperm(from: u64, num: u64, turn_on: i32) -> i32 {
19002    #[cfg(target_arch = "x86_64")]
19003    { <Arch as Syscalls>::syscall3(SYS_IOPERM, from as i64, num as i64, turn_on as i64) as i32 }
19004    #[cfg(not(target_arch = "x86_64"))]
19005    {
19006        let _ = (from, num, turn_on);
19007        ERRNO = ENOSYS_VAL;
19008        -1
19009    }
19010}
19011
19012#[no_mangle]
19013pub unsafe extern "C" fn iopl(level: i32) -> i32 {
19014    #[cfg(target_arch = "x86_64")]
19015    { <Arch as Syscalls>::syscall1(SYS_IOPL, level as i64) as i32 }
19016    #[cfg(not(target_arch = "x86_64"))]
19017    {
19018        let _ = level;
19019        ERRNO = ENOSYS_VAL;
19020        -1
19021    }
19022}
19023
19024// ============================================================
19025// xattr functions
19026// ============================================================
19027
19028#[no_mangle]
19029pub unsafe extern "C" fn getxattr(path: *const core::ffi::c_char, name: *const core::ffi::c_char, value: *mut u8, size: usize) -> isize {
19030    <Arch as Syscalls>::syscall4(sysno(191, 8), path as i64, name as i64, value as i64, size as i64) as isize
19031}
19032
19033#[no_mangle]
19034pub unsafe extern "C" fn lgetxattr(path: *const core::ffi::c_char, name: *const core::ffi::c_char, value: *mut u8, size: usize) -> isize {
19035    <Arch as Syscalls>::syscall4(sysno(192, 9), path as i64, name as i64, value as i64, size as i64) as isize
19036}
19037
19038#[no_mangle]
19039pub unsafe extern "C" fn fgetxattr(fd: i32, name: *const core::ffi::c_char, value: *mut u8, size: usize) -> isize {
19040    <Arch as Syscalls>::syscall4(sysno(193, 10), fd as i64, name as i64, value as i64, size as i64) as isize
19041}
19042
19043#[no_mangle]
19044pub unsafe extern "C" fn listxattr(path: *const core::ffi::c_char, list: *mut u8, size: usize) -> isize {
19045    <Arch as Syscalls>::syscall3(sysno(194, 11), path as i64, list as i64, size as i64) as isize
19046}
19047
19048#[no_mangle]
19049pub unsafe extern "C" fn llistxattr(path: *const core::ffi::c_char, list: *mut u8, size: usize) -> isize {
19050    <Arch as Syscalls>::syscall3(sysno(195, 12), path as i64, list as i64, size as i64) as isize
19051}
19052
19053#[no_mangle]
19054pub unsafe extern "C" fn flistxattr(fd: i32, list: *mut u8, size: usize) -> isize {
19055    <Arch as Syscalls>::syscall3(sysno(196, 13), fd as i64, list as i64, size as i64) as isize
19056}
19057
19058#[no_mangle]
19059pub unsafe extern "C" fn setxattr(path: *const core::ffi::c_char, name: *const core::ffi::c_char, value: *const u8, size: usize, flags: i32) -> i32 {
19060    <Arch as Syscalls>::syscall5(sysno(188, 5), path as i64, name as i64, value as i64, size as i64, flags as i64) as i32
19061}
19062
19063#[no_mangle]
19064pub unsafe extern "C" fn lsetxattr(path: *const core::ffi::c_char, name: *const core::ffi::c_char, value: *const u8, size: usize, flags: i32) -> i32 {
19065    <Arch as Syscalls>::syscall5(sysno(189, 6), path as i64, name as i64, value as i64, size as i64, flags as i64) as i32
19066}
19067
19068#[no_mangle]
19069pub unsafe extern "C" fn fsetxattr(fd: i32, name: *const core::ffi::c_char, value: *const u8, size: usize, flags: i32) -> i32 {
19070    <Arch as Syscalls>::syscall5(sysno(190, 7), fd as i64, name as i64, value as i64, size as i64, flags as i64) as i32
19071}
19072
19073#[no_mangle]
19074pub unsafe extern "C" fn removexattr(path: *const core::ffi::c_char, name: *const core::ffi::c_char) -> i32 {
19075    <Arch as Syscalls>::syscall2(sysno(197, 14), path as i64, name as i64) as i32
19076}
19077
19078#[no_mangle]
19079pub unsafe extern "C" fn lremovexattr(path: *const core::ffi::c_char, name: *const core::ffi::c_char) -> i32 {
19080    <Arch as Syscalls>::syscall2(sysno(198, 15), path as i64, name as i64) as i32
19081}
19082
19083#[no_mangle]
19084pub unsafe extern "C" fn fremovexattr(fd: i32, name: *const core::ffi::c_char) -> i32 {
19085    <Arch as Syscalls>::syscall2(sysno(199, 16), fd as i64, name as i64) as i32
19086}
19087
19088// ============================================================
19089// adjtime functions
19090// ============================================================
19091
19092#[no_mangle]
19093pub unsafe extern "C" fn adjtime(_delta: *const core::ffi::c_void, olddelta: *mut core::ffi::c_void) -> i32 {
19094    <Arch as Syscalls>::syscall1(SYS_ADJTIMEX, olddelta as i64) as i32
19095}
19096
19097#[no_mangle]
19098pub unsafe extern "C" fn adjtimex(buf: *mut core::ffi::c_void) -> i32 {
19099    <Arch as Syscalls>::syscall1(SYS_ADJTIMEX, buf as i64) as i32
19100}
19101
19102// ============================================================
19103// pty functions
19104// ============================================================
19105
19106#[no_mangle]
19107pub unsafe extern "C" fn grantpt(fd: i32) -> i32 {
19108    // PTY grant - just change ownership
19109    let mut s: u32 = 0;
19110    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5410, &mut s as *mut u32 as i64);
19111    0
19112}
19113
19114#[no_mangle]
19115pub unsafe extern "C" fn unlockpt(fd: i32) -> i32 {
19116    let mut unlock: i32 = 0;
19117    <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5411, &mut unlock as *mut i32 as i64);
19118    0
19119}
19120
19121#[no_mangle]
19122pub unsafe extern "C" fn ptsname(fd: i32) -> *mut core::ffi::c_char {
19123    static mut BUF: [core::ffi::c_char; 32] = [0; 32];
19124    let mut pty_nr: i32 = 0;
19125    if <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5413, &mut pty_nr as *mut i32 as i64) < 0 {
19126        return core::ptr::null_mut();
19127    }
19128    // Format /dev/pts/N
19129    BUF[0] = '/' as c_char; BUF[1] = 'd' as c_char; BUF[2] = 'e' as c_char; BUF[3] = 'v' as c_char;
19130    BUF[4] = '/' as c_char; BUF[5] = 'p' as c_char; BUF[6] = 't' as c_char; BUF[7] = 's' as c_char;
19131    BUF[8] = '/' as c_char;
19132    let mut n = pty_nr as usize;
19133    let mut i = 9;
19134    if n == 0 { BUF[i] = '0' as c_char; i += 1; }
19135    while n > 0 && i < 31 {
19136        BUF[i] = (b'0' + (n % 10) as u8) as c_char;
19137        n /= 10;
19138        i += 1;
19139    }
19140    BUF[i] = 0;
19141    BUF.as_mut_ptr()
19142}
19143
19144// ============================================================
19145// fpclassify functions
19146// ============================================================
19147
19148#[no_mangle]
19149pub unsafe extern "C" fn finite(x: f64) -> i32 {
19150    (!x.is_nan() && !x.is_infinite()) as i32
19151}
19152
19153#[no_mangle]
19154pub unsafe extern "C" fn finitef(x: f32) -> i32 {
19155    (!x.is_nan() && !x.is_infinite()) as i32
19156}
19157
19158#[no_mangle]
19159pub unsafe extern "C" fn __fpclassifyl(x: f64) -> i32 {
19160    __fpclassify(x)
19161}
19162
19163#[no_mangle]
19164pub unsafe extern "C" fn __signbitl(x: f64) -> i32 {
19165    __signbit(x)
19166}
19167
19168// ============================================================
19169// ftw functions
19170// ============================================================
19171
19172// ============================================================
19173// Bessel functions
19174// ============================================================
19175
19176#[no_mangle]
19177pub unsafe extern "C" fn j0(x: f64) -> f64 {
19178    j0_impl(x)
19179}
19180
19181#[no_mangle]
19182pub unsafe extern "C" fn j0f(x: f32) -> f32 {
19183    libm::j0f(x)
19184}
19185
19186#[no_mangle]
19187pub unsafe extern "C" fn j1(x: f64) -> f64 {
19188    libm::j1(x)
19189}
19190
19191#[no_mangle]
19192pub unsafe extern "C" fn j1f(x: f32) -> f32 {
19193    libm::j1f(x)
19194}
19195
19196#[no_mangle]
19197pub unsafe extern "C" fn jn(n: i32, x: f64) -> f64 {
19198    libm::jn(n, x)
19199}
19200
19201#[no_mangle]
19202pub unsafe extern "C" fn jnf(n: i32, x: f32) -> f32 {
19203    libm::jnf(n, x)
19204}
19205
19206#[no_mangle]
19207pub unsafe extern "C" fn y0(x: f64) -> f64 {
19208    y0_impl(x)
19209}
19210
19211#[no_mangle]
19212pub unsafe extern "C" fn y0f(x: f32) -> f32 {
19213    if x.is_nan() { return x; }
19214    if x < 0.0 { return __math_invalidf(x); }
19215    if x == 0.0 { feraiseexcept(FE_DIVBYZERO); return f32::NEG_INFINITY; }
19216    libm::y0f(x)
19217}
19218
19219#[no_mangle]
19220pub unsafe extern "C" fn y1(x: f64) -> f64 {
19221    if x.is_nan() { return x; }
19222    if x < 0.0 { return __math_invalid(x); }
19223    if x == 0.0 { feraiseexcept(FE_DIVBYZERO); return f64::NEG_INFINITY; }
19224    libm::y1(x)
19225}
19226
19227#[no_mangle]
19228pub unsafe extern "C" fn y1f(x: f32) -> f32 {
19229    if x.is_nan() { return x; }
19230    if x < 0.0 { return __math_invalidf(x); }
19231    if x == 0.0 { feraiseexcept(FE_DIVBYZERO); return f32::NEG_INFINITY; }
19232    libm::y1f(x)
19233}
19234
19235#[no_mangle]
19236pub unsafe extern "C" fn yn(n: i32, x: f64) -> f64 {
19237    if x.is_nan() { return x; }
19238    if x < 0.0 { return __math_invalid(x); }
19239    if x == 0.0 {
19240        feraiseexcept(FE_DIVBYZERO);
19241        if n >= 0 { return f64::NEG_INFINITY; }
19242    }
19243    libm::yn(n, x)
19244}
19245
19246#[no_mangle]
19247pub unsafe extern "C" fn ynf(n: i32, x: f32) -> f32 {
19248    if x.is_nan() { return x; }
19249    if x < 0.0 { return __math_invalidf(x); }
19250    if x == 0.0 {
19251        feraiseexcept(FE_DIVBYZERO);
19252        if n >= 0 { return f32::NEG_INFINITY; }
19253    }
19254    libm::ynf(n, x)
19255}
19256
19257// ============================================================
19258// ctype locale functions
19259// ============================================================
19260
19261#[no_mangle]
19262pub unsafe extern "C" fn __ctype_b_loc() -> *mut *const u16 {
19263    static mut TABLE: *const u16 = core::ptr::null();
19264    &mut TABLE
19265}
19266
19267#[no_mangle]
19268pub unsafe extern "C" fn __ctype_tolower_loc() -> *mut *const i32 {
19269    static mut TABLE: *const i32 = core::ptr::null();
19270    &mut TABLE
19271}
19272
19273#[no_mangle]
19274pub unsafe extern "C" fn __ctype_toupper_loc() -> *mut *const i32 {
19275    static mut TABLE: *const i32 = core::ptr::null();
19276    &mut TABLE
19277}
19278
19279#[no_mangle]
19280pub unsafe extern "C" fn __isalnum_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19281    (c >= '0' as i32 && c <= '9' as i32 || c >= 'A' as i32 && c <= 'Z' as i32 || c >= 'a' as i32 && c <= 'z' as i32) as i32
19282}
19283
19284#[no_mangle]
19285pub unsafe extern "C" fn __isalpha_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19286    (c >= 'A' as i32 && c <= 'Z' as i32 || c >= 'a' as i32 && c <= 'z' as i32) as i32
19287}
19288
19289#[no_mangle]
19290pub unsafe extern "C" fn __isblank_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19291    (c == ' ' as i32 || c == '\t' as i32) as i32
19292}
19293
19294#[no_mangle]
19295pub unsafe extern "C" fn __iscntrl_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19296    (c < 0x20 || c == 0x7f) as i32
19297}
19298
19299#[no_mangle]
19300pub unsafe extern "C" fn __isdigit_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19301    (c >= '0' as i32 && c <= '9' as i32) as i32
19302}
19303
19304#[no_mangle]
19305pub unsafe extern "C" fn __isgraph_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19306    (c > 0x20 && c < 0x7f) as i32
19307}
19308
19309#[no_mangle]
19310pub unsafe extern "C" fn __islower_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19311    (c >= 'a' as i32 && c <= 'z' as i32) as i32
19312}
19313
19314#[no_mangle]
19315pub unsafe extern "C" fn __isprint_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19316    (c >= 0x20 && c < 0x7f) as i32
19317}
19318
19319#[no_mangle]
19320pub unsafe extern "C" fn __ispunct_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19321    (c >= 0x21 && c <= 0x2f || c >= 0x3a && c <= 0x40 || c >= 0x5b && c <= 0x60 || c >= 0x7b && c <= 0x7e) as i32
19322}
19323
19324#[no_mangle]
19325pub unsafe extern "C" fn __isspace_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19326    (c == ' ' as i32 || c >= 0x09 && c <= 0x0d) as i32
19327}
19328
19329#[no_mangle]
19330pub unsafe extern "C" fn __isupper_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19331    (c >= 'A' as i32 && c <= 'Z' as i32) as i32
19332}
19333
19334#[no_mangle]
19335pub unsafe extern "C" fn __isxdigit_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
19336    (c >= '0' as i32 && c <= '9' as i32 || c >= 'A' as i32 && c <= 'F' as i32 || c >= 'a' as i32 && c <= 'f' as i32) as i32
19337}
19338
19339// ============================================================
19340// wide char locale functions
19341// ============================================================
19342
19343#[no_mangle]
19344pub unsafe extern "C" fn __iswalnum_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19345    (c >= '0' as u32 && c <= '9' as u32 || c >= 'A' as u32 && c <= 'Z' as u32 || c >= 'a' as u32 && c <= 'z' as u32) as i32
19346}
19347
19348#[no_mangle]
19349pub unsafe extern "C" fn __iswalpha_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19350    (c >= 'A' as u32 && c <= 'Z' as u32 || c >= 'a' as u32 && c <= 'z' as u32) as i32
19351}
19352
19353#[no_mangle]
19354pub unsafe extern "C" fn __iswblank_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19355    (c == ' ' as u32 || c == '\t' as u32) as i32
19356}
19357
19358#[no_mangle]
19359pub unsafe extern "C" fn __iswcntrl_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19360    (c < 0x20 || c == 0x7f) as i32
19361}
19362
19363#[no_mangle]
19364pub unsafe extern "C" fn __iswdigit_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19365    (c >= '0' as u32 && c <= '9' as u32) as i32
19366}
19367
19368#[no_mangle]
19369pub unsafe extern "C" fn __iswgraph_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19370    (c > 0x20 && c < 0x7f) as i32
19371}
19372
19373#[no_mangle]
19374pub unsafe extern "C" fn __iswlower_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19375    (c >= 'a' as u32 && c <= 'z' as u32) as i32
19376}
19377
19378#[no_mangle]
19379pub unsafe extern "C" fn __iswprint_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19380    (c >= 0x20 && c < 0x7f) as i32
19381}
19382
19383#[no_mangle]
19384pub unsafe extern "C" fn __iswpunct_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19385    (c >= 0x21 && c <= 0x2f || c >= 0x3a && c <= 0x40 || c >= 0x5b && c <= 0x60 || c >= 0x7b && c <= 0x7e) as i32
19386}
19387
19388#[no_mangle]
19389pub unsafe extern "C" fn __iswspace_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19390    (c == ' ' as u32 || c >= 0x09 && c <= 0x0d) as i32
19391}
19392
19393#[no_mangle]
19394pub unsafe extern "C" fn __iswupper_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19395    (c >= 'A' as u32 && c <= 'Z' as u32) as i32
19396}
19397
19398#[no_mangle]
19399pub unsafe extern "C" fn __iswxdigit_l(c: u32, _loc: *mut core::ffi::c_void) -> i32 {
19400    (c >= '0' as u32 && c <= '9' as u32 || c >= 'A' as u32 && c <= 'F' as u32 || c >= 'a' as u32 && c <= 'f' as u32) as i32
19401}
19402
19403#[no_mangle]
19404pub unsafe extern "C" fn __iswctype_l(c: u32, ctype: u32, _loc: *mut core::ffi::c_void) -> i32 {
19405    crate::iswctype(c as wint_t, ctype as wctype_t)
19406}
19407
19408#[no_mangle]
19409pub unsafe extern "C" fn __towlower_l(c: u32, _loc: *mut core::ffi::c_void) -> u32 {
19410    crate::towlower(c)
19411}
19412
19413#[no_mangle]
19414pub unsafe extern "C" fn __towupper_l(c: u32, _loc: *mut core::ffi::c_void) -> u32 {
19415    crate::towupper(c)
19416}
19417
19418#[no_mangle]
19419pub unsafe extern "C" fn __towctrans_l(c: u32, _trans: u32, _loc: *mut core::ffi::c_void) -> u32 {
19420    c
19421}
19422
19423// ============================================================
19424// _r functions
19425// ============================================================
19426
19427// ============================================================
19428// stdio internal functions
19429// ============================================================
19430
19431// ============================================================
19432// Misc functions
19433// ============================================================
19434
19435#[no_mangle]
19436pub unsafe extern "C" fn __assert_fail(expr: *const core::ffi::c_char, file: *const core::ffi::c_char, line: u32, func: *const core::ffi::c_char) {
19437    crate::write(2, b"Assertion failed: ".as_ptr() as *const core::ffi::c_void, 18);
19438    if !expr.is_null() { crate::write(2, expr as *const core::ffi::c_void, crate::strlen(expr)); }
19439    crate::write(2, b" (".as_ptr() as *const core::ffi::c_void, 2);
19440    if !file.is_null() { crate::write(2, file as *const core::ffi::c_void, crate::strlen(file)); }
19441    crate::write(2, b": ".as_ptr() as *const core::ffi::c_void, 2);
19442    let mut n = line as usize;
19443    let mut digits: [u8; 32] = [0; 32];
19444    let mut di = 0;
19445    if n == 0 { digits[0] = 0; di = 1; }
19446    while n > 0 && di < 32 { digits[di] = (n % 10) as u8; n /= 10; di += 1; }
19447    while di > 0 { di -= 1; let c = (b'0' + digits[di]) as c_char; crate::write(2, &c as *const c_char as *const core::ffi::c_void, 1); }
19448    crate::write(2, b")".as_ptr() as *const core::ffi::c_void, 1);
19449    if !func.is_null() { crate::write(2, func as *const core::ffi::c_void, crate::strlen(func)); }
19450    crate::write(2, b"\n".as_ptr() as *const core::ffi::c_void, 1);
19451    crate::abort()
19452}
19453
19454#[no_mangle]
19455pub unsafe extern "C" fn at_quick_exit(_func: Option<unsafe extern "C" fn()>) -> i32 {
19456    // Register for quick exit - simplified
19457    0
19458}
19459
19460#[no_mangle]
19461pub unsafe extern "C" fn brk(addr: *mut u8) -> i32 {
19462    <Arch as Syscalls>::syscall1(sysno(12, 214), addr as i64) as i32
19463}
19464
19465#[no_mangle]
19466pub unsafe extern "C" fn copy_file_range(fd_in: i32, off_in: *mut i64, fd_out: i32, off_out: *mut i64, len: usize, flags: u32) -> isize {
19467    <Arch as Syscalls>::syscall6(SYS_COPY_FILE_RANGE, fd_in as i64, off_in as i64, fd_out as i64, off_out as i64, len as i64, flags as i64) as isize
19468}
19469
19470#[no_mangle]
19471pub unsafe extern "C" fn ctermid(s: *mut core::ffi::c_char) -> *mut core::ffi::c_char {
19472    static mut BUF: [core::ffi::c_char; 20] = [0; 20];
19473    let dst = if s.is_null() { BUF.as_mut_ptr() } else { s };
19474    let src = b"/dev/tty\0".as_ptr() as *const core::ffi::c_char;
19475    let mut i = 0;
19476    while i < 9 { *dst.add(i) = *src.add(i); i += 1; }
19477    dst
19478}
19479
19480#[no_mangle]
19481pub unsafe extern "C" fn delete_module(name: *const core::ffi::c_char, flags: u32) -> i32 {
19482    <Arch as Syscalls>::syscall2(SYS_DELETE_MODULE, name as i64, flags as i64) as i32
19483}
19484
19485
19486
19487
19488
19489#[no_mangle]
19490pub unsafe extern "C" fn __duplocale(loc: *mut core::ffi::c_void) -> *mut core::ffi::c_void {
19491    loc
19492}
19493
19494#[no_mangle]
19495pub unsafe extern "C" fn euidaccess(pathname: *const core::ffi::c_char, mode: i32) -> i32 {
19496    faccessat(AT_FDCWD, pathname, mode, 0x200)
19497}
19498
19499#[no_mangle]
19500pub unsafe extern "C" fn fgetln(f: *mut core::ffi::c_void, lenp: *mut usize) -> *mut core::ffi::c_char {
19501    static mut BUF: [core::ffi::c_char; 4096] = [0; 4096];
19502    let mut i = 0;
19503    while i < 4095 {
19504        let c = getc(f as *mut FILE);
19505        if c < 0 { break; }
19506        BUF[i] = c as c_char;
19507        i += 1;
19508        if c == '\n' as i32 { break; }
19509    }
19510    BUF[i] = 0;
19511    if !lenp.is_null() { *lenp = i; }
19512    if i == 0 { core::ptr::null_mut() } else { BUF.as_mut_ptr() }
19513}
19514
19515#[no_mangle]
19516pub unsafe extern "C" fn fgetws(ws: *mut u32, n: i32, f: *mut core::ffi::c_void) -> *mut u32 {
19517    let mut i = 0;
19518    while i < n - 1 {
19519        let c = getwc(f as *mut core::ffi::c_void);
19520        if c == 0 { break; }
19521        *ws.add(i as usize) = c;
19522        i += 1;
19523        if c == '\n' as u32 { break; }
19524    }
19525    *ws.add(i as usize) = 0;
19526    if i == 0 { core::ptr::null_mut() } else { ws }
19527}
19528
19529#[no_mangle]
19530pub unsafe extern "C" fn fmtmsg(_classification: i64, label: *const core::ffi::c_char, _severity: i32, text: *const core::ffi::c_char, _action: *const core::ffi::c_char, _tag: *const core::ffi::c_char) -> i32 {
19531    if !label.is_null() { crate::write(2, label as *const core::ffi::c_void, crate::strlen(label)); }
19532    crate::write(2, b": ".as_ptr() as *const core::ffi::c_void, 2);
19533    if !text.is_null() { crate::write(2, text as *const core::ffi::c_void, crate::strlen(text)); }
19534    crate::write(2, b"\n".as_ptr() as *const core::ffi::c_void, 1);
19535    0
19536}
19537
19538#[no_mangle]
19539pub unsafe extern "C" fn ftime(tp: *mut core::ffi::c_void) -> i32 {
19540    let mut tv: timeval = core::mem::zeroed();
19541    if gettimeofday(&mut tv, core::ptr::null_mut()) == 0 {
19542        let tb = tp as *mut Timeb;
19543        (*tb).time = tv.tv_sec;
19544        (*tb).millitm = (tv.tv_usec / 1000) as u16;
19545        (*tb).timezone = 0;
19546        (*tb).dstflag = 0;
19547        0
19548    } else {
19549        -1
19550    }
19551}
19552
19553#[no_mangle]
19554pub unsafe extern "C" fn getdents(fd: i32, dirp: *mut u8, count: usize) -> isize {
19555    <Arch as Syscalls>::syscall3(SYS_GETDENTS64, fd as i64, dirp as i64, count as i64) as isize
19556}
19557
19558#[no_mangle]
19559pub unsafe extern "C" fn gethostid() -> i64 {
19560    // Read from /proc/sys/kernel/random/boot_id or similar
19561    let fd = crate::open(b"/proc/sys/kernel/random/boot_id\0".as_ptr() as *const core::ffi::c_char, 0, 0);
19562    if fd < 0 { return 0; }
19563    let mut buf: [u8; 64] = [0; 64];
19564    let n = crate::read(fd, buf.as_mut_ptr() as *mut core::ffi::c_void, 63);
19565    crate::close(fd);
19566    if n <= 0 { return 0; }
19567    buf[n as usize] = 0;
19568    crate::strtol(buf.as_ptr() as *const core::ffi::c_char, core::ptr::null_mut(), 16)
19569}
19570
19571#[no_mangle]
19572pub unsafe extern "C" fn getpass(prompt: *const core::ffi::c_char) -> *mut core::ffi::c_char {
19573    static mut BUF: [core::ffi::c_char; 128] = [0; 128];
19574    // Write prompt
19575    crate::write(2, prompt as *const core::ffi::c_void, crate::strlen(prompt));
19576    // Read password (simplified - no echo disable)
19577    let n = crate::read(0, BUF.as_mut_ptr() as *mut core::ffi::c_void, 127);
19578    if n > 0 {
19579        let end = if BUF[(n - 1) as usize] == '\n' as c_char { n - 1 } else { n };
19580        BUF[end as usize] = 0;
19581    } else {
19582        BUF[0] = 0;
19583    }
19584    BUF.as_mut_ptr()
19585}
19586
19587#[no_mangle]
19588pub unsafe extern "C" fn getsubopt(optionp: *mut *mut core::ffi::c_char, tokens: *const *const core::ffi::c_char, valuep: *mut *mut core::ffi::c_char) -> i32 {
19589    let s = *optionp;
19590    if s.is_null() { return -1; }
19591    // Find end of suboption
19592    let mut end = s;
19593    while *end != 0 && *end != ',' as c_char && *end != '=' as c_char { end = end.add(1); }
19594    let eq = *end == '=' as c_char;
19595    if eq { *end = 0; *valuep = end.add(1); }
19596    // Find matching token
19597    let mut i = 0;
19598    loop {
19599        let tok = *tokens.add(i);
19600        if tok.is_null() { break; }
19601        if crate::strcmp(s as *const u8, tok as *const u8) == 0 {
19602            // Skip to next option
19603    while *end != 0 && *end != ',' as c_char { end = end.add(1); }
19604            if *end == ',' as c_char { end = end.add(1); }
19605            *optionp = end;
19606            return i as i32;
19607        }
19608        i += 1;
19609    }
19610    -1
19611}
19612
19613#[no_mangle]
19614pub unsafe extern "C" fn getw(f: *mut core::ffi::c_void) -> i32 {
19615    let c0 = getc(f as *mut FILE);
19616    if c0 < 0 { return -1; }
19617    let c1 = getc(f as *mut FILE);
19618    if c1 < 0 { return -1; }
19619    let c2 = getc(f as *mut FILE);
19620    if c2 < 0 { return -1; }
19621    let c3 = getc(f as *mut FILE);
19622    if c3 < 0 { return -1; }
19623    (c0 | (c1 << 8) | (c2 << 16) | (c3 << 24)) as i32
19624}
19625
19626#[no_mangle]
19627pub unsafe extern "C" fn getwc(f: *mut core::ffi::c_void) -> u32 {
19628    getc(f as *mut FILE) as u32
19629}
19630
19631#[no_mangle]
19632pub unsafe extern "C" fn init_module(module_image: *mut u8, len: usize, param_values: *const core::ffi::c_char) -> i32 {
19633    <Arch as Syscalls>::syscall3(SYS_INIT_MODULE, module_image as i64, len as i64, param_values as i64) as i32
19634}
19635
19636
19637
19638#[no_mangle]
19639pub unsafe extern "C" fn issetugid() -> i32 {
19640    let ruid = crate::getuid();
19641    let euid = crate::geteuid();
19642    let rgid = crate::getgid();
19643    let egid = crate::getegid();
19644    (ruid != euid || rgid != egid) as i32
19645}
19646
19647// ============================================================
19648// poll functions
19649// ============================================================
19650
19651#[no_mangle]
19652pub unsafe extern "C" fn poll(fds: *mut core::ffi::c_void, nfds: u32, timeout: i32) -> i32 {
19653    #[cfg(target_arch = "x86_64")]
19654    { <Arch as Syscalls>::syscall3(SYS_POLL, fds as i64, nfds as i64, timeout as i64) as i32 }
19655    #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
19656    {
19657        <Arch as Syscalls>::syscall5(SYS_PPOLL, fds as i64, nfds as i64, timeout as i64, 0, 0) as i32
19658    }
19659}
19660
19661#[no_mangle]
19662pub unsafe extern "C" fn ppoll(fds: *mut core::ffi::c_void, nfds: u32, timeout: *const core::ffi::c_void, sigmask: *const u64) -> i32 {
19663    <Arch as Syscalls>::syscall5(SYS_PPOLL, fds as i64, nfds as i64, timeout as i64, sigmask as i64, 8) as i32
19664}
19665
19666#[no_mangle]
19667pub unsafe extern "C" fn pselect(nfds: i32, readfds: *mut u8, writefds: *mut u8, exceptfds: *mut u8, timeout: *const core::ffi::c_void, sigmask: *const u64) -> i32 {
19668    <Arch as Syscalls>::syscall6(SYS_PSELECT6, nfds as i64, readfds as i64, writefds as i64, exceptfds as i64, timeout as i64, sigmask as i64) as i32
19669}
19670
19671// ============================================================
19672// realpath function
19673// ============================================================
19674
19675// ============================================================
19676// quick_exit function
19677// ============================================================
19678
19679#[no_mangle]
19680pub unsafe extern "C" fn quick_exit(status: i32) -> ! {
19681    crate::_exit(status)
19682}
19683
19684// ============================================================
19685// stat functions
19686// ============================================================
19687
19688#[no_mangle]
19689pub unsafe extern "C" fn lstat(path: *const core::ffi::c_char, buf: *mut core::ffi::c_void) -> i32 {
19690    <Arch as Syscalls>::syscall4(SYS_NEWFSTATAT, AT_FDCWD as i64, path as i64, buf as i64, 0x100) as i32
19691}
19692
19693#[no_mangle]
19694pub unsafe extern "C" fn __xstat(_ver: i32, path: *const core::ffi::c_char, buf: *mut core::ffi::c_void) -> i32 {
19695    crate::stat(path, buf as *mut Stat)
19696}
19697
19698#[no_mangle]
19699pub unsafe extern "C" fn __lxstat(_ver: i32, path: *const core::ffi::c_char, buf: *mut core::ffi::c_void) -> i32 {
19700    crate::lstat(path, buf)
19701}
19702
19703#[no_mangle]
19704pub unsafe extern "C" fn __fxstat(_ver: i32, fd: i32, buf: *mut core::ffi::c_void) -> i32 {
19705    crate::fstat(fd, buf as *mut Stat)
19706}
19707
19708#[no_mangle]
19709pub unsafe extern "C" fn __fxstatat(_ver: i32, _dirfd: i32, path: *const core::ffi::c_char, buf: *mut core::ffi::c_void, _flags: i32) -> i32 {
19710    crate::stat(path, buf as *mut Stat)
19711}
19712
19713// ============================================================
19714// mempcpy function
19715// ============================================================
19716
19717#[no_mangle]
19718pub unsafe extern "C" fn mempcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8 {
19719    core::ptr::copy_nonoverlapping(src, dest, n);
19720    dest.add(n)
19721}
19722
19723// ============================================================
19724// mktemp functions
19725// ============================================================
19726
19727#[no_mangle]
19728pub unsafe extern "C" fn mkostemp(template: *mut core::ffi::c_char, _flags: i32) -> i32 {
19729    mkstemp(template)
19730}
19731
19732#[no_mangle]
19733pub unsafe extern "C" fn mkstemps(template: *mut core::ffi::c_char, _suffixlen: i32) -> i32 {
19734    mkstemp(template)
19735}
19736
19737// ============================================================
19738// system functions
19739// ============================================================
19740
19741#[no_mangle]
19742pub unsafe extern "C" fn ptrace(request: i32, mut args: ...) -> i64 {
19743    let pid = args.next_arg::<i64>();
19744    let addr = args.next_arg::<i64>();
19745    let data = args.next_arg::<i64>();
19746    <Arch as Syscalls>::syscall4(sysno(101, 117), request as i64, pid, addr, data)
19747}
19748
19749#[no_mangle]
19750pub unsafe extern "C" fn personality(persona: u64) -> i64 {
19751    <Arch as Syscalls>::syscall1(sysno(135, 92), persona as i64)
19752}
19753
19754#[no_mangle]
19755pub unsafe extern "C" fn reboot(magic: i32, magic2: i32, cmd: u32, arg: *mut u8) -> i32 {
19756    <Arch as Syscalls>::syscall4(SYS_REBOOT, magic as i64, magic2 as i64, cmd as i64, arg as i64) as i32
19757}
19758
19759#[no_mangle]
19760pub unsafe extern "C" fn pivot_root(new_root: *const core::ffi::c_char, put_old: *const core::ffi::c_char) -> i32 {
19761    <Arch as Syscalls>::syscall2(SYS_PIVOT_ROOT, new_root as i64, put_old as i64) as i32
19762}
19763
19764#[no_mangle]
19765pub unsafe extern "C" fn mount(source: *const core::ffi::c_char, target: *const core::ffi::c_char, filesystemtype: *const core::ffi::c_char, mountflags: u64, data: *const core::ffi::c_void) -> i32 {
19766    <Arch as Syscalls>::syscall5(SYS_MOUNT, source as i64, target as i64, filesystemtype as i64, mountflags as i64, data as i64) as i32
19767}
19768
19769#[no_mangle]
19770pub unsafe extern "C" fn umount(target: *const core::ffi::c_char) -> i32 {
19771    <Arch as Syscalls>::syscall2(SYS_UMOUNT2, target as i64, 0) as i32
19772}
19773
19774#[no_mangle]
19775pub unsafe extern "C" fn umount2(target: *const core::ffi::c_char, flags: i32) -> i32 {
19776    <Arch as Syscalls>::syscall2(SYS_UMOUNT2, target as i64, flags as i64) as i32
19777}
19778
19779// ============================================================
19780// resolver functions
19781// ============================================================
19782
19783
19784// ============================================================
19785// signal/error functions
19786// ============================================================
19787
19788#[no_mangle]
19789pub unsafe extern "C" fn psiginfo(_pinfo: *const core::ffi::c_void, s: *const core::ffi::c_char) {
19790    if !s.is_null() { crate::write(2, s as *const core::ffi::c_void, crate::strlen(s)); }
19791    crate::write(2, b"\n".as_ptr() as *const core::ffi::c_void, 1);
19792}
19793
19794#[no_mangle]
19795pub unsafe extern "C" fn psignal(sig: i32, s: *const core::ffi::c_char) {
19796    if !s.is_null() { crate::write(2, s as *const core::ffi::c_void, crate::strlen(s)); }
19797    crate::write(2, b": ".as_ptr() as *const core::ffi::c_void, 2);
19798    crate::write(2, strsignal(sig) as *const core::ffi::c_void, crate::strlen(strsignal(sig)));
19799    crate::write(2, b"\n".as_ptr() as *const core::ffi::c_void, 1);
19800}
19801
19802#[no_mangle]
19803pub unsafe extern "C" fn strsignal(sig: c_int) -> *const c_char {
19804    static NAMES: [&[u8]; 32] = [
19805        b"Unknown signal\0",
19806        b"Hangup\0",
19807        b"Interrupt\0",
19808        b"Quit\0",
19809        b"Illegal instruction\0",
19810        b"Trace/breakpoint trap\0",
19811        b"Aborted\0",
19812        b"Bus error\0",
19813        b"Floating point exception\0",
19814        b"Killed\0",
19815        b"User defined signal 1\0",
19816        b"Segmentation fault\0",
19817        b"User defined signal 2\0",
19818        b"Broken pipe\0",
19819        b"Alarm clock\0",
19820        b"Terminated\0",
19821        b"Stack fault\0",
19822        b"Child process status\0",
19823        b"Continued\0",
19824        b"Stopped (signal)\0",
19825        b"Stopped\0",
19826        b"Stopped (tty input)\0",
19827        b"Stopped (tty output)\0",
19828        b"Urgent I/O condition\0",
19829        b"CPU time limit exceeded\0",
19830        b"File size limit exceeded\0",
19831        b"Virtual timer expired\0",
19832        b"Profiling timer expired\0",
19833        b"Window changed\0",
19834        b"I/O possible\0",
19835        b"Power failure\0",
19836        b"Bad system call\0",
19837    ];
19838    static mut RT_BUF: [c_char; 32] = [0; 32];
19839    if sig > 0 && sig < 32 {
19840        return NAMES[sig as usize].as_ptr() as *const c_char;
19841    }
19842    if sig >= 32 && sig < 65 {
19843        let mut o = 0usize;
19844        for &c in b"Real-time signal \0" {
19845            if c == 0 { break; }
19846            RT_BUF[o] = c as c_char;
19847            o += 1;
19848        }
19849        let mut v = (sig - 32) as u32;
19850        let mut digits = [0u8; 10];
19851        let mut d = 0usize;
19852        if v == 0 { digits[0] = b'0'; d = 1; }
19853        while v > 0 { digits[d] = b'0' + (v % 10) as u8; v /= 10; d += 1; }
19854        while d > 0 { d -= 1; RT_BUF[o] = digits[d] as c_char; o += 1; }
19855        RT_BUF[o] = 0;
19856        return RT_BUF.as_ptr();
19857    }
19858    b"Unknown signal\0".as_ptr() as *const c_char
19859}
19860
19861#[no_mangle]
19862pub unsafe extern "C" fn __strerror_l(errnum: i32, _loc: *mut core::ffi::c_void) -> *const core::ffi::c_char {
19863    crate::strerror(errnum)
19864}
19865
19866// ============================================================
19867// preadv functions
19868// ============================================================
19869
19870#[no_mangle]
19871pub unsafe extern "C" fn preadv(fd: i32, iov: *const core::ffi::c_void, iovcnt: i32, offset: i64) -> isize {
19872    <Arch as Syscalls>::syscall4(sysno(295, 69), fd as i64, iov as i64, iovcnt as i64, offset) as isize
19873}
19874
19875#[no_mangle]
19876pub unsafe extern "C" fn pwritev(fd: i32, iov: *const core::ffi::c_void, iovcnt: i32, offset: i64) -> isize {
19877    <Arch as Syscalls>::syscall4(sysno(296, 70), fd as i64, iov as i64, iovcnt as i64, offset) as isize
19878}
19879
19880#[no_mangle]
19881pub unsafe extern "C" fn preadv2(fd: i32, iov: *const core::ffi::c_void, iovcnt: i32, offset: i64, flags: u32) -> isize {
19882    <Arch as Syscalls>::syscall5(sysno(327, 286), fd as i64, iov as i64, iovcnt as i64, offset, flags as i64) as isize
19883}
19884
19885#[no_mangle]
19886pub unsafe extern "C" fn pwritev2(fd: i32, iov: *const core::ffi::c_void, iovcnt: i32, offset: i64, flags: u32) -> isize {
19887    <Arch as Syscalls>::syscall5(sysno(328, 287), fd as i64, iov as i64, iovcnt as i64, offset, flags as i64) as isize
19888}
19889
19890// ============================================================
19891// nice function
19892// ============================================================
19893
19894#[no_mangle]
19895pub unsafe extern "C" fn nice(inc: i32) -> i32 {
19896    let r = <Arch as Syscalls>::syscall2(SYS_GETPRIORITY, 0, 0);
19897    if r < 0 { return -1; }
19898    <Arch as Syscalls>::syscall2(SYS_SETPRIORITY, 0, r + inc as i64) as i32
19899}
19900
19901// ============================================================
19902// misc functions
19903// ============================================================
19904
19905#[no_mangle]
19906pub unsafe extern "C" fn l64a(value: i64) -> *mut core::ffi::c_char {
19907    static mut BUF: [core::ffi::c_char; 7] = [0; 7];
19908    let mut v = value as u64;
19909    let mut i = 0;
19910    while v > 0 && i < 6 {
19911        let c = (v & 0x3f) as u8;
19912        BUF[i] = if c < 26 { c + b'A' } else if c < 52 { c - 26 + b'a' } else if c < 62 { c - 52 + b'0' } else if c == 62 { b'.' } else { b'/' } as core::ffi::c_char;
19913        v >>= 6;
19914        i += 1;
19915    }
19916    BUF[i] = 0;
19917    BUF.as_mut_ptr()
19918}
19919
19920#[no_mangle]
19921pub unsafe extern "C" fn lchmod(path: *const core::ffi::c_char, mode: u32) -> i32 {
19922    <Arch as Syscalls>::syscall4(SYS_FCHMODAT, AT_FDCWD as i64, path as i64, mode as i64, 0x100) as i32
19923}
19924
19925#[no_mangle]
19926pub unsafe extern "C" fn lutimes(filename: *const core::ffi::c_char, times: *const core::ffi::c_void) -> i32 {
19927    utimensat(AT_FDCWD, filename, times as *const timespec, 0x100)
19928}
19929
19930#[no_mangle]
19931pub unsafe extern "C" fn mknod(pathname: *const core::ffi::c_char, mode: u32, dev: u64) -> i32 {
19932    #[cfg(target_arch = "x86_64")]
19933    { <Arch as Syscalls>::syscall3(SYS_MKNOD, pathname as i64, mode as i64, dev as i64) as i32 }
19934    #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
19935    {
19936        <Arch as Syscalls>::syscall4(SYS_MKNODAT, AT_FDCWD as i64, pathname as i64, mode as i64, dev as i64) as i32
19937    }
19938}
19939
19940#[no_mangle]
19941pub unsafe extern "C" fn memfd_create(name: *const core::ffi::c_char, flags: u32) -> i32 {
19942    <Arch as Syscalls>::syscall2(sysno(319, 279), name as i64, flags as i64) as i32
19943}
19944
19945#[no_mangle]
19946pub unsafe extern "C" fn mlock2(addr: *const core::ffi::c_void, len: usize, flags: u32) -> i32 {
19947    <Arch as Syscalls>::syscall3(sysno(325, 284), addr as i64, len as i64, flags as i64) as i32
19948}
19949
19950
19951
19952#[no_mangle]
19953pub unsafe extern "C" fn remap_file_pages(addr: *mut core::ffi::c_void, size: usize, prot: i32, pgoff: usize, flags: u32) -> i32 {
19954    <Arch as Syscalls>::syscall5(sysno(216, 234), addr as i64, size as i64, prot as i64, pgoff as i64, flags as i64) as i32
19955}
19956
19957// ============================================================
19958// nan functions
19959// ============================================================
19960
19961#[no_mangle]
19962pub unsafe extern "C" fn nan(_tagp: *const core::ffi::c_char) -> f64 {
19963    f64::NAN
19964}
19965
19966#[no_mangle]
19967pub unsafe extern "C" fn nanf(_tagp: *const core::ffi::c_char) -> f32 {
19968    f32::NAN
19969}
19970
19971// ============================================================
19972// Remaining symbols - batch 1
19973// ============================================================
19974
19975#[no_mangle]
19976pub unsafe extern "C" fn __lgammal_r(x: f64, signgamp: *mut i32) -> f64 {
19977    *signgamp = 1;
19978    lgamma(x)
19979}
19980
19981#[no_mangle]
19982pub unsafe extern "C" fn __libc_current_sigrtmax() -> i32 {
19983    64
19984}
19985
19986#[no_mangle]
19987pub unsafe extern "C" fn _longjmp(env: *mut core::ffi::c_void, val: i32) {
19988    crate::longjmp(env as *mut u64, val)
19989}
19990
19991#[no_mangle]
19992pub unsafe extern "C" fn __newlocale(_mask: i32, _name: *const core::ffi::c_char, base: *mut core::ffi::c_void) -> *mut core::ffi::c_void {
19993    base
19994}
19995
19996#[no_mangle]
19997pub unsafe extern "C" fn __nl_langinfo(_item: i32) -> *mut core::ffi::c_char {
19998    b"\0".as_ptr() as *mut core::ffi::c_char
19999}
20000
20001#[no_mangle]
20002pub unsafe extern "C" fn __nl_langinfo_l(_item: i32, _loc: *mut core::ffi::c_void) -> *mut core::ffi::c_char {
20003    b"\0".as_ptr() as *mut core::ffi::c_char
20004}
20005
20006#[no_mangle]
20007pub unsafe extern "C" fn ns_get16(cp: *const u8) -> u16 {
20008    ((*cp.add(0) as u16) << 8) | *cp.add(1) as u16
20009}
20010
20011#[no_mangle]
20012pub unsafe extern "C" fn ns_get32(cp: *const u8) -> u32 {
20013    ((*cp.add(0) as u32) << 24) | ((*cp.add(1) as u32) << 16) | ((*cp.add(2) as u32) << 8) | *cp.add(3) as u32
20014}
20015
20016#[no_mangle]
20017pub unsafe extern "C" fn ns_put16(s: u16, dst: *mut u8) {
20018    *dst.add(0) = (s >> 8) as u8;
20019    *dst.add(1) = (s & 0xff) as u8;
20020}
20021
20022#[no_mangle]
20023pub unsafe extern "C" fn ns_put32(l: u32, dst: *mut u8) {
20024    *dst.add(0) = (l >> 24) as u8;
20025    *dst.add(1) = ((l >> 16) & 0xff) as u8;
20026    *dst.add(2) = ((l >> 8) & 0xff) as u8;
20027    *dst.add(3) = (l & 0xff) as u8;
20028}
20029
20030#[no_mangle]
20031pub unsafe extern "C" fn posix_close(fd: i32) -> i32 {
20032    crate::close(fd)
20033}
20034
20035#[no_mangle]
20036pub unsafe extern "C" fn posix_openpt(flags: i32) -> i32 {
20037    crate::open(b"/dev/ptmx\0".as_ptr() as *const core::ffi::c_char, flags, 0)
20038}
20039
20040#[no_mangle]
20041pub unsafe extern "C" fn putw(w: i32, f: *mut core::ffi::c_void) {
20042    putc((w & 0xff) as i32, f as *mut FILE);
20043    putc(((w >> 8) & 0xff) as i32, f as *mut FILE);
20044    putc(((w >> 16) & 0xff) as i32, f as *mut FILE);
20045    putc(((w >> 24) & 0xff) as i32, f as *mut FILE);
20046}
20047
20048
20049
20050#[no_mangle]
20051pub unsafe extern "C" fn rand_r(seedp: *mut u32) -> i32 {
20052    let seed = (*seedp).wrapping_mul(1103515245).wrapping_add(12345);
20053    *seedp = seed;
20054    ((seed >> 16) & 0x7fff) as i32
20055}
20056
20057#[no_mangle]
20058pub unsafe extern "C" fn reallocarray(ptr: *mut core::ffi::c_void, nmemb: usize, size: usize) -> *mut core::ffi::c_void {
20059    let total = match nmemb.checked_mul(size) {
20060        Some(v) => v,
20061        None => { ERRNO = ENOMEM; return core::ptr::null_mut(); }
20062    };
20063    crate::realloc(ptr, total)
20064}
20065
20066#[no_mangle]
20067pub unsafe extern "C" fn __res_state() -> *mut core::ffi::c_void {
20068    static mut STATE: [u8; 512] = [0; 512];
20069    STATE.as_mut_ptr() as *mut core::ffi::c_void
20070}
20071
20072#[no_mangle]
20073pub unsafe extern "C" fn sbrk(increment: isize) -> *mut u8 {
20074    let cur = <Arch as Syscalls>::syscall1(sysno(12, 214), 0);
20075    if increment == 0 { return cur as *mut u8; }
20076    let new = cur + increment as i64;
20077    let r = <Arch as Syscalls>::syscall1(sysno(12, 214), new);
20078    if r < 0 { return -1isize as usize as *mut u8; }
20079    cur as *mut u8
20080}
20081
20082#[no_mangle]
20083pub unsafe extern "C" fn scalb(x: f64, exp: f64) -> f64 {
20084    if x.is_nan() || exp.is_nan() { return x * exp; }
20085    if !exp.is_finite() {
20086        let r = if exp > 0.0 { x * exp } else { x / (-exp) };
20087        if r.is_nan() && !x.is_nan() {
20088            feraiseexcept(FE_INVALID);
20089        }
20090        return r;
20091    }
20092    if libm::rint(exp) != exp {
20093        return __math_invalid(exp);
20094    }
20095    if exp > 65000.0 { return libm::scalbn(x, 65000); }
20096    if -exp > 65000.0 { return libm::scalbn(x, -65000); }
20097    libm::scalbn(x, exp as i32)
20098}
20099
20100#[no_mangle]
20101pub unsafe extern "C" fn scalbf(x: f32, exp: f32) -> f32 {
20102    if x.is_nan() || exp.is_nan() { return x * exp; }
20103    if !exp.is_finite() {
20104        let r = if exp > 0.0 { x * exp } else { x / (-exp) };
20105        if r.is_nan() && !x.is_nan() {
20106            feraiseexcept(FE_INVALID);
20107        }
20108        return r;
20109    }
20110    if libm::rintf(exp) != exp {
20111        return __math_invalidf(exp);
20112    }
20113    if exp > 65000.0 { return libm::scalbnf(x, 65000); }
20114    if -exp > 65000.0 { return libm::scalbnf(x, -65000); }
20115    libm::scalbnf(x, exp as i32)
20116}
20117
20118#[no_mangle]
20119pub unsafe extern "C" fn __sched_cpucount(setsize: usize, setp: *const u8) -> i32 {
20120    let mut count = 0;
20121    let mut i = 0;
20122    while i < setsize * 8 {
20123        if (*setp.add(i / 8) >> (i % 8)) & 1 != 0 { count += 1; }
20124        i += 1;
20125    }
20126    count
20127}
20128
20129
20130
20131#[no_mangle]
20132pub unsafe extern "C" fn select(nfds: i32, readfds: *mut u8, writefds: *mut u8, exceptfds: *mut u8, timeout: *mut core::ffi::c_void) -> i32 {
20133    <Arch as Syscalls>::syscall6(sysno(23, 72), nfds as i64, readfds as i64, writefds as i64, exceptfds as i64, timeout as i64, 0) as i32
20134}
20135
20136
20137
20138#[no_mangle]
20139pub unsafe extern "C" fn sendfile(out_fd: i32, in_fd: i32, offset: *mut i64, count: usize) -> isize {
20140    <Arch as Syscalls>::syscall4(sysno(40, 71), out_fd as i64, in_fd as i64, offset as i64, count as i64) as isize
20141}
20142
20143
20144
20145
20146
20147#[no_mangle]
20148pub unsafe extern "C" fn __setjmp(env: *mut core::ffi::c_void) -> i32 {
20149    crate::setjmp(env as *mut u64)
20150}
20151
20152#[no_mangle]
20153pub unsafe extern "C" fn _setjmp(env: *mut core::ffi::c_void) -> i32 {
20154    crate::setjmp(env as *mut u64)
20155}
20156
20157#[no_mangle]
20158pub unsafe extern "C" fn setlinebuf(stream: *mut core::ffi::c_void) {
20159    setvbuf(stream as *mut FILE, core::ptr::null_mut(), 1, 0);
20160}
20161
20162
20163
20164
20165
20166
20167
20168
20169
20170
20171
20172
20173
20174
20175
20176#[no_mangle]
20177pub unsafe extern "C" fn significand(x: f64) -> f64 {
20178    let bits = x.to_bits();
20179    let exp = ((bits >> 52) & 0x7ff) as i32;
20180    if exp == 0 || exp == 0x7ff { return x; }
20181    f64::from_bits((bits & 0x000fffffffffffff) | (1023u64 << 52))
20182}
20183
20184#[no_mangle]
20185pub unsafe extern "C" fn significandf(x: f32) -> f32 {
20186    let bits = x.to_bits();
20187    let exp = ((bits >> 23) & 0xff) as i32;
20188    if exp == 0 || exp == 0xff { return x; }
20189    f32::from_bits((bits & 0x007fffff) | (127u32 << 23))
20190}
20191
20192
20193
20194
20195
20196#[no_mangle]
20197pub unsafe extern "C" fn sigset(_sig: i32, handler: Option<unsafe extern "C" fn(i32)>) -> Option<unsafe extern "C" fn(i32)> {
20198    handler
20199}
20200
20201#[no_mangle]
20202pub unsafe extern "C" fn sincos(x: f64, sin: *mut f64, cos: *mut f64) {
20203    *sin = libm::sin(x);
20204    *cos = libm::cos(x);
20205}
20206
20207#[no_mangle]
20208pub unsafe extern "C" fn sincosf(x: f32, sin: *mut f32, cos: *mut f32) {
20209    *sin = libm::sinf(x);
20210    *cos = libm::cosf(x);
20211}
20212
20213
20214
20215
20216
20217
20218
20219
20220
20221unsafe fn nd_ascii_lower(c: c_char) -> c_int {
20222    let b = c as u8;
20223    if b >= b'A' && b <= b'Z' { (b + 32) as c_int } else { b as c_int }
20224}
20225
20226unsafe fn nd_strncasecmp(s1: *const c_char, s2: *const c_char, n: usize) -> c_int {
20227    let mut i = 0usize;
20228    while i < n {
20229        let c1 = nd_ascii_lower(*s1.add(i));
20230        let c2 = nd_ascii_lower(*s2.add(i));
20231        if c1 != c2 || c1 == 0 { return c1 - c2; }
20232        i += 1;
20233    }
20234    0
20235}
20236
20237#[no_mangle]
20238pub unsafe extern "C" fn strcasecmp(s1: *const core::ffi::c_char, s2: *const core::ffi::c_char) -> i32 {
20239    nd_strncasecmp(s1, s2, usize::MAX)
20240}
20241
20242#[no_mangle]
20243pub unsafe extern "C" fn __strcasecmp_l(s1: *const core::ffi::c_char, s2: *const core::ffi::c_char, _loc: *mut core::ffi::c_void) -> i32 {
20244    nd_strncasecmp(s1, s2, usize::MAX)
20245}
20246
20247#[no_mangle]
20248pub unsafe extern "C" fn strcasestr(haystack: *const core::ffi::c_char, needle: *const core::ffi::c_char) -> *mut core::ffi::c_char {
20249    let nlen = crate::strlen(needle);
20250    if nlen == 0 { return haystack as *mut core::ffi::c_char; }
20251    let mut i = 0;
20252    loop {
20253        let h = haystack.add(i);
20254        if *h == 0 { return core::ptr::null_mut(); }
20255        if crate::strncasecmp(h, needle, nlen) == 0 { return h as *mut core::ffi::c_char; }
20256        i += 1;
20257    }
20258}
20259
20260#[no_mangle]
20261pub unsafe extern "C" fn __strcoll_l(s1: *const core::ffi::c_char, s2: *const core::ffi::c_char, _loc: *mut core::ffi::c_void) -> i32 {
20262    crate::strcmp(s1 as *const u8, s2 as *const u8)
20263}
20264
20265#[no_mangle]
20266pub unsafe extern "C" fn strncasecmp(s1: *const core::ffi::c_char, s2: *const core::ffi::c_char, n: usize) -> i32 {
20267    nd_strncasecmp(s1, s2, n)
20268}
20269
20270#[no_mangle]
20271pub unsafe extern "C" fn __strncasecmp_l(s1: *const core::ffi::c_char, s2: *const core::ffi::c_char, n: usize, _loc: *mut core::ffi::c_void) -> i32 {
20272    nd_strncasecmp(s1, s2, n)
20273}
20274
20275#[no_mangle]
20276pub unsafe extern "C" fn strsep(stringp: *mut *mut core::ffi::c_char, delim: *const core::ffi::c_char) -> *mut core::ffi::c_char {
20277    let s = *stringp;
20278    if s.is_null() { return core::ptr::null_mut(); }
20279    let mut p = s;
20280    while *p != 0 {
20281        let mut d = delim;
20282        while *d != 0 {
20283            if *p == *d { *p = 0; *stringp = p.add(1); return s; }
20284            d = d.add(1);
20285        }
20286        p = p.add(1);
20287    }
20288    *stringp = core::ptr::null_mut();
20289    s
20290}
20291
20292#[no_mangle]
20293pub unsafe extern "C" fn strtoimax(nptr: *const core::ffi::c_char, endptr: *mut *mut core::ffi::c_char, base: i32) -> i64 {
20294    crate::strtol(nptr, endptr, base)
20295}
20296
20297#[no_mangle]
20298pub unsafe extern "C" fn strtok_r(s: *mut core::ffi::c_char, delim: *const core::ffi::c_char, saveptr: *mut *mut core::ffi::c_char) -> *mut core::ffi::c_char {
20299    let mut s = if s.is_null() { *saveptr } else { s };
20300    if s.is_null() { return core::ptr::null_mut(); }
20301    // Skip leading delimiters
20302    while *s != 0 {
20303        let mut d = delim;
20304        let mut found = false;
20305        while *d != 0 {
20306            if *s == *d { found = true; break; }
20307            d = d.add(1);
20308        }
20309        if !found { break; }
20310        s = s.add(1);
20311    }
20312    if *s == 0 { *saveptr = s; return core::ptr::null_mut(); }
20313    let start = s;
20314    // Find end of token
20315    while *s != 0 {
20316        let mut d = delim;
20317        while *d != 0 {
20318            if *s == *d { *s = 0; *saveptr = s.add(1); return start; }
20319            d = d.add(1);
20320        }
20321        s = s.add(1);
20322    }
20323    *saveptr = s;
20324    start
20325}
20326
20327#[no_mangle]
20328pub unsafe extern "C" fn strtoumax(nptr: *const core::ffi::c_char, endptr: *mut *mut core::ffi::c_char, base: i32) -> u64 {
20329    crate::strtoul(nptr, endptr, base) as u64
20330}
20331
20332#[no_mangle]
20333pub unsafe extern "C" fn __strxfrm_l(dest: *mut core::ffi::c_char, src: *const core::ffi::c_char, n: usize, _loc: *mut core::ffi::c_void) -> usize {
20334    crate::strlcpy(dest as *mut u8, src as *const u8, n)
20335}
20336
20337#[no_mangle]
20338pub unsafe extern "C" fn swab(src: *const u8, dest: *mut u8, nbytes: isize) {
20339    let mut i = 0;
20340    while i + 1 < nbytes {
20341        let a = *src.add(i as usize);
20342        let b = *src.add(i as usize + 1);
20343        *dest.add(i as usize) = b;
20344        *dest.add(i as usize + 1) = a;
20345        i += 2;
20346    }
20347}
20348
20349
20350
20351
20352
20353
20354
20355
20356
20357
20358
20359#[no_mangle]
20360pub unsafe extern "C" fn __tls_get_addr(ti: *mut core::ffi::c_void) -> *mut u8 {
20361    // TLS access - return pointer to TLS block
20362    let p = ti as *mut usize;
20363    let _module_id = *p;
20364    let offset = *p.add(1);
20365    // For now, return a static buffer
20366    static mut TLS_BUF: [u8; 4096] = [0; 4096];
20367    TLS_BUF.as_mut_ptr().add(offset)
20368}
20369
20370#[no_mangle]
20371pub unsafe extern "C" fn __tolower_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
20372    if c >= 'A' as i32 && c <= 'Z' as i32 { c + 32 } else { c }
20373}
20374
20375#[no_mangle]
20376pub unsafe extern "C" fn __toupper_l(c: i32, _loc: *mut core::ffi::c_void) -> i32 {
20377    if c >= 'a' as i32 && c <= 'z' as i32 { c - 32 } else { c }
20378}
20379
20380#[no_mangle]
20381pub unsafe extern "C" fn ulimit(cmd: c_int, mut args: ...) -> c_long {
20382    let mut rl: Rlimit = core::mem::zeroed();
20383    if getrlimit(RLIMIT_FSIZE, &mut rl) != 0 { return -1; }
20384    if cmd == 2 {
20385        let val = args.next_arg::<c_long>();
20386        rl.rlim_cur = 512u64.wrapping_mul(val as u64);
20387        if setrlimit(RLIMIT_FSIZE, &rl) != 0 { return -1; }
20388    }
20389    (rl.rlim_cur / 512) as c_long
20390}
20391
20392#[repr(C)]
20393struct UtsName {
20394    sysname: [u8; 65],
20395    nodename: [u8; 65],
20396    release: [u8; 65],
20397    version: [u8; 65],
20398    machine: [u8; 65],
20399    domainname: [u8; 65],
20400}
20401
20402#[no_mangle]
20403pub unsafe extern "C" fn uname(buf: *mut c_void) -> c_int {
20404    if buf.is_null() { ERRNO = EINVAL; return -1; }
20405    let mut uts: UtsName = core::mem::zeroed();
20406    let r = <Arch as Syscalls>::syscall1(SYS_UNAME, &mut uts as *mut UtsName as i64);
20407    if r < 0 { ERRNO = (-r) as c_int; return -1; }
20408    core::ptr::copy_nonoverlapping(&uts as *const UtsName as *const u8, buf as *mut u8, core::mem::size_of::<UtsName>());
20409    0
20410}
20411
20412#[no_mangle]
20413pub unsafe extern "C" fn unshare(flags: i32) -> i32 {
20414    let r = <Arch as Syscalls>::syscall1(SYS_UNSHARE, flags as i64);
20415    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
20416}
20417
20418#[no_mangle]
20419pub unsafe extern "C" fn updwtmpx(wtmpx_file: *const core::ffi::c_char, utx: *const core::ffi::c_void) {
20420    updwtmp(wtmpx_file, utx)
20421}
20422
20423#[no_mangle]
20424pub unsafe extern "C" fn __uselocale(loc: *mut core::ffi::c_void) -> *mut core::ffi::c_void {
20425    loc
20426}
20427
20428#[repr(C)]
20429pub struct Utimbuf { actime: i64, modtime: i64 }
20430
20431#[no_mangle]
20432pub unsafe extern "C" fn utime(filename: *const c_char, times: *const Utimbuf) -> c_int {
20433    if times.is_null() {
20434        return utimensat(AT_FDCWD, filename, core::ptr::null(), 0);
20435    }
20436    let ts = [
20437        timespec { tv_sec: (*times).actime, tv_nsec: 0 },
20438        timespec { tv_sec: (*times).modtime, tv_nsec: 0 },
20439    ];
20440    utimensat(AT_FDCWD, filename, ts.as_ptr(), 0)
20441}
20442
20443#[no_mangle]
20444pub unsafe extern "C" fn vhangup() -> c_int {
20445    let r = <Arch as Syscalls>::syscall0(SYS_VHANGUP);
20446    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
20447}
20448
20449#[no_mangle]
20450pub unsafe extern "C" fn vmsplice(fd: i32, iov: *const c_void, nr_segs: usize, flags: u32) -> isize {
20451    let r = <Arch as Syscalls>::syscall4(SYS_VMSPLICE, fd as i64, iov as i64, nr_segs as i64, flags as i64);
20452    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
20453}
20454
20455
20456
20457#[no_mangle]
20458pub unsafe extern "C" fn wait4(pid: i32, wstatus: *mut i32, options: i32, rusage: *mut core::ffi::c_void) -> i32 {
20459    <Arch as Syscalls>::syscall4(SYS_WAIT4, pid as i64, wstatus as i64, options as i64, rusage as i64) as i32
20460}
20461
20462#[no_mangle]
20463pub unsafe extern "C" fn waitid(idtype: i32, id: u32, infop: *mut core::ffi::c_void, options: i32) -> i32 {
20464    <Arch as Syscalls>::syscall4(sysno(247, 95), idtype as i64, id as i64, infop as i64, options as i64) as i32
20465}
20466
20467#[no_mangle]
20468pub unsafe extern "C" fn __wcscoll_l(s1: *const u32, s2: *const u32, _loc: *mut core::ffi::c_void) -> i32 {
20469    crate::wcscmp(s1 as *const i32, s2 as *const i32)
20470}
20471
20472#[no_mangle]
20473pub unsafe extern "C" fn __wcsxfrm_l(dest: *mut u32, src: *const u32, n: usize, _loc: *mut core::ffi::c_void) -> usize {
20474    crate::wcscpy(dest as *mut i32, src as *const i32);
20475    n
20476}
20477
20478#[no_mangle]
20479pub unsafe extern "C" fn wcwidth(c: u32) -> i32 {
20480    if c == 0 { return 0; }
20481    if c < 32 || (c >= 0x7f && c < 0xa0) { return -1; }
20482    1
20483}
20484
20485
20486
20487
20488
20489// ============================================================
20490// Final missing symbols
20491// ============================================================
20492
20493
20494
20495#[no_mangle]
20496pub unsafe extern "C" fn strtod_l(nptr: *const core::ffi::c_char, endptr: *mut *mut core::ffi::c_char, _loc: *mut core::ffi::c_void) -> f64 {
20497    crate::strtod(nptr, endptr)
20498}
20499
20500#[no_mangle]
20501pub unsafe extern "C" fn strtof_l(nptr: *const core::ffi::c_char, endptr: *mut *mut core::ffi::c_char, _loc: *mut core::ffi::c_void) -> f32 {
20502    crate::strtof(nptr, endptr)
20503}
20504
20505#[no_mangle]
20506pub unsafe extern "C" fn strtold_l(nptr: *const core::ffi::c_char, endptr: *mut *mut core::ffi::c_char, _loc: *mut core::ffi::c_void) -> f64 {
20507    crate::strtod(nptr, endptr)
20508}
20509
20510// ============================================================
20511// Directory operations - real implementations
20512// ============================================================
20513
20514#[repr(C)]
20515struct linux_dirent64 {
20516    d_ino: u64,
20517    d_off: i64,
20518    d_reclen: u16,
20519    d_type: u8,
20520    d_name: [u8; 0], // flexible array
20521}
20522
20523static mut DIR_BUF: [u8; 1024] = [0; 1024];
20524static mut DIR_FD: i32 = -1;
20525static mut DIR_POS: usize = 0;
20526static mut DIR_LEN: usize = 0;
20527
20528#[no_mangle]
20529pub unsafe extern "C" fn opendir(dirname: *const core::ffi::c_char) -> *mut core::ffi::c_void {
20530    let fd = openat(AT_FDCWD, dirname, O_DIRECTORY, 0); // O_RDONLY | O_DIRECTORY
20531    if fd < 0 { return core::ptr::null_mut(); }
20532    DIR_FD = fd;
20533    DIR_POS = 0;
20534    DIR_LEN = 0;
20535    &DIR_FD as *const i32 as *mut core::ffi::c_void
20536}
20537
20538#[no_mangle]
20539pub unsafe extern "C" fn closedir(dirp: *mut core::ffi::c_void) -> i32 {
20540    if dirp.is_null() { return -1; }
20541    let fd = *(dirp as *const i32);
20542    crate::close(fd)
20543}
20544
20545#[no_mangle]
20546pub unsafe extern "C" fn readdir(dirp: *mut core::ffi::c_void) -> *mut core::ffi::c_void {
20547    if dirp.is_null() { return core::ptr::null_mut(); }
20548    let fd = *(dirp as *const i32);
20549
20550    loop {
20551        if DIR_POS >= DIR_LEN {
20552            let nread = <Arch as Syscalls>::syscall3(SYS_GETDENTS64, fd as i64, DIR_BUF.as_mut_ptr() as i64, 1024) as isize;
20553            if nread <= 0 { return core::ptr::null_mut(); }
20554            DIR_LEN = nread as usize;
20555            DIR_POS = 0;
20556        }
20557
20558        let ent = DIR_BUF.as_ptr().add(DIR_POS) as *const linux_dirent64;
20559        let ent_ref = &*ent;
20560        DIR_POS += ent_ref.d_reclen as usize;
20561
20562        // Return pointer to the entry (reusing static buffer)
20563        return ent as *mut core::ffi::c_void;
20564    }
20565}
20566
20567#[no_mangle]
20568pub unsafe extern "C" fn readdir_r(dirp: *mut core::ffi::c_void, _entry: *mut core::ffi::c_void, result: *mut *mut core::ffi::c_void) -> i32 {
20569    let ent = readdir(dirp);
20570    if ent.is_null() {
20571        *result = core::ptr::null_mut();
20572    } else {
20573        *result = ent;
20574    }
20575    0
20576}
20577
20578#[no_mangle]
20579pub unsafe extern "C" fn seekdir(dirp: *mut core::ffi::c_void, loc: i64) {
20580    if dirp.is_null() { return; }
20581    let fd = *(dirp as *const i32);
20582    <Arch as Syscalls>::syscall3(SYS_LSEEK, fd as i64, loc, 0);
20583}
20584
20585#[no_mangle]
20586pub unsafe extern "C" fn telldir(_dirp: *mut core::ffi::c_void) -> i64 {
20587    DIR_POS as i64
20588}
20589
20590#[no_mangle]
20591pub unsafe extern "C" fn rewinddir(_dirp: *mut core::ffi::c_void) {
20592    DIR_POS = 0;
20593    DIR_LEN = 0;
20594}
20595
20596#[no_mangle]
20597pub unsafe extern "C" fn dirfd(dirp: *mut core::ffi::c_void) -> i32 {
20598    if dirp.is_null() { return -1; }
20599    unsafe { *(dirp as *const i32) }
20600}
20601
20602// ============================================================
20603// Memory management - real implementations
20604// ============================================================
20605
20606#[no_mangle]
20607pub unsafe extern "C" fn mprotect(addr: *mut u8, len: usize, prot: i32) -> i32 {
20608    <Arch as Syscalls>::syscall3(SYS_MPROTECT, addr as i64, len as i64, prot as i64) as i32
20609}
20610
20611#[no_mangle]
20612pub unsafe extern "C" fn msync(addr: *mut u8, len: usize, flags: i32) -> i32 {
20613    <Arch as Syscalls>::syscall3(sysno(26, 227), addr as i64, len as i64, flags as i64) as i32
20614}
20615
20616#[no_mangle]
20617pub unsafe extern "C" fn mlock(addr: *const u8, len: usize) -> i32 {
20618    <Arch as Syscalls>::syscall2(sysno(149, 228), addr as i64, len as i64) as i32
20619}
20620
20621#[no_mangle]
20622pub unsafe extern "C" fn munlock(addr: *const u8, len: usize) -> i32 {
20623    <Arch as Syscalls>::syscall2(sysno(150, 229), addr as i64, len as i64) as i32
20624}
20625
20626#[no_mangle]
20627pub unsafe extern "C" fn mlockall(flags: i32) -> i32 {
20628    <Arch as Syscalls>::syscall1(sysno(151, 230), flags as i64) as i32
20629}
20630
20631#[no_mangle]
20632pub unsafe extern "C" fn munlockall() -> i32 {
20633    <Arch as Syscalls>::syscall0(sysno(152, 231)) as i32
20634}
20635
20636#[no_mangle]
20637pub unsafe extern "C" fn madvise(addr: *mut u8, len: usize, advice: i32) -> i32 {
20638    <Arch as Syscalls>::syscall3(sysno(28, 233), addr as i64, len as i64, advice as i64) as i32
20639}
20640
20641#[no_mangle]
20642pub unsafe extern "C" fn mincore(addr: *mut u8, len: usize, vec: *mut u8) -> i32 {
20643    <Arch as Syscalls>::syscall3(sysno(27, 232), addr as i64, len as i64, vec as i64) as i32
20644}
20645
20646// ============================================================
20647
20648// ============================================================
20649// Missing math functions
20650// ============================================================
20651
20652#[no_mangle]
20653pub unsafe extern "C" fn drem(x: f64, y: f64) -> f64 {
20654    remainder(x, y)
20655}
20656
20657#[no_mangle]
20658pub unsafe extern "C" fn dremf(x: f32, y: f32) -> f32 {
20659    remainderf(x, y)
20660}
20661
20662#[no_mangle]
20663pub unsafe extern "C" fn pow10(x: f64) -> f64 {
20664    libm::pow(10.0, x)
20665}
20666
20667#[no_mangle]
20668pub unsafe extern "C" fn pow10f(x: f32) -> f32 {
20669    libm::powf(10.0, x)
20670}
20671
20672#[no_mangle]
20673pub unsafe extern "C" fn pow10l(x: f64) -> f64 {
20674    libm::pow(10.0, x)
20675}
20676
20677#[no_mangle]
20678pub unsafe extern "C" fn isless(x: f64, y: f64) -> i32 {
20679    if x.is_nan() || y.is_nan() { 0 } else { (x < y) as i32 }
20680}
20681
20682#[no_mangle]
20683pub unsafe extern "C" fn islessf(x: f32, y: f32) -> i32 {
20684    if x.is_nan() || y.is_nan() { 0 } else { (x < y) as i32 }
20685}
20686
20687#[no_mangle]
20688pub unsafe extern "C" fn lgamma_r(x: f64, signgamp: *mut i32) -> f64 {
20689    lgamma_r_impl(x, signgamp)
20690}
20691
20692#[no_mangle]
20693pub unsafe extern "C" fn lgammaf_r(x: f32, signgamp: *mut i32) -> f32 {
20694    if x.is_nan() {
20695        if !signgamp.is_null() { *signgamp = 1; }
20696        return x;
20697    }
20698    if x == 0.0 {
20699        if !signgamp.is_null() { *signgamp = if x.is_sign_negative() { -1 } else { 1 }; }
20700        feraiseexcept(FE_DIVBYZERO);
20701        return f32::INFINITY;
20702    }
20703    let (r, sign) = libm::lgammaf_r(x);
20704    if !signgamp.is_null() { *signgamp = sign; }
20705    r
20706}
20707
20708#[no_mangle]
20709pub unsafe extern "C" fn lgammal_r(x: f64, signgamp: *mut i32) -> f64 {
20710    lgamma_r(x, signgamp)
20711}
20712
20713// ============================================================
20714// Comparison macros
20715// ============================================================
20716
20717#[no_mangle]
20718pub unsafe extern "C" fn islessequal(x: f64, y: f64) -> i32 {
20719    if x.is_nan() || y.is_nan() { 0 } else { (x <= y) as i32 }
20720}
20721
20722#[no_mangle]
20723pub unsafe extern "C" fn islessequalf(x: f32, y: f32) -> i32 {
20724    if x.is_nan() || y.is_nan() { 0 } else { (x <= y) as i32 }
20725}
20726
20727#[no_mangle]
20728pub unsafe extern "C" fn islessgreater(x: f64, y: f64) -> i32 {
20729    if x.is_nan() || y.is_nan() { 0 } else { (x < y || x > y) as i32 }
20730}
20731
20732#[no_mangle]
20733pub unsafe extern "C" fn islessgreaterf(x: f32, y: f32) -> i32 {
20734    if x.is_nan() || y.is_nan() { 0 } else { (x < y || x > y) as i32 }
20735}
20736
20737#[no_mangle]
20738pub unsafe extern "C" fn isgreater(x: f64, y: f64) -> i32 {
20739    if x.is_nan() || y.is_nan() { 0 } else { (x > y) as i32 }
20740}
20741
20742#[no_mangle]
20743pub unsafe extern "C" fn isgreaterf(x: f32, y: f32) -> i32 {
20744    if x.is_nan() || y.is_nan() { 0 } else { (x > y) as i32 }
20745}
20746
20747#[no_mangle]
20748pub unsafe extern "C" fn isgreaterequal(x: f64, y: f64) -> i32 {
20749    if x.is_nan() || y.is_nan() { 0 } else { (x >= y) as i32 }
20750}
20751
20752#[no_mangle]
20753pub unsafe extern "C" fn isgreaterequalf(x: f32, y: f32) -> i32 {
20754    if x.is_nan() || y.is_nan() { 0 } else { (x >= y) as i32 }
20755}
20756
20757// ============================================================
20758// musl ABI compatibility helpers
20759// ============================================================
20760
20761#[no_mangle]
20762pub unsafe extern "C" fn stpcpy(dest: *mut c_char, src: *const c_char) -> *mut c_char {
20763    let mut d = dest;
20764    let mut s = src;
20765    while *s != 0 {
20766        *d = *s;
20767        d = d.add(1);
20768        s = s.add(1);
20769    }
20770    *d = 0;
20771    d
20772}
20773
20774#[no_mangle]
20775pub unsafe extern "C" fn stpncpy(dest: *mut c_char, src: *const c_char, n: usize) -> *mut c_char {
20776    let mut i = 0;
20777    while i < n && *src.add(i) != 0 {
20778        *dest.add(i) = *src.add(i);
20779        i += 1;
20780    }
20781    let end = dest.add(i);
20782    while i < n {
20783        *dest.add(i) = 0;
20784        i += 1;
20785    }
20786    end
20787}
20788
20789#[no_mangle]
20790pub unsafe extern "C" fn strchrnul(s: *const c_char, c: c_int) -> *mut c_char {
20791    let mut p = s;
20792    while *p != 0 && *p as c_int != c {
20793        p = p.add(1);
20794    }
20795    p as *mut c_char
20796}
20797
20798#[no_mangle]
20799pub unsafe extern "C" fn fstatat(dirfd: c_int, path: *const c_char, buf: *mut Stat, flags: c_int) -> c_int {
20800    let r = sys_newfstatat(dirfd, path, buf as *mut u8, flags);
20801    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
20802}
20803
20804#[no_mangle]
20805pub unsafe extern "C" fn execvpe(
20806    file: *const c_char,
20807    argv: *const *const c_char,
20808    envp: *const *const c_char,
20809) -> c_int {
20810    if file.is_null() { return -1; }
20811    let mut has_slash = false;
20812    let mut p = file;
20813    while *p != 0 {
20814        if *p == b'/' as c_char { has_slash = true; break; }
20815        p = p.add(1);
20816    }
20817    if has_slash {
20818        return execve(file, argv, envp) as c_int;
20819    }
20820
20821    let file_len = crate::strlen(file);
20822    let path = crate::getenv(b"PATH\0".as_ptr() as *const c_char);
20823    if path.is_null() {
20824        return execve(file, argv, envp) as c_int;
20825    }
20826
20827    let mut buf = [0 as c_char; 4096];
20828    let mut dir = path;
20829    loop {
20830        let mut end = dir;
20831        while *end != 0 && *end != b':' as c_char { end = end.add(1); }
20832        let dlen = end.offset_from(dir) as usize;
20833        if dlen + 1 + file_len < buf.len() {
20834            let mut i = 0;
20835            while i < dlen {
20836                buf[i] = *dir.add(i);
20837                i += 1;
20838            }
20839            buf[i] = b'/' as c_char;
20840            i += 1;
20841            let mut j = 0;
20842            while j < file_len {
20843                buf[i + j] = *file.add(j);
20844                j += 1;
20845            }
20846            buf[i + j] = 0;
20847            execve(buf.as_ptr(), argv, envp);
20848        }
20849        if *end == 0 { break; }
20850        dir = end.add(1);
20851    }
20852    -1
20853}
20854
20855// Locale-aware entry points. crabc currently has a single global locale,
20856// so these are source/ABI-compatible wrappers around the normal functions.
20857#[no_mangle]
20858pub unsafe extern "C" fn strcoll_l(s1: *const c_char, s2: *const c_char, _loc: locale_t) -> c_int {
20859    strcoll(s1, s2)
20860}
20861
20862#[no_mangle]
20863pub unsafe extern "C" fn strxfrm_l(dest: *mut c_char, src: *const c_char, n: usize, _loc: locale_t) -> usize {
20864    strxfrm(dest, src, n)
20865}
20866
20867#[no_mangle]
20868pub unsafe extern "C" fn strerror_l(errnum: c_int, _loc: locale_t) -> *mut c_char {
20869    strerror(errnum)
20870}
20871
20872#[no_mangle]
20873pub unsafe extern "C" fn strcasecmp_l(s1: *const c_char, s2: *const c_char, _loc: locale_t) -> c_int {
20874    strcasecmp(s1, s2)
20875}
20876
20877#[no_mangle]
20878pub unsafe extern "C" fn strncasecmp_l(s1: *const c_char, s2: *const c_char, n: usize, _loc: locale_t) -> c_int {
20879    strncasecmp(s1, s2, n)
20880}
20881
20882#[no_mangle]
20883pub unsafe extern "C" fn strftime_l(s: *mut c_char, max: usize, fmt: *const c_char, tm: *const tm, _loc: locale_t) -> usize {
20884    strftime(s, max, fmt, tm)
20885}
20886
20887#[no_mangle]
20888pub unsafe extern "C" fn nl_langinfo_l(item: c_int, _loc: locale_t) -> *mut c_char {
20889    nl_langinfo(item)
20890}
20891
20892#[no_mangle]
20893pub unsafe extern "C" fn wcscoll_l(s1: *const u32, s2: *const u32, _loc: locale_t) -> c_int {
20894    wcscoll(s1, s2)
20895}
20896
20897#[no_mangle]
20898pub unsafe extern "C" fn wcsxfrm_l(dst: *mut wchar_t, src: *const wchar_t, n: usize, _loc: locale_t) -> usize {
20899    wcsxfrm(dst, src, n)
20900}
20901
20902#[no_mangle]
20903pub unsafe extern "C" fn wcsftime_l(s: *mut u32, max: usize, fmt: *const u32, tm: *const c_void, _loc: locale_t) -> usize {
20904    wcsftime(s, max, fmt, tm)
20905}
20906
20907#[no_mangle]
20908pub unsafe extern "C" fn wctype_l(name: *const c_char, _loc: locale_t) -> wctype_t {
20909    wctype(name)
20910}
20911
20912#[no_mangle]
20913pub unsafe extern "C" fn wctrans_l(name: *const c_char, _loc: locale_t) -> wctrans_t {
20914    wctrans(name)
20915}
20916
20917#[no_mangle]
20918pub unsafe extern "C" fn towlower_l(c: wint_t, _loc: locale_t) -> wint_t {
20919    towlower(c)
20920}
20921
20922#[no_mangle]
20923pub unsafe extern "C" fn towupper_l(c: wint_t, _loc: locale_t) -> wint_t {
20924    towupper(c)
20925}
20926
20927#[no_mangle]
20928pub unsafe extern "C" fn towctrans_l(c: wint_t, desc: wctrans_t, _loc: locale_t) -> wint_t {
20929    towctrans(c, desc)
20930}
20931
20932#[no_mangle] pub unsafe extern "C" fn iswalnum_l(c: wint_t, _l: locale_t) -> c_int { iswalnum(c) }
20933#[no_mangle] pub unsafe extern "C" fn iswalpha_l(c: wint_t, _l: locale_t) -> c_int { iswalpha(c) }
20934#[no_mangle] pub unsafe extern "C" fn iswblank_l(c: wint_t, _l: locale_t) -> c_int { iswblank(c) }
20935#[no_mangle] pub unsafe extern "C" fn iswcntrl_l(c: wint_t, _l: locale_t) -> c_int { iswcntrl(c) }
20936#[no_mangle] pub unsafe extern "C" fn iswdigit_l(c: wint_t, _l: locale_t) -> c_int { iswdigit(c) }
20937#[no_mangle] pub unsafe extern "C" fn iswgraph_l(c: wint_t, _l: locale_t) -> c_int { iswgraph(c) }
20938#[no_mangle] pub unsafe extern "C" fn iswlower_l(c: wint_t, _l: locale_t) -> c_int { iswlower(c) }
20939#[no_mangle] pub unsafe extern "C" fn iswprint_l(c: wint_t, _l: locale_t) -> c_int { iswprint(c) }
20940#[no_mangle] pub unsafe extern "C" fn iswpunct_l(c: wint_t, _l: locale_t) -> c_int { iswpunct(c) }
20941#[no_mangle] pub unsafe extern "C" fn iswspace_l(c: wint_t, _l: locale_t) -> c_int { iswspace(c) }
20942#[no_mangle] pub unsafe extern "C" fn iswupper_l(c: wint_t, _l: locale_t) -> c_int { iswupper(c) }
20943#[no_mangle] pub unsafe extern "C" fn iswxdigit_l(c: wint_t, _l: locale_t) -> c_int { iswxdigit(c) }
20944#[no_mangle] pub unsafe extern "C" fn iswctype_l(c: wint_t, desc: wctype_t, _l: locale_t) -> c_int { iswctype(c, desc) }
20945
20946// ISO C99 scanf ABI aliases expected by musl binaries.
20947#[no_mangle] pub unsafe extern "C" fn __isoc99_scanf(fmt: *const c_char, args: ...) -> c_int { vfscanf(stdin, fmt, args) }
20948#[no_mangle] pub unsafe extern "C" fn __isoc99_fscanf(f: *mut FILE, fmt: *const c_char, args: ...) -> c_int { vfscanf(f, fmt, args) }
20949#[no_mangle] pub unsafe extern "C" fn __isoc99_sscanf(s: *const c_char, fmt: *const c_char, args: ...) -> c_int { vsscanf(s, fmt, args) }
20950#[no_mangle] pub unsafe extern "C" fn __isoc99_vscanf(fmt: *const c_char, args: VaList) -> c_int { vfscanf(stdin, fmt, args) }
20951#[no_mangle] pub unsafe extern "C" fn __isoc99_vfscanf(f: *mut FILE, fmt: *const c_char, args: VaList) -> c_int { vfscanf(f, fmt, args) }
20952#[no_mangle] pub unsafe extern "C" fn __isoc99_vsscanf(s: *const c_char, fmt: *const c_char, args: VaList) -> c_int { vsscanf(s, fmt, args) }
20953#[no_mangle] pub unsafe extern "C" fn __isoc99_wscanf(fmt: *const wchar_t, args: ...) -> c_int { vfwscanf(stdin, fmt, args) }
20954#[no_mangle] pub unsafe extern "C" fn __isoc99_fwscanf(f: *mut FILE, fmt: *const wchar_t, args: ...) -> c_int { vfwscanf(f, fmt, args) }
20955#[no_mangle] pub unsafe extern "C" fn __isoc99_swscanf(s: *const wchar_t, fmt: *const wchar_t, args: ...) -> c_int { vswscanf(s, fmt, args) }
20956#[no_mangle] pub unsafe extern "C" fn __isoc99_vwscanf(fmt: *const wchar_t, args: VaList) -> c_int { vfwscanf(stdin, fmt, args) }
20957#[no_mangle] pub unsafe extern "C" fn __isoc99_vfwscanf(f: *mut FILE, fmt: *const wchar_t, args: VaList) -> c_int { vfwscanf(f, fmt, args) }
20958#[no_mangle] pub unsafe extern "C" fn __isoc99_vswscanf(s: *const wchar_t, fmt: *const wchar_t, args: VaList) -> c_int { vswscanf(s, fmt, args) }
20959
20960// Unlocked stdio entry points. The current stdio implementation is not
20961// thread-safe anyway, so these are aliases for the normal entry points.
20962#[no_mangle] pub unsafe extern "C" fn clearerr_unlocked(f: *mut FILE) { clearerr(f) }
20963#[no_mangle] pub unsafe extern "C" fn feof_unlocked(f: *mut FILE) -> c_int { feof(f) }
20964#[no_mangle] pub unsafe extern "C" fn ferror_unlocked(f: *mut FILE) -> c_int { ferror(f) }
20965#[no_mangle] pub unsafe extern "C" fn fileno_unlocked(f: *mut FILE) -> c_int { fileno(f) }
20966#[no_mangle] pub unsafe extern "C" fn fflush_unlocked(f: *mut FILE) -> c_int { fflush(f) }
20967#[no_mangle] pub unsafe extern "C" fn fgetc_unlocked(f: *mut FILE) -> c_int { fgetc(f) }
20968#[no_mangle] pub unsafe extern "C" fn fgets_unlocked(s: *mut c_char, n: c_int, f: *mut FILE) -> *mut c_char { fgets(s, n, f) }
20969#[no_mangle] pub unsafe extern "C" fn fputc_unlocked(c: c_int, f: *mut FILE) -> c_int { fputc(c, f) }
20970#[no_mangle] pub unsafe extern "C" fn fputs_unlocked(s: *const c_char, f: *mut FILE) -> c_int { fputs(s, f) }
20971#[no_mangle] pub unsafe extern "C" fn fread_unlocked(p: *mut c_void, size: usize, n: usize, f: *mut FILE) -> usize { fread(p, size, n, f) }
20972#[no_mangle] pub unsafe extern "C" fn fwrite_unlocked(p: *const c_void, size: usize, n: usize, f: *mut FILE) -> usize { fwrite(p, size, n, f) }
20973#[no_mangle] pub unsafe extern "C" fn fgetwc_unlocked(f: *mut FILE) -> wint_t { fgetwc(f) }
20974#[no_mangle] pub unsafe extern "C" fn fgetws_unlocked(s: *mut u32, n: c_int, f: *mut c_void) -> *mut u32 { fgetws(s, n, f) }
20975#[no_mangle] pub unsafe extern "C" fn fputwc_unlocked(c: wchar_t, f: *mut FILE) -> wint_t { fputwc(c, f) }
20976#[no_mangle] pub unsafe extern "C" fn fputws_unlocked(s: *const wchar_t, f: *mut FILE) -> c_int { fputws(s, f) }
20977#[no_mangle] pub unsafe extern "C" fn getwc_unlocked(f: *mut c_void) -> wint_t { getwc(f) }
20978#[no_mangle] pub unsafe extern "C" fn putwc_unlocked(c: u32, f: *mut c_void) -> wint_t { putwc(c, f) }
20979#[no_mangle] pub unsafe extern "C" fn getwchar_unlocked() -> wint_t { getwchar() }
20980#[no_mangle] pub unsafe extern "C" fn putwchar_unlocked(c: wchar_t) -> wint_t { putwchar(c) }
20981#[no_mangle] pub unsafe extern "C" fn fpurge(f: *mut FILE) { clearerr(f) }
20982#[no_mangle] pub unsafe extern "C" fn _IO_getc(f: *mut FILE) -> c_int { getc(f) }
20983#[no_mangle] pub unsafe extern "C" fn _IO_putc(c: c_int, f: *mut FILE) -> c_int { putc(c, f) }
20984#[no_mangle] pub unsafe extern "C" fn _IO_getc_unlocked(f: *mut FILE) -> c_int { getc(f) }
20985#[no_mangle] pub unsafe extern "C" fn _IO_putc_unlocked(c: c_int, f: *mut FILE) -> c_int { putc(c, f) }
20986#[no_mangle] pub unsafe extern "C" fn _IO_feof_unlocked(f: *mut FILE) -> c_int { feof(f) }
20987#[no_mangle] pub unsafe extern "C" fn _IO_ferror_unlocked(f: *mut FILE) -> c_int { ferror(f) }
20988
20989// ABI aliases used by musl and older C libraries.
20990#[no_mangle] pub unsafe extern "C" fn __getauxval(t: c_ulong) -> c_ulong { getauxval(t) }
20991#[no_mangle] pub unsafe extern "C" fn __longjmp(env: *const c_ulong, val: c_int) -> ! { longjmp(env, val) }
20992#[no_mangle] pub unsafe extern "C" fn bsd_signal(sig: c_int, handler: usize) -> usize { signal(sig, handler) }
20993#[no_mangle] pub unsafe extern "C" fn __sysv_signal(sig: c_int, handler: usize) -> usize { signal(sig, handler) }
20994#[no_mangle] pub unsafe extern "C" fn eaccess(path: *const c_char, mode: c_int) -> c_int { access(path, mode) }
20995#[no_mangle] pub unsafe extern "C" fn __xpg_basename(path: *mut c_char) -> *mut c_char { basename(path) }
20996#[no_mangle] pub unsafe extern "C" fn __xpg_strerror_r(errnum: c_int, buf: *mut c_char, len: usize) -> c_int { strerror_r(errnum, buf, len) }
20997#[no_mangle] pub unsafe extern "C" fn __posix_getopt(argc: c_int, argv: *const *const c_char, optstring: *const c_char) -> c_int { getopt(argc, argv, optstring) }
20998
20999// ============================================================
21000// Remaining musl ABI entry points
21001// ============================================================
21002
21003#[no_mangle]
21004pub unsafe extern "C" fn cfsetspeed(termios_p: *mut c_void, speed: u32) -> c_int {
21005    let r = cfsetispeed(termios_p, speed);
21006    if r != 0 { return r; }
21007    cfsetospeed(termios_p, speed)
21008}
21009
21010#[no_mangle]
21011pub unsafe extern "C" fn futimesat(dirfd: c_int, path: *const c_char, times: *const timeval) -> c_int {
21012    if times.is_null() {
21013        return utimensat(dirfd, path, core::ptr::null(), 0);
21014    }
21015    let tv = times as *const [timeval; 2];
21016    let mut ts: [timespec; 2] = [
21017        timespec { tv_sec: (*tv)[0].tv_sec, tv_nsec: (*tv)[0].tv_usec * 1000 },
21018        timespec { tv_sec: (*tv)[1].tv_sec, tv_nsec: (*tv)[1].tv_usec * 1000 },
21019    ];
21020    for t in &mut ts {
21021        if t.tv_nsec < 0 || t.tv_nsec >= 1_000_000_000 {
21022            ERRNO = EINVAL;
21023            return -1;
21024        }
21025    }
21026    utimensat(dirfd, path, ts.as_ptr(), 0)
21027}
21028
21029#[no_mangle]
21030pub unsafe extern "C" fn membarrier(cmd: c_int, flags: c_int, cpu_id: c_int) -> c_int {
21031    <Arch as Syscalls>::syscall3(SYS_MEMBARRIER, cmd as i64, flags as i64, cpu_id as i64) as c_int
21032}
21033
21034#[no_mangle]
21035pub unsafe extern "C" fn mremap(
21036    old_address: *mut c_void,
21037    old_size: usize,
21038    new_size: usize,
21039    flags: c_int,
21040    mut args: ...
21041) -> *mut c_void {
21042    let new_address = if flags & 2 != 0 { args.next_arg::<*mut c_void>() } else { core::ptr::null_mut() };
21043    let r = <Arch as Syscalls>::syscall5(
21044        SYS_MREMAP,
21045        old_address as i64,
21046        old_size as i64,
21047        new_size as i64,
21048        flags as i64,
21049        new_address as i64,
21050    );
21051    if r < 0 {
21052        ERRNO = (-r) as c_int;
21053        return (-1isize) as *mut c_void;
21054    }
21055    r as *mut c_void
21056}
21057
21058#[no_mangle]
21059pub unsafe extern "C" fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: usize) -> c_int {
21060    let name = ptsname(fd);
21061    if name.is_null() { return -1; }
21062    let n = crate::strlen(name);
21063    if n + 1 > buflen {
21064        ERRNO = ERANGE_VAL;
21065        return ERANGE_VAL;
21066    }
21067    core::ptr::copy_nonoverlapping(name, buf, n + 1);
21068    0
21069}
21070
21071#[no_mangle]
21072pub unsafe extern "C" fn posix_getdents(fd: c_int, buf: *mut c_void, len: usize, flags: c_int) -> isize {
21073    if flags != 0 {
21074        ERRNO = EINVAL;
21075        return -1;
21076    }
21077    let r = <Arch as Syscalls>::syscall3(SYS_GETDENTS64, fd as i64, buf as i64, len as i64);
21078    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
21079}
21080
21081#[no_mangle]
21082pub unsafe extern "C" fn riscv_flush_icache(start: *mut c_void, end: *mut c_void, flags: c_ulong) -> c_int {
21083    #[cfg(target_arch = "riscv64")]
21084    {
21085        let r = <Arch as Syscalls>::syscall3(259, start as i64, end as i64, flags as i64);
21086        if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21087    }
21088    #[cfg(not(target_arch = "riscv64"))]
21089    {
21090        let _ = (start, end, flags);
21091        0
21092    }
21093}
21094
21095#[no_mangle]
21096pub unsafe extern "C" fn __riscv_flush_icache(start: *mut c_void, end: *mut c_void, flags: c_ulong) -> c_int {
21097    riscv_flush_icache(start, end, flags)
21098}
21099
21100#[no_mangle]
21101pub unsafe extern "C" fn mkostemps(template: *mut c_char, suffixlen: c_int, flags: c_int) -> c_int {
21102    let fd = mkstemps(template, suffixlen);
21103    if fd >= 0 && flags & O_CLOEXEC != 0 {
21104        sys_fcntl(fd, F_SETFD, FD_CLOEXEC as i64);
21105    }
21106    fd
21107}
21108
21109#[no_mangle]
21110pub unsafe extern "C" fn statfs(path: *const c_char, buf: *mut c_void) -> c_int {
21111    let r = <Arch as Syscalls>::syscall2(SYS_STATFS, path as i64, buf as i64);
21112    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21113}
21114
21115#[no_mangle]
21116pub unsafe extern "C" fn fstatfs(fd: c_int, buf: *mut c_void) -> c_int {
21117    let r = <Arch as Syscalls>::syscall2(SYS_FSTATFS, fd as i64, buf as i64);
21118    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21119}
21120
21121#[no_mangle]
21122pub unsafe extern "C" fn sysinfo(info: *mut c_void) -> c_int {
21123    let r = <Arch as Syscalls>::syscall1(SYS_SYSINFO, info as i64);
21124    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21125}
21126
21127#[no_mangle]
21128pub unsafe extern "C" fn pthread_tryjoin_np(thread: PthreadT, retval: *mut *mut c_void) -> c_int {
21129    let slot = thread as *mut Thread;
21130    if slot.is_null() { return EINVAL; }
21131    if (*slot).detach_state == DT_DETACHED { return EINVAL; }
21132    let tid = core::ptr::read_volatile(&raw const (*slot).tid);
21133    if tid > 0 { return EBUSY; }
21134    if tid < 0 { return EINVAL; }
21135    pthread_join(thread, retval)
21136}
21137
21138#[no_mangle]
21139pub unsafe extern "C" fn pthread_timedjoin_np(thread: PthreadT, retval: *mut *mut c_void, abstime: *const timespec) -> c_int {
21140    let slot = thread as *mut Thread;
21141    if slot.is_null() { return EINVAL; }
21142    if (*slot).detach_state == DT_DETACHED { return EINVAL; }
21143    loop {
21144        let r = pthread_tryjoin_np(thread, retval);
21145        if r != EBUSY { return r; }
21146        let tid = core::ptr::read_volatile(&raw const (*slot).tid);
21147        if tid <= 0 { continue; }
21148        let e = futex_timedwait(&raw mut (*slot).tid, tid, abstime);
21149        if e == ETIMEDOUT { return ETIMEDOUT; }
21150    }
21151}
21152
21153
21154// utmp/utmpx are backed by the classic /var/run/utmp file.  musl itself
21155// leaves these as no-ops; crabc provides the real file-backed API.
21156#[repr(C)]
21157pub struct UtmpExit {
21158    pub e_termination: i16,
21159    pub e_exit: i16,
21160}
21161
21162#[repr(C)]
21163pub struct Utmpx {
21164    pub ut_type: i16,
21165    pub __ut_pad1: i16,
21166    pub ut_pid: i32,
21167    pub ut_line: [c_char; 32],
21168    pub ut_id: [c_char; 4],
21169    pub ut_user: [c_char; 32],
21170    pub ut_host: [c_char; 256],
21171    pub ut_exit: UtmpExit,
21172    pub ut_session: i32,
21173    pub __ut_pad2: i32,
21174    pub ut_tv: timeval,
21175    pub ut_addr_v6: [u32; 4],
21176    pub __unused: [u8; 20],
21177}
21178
21179const UTMP_SIZE: usize = 400;
21180const _: [(); UTMP_SIZE] = [(); core::mem::size_of::<Utmpx>()];
21181
21182static mut UTMP_FD: c_int = -1;
21183static mut UTMP_PATH: [u8; 256] = [0; 256];
21184static mut UTMP_PATH_SET: bool = false;
21185#[repr(align(8))]
21186struct UtmpBuf([u8; UTMP_SIZE]);
21187static mut UTMP_BUF: UtmpBuf = UtmpBuf([0; UTMP_SIZE]);
21188
21189unsafe fn utmp_path_ptr() -> *const c_char {
21190    if !UTMP_PATH_SET {
21191        let default = b"/var/run/utmp\0";
21192        let mut i = 0;
21193        while i < default.len() && i < UTMP_PATH.len() {
21194            UTMP_PATH[i] = default[i];
21195            i += 1;
21196        }
21197        UTMP_PATH_SET = true;
21198    }
21199    UTMP_PATH.as_ptr() as *const c_char
21200}
21201
21202unsafe fn utmp_open_read() -> c_int {
21203    if UTMP_FD >= 0 {
21204        crate::close(UTMP_FD);
21205    }
21206    UTMP_FD = crate::open(utmp_path_ptr(), 0, 0);
21207    UTMP_FD
21208}
21209
21210unsafe fn utmp_open_append() -> c_int {
21211    crate::open(utmp_path_ptr(), 1 | 64 | 1024, 0o644)
21212}
21213
21214#[no_mangle]
21215pub unsafe extern "C" fn setutent() {
21216    let _ = utmp_open_read();
21217}
21218
21219#[no_mangle]
21220pub unsafe extern "C" fn endutent() {
21221    if UTMP_FD >= 0 {
21222        crate::close(UTMP_FD);
21223        UTMP_FD = -1;
21224    }
21225}
21226
21227#[no_mangle]
21228pub unsafe extern "C" fn getutent() -> *mut c_void {
21229    if UTMP_FD < 0 && utmp_open_read() < 0 {
21230        return core::ptr::null_mut();
21231    }
21232    let n = crate::read(UTMP_FD, UTMP_BUF.0.as_mut_ptr() as *mut c_void, UTMP_SIZE);
21233    if n == UTMP_SIZE as isize {
21234        UTMP_BUF.0.as_mut_ptr() as *mut c_void
21235    } else {
21236        core::ptr::null_mut()
21237    }
21238}
21239
21240unsafe fn utmp_id_eq(a: &[c_char; 4], b: &[c_char; 4]) -> bool {
21241    a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]
21242}
21243
21244unsafe fn utmp_line_eq(a: &[c_char; 32], b: &[c_char; 32]) -> bool {
21245    let mut i = 0;
21246    while i < 32 {
21247        if a[i] != b[i] { return false; }
21248        if a[i] == 0 { return true; }
21249        i += 1;
21250    }
21251    true
21252}
21253
21254#[no_mangle]
21255pub unsafe extern "C" fn getutid(ut: *const c_void) -> *mut c_void {
21256    if ut.is_null() { return core::ptr::null_mut(); }
21257    let want = &*(ut as *const Utmpx);
21258    loop {
21259        let p = getutent();
21260        if p.is_null() { return p; }
21261        let cur = &*(p as *const Utmpx);
21262        let matched = match want.ut_type {
21263            1 | 2 | 3 | 4 => cur.ut_type == want.ut_type,
21264            _ => utmp_id_eq(&cur.ut_id, &want.ut_id)
21265                && (want.ut_type == 0 || cur.ut_type == want.ut_type),
21266        };
21267        if matched { return p; }
21268    }
21269}
21270
21271#[no_mangle]
21272pub unsafe extern "C" fn getutline(ut: *const c_void) -> *mut c_void {
21273    if ut.is_null() { return core::ptr::null_mut(); }
21274    let want = &*(ut as *const Utmpx);
21275    loop {
21276        let p = getutent();
21277        if p.is_null() { return p; }
21278        if utmp_line_eq(&(*(p as *const Utmpx)).ut_line, &want.ut_line) {
21279            return p;
21280        }
21281    }
21282}
21283
21284#[no_mangle]
21285pub unsafe extern "C" fn pututline(ut: *const c_void) -> *mut c_void {
21286    if ut.is_null() { return core::ptr::null_mut(); }
21287    let fd = utmp_open_append();
21288    if fd < 0 { return core::ptr::null_mut(); }
21289    let n = crate::write(fd, ut, UTMP_SIZE);
21290    crate::close(fd);
21291    if n == UTMP_SIZE as isize { ut as *mut c_void } else { core::ptr::null_mut() }
21292}
21293
21294#[no_mangle]
21295pub unsafe extern "C" fn updwtmp(file: *const c_char, ut: *const c_void) {
21296    if file.is_null() || ut.is_null() { return; }
21297    let fd = crate::open(file, 1 | 64 | 1024, 0o644);
21298    if fd >= 0 {
21299        let _ = crate::write(fd, ut, UTMP_SIZE);
21300        crate::close(fd);
21301    }
21302}
21303
21304unsafe fn utmp_set_name(file: *const c_char) -> c_int {
21305    if file.is_null() { return -1; }
21306    let len = crate::strlen(file);
21307    if len + 1 > UTMP_PATH.len() { return -1; }
21308    if UTMP_FD >= 0 {
21309        crate::close(UTMP_FD);
21310        UTMP_FD = -1;
21311    }
21312    core::ptr::copy_nonoverlapping(file, UTMP_PATH.as_mut_ptr() as *mut c_char, len + 1);
21313    UTMP_PATH_SET = true;
21314    0
21315}
21316
21317#[no_mangle]
21318pub unsafe extern "C" fn utmpname(file: *const c_char) -> c_int { utmp_set_name(file) }
21319
21320#[no_mangle]
21321pub unsafe extern "C" fn utmpxname(file: *const c_char) -> c_int { utmp_set_name(file) }
21322
21323
21324// Data symbols and internal aliases still referenced by some musl binaries.
21325#[no_mangle] pub static mut ___environ: *mut *mut c_char = core::ptr::null_mut();
21326#[no_mangle] pub static mut _environ: *mut *mut c_char = core::ptr::null_mut();
21327#[no_mangle] pub unsafe extern "C" fn __freelocale(loc: locale_t) { freelocale(loc) }
21328#[no_mangle] pub unsafe extern "C" fn __getdelim(lineptr: *mut *mut c_char, n: *mut usize, delim: c_int, stream: *mut FILE) -> isize { getdelim(lineptr, n, delim, stream) }
21329#[no_mangle] pub unsafe extern "C" fn __strtod_l(s: *const c_char, end: *mut *mut c_char, loc: locale_t) -> f64 { strtod_l(s, end, loc) }
21330#[no_mangle] pub unsafe extern "C" fn __strtof_l(s: *const c_char, end: *mut *mut c_char, loc: locale_t) -> f32 { strtof_l(s, end, loc) }
21331#[no_mangle] pub unsafe extern "C" fn __strtold_l(s: *const c_char, end: *mut *mut c_char, loc: locale_t) -> f64 { strtold_l(s, end, loc) }
21332
21333#[no_mangle] pub unsafe extern "C" fn __strtol_internal(s: *const c_char, end: *mut *mut c_char, base: c_int) -> c_long { strtol(s, end, base) }
21334#[no_mangle] pub unsafe extern "C" fn __strtoul_internal(s: *const c_char, end: *mut *mut c_char, base: c_int) -> c_ulong { strtoul(s, end, base) }
21335#[no_mangle] pub unsafe extern "C" fn __strtoll_internal(s: *const c_char, end: *mut *mut c_char, base: c_int) -> c_longlong { strtoll(s, end, base) }
21336#[no_mangle] pub unsafe extern "C" fn __strtoull_internal(s: *const c_char, end: *mut *mut c_char, base: c_int) -> c_ulonglong { strtoull(s, end, base) }
21337#[no_mangle] pub unsafe extern "C" fn __strtoimax_internal(s: *const c_char, end: *mut *mut c_char, base: c_int) -> i64 { strtoimax(s, end, base) }
21338#[no_mangle] pub unsafe extern "C" fn __strtoumax_internal(s: *const c_char, end: *mut *mut c_char, base: c_int) -> u64 { strtoumax(s, end, base) }
21339
21340// ============================================================
21341// Resolver (UDP DNS)
21342// ============================================================
21343
21344const MAX_NS: usize = 3;
21345const MAX_SEARCH: usize = 6;
21346const HOST_NOT_FOUND: c_int = 1;
21347const TRY_AGAIN: c_int = 2;
21348const NO_RECOVERY: c_int = 3;
21349const NO_DATA: c_int = 4;
21350
21351static mut NS_COUNT: usize = 0;
21352static mut NS_ADDRS: [u32; MAX_NS] = [0; MAX_NS];
21353static mut SEARCH_COUNT: usize = 0;
21354static mut SEARCH_DOMAINS: [[u8; 256]; MAX_SEARCH] = [[0; 256]; MAX_SEARCH];
21355static mut RESOLV_INITIALIZED: bool = false;
21356
21357#[repr(C)]
21358struct SockAddrIn {
21359    sin_family: u16,
21360    sin_port: u16,
21361    sin_addr: u32,
21362    sin_zero: [u8; 8],
21363}
21364
21365#[repr(C)]
21366struct PollFd {
21367    fd: c_int,
21368    events: i16,
21369    revents: i16,
21370}
21371
21372unsafe fn resolv_skip_ws(line: &[u8], mut i: usize) -> usize {
21373    while i < line.len() && (line[i] == b' ' || line[i] == b'\t') { i += 1; }
21374    i
21375}
21376
21377unsafe fn resolv_token<'a>(line: &'a [u8], mut i: usize) -> (&'a [u8], usize) {
21378    let start = i;
21379    while i < line.len() && line[i] != b' ' && line[i] != b'\t' && line[i] != b'#' { i += 1; }
21380    (&line[start..i], i)
21381}
21382
21383unsafe fn resolv_parse_config() -> c_int {
21384    RESOLV_INITIALIZED = true;
21385    NS_COUNT = 0;
21386    SEARCH_COUNT = 0;
21387    let path = b"/etc/resolv.conf\0";
21388    let fd = crate::open(path.as_ptr() as *const c_char, 0, 0);
21389    if fd < 0 { return -1; }
21390    let mut buf = [0u8; 4096];
21391    let n = crate::read(fd, buf.as_mut_ptr() as *mut c_void, buf.len());
21392    crate::close(fd);
21393    if n <= 0 { return -1; }
21394    let len = n as usize;
21395    let mut i = 0;
21396    while i < len {
21397        let start = i;
21398        while i < len && buf[i] != b'\n' { i += 1; }
21399        let line = &buf[start..i];
21400        i += 1;
21401        let mut j = resolv_skip_ws(line, 0);
21402        if j >= line.len() || line[j] == b'#' { continue; }
21403        let (key, next) = resolv_token(line, j);
21404        j = next;
21405        if key == b"nameserver" {
21406            j = resolv_skip_ws(line, j);
21407            let (tok, _) = resolv_token(line, j);
21408            if !tok.is_empty() && NS_COUNT < MAX_NS {
21409                let mut name = [0u8; 64];
21410                let l = core::cmp::min(tok.len(), 63);
21411                name[..l].copy_from_slice(&tok[..l]);
21412                let addr = crate::inet_addr(name.as_ptr() as *const c_char);
21413                if addr != u32::MAX {
21414                    NS_ADDRS[NS_COUNT] = addr;
21415                    NS_COUNT += 1;
21416                }
21417            }
21418        } else if key == b"search" || key == b"domain" {
21419            loop {
21420                j = resolv_skip_ws(line, j);
21421                if j >= line.len() || line[j] == b'#' { break; }
21422                let (tok, next) = resolv_token(line, j);
21423                j = next;
21424                if tok.is_empty() { break; }
21425                if SEARCH_COUNT < MAX_SEARCH {
21426                    let l = core::cmp::min(tok.len(), 255);
21427                    SEARCH_DOMAINS[SEARCH_COUNT][..l].copy_from_slice(&tok[..l]);
21428                    SEARCH_DOMAINS[SEARCH_COUNT][l] = 0;
21429                    SEARCH_COUNT += 1;
21430                }
21431                if key == b"domain" { break; }
21432            }
21433        }
21434    }
21435    0
21436}
21437
21438#[no_mangle]
21439pub unsafe extern "C" fn res_init() -> c_int {
21440    let _ = resolv_parse_config();
21441    0
21442}
21443
21444#[no_mangle]
21445pub unsafe extern "C" fn res_mkquery(
21446    op: c_int,
21447    dname: *const c_char,
21448    class: c_int,
21449    type_: c_int,
21450    _data: *const u8,
21451    _datalen: c_int,
21452    _newrr: *const u8,
21453    buf: *mut u8,
21454    buflen: c_int,
21455) -> c_int {
21456    if dname.is_null() || buf.is_null() { return -1; }
21457    let mut l = crate::strnlen(dname as *const u8, 255);
21458    if l > 0 && *dname.add(l - 1) == b'.' as c_char { l -= 1; }
21459    if l > 0 && *dname.add(l - 1) == b'.' as c_char { return -1; }
21460    let n = 17 + l + if l != 0 { 1 } else { 0 };
21461    if l > 253 || buflen < n as c_int || op < 0 || op > 15 || class < 0 || class > 255 || type_ < 0 || type_ > 255 {
21462        return -1;
21463    }
21464    let mut q = [0u8; 280];
21465    crate::memset(q.as_mut_ptr() as *mut c_void, 0, n);
21466    q[2] = (op * 8 + 1) as u8;
21467    q[3] = 32;
21468    q[5] = 1;
21469    core::ptr::copy_nonoverlapping(dname as *const u8, q.as_mut_ptr().add(13), l);
21470    let mut i = 13;
21471    while q[i] != 0 {
21472        let mut j = i;
21473        while q[j] != 0 && q[j] != b'.' { j += 1; }
21474        if j - i - 1 > 62 { return -1; }
21475        q[i - 1] = (j - i) as u8;
21476        i = j + 1;
21477    }
21478    q[i + 1] = type_ as u8;
21479    q[i + 3] = class as u8;
21480    let mut ts = timespec { tv_sec: 0, tv_nsec: 0 };
21481    let _ = clock_gettime(CLOCK_REALTIME, &mut ts);
21482    let id = (((ts.tv_nsec as u64) + (ts.tv_nsec as u64) / 65536) & 0xffff) as u16;
21483    q[0] = (id >> 8) as u8;
21484    q[1] = id as u8;
21485    core::ptr::copy_nonoverlapping(q.as_ptr(), buf, n);
21486    n as c_int
21487}
21488
21489unsafe fn res_send_inner(msg: *const u8, msglen: c_int, answer: *mut u8, anslen: c_int) -> c_int {
21490    if msg.is_null() || answer.is_null() || msglen < 12 || anslen < 12 { return -1; }
21491    if !RESOLV_INITIALIZED { let _ = resolv_parse_config(); }
21492    if NS_COUNT == 0 {
21493        h_errno = TRY_AGAIN;
21494        return -1;
21495    }
21496    for n in 0..NS_COUNT {
21497        let fd = crate::socket(AF_INET, SOCK_DGRAM, 0);
21498        if fd < 0 { continue; }
21499        let sa = SockAddrIn {
21500            sin_family: AF_INET as u16,
21501            sin_port: 53u16.to_be(),
21502            sin_addr: NS_ADDRS[n],
21503            sin_zero: [0; 8],
21504        };
21505        let sent = crate::sendto(fd, msg as *const c_void, msglen as usize, 0, &sa as *const SockAddrIn as *const crate::sockaddr, 16);
21506        if sent != msglen as isize {
21507            crate::close(fd);
21508            continue;
21509        }
21510        let mut pfd = PollFd { fd, events: 1, revents: 0 };
21511        let pr = crate::poll(&mut pfd as *mut PollFd as *mut c_void, 1, 5000);
21512        if pr <= 0 {
21513            crate::close(fd);
21514            continue;
21515        }
21516        let r = crate::recvfrom(fd, answer as *mut c_void, anslen as usize, 0, core::ptr::null_mut(), core::ptr::null_mut());
21517        crate::close(fd);
21518        if r >= 12 {
21519            let id_ok = *answer == *msg && *answer.add(1) == *msg.add(1);
21520            let qr = (*answer.add(2) & 0x80) != 0;
21521            if id_ok && qr {
21522                return r as c_int;
21523            }
21524        }
21525    }
21526    h_errno = TRY_AGAIN;
21527    -1
21528}
21529
21530#[no_mangle]
21531pub unsafe extern "C" fn res_send(msg: *const u8, msglen: c_int, answer: *mut u8, anslen: c_int) -> c_int {
21532    if anslen < 512 {
21533        let mut buf = [0u8; 512];
21534        let r = res_send_inner(msg, msglen, buf.as_mut_ptr(), 512);
21535        if r >= 0 {
21536            let copy = core::cmp::min(r, anslen) as usize;
21537            if copy > 0 { core::ptr::copy_nonoverlapping(buf.as_ptr(), answer, copy); }
21538        }
21539        return r;
21540    }
21541    res_send_inner(msg, msglen, answer, anslen)
21542}
21543
21544#[no_mangle]
21545pub unsafe extern "C" fn res_query(
21546    dname: *const c_char,
21547    class: c_int,
21548    type_: c_int,
21549    answer: *mut u8,
21550    anslen: c_int,
21551) -> c_int {
21552    let mut q = [0u8; 280];
21553    let ql = res_mkquery(0, dname, class, type_, core::ptr::null(), 0, core::ptr::null(), q.as_mut_ptr(), q.len() as c_int);
21554    if ql < 0 { return ql; }
21555    let r = res_send(q.as_ptr(), ql, answer, anslen);
21556    if r < 12 {
21557        h_errno = TRY_AGAIN;
21558        return -1;
21559    }
21560    let rcode = answer.add(3).read() & 0x0f;
21561    if rcode == 3 {
21562        h_errno = HOST_NOT_FOUND;
21563        return -1;
21564    }
21565    if rcode == 0 && *answer.add(6) == 0 && *answer.add(7) == 0 {
21566        h_errno = NO_DATA;
21567        return -1;
21568    }
21569    if rcode != 0 {
21570        h_errno = NO_RECOVERY;
21571        return -1;
21572    }
21573    r
21574}
21575
21576#[no_mangle]
21577pub unsafe extern "C" fn res_querydomain(
21578    name: *const c_char,
21579    domain: *const c_char,
21580    class: c_int,
21581    type_: c_int,
21582    answer: *mut u8,
21583    anslen: c_int,
21584) -> c_int {
21585    if domain.is_null() || *domain == 0 { return res_query(name, class, type_, answer, anslen); }
21586    let mut buf = [0u8; 512];
21587    let nl = crate::strlen(name);
21588    let dl = crate::strlen(domain);
21589    if nl + 1 + dl >= buf.len() { return -1; }
21590    core::ptr::copy_nonoverlapping(name, buf.as_mut_ptr() as *mut c_char, nl);
21591    buf[nl] = b'.';
21592    core::ptr::copy_nonoverlapping(domain, buf.as_mut_ptr().add(nl + 1) as *mut c_char, dl);
21593    buf[nl + 1 + dl] = 0;
21594    res_query(buf.as_ptr() as *const c_char, class, type_, answer, anslen)
21595}
21596
21597#[no_mangle]
21598pub unsafe extern "C" fn res_search(
21599    name: *const c_char,
21600    class: c_int,
21601    type_: c_int,
21602    answer: *mut u8,
21603    anslen: c_int,
21604) -> c_int {
21605    if name.is_null() { return -1; }
21606    if !RESOLV_INITIALIZED { let _ = resolv_parse_config(); }
21607    let len = crate::strlen(name);
21608    let mut dots = 0;
21609    for i in 0..len {
21610        if *name.add(i) == b'.' as c_char { dots += 1; }
21611    }
21612    let trailing_dot = len > 0 && *name.add(len - 1) == b'.' as c_char;
21613    if trailing_dot || dots >= 1 {
21614        let r = res_query(name, class, type_, answer, anslen);
21615        if r >= 0 { return r; }
21616        if trailing_dot { return -1; }
21617    }
21618    for i in 0..SEARCH_COUNT {
21619        let dom = SEARCH_DOMAINS[i].as_ptr() as *const c_char;
21620        let r = res_querydomain(name, dom, class, type_, answer, anslen);
21621        if r >= 0 { return r; }
21622        if h_errno != HOST_NOT_FOUND && h_errno != NO_DATA { return -1; }
21623    }
21624    if dots == 0 {
21625        return res_query(name, class, type_, answer, anslen);
21626    }
21627    -1
21628}
21629
21630// ============================================================
21631// Host and address resolution
21632// ============================================================
21633
21634#[repr(C)]
21635pub struct HostEnt {
21636    pub h_name: *mut c_char,
21637    pub h_aliases: *mut *mut c_char,
21638    pub h_addrtype: c_int,
21639    pub h_length: c_int,
21640    pub h_addr_list: *mut *mut c_char,
21641}
21642
21643#[repr(C)]
21644pub struct AddrInfo {
21645    pub ai_flags: c_int,
21646    pub ai_family: c_int,
21647    pub ai_socktype: c_int,
21648    pub ai_protocol: c_int,
21649    pub ai_addrlen: u32,
21650    pub ai_addr: *mut c_void,
21651    pub ai_canonname: *mut c_char,
21652    pub ai_next: *mut AddrInfo,
21653}
21654
21655static mut HOST_ENT: HostEnt = HostEnt {
21656    h_name: core::ptr::null_mut(),
21657    h_aliases: core::ptr::null_mut(),
21658    h_addrtype: 0,
21659    h_length: 0,
21660    h_addr_list: core::ptr::null_mut(),
21661};
21662static mut HOST_NAME: [c_char; 256] = [0; 256];
21663static mut HOST_ALIASES: [*mut c_char; 1] = [core::ptr::null_mut()];
21664static mut HOST_ADDR: [u8; 16] = [0; 16];
21665static mut HOST_ADDR_PTRS: [*mut c_char; 2] = [core::ptr::null_mut(); 2];
21666
21667unsafe fn dns_skip_name(p: *const u8, end: *const u8) -> *const u8 {
21668    let mut q = p;
21669    while q < end {
21670        let c = *q;
21671        if c == 0 { return q.add(1); }
21672        if c & 0xc0 == 0xc0 { return q.add(2); }
21673        q = q.add(1 + c as usize);
21674    }
21675    end
21676}
21677
21678unsafe fn dns_read_u16(p: *const u8) -> u16 {
21679    ((*p as u16) << 8) | *p.add(1) as u16
21680}
21681
21682unsafe fn dns_expand_name(p: *const u8, msg: *const u8, out: *mut c_char, outlen: usize) -> bool {
21683    let mut q = p;
21684    let mut o = 0usize;
21685    let mut jumps = 0;
21686    loop {
21687        let c = *q;
21688        if c == 0 {
21689            if o < outlen { *out.add(o) = 0; }
21690            return true;
21691        }
21692        if c & 0xc0 == 0xc0 {
21693            let off = (((c & 0x3f) as usize) << 8) | *q.add(1) as usize;
21694            q = msg.add(off);
21695            jumps += 1;
21696            if jumps > 16 { return false; }
21697            continue;
21698        }
21699        let l = c as usize;
21700        if l > 63 { return false; }
21701        if o + l + 1 >= outlen { return false; }
21702        core::ptr::copy_nonoverlapping(q.add(1), out.add(o) as *mut u8, l);
21703        o += l;
21704        *out.add(o) = b'.' as c_char;
21705        o += 1;
21706        q = q.add(1 + l);
21707    }
21708}
21709
21710unsafe fn host_from_answer(answer: *const u8, len: c_int, af: c_int) -> *mut HostEnt {
21711    if len < 12 { return core::ptr::null_mut(); }
21712    let end = answer.add(len as usize);
21713    let qd = dns_read_u16(answer.add(4)) as usize;
21714    let an = dns_read_u16(answer.add(6)) as usize;
21715    let mut p = answer.add(12);
21716    for _ in 0..qd {
21717        p = dns_skip_name(p, end);
21718        p = p.add(4);
21719    }
21720    let want_type: u16 = if af == AF_INET6 { 28 } else { 1 };
21721    let want_len = if af == AF_INET6 { 16 } else { 4 };
21722    for _ in 0..an {
21723        p = dns_skip_name(p, end);
21724        if p.add(10) > end { break; }
21725        let typ = dns_read_u16(p);
21726        let class = dns_read_u16(p.add(2));
21727        let rdlen = dns_read_u16(p.add(8)) as usize;
21728        let rdata = p.add(10);
21729        if rdata.add(rdlen) > end { break; }
21730        if typ == want_type && class == 1 && rdlen == want_len {
21731            core::ptr::copy_nonoverlapping(rdata, HOST_ADDR.as_mut_ptr(), want_len);
21732            HOST_ENT.h_addrtype = af;
21733            HOST_ENT.h_length = want_len as c_int;
21734            HOST_ADDR_PTRS[0] = HOST_ADDR.as_mut_ptr() as *mut c_char;
21735            HOST_ADDR_PTRS[1] = core::ptr::null_mut();
21736            HOST_ENT.h_addr_list = HOST_ADDR_PTRS.as_mut_ptr();
21737            HOST_ENT.h_aliases = HOST_ALIASES.as_mut_ptr();
21738            HOST_ENT.h_name = HOST_NAME.as_mut_ptr();
21739            h_errno = 0;
21740            return &raw mut HOST_ENT;
21741        }
21742        p = rdata.add(rdlen);
21743    }
21744    core::ptr::null_mut()
21745}
21746
21747#[no_mangle]
21748pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut HostEnt {
21749    gethostbyname2(name, AF_INET)
21750}
21751
21752#[no_mangle]
21753pub unsafe extern "C" fn gethostbyname2(name: *const c_char, af: c_int) -> *mut HostEnt {
21754    if name.is_null() { h_errno = HOST_NOT_FOUND; return core::ptr::null_mut(); }
21755    let mut addr = [0u8; 16];
21756    let addrlen = if af == AF_INET6 { 16 } else { 4 };
21757    if inet_pton(af, name, addr.as_mut_ptr() as *mut c_void) == 1 {
21758        core::ptr::copy_nonoverlapping(addr.as_ptr(), HOST_ADDR.as_mut_ptr(), addrlen);
21759        let n = crate::strlen(name);
21760        let l = core::cmp::min(n, 255);
21761        core::ptr::copy_nonoverlapping(name, HOST_NAME.as_mut_ptr(), l);
21762        HOST_NAME[l] = 0;
21763        HOST_ENT.h_name = HOST_NAME.as_mut_ptr();
21764        HOST_ENT.h_aliases = HOST_ALIASES.as_mut_ptr();
21765        HOST_ENT.h_addrtype = af;
21766        HOST_ENT.h_length = addrlen as c_int;
21767        HOST_ADDR_PTRS[0] = HOST_ADDR.as_mut_ptr() as *mut c_char;
21768        HOST_ADDR_PTRS[1] = core::ptr::null_mut();
21769        HOST_ENT.h_addr_list = HOST_ADDR_PTRS.as_mut_ptr();
21770        h_errno = 0;
21771        return &raw mut HOST_ENT;
21772    }
21773    let mut answer = [0u8; 512];
21774    let qtype = if af == AF_INET6 { 28 } else { 1 };
21775    let r = res_query(name, 1, qtype, answer.as_mut_ptr(), answer.len() as c_int);
21776    if r < 0 {
21777        if h_errno == 0 { h_errno = TRY_AGAIN; }
21778        return core::ptr::null_mut();
21779    }
21780    let ent = host_from_answer(answer.as_ptr(), r, af);
21781    if !ent.is_null() {
21782        let n = crate::strlen(name);
21783        let l = core::cmp::min(n, 255);
21784        core::ptr::copy_nonoverlapping(name, HOST_NAME.as_mut_ptr(), l);
21785        HOST_NAME[l] = 0;
21786    } else {
21787        h_errno = HOST_NOT_FOUND;
21788    }
21789    ent
21790}
21791
21792#[no_mangle]
21793pub unsafe extern "C" fn gethostbyaddr(addr: *const c_void, len: u32, type_: c_int) -> *mut HostEnt {
21794    if addr.is_null() || type_ != AF_INET || len != 4 { h_errno = HOST_NOT_FOUND; return core::ptr::null_mut(); }
21795    let a = addr as *const u8;
21796    let mut name = [0u8; 128];
21797    let mut pos = 0;
21798    for i in 0..4 {
21799        let v = *a.add(3 - i) as u32;
21800        if v >= 100 { name[pos] = b'0' + (v / 100) as u8; pos += 1; }
21801        if v >= 10 { name[pos] = b'0' + ((v / 10) % 10) as u8; pos += 1; }
21802        name[pos] = b'0' + (v % 10) as u8; pos += 1;
21803        name[pos] = b'.'; pos += 1;
21804    }
21805    let suffix = b"in-addr.arpa";
21806    for &c in suffix { name[pos] = c; pos += 1; }
21807    name[pos] = 0;
21808    let mut answer = [0u8; 512];
21809    let r = res_query(name.as_ptr() as *const c_char, 1, 12, answer.as_mut_ptr(), answer.len() as c_int);
21810    if r < 12 { h_errno = HOST_NOT_FOUND; return core::ptr::null_mut(); }
21811    let end = answer.as_ptr().add(r as usize);
21812    let qd = dns_read_u16(answer.as_ptr().add(4)) as usize;
21813    let an = dns_read_u16(answer.as_ptr().add(6)) as usize;
21814    let mut p = answer.as_ptr().add(12);
21815    for _ in 0..qd { p = dns_skip_name(p, end); p = p.add(4); }
21816    for _ in 0..an {
21817        p = dns_skip_name(p, end);
21818        if p.add(10) > end { break; }
21819        let typ = dns_read_u16(p);
21820        let rdlen = dns_read_u16(p.add(8)) as usize;
21821        let rdata = p.add(10);
21822        if typ == 12 && dns_expand_name(rdata, answer.as_ptr(), HOST_NAME.as_mut_ptr(), HOST_NAME.len()) {
21823            let mut o = crate::strlen(HOST_NAME.as_ptr());
21824            if o > 0 && HOST_NAME[o - 1] == b'.' as c_char { o -= 1; }
21825            HOST_NAME[o] = 0;
21826            core::ptr::copy_nonoverlapping(a, HOST_ADDR.as_mut_ptr(), 4);
21827            HOST_ENT.h_name = HOST_NAME.as_mut_ptr();
21828            HOST_ENT.h_aliases = HOST_ALIASES.as_mut_ptr();
21829            HOST_ENT.h_addrtype = AF_INET;
21830            HOST_ENT.h_length = 4;
21831            HOST_ADDR_PTRS[0] = HOST_ADDR.as_mut_ptr() as *mut c_char;
21832            HOST_ADDR_PTRS[1] = core::ptr::null_mut();
21833            HOST_ENT.h_addr_list = HOST_ADDR_PTRS.as_mut_ptr();
21834            h_errno = 0;
21835            return &raw mut HOST_ENT;
21836        }
21837        p = rdata.add(rdlen);
21838    }
21839    h_errno = HOST_NOT_FOUND;
21840    core::ptr::null_mut()
21841}
21842
21843// ============================================================
21844// Legacy syscall/stdio/signal compatibility
21845// ============================================================
21846
21847#[inline]
21848fn sysno(x86_64: i64, generic: i64) -> i64 {
21849    if cfg!(target_arch = "x86_64") { x86_64 } else { generic }
21850}
21851
21852#[no_mangle]
21853pub unsafe extern "C" fn settimeofday(tv: *const c_void, tz: *const c_void) -> c_int {
21854    let r = <Arch as Syscalls>::syscall2(sysno(164, 170), tv as i64, tz as i64);
21855    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21856}
21857
21858#[no_mangle]
21859pub unsafe extern "C" fn stime(t: *const i64) -> c_int {
21860    if t.is_null() { ERRNO = EINVAL; return -1; }
21861    let tv = timeval { tv_sec: *t, tv_usec: 0 };
21862    settimeofday(&tv as *const timeval as *const c_void, core::ptr::null())
21863}
21864
21865#[no_mangle]
21866pub unsafe extern "C" fn times(buf: *mut c_void) -> c_long {
21867    let r = <Arch as Syscalls>::syscall1(sysno(100, 153), buf as i64);
21868    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_long }
21869}
21870
21871#[no_mangle]
21872pub unsafe extern "C" fn splice(fd_in: c_int, off_in: *mut i64, fd_out: c_int, off_out: *mut i64, len: usize, flags: u32) -> isize {
21873    let r = <Arch as Syscalls>::syscall6(sysno(275, 76), fd_in as i64, off_in as i64, fd_out as i64, off_out as i64, len as i64, flags as i64);
21874    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
21875}
21876
21877#[no_mangle]
21878pub unsafe extern "C" fn tee(fd_in: c_int, fd_out: c_int, len: usize, flags: u32) -> isize {
21879    let r = <Arch as Syscalls>::syscall4(sysno(276, 77), fd_in as i64, fd_out as i64, len as i64, flags as i64);
21880    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
21881}
21882
21883#[no_mangle]
21884pub unsafe extern "C" fn statx(dirfd: c_int, path: *const c_char, flags: c_int, mask: u32, buf: *mut c_void) -> c_int {
21885    let r = <Arch as Syscalls>::syscall5(sysno(332, 291), dirfd as i64, path as i64, flags as i64, mask as i64, buf as i64);
21886    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21887}
21888
21889#[no_mangle]
21890pub unsafe extern "C" fn setns(fd: c_int, nstype: c_int) -> c_int {
21891    let r = <Arch as Syscalls>::syscall2(SYS_SETNS, fd as i64, nstype as i64);
21892    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21893}
21894
21895#[no_mangle]
21896pub unsafe extern "C" fn setfsuid(uid: u32) -> c_int {
21897    <Arch as Syscalls>::syscall1(sysno(122, 151), uid as i64) as c_int
21898}
21899
21900#[no_mangle]
21901pub unsafe extern "C" fn setfsgid(gid: u32) -> c_int {
21902    <Arch as Syscalls>::syscall1(sysno(123, 152), gid as i64) as c_int
21903}
21904
21905#[no_mangle]
21906pub unsafe extern "C" fn setregid(rgid: u32, egid: u32) -> c_int {
21907    let r = <Arch as Syscalls>::syscall2(sysno(114, 143), rgid as i64, egid as i64);
21908    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21909}
21910
21911#[no_mangle]
21912pub unsafe extern "C" fn process_vm_readv(pid: c_int, local: *const c_void, liovcnt: usize, remote: *const c_void, riovcnt: usize, flags: u64) -> isize {
21913    let r = <Arch as Syscalls>::syscall6(sysno(310, 270), pid as i64, local as i64, liovcnt as i64, remote as i64, riovcnt as i64, flags as i64);
21914    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
21915}
21916
21917#[no_mangle]
21918pub unsafe extern "C" fn process_vm_writev(pid: c_int, local: *const c_void, liovcnt: usize, remote: *const c_void, riovcnt: usize, flags: u64) -> isize {
21919    let r = <Arch as Syscalls>::syscall6(sysno(311, 271), pid as i64, local as i64, liovcnt as i64, remote as i64, riovcnt as i64, flags as i64);
21920    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as isize }
21921}
21922
21923#[no_mangle]
21924pub unsafe extern "C" fn tcgetwinsize(fd: c_int, ws: *mut c_void) -> c_int {
21925    if fd < 0 || ws.is_null() { ERRNO = EINVAL; return -1; }
21926    let r = <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5413, ws as i64);
21927    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21928}
21929
21930#[no_mangle]
21931pub unsafe extern "C" fn tcsetwinsize(fd: c_int, ws: *const c_void) -> c_int {
21932    if fd < 0 || ws.is_null() { ERRNO = EINVAL; return -1; }
21933    let r = <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5414, ws as i64);
21934    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
21935}
21936
21937#[no_mangle]
21938pub unsafe extern "C" fn sockatmark(fd: c_int) -> c_int {
21939    let mut at: c_int = 0;
21940    let r = <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x8905, &mut at as *mut c_int as i64);
21941    if r < 0 { ERRNO = (-r) as c_int; -1 } else { at }
21942}
21943
21944#[no_mangle]
21945pub unsafe extern "C" fn isastream(fd: c_int) -> c_int {
21946    let mut buf = [0u8; 64];
21947    let r = <Arch as Syscalls>::syscall3(SYS_IOCTL, fd as i64, 0x5401, buf.as_mut_ptr() as i64);
21948    if r < 0 { ERRNO = (-r) as c_int; 0 } else { 1 }
21949}
21950
21951#[no_mangle]
21952pub unsafe extern "C" fn posix_madvise(addr: *mut c_void, len: usize, advice: c_int) -> c_int {
21953    madvise(addr as *mut u8, len, advice)
21954}
21955
21956#[no_mangle]
21957pub unsafe extern "C" fn secure_getenv(name: *const c_char) -> *mut c_char {
21958    if getauxval(23) != 0 { return core::ptr::null_mut(); }
21959    getenv(name)
21960}
21961
21962#[no_mangle]
21963pub unsafe extern "C" fn sigandset(dest: *mut c_ulong, left: *const c_ulong, right: *const c_ulong) -> c_int {
21964    if dest.is_null() || left.is_null() || right.is_null() { return -1; }
21965    *dest = *left & *right;
21966    0
21967}
21968
21969#[no_mangle]
21970pub unsafe extern "C" fn sigorset(dest: *mut c_ulong, left: *const c_ulong, right: *const c_ulong) -> c_int {
21971    if dest.is_null() || left.is_null() || right.is_null() { return -1; }
21972    *dest = *left | *right;
21973    0
21974}
21975
21976#[no_mangle]
21977pub unsafe extern "C" fn sigisemptyset(set: *const c_ulong) -> c_int {
21978    if set.is_null() { return 1; }
21979    (*set == 0) as c_int
21980}
21981
21982#[no_mangle]
21983pub unsafe extern "C" fn sighold(sig: c_int) -> c_int {
21984    let set: c_ulong = 1u64 << (sig - 1) as u32;
21985    sigprocmask(0, &set, core::ptr::null_mut());
21986    0
21987}
21988
21989#[no_mangle]
21990pub unsafe extern "C" fn sigignore(sig: c_int) -> c_int {
21991    let _ = signal(sig, 1);
21992    0
21993}
21994
21995#[no_mangle]
21996pub unsafe extern "C" fn sigrelse(sig: c_int) -> c_int {
21997    let set: c_ulong = 1u64 << (sig - 1) as u32;
21998    sigprocmask(1, &set, core::ptr::null_mut());
21999    0
22000}
22001
22002#[no_mangle]
22003pub unsafe extern "C" fn siginterrupt(sig: c_int, flag: c_int) -> c_int {
22004    let mut sa: sigaction = core::mem::zeroed();
22005    if sigaction(sig, core::ptr::null(), &mut sa) != 0 { return -1; }
22006    if flag != 0 { sa.sa_flags &= !(SA_RESTART as c_ulong); } else { sa.sa_flags |= SA_RESTART as c_ulong; }
22007    sigaction(sig, &sa, core::ptr::null_mut())
22008}
22009
22010#[no_mangle]
22011pub unsafe extern "C" fn sigpause(sig: c_int) -> c_int {
22012    let set: c_ulong = 1u64 << (sig - 1) as u32;
22013    sigsuspend(&set)
22014}
22015
22016#[no_mangle]
22017pub unsafe extern "C" fn semtimedop(semid: c_int, sops: *mut c_void, nsops: usize, timeout: *const timespec) -> c_int {
22018    let r = <Arch as Syscalls>::syscall4(sysno(220, 192), semid as i64, sops as i64, nsops as i64, timeout as i64);
22019    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
22020}
22021
22022#[no_mangle]
22023pub unsafe extern "C" fn wait3(status: *mut c_int, options: c_int, rusage: *mut c_void) -> i32 {
22024    wait4(-1, status, options, rusage) as i32
22025}
22026
22027#[no_mangle]
22028pub unsafe extern "C" fn tempnam(dir: *const c_char, pfx: *const c_char) -> *mut c_char {
22029    let mut path = [0 as c_char; 256];
22030    let mut i = 0;
22031    if !dir.is_null() {
22032        while *dir.add(i) != 0 && i < 200 { path[i] = *dir.add(i); i += 1; }
22033        if i > 0 && path[i-1] != b'/' as c_char { path[i] = b'/' as c_char; i += 1; }
22034    } else {
22035        for &c in b"/tmp/" { path[i] = c as c_char; i += 1; }
22036    }
22037    if !pfx.is_null() {
22038        let mut j = 0;
22039        while *pfx.add(j) != 0 && i < 220 { path[i] = *pfx.add(j); i += 1; j += 1; }
22040    }
22041    for &c in b"XXXXXX" { path[i] = c as c_char; i += 1; }
22042    path[i] = 0;
22043    let fd = mkstemp(path.as_mut_ptr());
22044    if fd < 0 { return core::ptr::null_mut(); }
22045    close(fd);
22046    unlink(path.as_ptr());
22047    let n = strlen(path.as_ptr());
22048    let out = malloc(n + 1) as *mut c_char;
22049    if out.is_null() { return core::ptr::null_mut(); }
22050    core::ptr::copy_nonoverlapping(path.as_ptr(), out, n + 1);
22051    out
22052}
22053
22054#[no_mangle]
22055pub unsafe extern "C" fn putwc(c: u32, f: *mut c_void) -> u32 {
22056    fputwc(c as c_int, f as *mut FILE) as u32
22057}
22058
22059#[no_mangle]
22060pub unsafe extern "C" fn __uflow(f: *mut c_void) -> c_int {
22061    fgetc(f as *mut FILE)
22062}
22063
22064#[no_mangle]
22065pub unsafe extern "C" fn __xmknod(_ver: c_int, path: *const c_char, mode: c_uint, dev: u64) -> c_int {
22066    mknod(path, mode, dev)
22067}
22068
22069#[no_mangle]
22070pub unsafe extern "C" fn __xmknodat(_ver: c_int, dirfd: c_int, path: *const c_char, mode: c_uint, dev: u64) -> c_int {
22071    mknodat(dirfd, path, mode, dev)
22072}
22073
22074#[no_mangle]
22075pub unsafe extern "C" fn name_to_handle_at(dirfd: c_int, path: *const c_char, handle: *mut c_void, mount_id: *mut c_int, flags: c_int) -> c_int {
22076    let r = <Arch as Syscalls>::syscall5(sysno(303, 264), dirfd as i64, path as i64, handle as i64, mount_id as i64, flags as i64);
22077    if r < 0 { ERRNO = (-r) as c_int; -1 } else { 0 }
22078}
22079
22080#[no_mangle]
22081pub unsafe extern "C" fn open_by_handle_at(mount_fd: c_int, handle: *mut c_void, flags: c_int) -> c_int {
22082    let r = <Arch as Syscalls>::syscall3(sysno(304, 265), mount_fd as i64, handle as i64, flags as i64);
22083    if r < 0 { ERRNO = (-r) as c_int; -1 } else { r as c_int }
22084}
22085
22086#[no_mangle]
22087pub unsafe extern "C" fn dn_skipname(comp: *const u8, eom: *const u8) -> c_int {
22088    let p = dns_skip_name(comp, eom);
22089    if p <= eom { (p as isize - comp as isize) as c_int } else { -1 }
22090}
22091
22092#[no_mangle]
22093pub unsafe extern "C" fn dn_comp(exp: *const c_char, dst: *mut u8, dstsiz: c_int, _dnptrs: *mut *mut u8, _lastdnptr: *mut *mut u8) -> c_int {
22094    if exp.is_null() || dst.is_null() || dstsiz <= 0 { return -1; }
22095    let mut o = 0usize;
22096    let mut p = exp;
22097    loop {
22098        let start = p;
22099        while *p != 0 && *p != b'.' as c_char { p = p.add(1); }
22100        let l = p as usize - start as usize;
22101        if l > 63 || o + l + 2 > dstsiz as usize { return -1; }
22102        *dst.add(o) = l as u8; o += 1;
22103        core::ptr::copy_nonoverlapping(start as *const u8, dst.add(o), l);
22104        o += l;
22105        if *p == 0 { break; }
22106        p = p.add(1);
22107    }
22108    if o + 1 > dstsiz as usize { return -1; }
22109    *dst.add(o) = 0;
22110    (o + 1) as c_int
22111}
22112
22113// ============================================================
22114// Shadow database
22115// ============================================================
22116
22117#[repr(C)]
22118#[derive(Copy, Clone)]
22119pub struct Spwd {
22120    pub sp_namp: *mut c_char,
22121    pub sp_pwdp: *mut c_char,
22122    pub sp_lstchg: c_long,
22123    pub sp_min: c_long,
22124    pub sp_max: c_long,
22125    pub sp_warn: c_long,
22126    pub sp_inact: c_long,
22127    pub sp_expire: c_long,
22128    pub sp_flag: c_ulong,
22129}
22130
22131static mut SPWD_ENT: Spwd = Spwd {
22132    sp_namp: core::ptr::null_mut(), sp_pwdp: core::ptr::null_mut(),
22133    sp_lstchg: 0, sp_min: 0, sp_max: 0, sp_warn: 0, sp_inact: 0,
22134    sp_expire: 0, sp_flag: 0,
22135};
22136static mut SPWD_BUF: [c_char; 1024] = [0; 1024];
22137static mut SPWD_FILE: *mut FILE = core::ptr::null_mut();
22138
22139unsafe fn parse_spwd(line: *const c_char, ent: *mut Spwd, buf: *mut c_char, buflen: usize) -> bool {
22140    let mut src = line;
22141    let mut o = 0usize;
22142    let mut fields: [*mut c_char; 9] = [core::ptr::null_mut(); 9];
22143    let mut n = 0usize;
22144    while n < 9 {
22145        let start = o;
22146        while *src != 0 && *src != b':' as c_char {
22147            if o + 1 >= buflen { return false; }
22148            *buf.add(o) = *src;
22149            o += 1;
22150            src = src.add(1);
22151        }
22152        *buf.add(o) = 0;
22153        o += 1;
22154        fields[n] = buf.add(start);
22155        n += 1;
22156        if *src == 0 { break; }
22157        src = src.add(1);
22158    }
22159    if n < 9 { return false; }
22160    (*ent).sp_namp = fields[0];
22161    (*ent).sp_pwdp = fields[1];
22162    (*ent).sp_lstchg = crate::strtol(fields[2], core::ptr::null_mut(), 10) as c_long;
22163    (*ent).sp_min = crate::strtol(fields[3], core::ptr::null_mut(), 10) as c_long;
22164    (*ent).sp_max = crate::strtol(fields[4], core::ptr::null_mut(), 10) as c_long;
22165    (*ent).sp_warn = crate::strtol(fields[5], core::ptr::null_mut(), 10) as c_long;
22166    (*ent).sp_inact = crate::strtol(fields[6], core::ptr::null_mut(), 10) as c_long;
22167    (*ent).sp_expire = crate::strtol(fields[7], core::ptr::null_mut(), 10) as c_long;
22168    (*ent).sp_flag = crate::strtoul(fields[8], core::ptr::null_mut(), 10) as c_ulong;
22169    true
22170}
22171
22172#[no_mangle]
22173pub unsafe extern "C" fn setspent() {
22174    endspent();
22175    SPWD_FILE = crate::fopen(b"/etc/shadow\0".as_ptr() as *const c_char, b"r\0".as_ptr() as *const c_char);
22176}
22177
22178#[no_mangle]
22179pub unsafe extern "C" fn endspent() {
22180    if !SPWD_FILE.is_null() { crate::fclose(SPWD_FILE); SPWD_FILE = core::ptr::null_mut(); }
22181}
22182
22183#[no_mangle]
22184pub unsafe extern "C" fn getspent() -> *mut Spwd {
22185    if SPWD_FILE.is_null() { setspent(); if SPWD_FILE.is_null() { return core::ptr::null_mut(); } }
22186    let mut line = [0 as c_char; 1024];
22187    loop {
22188        if crate::fgets(line.as_mut_ptr(), 1024, SPWD_FILE).is_null() { return core::ptr::null_mut(); }
22189        if parse_spwd(line.as_ptr(), &raw mut SPWD_ENT, SPWD_BUF.as_mut_ptr(), SPWD_BUF.len()) {
22190            return &raw mut SPWD_ENT;
22191        }
22192    }
22193}
22194
22195#[no_mangle]
22196pub unsafe extern "C" fn fgetspent(f: *mut FILE) -> *mut Spwd {
22197    if f.is_null() { return core::ptr::null_mut(); }
22198    let mut line = [0 as c_char; 1024];
22199    loop {
22200        if crate::fgets(line.as_mut_ptr(), 1024, f).is_null() { return core::ptr::null_mut(); }
22201        if parse_spwd(line.as_ptr(), &raw mut SPWD_ENT, SPWD_BUF.as_mut_ptr(), SPWD_BUF.len()) {
22202            return &raw mut SPWD_ENT;
22203        }
22204    }
22205}
22206
22207#[no_mangle]
22208pub unsafe extern "C" fn getspnam(name: *const c_char) -> *mut Spwd {
22209    if name.is_null() { return core::ptr::null_mut(); }
22210    setspent();
22211    loop {
22212        let sp = getspent();
22213        if sp.is_null() { break; }
22214        if crate::strcmp((*sp).sp_namp as *const u8, name as *const u8) == 0 { endspent(); return sp; }
22215    }
22216    endspent();
22217    core::ptr::null_mut()
22218}
22219
22220#[no_mangle]
22221pub unsafe extern "C" fn getspnam_r(name: *const c_char, sp: *mut Spwd, _buf: *mut c_char, _buflen: usize, result: *mut *mut Spwd) -> c_int {
22222    if result.is_null() { return EINVAL; }
22223    let p = getspnam(name);
22224    if p.is_null() { *result = core::ptr::null_mut(); 0 } else { *sp = *p; *result = sp; 0 }
22225}
22226
22227#[no_mangle]
22228pub unsafe extern "C" fn putspent(sp: *const Spwd, f: *mut FILE) -> c_int {
22229    if sp.is_null() || f.is_null() { return -1; }
22230    crate::fprintf(f, b"%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%lu\\n\0".as_ptr() as *const c_char,
22231        (*sp).sp_namp, (*sp).sp_pwdp, (*sp).sp_lstchg, (*sp).sp_min, (*sp).sp_max,
22232        (*sp).sp_warn, (*sp).sp_inact, (*sp).sp_expire, (*sp).sp_flag)
22233}
22234
22235#[no_mangle]
22236pub unsafe extern "C" fn getgrouplist(user: *const c_char, group: u32, groups: *mut u32, ngroups: *mut i32) -> c_int {
22237    if user.is_null() || groups.is_null() || ngroups.is_null() { return -1; }
22238    let max = *ngroups as usize;
22239    let mut n = 0usize;
22240    if n < max { *groups.add(n) = group; }
22241    n += 1;
22242    setgrent();
22243    loop {
22244        let g = getgrent();
22245        if g.is_null() { break; }
22246        if (*g).gr_gid == group { continue; }
22247        let mut found = false;
22248        let mut i = 0;
22249        while !(*(*g).gr_mem.add(i)).is_null() {
22250            if crate::strcmp(*(*g).gr_mem.add(i) as *const u8, user as *const u8) == 0 {
22251                found = true;
22252                break;
22253            }
22254            i += 1;
22255        }
22256        if found {
22257            if n < max { *groups.add(n) = (*g).gr_gid; }
22258            n += 1;
22259        }
22260    }
22261    endgrent();
22262    if n > max { *ngroups = n as i32; return -1; }
22263    *ngroups = n as i32;
22264    n as c_int
22265}